commit f9ebd743cc16dfebbe6ec772f75ea616c5466032 Author: nakst <> Date: Fri Aug 13 21:22:26 2021 +0100 hide email diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24df049 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.swp +*.swo +tags +.project.gf + +bin/ +cross/ +old/ +root/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a3366da --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,238 @@ +# Contributing Guidelines + +## Map + +- `apps/` Builtin applications. +- `boot/` Contains files for booting the operating system. + - `x86/` ...on x86. + - `esfs-stage1.s` Loads `loader.s` from the start of a EsFS volume and passes control to it. + - `esfs-stage2.s` Provides basic read-only EsFS functions for `loader.s`. + - `loader.s` Loads the kernel and passes control to it. + - `mbr.s` Finds and loads a bootable partition. + - `uefi.c` UEFI bootloader first stage. + - `uefi_loader.s` UEFI bootloader second stage. + - `vbe.s` Sets the VBE graphics mode. +- `desktop/` Contains files for Desktop, which provides both the desktop environment, and a layer between applications and the kernel. + - `api.cpp` API initialisation and internal messaging. + - `api.s` API functions that must be implemented in assembly. + - `calculator.cpp` Evaluates basic math expressions. + - `crti.s, ctrn.s` Global constructors and destructors setup. + - `cstdlib.cpp` Provides the system call interface for the POSIX subsystem. + - `desktop.cpp` Desktop. Manages windows and the taskbar. + - `glue.cpp` Entry point for applications using the POSIX subsystem. + - `gui.cpp` The GUI. + - `icons.header` A list of available icons. + - `list_view.cpp` A list view control for the GUI. + - `os.header` The header file containing the API's definitions. + - `prefix.h` The header file prefix for C/C++. + - `renderer.cpp` Provides visual style management and software rendering. + - `renderer2.cpp` Vector graphics rendering. + - `start.cpp` Entry point for all applications. + - `syscall.cpp` Kernel system call wrappers. + - `text.cpp` Text rendering and text-based GUI elements. +- `drivers/` Kernel drivers. + - `acpi.cpp` A layer between the kernel and ACPICA. Also starts application processors on SMP systems. + - `ata.cpp` A ATA/IDE driver. + - `esfs2.cpp` The EssenceFS filesystem driver. + - `fat.cpp` The FAT12 filesystem driver. + - `hda.cpp` Intel HD Audio driver. + - `pci.cpp` Finds devices on the PCI bus. + - `ps2.cpp` A driver for PS/2 keyboard and mice. + - `vbe.cpp` Basic VBE SVGA driver. + - `vga.cpp` Basic VGA driver. +- `kernel/` The kernel and its drivers. + - `audio.cpp` Audio system. + - `config.mtsrc` System configuration. Describes all the modules that should be built, and when they should be loaded. + - `devices.cpp` The device and IO manager. + - `elf.cpp` Parses and loads ELF executables and kernel modules. + - `graphics.cpp` Graphics system. Mostly deprecated. + - `kernel.h` Internal kernel definitions. Includes all other source files in the kernel. + - `main.cpp` Kernel initilisation and shutdown. + - `memory.cpp` Physical, virtual and shared memory management. + - `module.h` Kernel API available to driver modules. + - `objects.cpp` Manages object and handles shared between the kernel and applications. + - `posix.cpp` The (optional) POSIX subsystem. + - `scheduler.cpp` A scheduler, and manager of threads and processes. + - `symbols.cpp` Locating kernel symbols. + - `synchronisation.cpp` Defines synchronisation primitives. Closely linked with the scheduler. + - `syscall.cpp` Defers system calls to other parts of the kernel. + - `terminal.cpp` Kernel debugging and serial output. + - `vfs.cpp` The virtual filesystem. + - `windows.cpp` The window manager. Passes messages from HID devices to applications. + - `x86_64.cpp` Code for the x64 architecture. + - `x86_64.h` Definitions specific to the x64 architecture. + - `x86_64.s` Assembly code for the x64 architecture. +- `ports/` A mess of ported applications. Enter with caution. +- `res/` Resources, such as fonts and visual styles. + - `Fonts` Fonts used by the GUI. + - `Icons` Icon packs used by the GUI. + - `Sample Images` Sample images. + - `Themes` Themes for the user interface.. +- `shared/` Shared code between the componenets of the operating system. + - `arena.cpp` Fixed-size allocations. + - `avl_tree.cpp` Balanced binary tree, and maps. + - `bitset.cpp` Managing sparse bitsets. + - `common.cpp` Common functions. + - `format_string.cpp` Locale-dependent text formatter. + - `hash.cpp` Hash functions. + - `heap.cpp` Heap allocator. + - `linked_list.cpp` Doubly-linked lists. + - `stb_ds.h`, `stb_image.h`, `stb_sprintf.h` STB libraries. + - `style_parser.cpp` Parsing visual style specifiers. + - `unicode.cpp` Functions for managing Unicode and UTF-8 strings. + - `vga_font.cpp` A fallback bitmap font. +- `util/` Utilities for building the operating system. + - `build.c` The build system. + - `esfs2.h` A version of EssenceFS for use on linux from the command line. + - `header_generator.c` Language independent header generation. + - `render_svg.c` Renders SVG icons. + +## Code Style + +Functions and structures names use `PascalCase`. +Variables use `camelCase`, while constants and macros use `SCREAMING_SNAKE_CASE`. + +Tabs are `\t`, and are 8 characters in size. + +Braces are placed at the end of the line: + + if (a > b) { + ... + } + +Blocks are always surrounded by newlines, and always have braces. + + int x = 5; + + if (x < 6) { + x++; // Postfix operators are preferred. + } + +Exception: If there are lot of short, linked blocks, then they may be written like this- + + if (width == DIMENSION_PUSH) { bool a = grid->widths[i] == DIMENSION_PUSH; grid->widths[i] = DIMENSION_PUSH; if (!a) pushH++; } + else if (grid->widths[i] < width && grid->widths[i] != DIMENSION_PUSH) grid->widths[i] = width; + if (height == DIMENSION_PUSH) { bool a = grid->heights[j] == DIMENSION_PUSH; grid->heights[j] = DIMENSION_PUSH; if (!a) pushV++; } + else if (grid->heights[j] < height && grid->heights[j] != DIMENSION_PUSH) grid->heights[j] = height; + +Function names are always descriptive, and use prepositions and conjuctions if neccesary. + + EsFileReadAll // Symbols provided by the API are prefixed with Es-. + EsDrawSurface + EsMemoryZero + +Variable names are usually descriptive, but sometimes shortened names are used for short-lived variables. + + EsMessage m = {}; + m.type = OS_MESSAGE_MEASURE; + EsMessagePost(&m); + +Operators are padded with spaces on either side. + + bounds.left = (grid->bounds.left + grid->bounds.right) / 2 - 4; + +A space should be placed between a cast and its expression. + + int x = (float) y; + +Although the operating system is written in C++, most C++ features are avoided. +However, the kernel uses a lot of member functions. + + struct Window { + void Update(bool fromUser); + void SetCursorStyle(OSCursorStyle style); + void NeedWMTimer(int hz); + void Destroy(); + bool Move(OSRectangle &newBounds); + void ClearImage(); + + Mutex mutex; // Mutex for drawing to the window. Also needed when moving the window. + Surface *surface; + OSPoint position; + size_t width, height; + ... + } + +Default arguments often provided as functions grow over time. + +There is no limit on function size. However, you should avoid regularly exceeding 120 columns. + +Pointers are declared like this: `Type *name;`. + +Identifiers may be prefixed with `i`, `e` or `c` to indicate inclusive, exclusive or C-style-zero-terminated-string respectively. + +## Kernel and Driver Development + +See `module.h` for definitions available to driver developers. See `drivers/fat.cpp` and `drivers/ata.cpp` for simple examples of the driver API. + +The following subroutines may be of interest: + + void KWaitMicroseconds(uint64_t mcs); // Spin until a given number of microseconds have elapsed. + void EsPrint(const char *format, ...); // Print a message to serial output. (Ctrl+Alt+3 in Qemu) + void KernelPanic(const char *format, ...); // Print a message and halt the OS. + Defer(); // Defer a statement. Deferred statements will be executed in reverse order when they go out of scope. + size_t EsCStringLength(const char *string); // Get the length of a zero-terminated string. + void EsMemoryCopy(void *destination, const void *source, size_t bytes); // Copy memory forwards. + void EsMemoryZero(void *destination, size_t bytes); // Zero a buffer. + void EsMemoryMove(void *start, void *end, intptr_t amount, bool zeroEmptySpace); // Move a memory region left (amount < 0) or right (amount > 0). + int EsMemoryCopy(const void *a, const void *b, size_t bytes); // Compare two memory regions. Returns 0 if equal. + uint8_t EsSumBytes(uint8_t *source, size_t bytes); // Calculate the 8-bit sum of the bytes in a buffer. + size_t EsStringFormat(char *buffer, size_t bufferLength, const char *format, ...); // Format a string. Returns the length. + uint8_t EsGetRandomByte(); // Get a non-secure random byte. + void EsSort(void *base, size_t count, size_t size, int (*compare)(const void *, const void *, void *), void *callbackArgument); // Sort an array of count items of size size. + uint32_t CalculateCRC32(void *buffer, size_t length); // Calculate the CRC32 checksum of a buffer. + void ProcessorEnableInterrupts(); // Enable interrupts. + void ProcessorDisableInterrupts(); // Disable interrupts. Critical interrupts, such as TLB shootdown IPIs, will remain enabled. + void ProcessorOut(uint16_t port, uint_t value); // Write to an IO port. + uint_t ProcessorIn(uint16_t port); // Read from an IO port. + uint64_t ProcessorReadTimeStamp(); // Read the time stamp in ticks. acpi.timestampTicksPerMs gives the number of ticks per millisecond. + bool KRegisterIRQ(uintptr_t interruptIndex, IRQHandler handler, void *context, const char *cOwner); // Register an IRQ handler. Returns false if the IRQ could not be registered. The handler should return false if its devices was not responsible for the IRQ. + void *MMMapPhysical(MMSpace *space /* = kernelMMSpace */, uintptr_t offset, size_t bytes); // Memory mapped IO. + void *EsHeapAllocate(size_t size, bool zero); // Allocate memory from the heap. + void EsHeapFree(void *pointer); // Free memory from the heap. + bool KThreadCreate(const char *cName, void (*startAddress)(uintptr_t), uintptr_t argument = 0); // Create a thread. + +Synchronisation: + + void Mutex::Acquire(); + void Mutex::Release(); + void Mutex::AssertLocked(); + + void Spinlock::Acquire(); // Disables interrupts. + void Spinlock::Release(); + void Spinlock::AssertLocked(); + + bool Event::Set(); + void Event::Reset(); + bool Event::Pool(); + bool Event::Wait(uintptr_t timeoutMs); // Return false on timeout. + // event.autoReset determines whether the event will automatically reset after Poll() or Wait() return. + +Linked lists: + + LinkedList::InsertStart(LinkedItem *item); // Insert an item at the start of a linked list. + LinkedList::InsertEnd(LinkedItem *item); // Insert an item at the end of a linked list. + LinkedList::Remove(LinkedItem *item); // Remove an item from a linked list. + + struct LinkedList { + LinkedItem *firstItem; // The start of the linked list. + LinkedItem *lastItem; // The end of the linked list. + size_t count; // The number of items in the linked list. + } + + struct LinkedItem { + LinkedItem *previousItem; // The previous item in the linked list. + LinkedItem *nextItem; // The next item in the linked list. + LinkedList *list; // The list the item is in. + T *thisItem; // A pointer to the item itself. + } + +## Contributors + +Put your name here! + +- nakst +- Brett R. Toomey +- vtlmks +- Aleksander Birkeland + diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..500b2c3 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,32 @@ +MIT License + +Copyright (c) 2017-2021 nakst and other contributors (see CONTRIBUTING.md). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +This project also include the work of other projects. +All trademarks are registered trademarks of their respective owners. +They licenses may be found in the following files: + - util/nanosvg.h + - shared/stb_image.h, shared/stb_sprintf.h, shared/stb_ds.h and util/stb_truetype.h + - res/Fonts/Hack License.txt, res/Fonts/Inter License.txt + - res/Icons/elementary Icons License.txt + - res/Media/Licenses.txt + - Ported applications have their licenses in their respective folders. +Please tell me if I've forgotten something! diff --git a/README.md b/README.md new file mode 100644 index 0000000..878c8f2 --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +# **Essence** — An Operating System + +![Screenshot of the OS running in an emulator, showing File Manager, and the new tab screen.](https://essence.handmade.network/static/media/image/p-essence-s1.png) +![Screenshot of the OS running in an emulator, showing GCC running under the POSIX subsystem.](https://essence.handmade.network/static/media/image/p-essence-s3.png) +![Screenshot of the OS running in an emulator, showing the shutdown dialog.](https://essence.handmade.network/static/media/image/p-essence-s5.png) + +## Support + +To support development, you can donate to my Patreon: https://www.patreon.com/nakst. + +## Features + +Kernel +* Audio mixer. +* Filesystem independent cache manager. +* Memory manager with shared memory, memory-mapped files and multithreaded paging zeroing and working set balancing. +* Networking stack for TCP/IP. +* Scheduler with multiple priority levels and priority inversion. +* On-demand module loading. +* Virtual filesystem. +* Window manager. +* Optional POSIX subsystem, capable of running GCC and some Busybox tools. + +Applications +* File Manager +* Text Editor +* IRC Client +* System Monitor + +Ports +* Bochs +* GCC and Binutils +* FFmpeg +* Mesa (for software-rendered OpenGL) +* Musl + +Drivers +* Power management: ACPI with ACPICA. +* Secondary storage: IDE, AHCI and NVMe. +* Graphics: BGA and SVGA. +* Read-write filesystems: EssenceFS. +* Read-only filesystems: Ext2, FAT, NTFS, ISO9660. +* Audio: HD Audio. +* NICs: 8254x. +* USB: XHCI, bulk storage devices, human interface devices. + +Desktop +* Custom user interface library. +* Software vector renderer with complex animation support. +* Tabbed windows. +* Multi-lingual text rendering and layout with FreeType and Harfbuzz. + +## Discussion + +Visit https://essence.handmade.network/forums. + +## Building + +**Warning: This software is still in development. Expect bugs.** + +### Linux + +Download this project's source. + + git clone --depth=1 https://gitlab.com/nakst/essence.git/ + +Start the build system. + + ./start.sh + +Follow the on-screen instructions to build a cross compiler. + +Once complete, you can test the operating system in an emulator. +* Please note that by default a checked build is produced, which runs additional checks at runtime (such as heap validation on every allocation and deallocation). This may impact the performance during testing. +* If you have Qemu installed, run `t2` in the build system. +* If you have VirtualBox installed, make a 128MB drive called `vbox.vdi` in the `bin` folder, attach it as a to a virtual machine called "Essence" (choose "Windows 7 64-bit" as the OS), and run `v` in the build system. + +## Configuration + +From within the build system, run the command `config` to open the configuration editor. Click an option to change its value, and then click the `Save` button. You changes are saved locally, and will not be uploaded by Git. Not all configurations are likely to work; if you don't know what you're doing, it's probably best to stick with the defaults. + +## Generating the API header + +If you want your project to target Essence, you need to generate the API header for your programming language of choice. + + g++ -o bin/build_core util/build_core.c + bin/build_core headers + +Currently supported languages are 'c' (also works for C++), 'zig' and 'odin'. + +There is currently no documentation for the API; for examples of how to use the API, consult the standard applications in the `apps/` folder of the source tree. A minimal application is demonstrated in `apps/hello.c` and `apps/hello.ini`. By placing your application's `.ini` file in the `apps/` folder, it will be automatically built by the build system. diff --git a/apps/bochs.ini b/apps/bochs.ini new file mode 100644 index 0000000..7a7e168 --- /dev/null +++ b/apps/bochs.ini @@ -0,0 +1,17 @@ +[general] +name=Bochs +icon=icon_applications_development +permission_posix_subsystem=1 + +[build] +custom_compile_command=cp root/Applications/POSIX/bin/bochs root/Applications/Bochs.esx +require=root/Applications/POSIX/bin/bochs + +[@file_type] +extension=bochsrc +name=Bochs configuration +icon=icon_applications_development + +[@handler] +extension=bochsrc +action=open diff --git a/apps/file_manager.ini b/apps/file_manager.ini new file mode 100644 index 0000000..d96242c --- /dev/null +++ b/apps/file_manager.ini @@ -0,0 +1,114 @@ +[general] +name=File Manager +icon=icon_system_file_manager +permission_all_files=1 +use_single_process=1 + +[build] +source=apps/file_manager/main.cpp + +[@file_type] +extension=esx +name=Executable +icon=icon_application_default_icon + +[@file_type] +extension=ini +name=Configuration file +icon=icon_application_x_desktop + +[@file_type] +extension=esx_symbols +name=Debugging data +icon=icon_extension + +[@file_type] +extension=exe +name=PC executable +icon=icon_application_x_ms_dos_executable + +[@file_type] +extension=png +name=PNG image +icon=icon_image_x_generic + +[@file_type] +extension=jpg +name=JPG image +icon=icon_image_x_generic + +[@file_type] +extension=ttf +name=TrueType font +icon=icon_font_x_generic + +[@file_type] +extension=otf +name=OpenType font +icon=icon_font_x_generic + +[@file_type] +extension=a +name=Static library +icon=icon_extension + +[@file_type] +extension=dat +name=Database +icon=icon_office_database + +[@file_type] +extension=icon_pack +name=Icon pack +icon=icon_package_x_generic + +[@file_type] +extension=ekm +name=Kernel module +icon=icon_extension + +[@file_type] +extension=o +name=Binary object +icon=icon_extension + +[@file_type] +extension=c +name=C source +icon=icon_text_x_csrc + +[@file_type] +extension=cpp +name=C++ source +icon=icon_text_x_csrc + +[@file_type] +extension=h +name=C header +icon=icon_text_x_csrc + +[@file_type] +extension=txt +name=Text file +icon=icon_text + +[@file_type] +extension=md +name=Markdown file +icon=icon_text_markdown + +[@file_type] +extension=ogg +name=OGG audio +icon=icon_audio_x_generic + +[@file_type] +extension=mp4 +name=MP4 video +icon=icon_view_list_video_symbolic + +[@file_type] +extension=wav +name=Wave audio +icon=icon_audio_x_generic +ES_ICON_AUDIO_X_GENERIC diff --git a/apps/file_manager/commands.cpp b/apps/file_manager/commands.cpp new file mode 100644 index 0000000..556d17d --- /dev/null +++ b/apps/file_manager/commands.cpp @@ -0,0 +1,170 @@ +void CommandRename(Instance *instance, EsElement *, EsCommand *) { + intptr_t index = -1; + + for (uintptr_t i = 0; i < instance->listContents.Length(); i++) { + ListEntry *entry = &instance->listContents[i]; + + if (entry->selected) { + index = i; + break; + } + } + + EsAssert(index != -1); + + instance->rename.textbox = EsListViewCreateInlineTextbox(instance->list, 0, index, ES_LIST_VIEW_INLINE_TEXTBOX_COPY_EXISTING_TEXT); + instance->rename.index = index; + + FolderEntry *entry = instance->listContents[index].entry; + + if (entry->extensionOffset != entry->nameBytes) { + // Don't include the file extension in the initial selection. + EsTextboxSetSelection(instance->rename.textbox, 0, 0, 0, entry->extensionOffset - 1); + } + + instance->rename.textbox->messageUser = [] (EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_TEXTBOX_EDIT_END) { + Instance *instance = element->instance; + + String name = {}; + name.text = EsTextboxGetContents((EsTextbox *) element, &name.bytes); + name.allocated = name.bytes; + + if (!name.bytes || message->endEdit.rejected) { + StringDestroy(&name); + } else { + FolderEntry *entry = instance->listContents[instance->rename.index].entry; + String oldName = entry->GetName(); + + BlockingTaskQueue(instance, { + .string = name, + .string2 = StringDuplicate(oldName), + .cDescription = interfaceString_FileManagerRenameTask, + + .callback = [] (Instance *instance, Task *task) { + if (StringEquals(task->string, task->string2)) { + task->result = ES_SUCCESS; + } else { + task->result = instance->folder->itemHandler->renameItem(instance->folder, task->string2, task->string); + } + }, + + .then = [] (Instance *instance, Task *task) { + if (task->result != ES_SUCCESS) { + InstanceReportError(instance, ERROR_RENAME_ITEM, task->result); + } else { + Folder *folder = instance->folder; + + size_t newPathBytes; + char *newPath = EsStringAllocateAndFormat(&newPathBytes, "%s%s", STRFMT(instance->folder->path), STRFMT(task->string)); + size_t oldPathBytes; + char *oldPath = EsStringAllocateAndFormat(&oldPathBytes, "%s%s", STRFMT(instance->folder->path), STRFMT(task->string2)); + + FolderPathMoved(instance, { .text = oldPath, .bytes = oldPathBytes }, { .text = newPath, .bytes = newPathBytes }); + + EsDirectoryChild information = {}; + EsPathQueryInformation(newPath, newPathBytes, &information); + uint64_t id = FolderRemoveEntryAndUpdateInstances(folder, STRING(task->string2)); + FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance, false, id); + + EsHeapFree(oldPath); + EsHeapFree(newPath); + } + + StringDestroy(&task->string); + StringDestroy(&task->string2); + }, + }); + } + + EsElementDestroy(element); + } + + return 0; + }; +} + +void CommandNewFolder(Instance *instance, EsElement *, EsCommand *) { + String name = StringAllocateAndFormat("%z", interfaceString_FileManagerNewFolderName); + + BlockingTaskQueue(instance, { + .string = name, + .cDescription = interfaceString_FileManagerNewFolderTask, + + .callback = [] (Instance *instance, Task *task) { + task->result = instance->folder->itemHandler->createChildFolder(instance->folder, &task->string, true); + }, + + .then = [] (Instance *instance, Task *task) { + if (task->result != ES_SUCCESS) { + InstanceReportError(instance, ERROR_NEW_FOLDER, task->result); + } else { + Folder *folder = instance->folder; + EsDirectoryChild information = {}; + information.type = ES_NODE_DIRECTORY; + FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance, false); + CommandRename(instance, nullptr, nullptr); + } + + StringDestroy(&task->string); + }, + }); +} + +void InstanceRegisterCommands(Instance *instance) { + uint32_t stableCommandID = 1; + + EsCommandRegister(&instance->commandGoBackwards, instance, [] (Instance *instance, EsElement *, EsCommand *) { + EsAssert(instance->pathBackwardHistory.Length()); + HistoryEntry entry = instance->pathBackwardHistory.Pop(); + StringDestroy(&instance->delayedFocusItem); + instance->delayedFocusItem = entry.focusedItem; + InstanceLoadFolder(instance, entry.path, LOAD_FOLDER_BACK); + }, stableCommandID++, "Backspace|Alt+Left"); + + EsCommandRegister(&instance->commandGoForwards, instance, [] (Instance *instance, EsElement *, EsCommand *) { + EsAssert(instance->pathForwardHistory.Length()); + HistoryEntry entry = instance->pathForwardHistory.Pop(); + StringDestroy(&instance->delayedFocusItem); + instance->delayedFocusItem = entry.focusedItem; + InstanceLoadFolder(instance, entry.path, LOAD_FOLDER_FORWARD); + }, stableCommandID++, "Alt+Right"); + + EsCommandRegister(&instance->commandGoParent, instance, [] (Instance *instance, EsElement *, EsCommand *) { + String parent = PathGetParent(instance->folder->path); + InstanceLoadFolder(instance, StringDuplicate(parent)); + }, stableCommandID++, "Alt+Up"); + + EsCommandRegister(&instance->commandRefresh, instance, [] (Instance *instance, EsElement *, EsCommand *) { + EsMutexAcquire(&loadedFoldersMutex); + FolderRefresh(instance->folder); + EsMutexRelease(&loadedFoldersMutex); + }, stableCommandID++, "F5"); + + EsCommandRegister(&instance->commandNewFolder, instance, CommandNewFolder, stableCommandID++, "Ctrl+Shift+N"); + EsCommandRegister(&instance->commandRename, instance, CommandRename, stableCommandID++, "F2"); + + EsCommandRegister(&instance->commandViewDetails, instance, [] (Instance *instance, EsElement *, EsCommand *) { + instance->viewSettings.viewType = VIEW_DETAILS; + InstanceRefreshViewType(instance); + InstanceViewSettingsUpdated(instance); + }, stableCommandID++); + + EsCommandRegister(&instance->commandViewTiles, instance, [] (Instance *instance, EsElement *, EsCommand *) { + instance->viewSettings.viewType = VIEW_TILES; + InstanceRefreshViewType(instance); + InstanceViewSettingsUpdated(instance); + }, stableCommandID++); + + EsCommandRegister(&instance->commandViewThumbnails, instance, [] (Instance *instance, EsElement *, EsCommand *) { + instance->viewSettings.viewType = VIEW_THUMBNAILS; + InstanceRefreshViewType(instance); + InstanceViewSettingsUpdated(instance); + }, stableCommandID++); + + EsCommandSetDisabled(&instance->commandViewDetails, false); + EsCommandSetDisabled(&instance->commandViewTiles, false); + EsCommandSetDisabled(&instance->commandViewThumbnails, false); + + EsCommandSetCheck(&instance->commandViewDetails, ES_CHECK_CHECKED, false); +} diff --git a/apps/file_manager/folder.cpp b/apps/file_manager/folder.cpp new file mode 100644 index 0000000..b30c270 --- /dev/null +++ b/apps/file_manager/folder.cpp @@ -0,0 +1,597 @@ +#define NAMESPACE_HANDLER_FILE_SYSTEM (1) +#define NAMESPACE_HANDLER_DRIVES_PAGE (2) +#define NAMESPACE_HANDLER_ROOT (3) // Acts as a container handler where needed. +#define NAMESPACE_HANDLER_INVALID (4) // For when a folder does not exist. + +EsMutex loadedFoldersMutex; +Array loadedFolders; + +#define MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES (20) +Array foldersWithNoAttachedInstances; + +///////////////////////////////// + +bool FSDirHandlesPath(String path) { + EsDirectoryChild information; + + if (EsPathQueryInformation(STRING(path), &information)) { + return information.type == ES_NODE_DIRECTORY; + } else { + return false; + } +} + +EsError FSDirCreateChildFolder(Folder *folder, String *name, bool findUniqueName) { + size_t pathBytes; + char *path; + + if (findUniqueName) { + const char *extra = " "; + path = EsStringAllocateAndFormat(&pathBytes, "%s%s%z", STRFMT(folder->path), STRFMT((*name)), extra); + pathBytes = EsPathFindUniqueName(path, pathBytes - EsCStringLength(extra), pathBytes); + StringDestroy(name); + *name = StringAllocateAndFormat("%s", pathBytes - folder->path.bytes, path + folder->path.bytes); + } else { + path = EsStringAllocateAndFormat(&pathBytes, "%s%s", STRFMT(folder->path), STRFMT((*name))); + } + + EsError error = EsPathCreate(path, pathBytes, ES_NODE_DIRECTORY, false); + EsHeapFree(path); + return error; +} + +EsError FSDirRenameItem(Folder *folder, String oldName, String newName) { + size_t oldPathBytes; + char *oldPath = EsStringAllocateAndFormat(&oldPathBytes, "%s%s", STRFMT(folder->path), STRFMT(oldName)); + + size_t newPathBytes; + char *newPath = EsStringAllocateAndFormat(&newPathBytes, "%s%s", STRFMT(folder->path), STRFMT(newName)); + + EsError error = EsPathMove(oldPath, oldPathBytes, newPath, newPathBytes); + + EsHeapFree(oldPath); + EsHeapFree(newPath); + + return error; +}; + +EsError FSDirEnumerate(Folder *folder) { + // Get the initial directory children. + // TODO Recurse mode. + + EsNodeType type; + + if (!EsPathExists(STRING(folder->path), &type) || type != ES_NODE_DIRECTORY) { + return ES_ERROR_FILE_DOES_NOT_EXIST; + } + + EsDirectoryChild *buffer = nullptr; + ptrdiff_t _entryCount = EsDirectoryEnumerateChildren(STRING(folder->path), &buffer); + + if (ES_CHECK_ERROR(_entryCount)) { + EsHeapFree(buffer); + return (EsError) _entryCount; + } + + FolderAddEntries(folder, buffer, _entryCount); + EsHeapFree(buffer); + + return ES_SUCCESS; +} + +void FSDirGetTotalSize(Folder *folder) { + EsDirectoryChild information; + + if (EsPathQueryInformation(STRING(folder->path), &information)) { + folder->spaceUsed = information.fileSize; + folder->spaceTotal = 0; + } +} + +String FSDirGetPathForChildFolder(Folder *folder, String item) { + return StringAllocateAndFormat("%s%s/", STRFMT(folder->path), STRFMT(item)); +} + +///////////////////////////////// + +bool DrivesPageHandlesPath(String path) { + return StringEquals(path, StringFromLiteralWithSize(INTERFACE_STRING(FileManagerDrivesPage))); +} + +uint32_t DrivesPageGetFileType(String path) { + path = PathRemoveTrailingSlash(path); + String string = PathGetSection(path, PathCountSections(path)); + EsVolumeInformation volume; + + if (EsMountPointGetVolumeInformation(STRING(string), &volume)) { + if (volume.driveType == ES_DRIVE_TYPE_HDD ) return KNOWN_FILE_TYPE_DRIVE_HDD; + if (volume.driveType == ES_DRIVE_TYPE_SSD ) return KNOWN_FILE_TYPE_DRIVE_SSD; + if (volume.driveType == ES_DRIVE_TYPE_CDROM ) return KNOWN_FILE_TYPE_DRIVE_CDROM; + if (volume.driveType == ES_DRIVE_TYPE_USB_MASS_STORAGE) return KNOWN_FILE_TYPE_DRIVE_USB_MASS_STORAGE; + return KNOWN_FILE_TYPE_DRIVE_HDD; + } + + return KNOWN_FILE_TYPE_DRIVE_HDD; +} + +void DrivesPageGetTotalSize(Folder *folder) { + EsVolumeInformation information; + + if (EsMountPointGetVolumeInformation(STRING(folder->path), &information)) { + folder->spaceUsed = information.spaceUsed; + folder->spaceTotal = information.spaceTotal; + } +} + +void DrivesPageGetVisibleName(EsBuffer *buffer, String path) { + path = PathRemoveTrailingSlash(path); + String string = PathGetSection(path, PathCountSections(path)); + EsVolumeInformation volume; + + if (EsMountPointGetVolumeInformation(STRING(string), &volume)) { + EsBufferFormat(buffer, "%s", volume.labelBytes, volume.label); + return; + } + + EsBufferFormat(buffer, "%s", STRFMT(string)); +} + +EsError DrivesPageEnumerate(Folder *folder) { + EsMutexAcquire(&drivesMutex); + EsDirectoryChild information = {}; + information.type = ES_NODE_DIRECTORY; + + for (uintptr_t i = 0; i < drives.Length(); i++) { + Drive *drive = &drives[i]; + information.fileSize = drive->information.spaceTotal; + FolderAddEntry(folder, drive->prefix, drive->prefixBytes, &information); + } + + EsMutexRelease(&drivesMutex); + return ES_SUCCESS; +} + +String DrivesPageGetPathForChildFolder(Folder *, String item) { + return StringAllocateAndFormat("%s/", STRFMT(item)); +} + +void DrivesPageGetDefaultViewSettings(Folder *, FolderViewSettings *settings) { + settings->viewType = VIEW_TILES; +} + +///////////////////////////////// + +uint32_t NamespaceDefaultGetFileType(String) { + return KNOWN_FILE_TYPE_DIRECTORY; +} + +void NamespaceDefaultGetVisibleName(EsBuffer *buffer, String path) { + String string = PathGetSection(path, -1); + EsBufferFormat(buffer, "%s", STRFMT(string)); +} + +uint32_t NamespaceRootGetFileType(String path) { + if (StringEquals(path, StringFromLiteralWithSize(INTERFACE_STRING(FileManagerDrivesPage)))) { + return KNOWN_FILE_TYPE_DRIVES_PAGE; + } else { + return KNOWN_FILE_TYPE_DIRECTORY; + } +} + +void NamespaceRootGetVisibleName(EsBuffer *buffer, String path) { + EsBufferFormat(buffer, "%s", STRFMT(StringSlice(path, 0, path.bytes - 1))); +} + +EsError NamespaceInvalidEnumerate(Folder *folder) { + folder->cEmptyMessage = folder->driveRemoved ? interfaceString_FileManagerInvalidDrive : interfaceString_FileManagerInvalidPath; + return ES_SUCCESS; +} + +NamespaceHandler namespaceHandlers[] = { + { + .type = NAMESPACE_HANDLER_DRIVES_PAGE, + .rootContainerHandlerType = NAMESPACE_HANDLER_ROOT, + .handlesPath = DrivesPageHandlesPath, + .getFileType = DrivesPageGetFileType, + .getVisibleName = DrivesPageGetVisibleName, + .getTotalSize = DrivesPageGetTotalSize, + .getPathForChildFolder = DrivesPageGetPathForChildFolder, + .getDefaultViewSettings = DrivesPageGetDefaultViewSettings, + .enumerate = DrivesPageEnumerate, + }, + + { + .type = NAMESPACE_HANDLER_FILE_SYSTEM, + .rootContainerHandlerType = NAMESPACE_HANDLER_DRIVES_PAGE, + .handlesPath = FSDirHandlesPath, + .getFileType = NamespaceDefaultGetFileType, + .getVisibleName = NamespaceDefaultGetVisibleName, + .getTotalSize = FSDirGetTotalSize, + .getPathForChildFolder = FSDirGetPathForChildFolder, + .createChildFolder = FSDirCreateChildFolder, + .renameItem = FSDirRenameItem, + .enumerate = FSDirEnumerate, + }, + + { + .type = NAMESPACE_HANDLER_ROOT, + .handlesPath = [] (String) { return false; }, + .getFileType = NamespaceRootGetFileType, + .getVisibleName = NamespaceRootGetVisibleName, + }, + + { + .type = NAMESPACE_HANDLER_INVALID, + .rootContainerHandlerType = NAMESPACE_HANDLER_ROOT, + .handlesPath = [] (String) { return true; }, + .getFileType = NamespaceDefaultGetFileType, + .getVisibleName = NamespaceDefaultGetVisibleName, + .enumerate = NamespaceInvalidEnumerate, + }, +}; + +void NamespaceFindHandlersForPath(NamespaceHandler **itemHandler, NamespaceHandler **containerHandler, String path) { + String pathContainer = PathGetParent(path); + *itemHandler = *containerHandler = nullptr; + + for (uintptr_t i = 0; i < sizeof(namespaceHandlers) / sizeof(namespaceHandlers[0]); i++) { + if (!(*itemHandler) && namespaceHandlers[i].handlesPath(path)) { + *itemHandler = &namespaceHandlers[i]; + } + + if (pathContainer.bytes && !(*containerHandler) && namespaceHandlers[i].handlesPath(pathContainer)) { + *containerHandler = &namespaceHandlers[i]; + } + } + + if (!pathContainer.bytes && (*itemHandler)) { + for (uintptr_t i = 0; i < sizeof(namespaceHandlers) / sizeof(namespaceHandlers[0]); i++) { + if (namespaceHandlers[i].type == (*itemHandler)->rootContainerHandlerType) { + *containerHandler = &namespaceHandlers[i]; + break; + } + } + } +} + +uint32_t NamespaceGetIcon(String path) { + NamespaceHandler *itemHandler, *containerHandler; + NamespaceFindHandlersForPath(&itemHandler, &containerHandler, path); + + if (containerHandler) { + return knownFileTypes[containerHandler->getFileType(path)].iconID; + } else { + return ES_ICON_FOLDER; + } +} + +void NamespaceGetVisibleName(EsBuffer *buffer, String path) { + NamespaceHandler *itemHandler, *containerHandler; + NamespaceFindHandlersForPath(&itemHandler, &containerHandler, path); + + if (containerHandler) { + containerHandler->getVisibleName(buffer, path); + } else { + String string = PathGetSection(path, -1); + EsBufferFormat(buffer, "%s", STRFMT(string)); + } +} + +///////////////////////////////// + +void BookmarkAdd(String path, bool saveConfiguration = true) { + bookmarks.Add(StringDuplicate(path)); + if (saveConfiguration) ConfigurationSave(); + + for (uintptr_t i = 0; i < instances.Length(); i++) { + EsListViewInsert(instances[i]->placesView, PLACES_VIEW_GROUP_BOOKMARKS, bookmarks.Length(), bookmarks.Length()); + } +} + +void BookmarkRemove(String path) { + for (uintptr_t i = 0; i < bookmarks.Length(); i++) { + if (0 == EsStringCompareRaw(STRING(bookmarks[i]), STRING(path))) { + bookmarks.Delete(i); + + for (uintptr_t i = 0; i < instances.Length(); i++) { + EsListViewRemove(instances[i]->placesView, PLACES_VIEW_GROUP_BOOKMARKS, i + 1, i + 1); + } + + ConfigurationSave(); + return; + } + } + + EsAssert(false); +} + +///////////////////////////////// + +void FolderEntryCloseHandle(Folder *folder, FolderEntry *entry) { + entry->handles--; + + if (!entry->handles) { + if (entry->name != entry->internalName) { + EsHeapFree(entry->internalName); + } + + EsHeapFree(entry->name); + EsArenaFree(&folder->entryArena, entry); + } +} + +void FolderDestroy(Folder *folder) { + for (uintptr_t i = 0; i < folder->entries.slotCount; i++) { + if (folder->entries.slots[i].key.used) { + FolderEntryCloseHandle(folder, (FolderEntry *) folder->entries.slots[i].value); + } + } + + EsHeapFree(folder); +} + +void FolderDetachInstance(Instance *instance) { + Folder *folder = instance->folder; + if (!folder) return; + instance->folder = nullptr; + folder->attachedInstances.FindAndDeleteSwap(instance, true); + + if (!folder->attachedInstances.Length() && !folder->attachingInstances.Length()) { + foldersWithNoAttachedInstances.Add(folder); + + if (foldersWithNoAttachedInstances.Length() > MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES) { + Folder *leastRecentlyUsed = foldersWithNoAttachedInstances[0]; + loadedFolders.FindAndDeleteSwap(leastRecentlyUsed, true); + foldersWithNoAttachedInstances.Delete(0); + FolderDestroy(leastRecentlyUsed); + } + } +} + +FolderEntry *FolderAddEntry(Folder *folder, const char *_name, size_t nameBytes, EsDirectoryChild *information, uint64_t id) { + char *name = (char *) EsHeapAllocate(nameBytes + 1, false); + name[nameBytes] = 0; + EsMemoryCopy(name, _name, nameBytes); + + FolderEntry *entry = (FolderEntry *) HashTableGetLong(&folder->entries, name, nameBytes); + + if (!entry) { + entry = (FolderEntry *) EsArenaAllocate(&folder->entryArena, true); + HashTablePutLong(&folder->entries, name, nameBytes, entry, false); + + static uint64_t nextEntryID = 1; + entry->id = id ?: __sync_fetch_and_add(&nextEntryID, 1); + entry->handles = 1; + entry->name = name; + entry->nameBytes = nameBytes; + entry->extensionOffset = PathGetExtension(entry->GetName()).text - name; + entry->internalName = name; + entry->internalNameBytes = nameBytes; + + if (folder->itemHandler->getVisibleName != NamespaceDefaultGetVisibleName) { + String path = StringAllocateAndFormat("%s%s", STRFMT(folder->path), STRFMT(entry->GetName())); + uint8_t _buffer[256]; + EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; + folder->itemHandler->getVisibleName(&buffer, path); + entry->nameBytes = buffer.position; + entry->name = (char *) EsHeapAllocate(buffer.position, false); + EsMemoryCopy(entry->name, _buffer, buffer.position); + StringDestroy(&path); + } + } else { + EsHeapFree(name); + name = entry->name; + entry->previousSize = entry->size; + } + + entry->size = information->fileSize; + entry->isFolder = information->type == ES_NODE_DIRECTORY; + entry->sizeUnknown = entry->isFolder && information->directoryChildren == ES_DIRECTORY_CHILDREN_UNKNOWN; + + return entry; +} + +void FolderAddEntries(Folder *folder, EsDirectoryChild *buffer, size_t entryCount) { + for (uintptr_t i = 0; i < entryCount; i++) { + FolderAddEntry(folder, buffer[i].name, buffer[i].nameBytes, &buffer[i]); + } +} + +void FolderAddEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes, + EsDirectoryChild *information, Instance *selectItem, bool mutexAlreadyAcquired, uint64_t id = 0) { + if (!mutexAlreadyAcquired) EsMutexAcquire(&loadedFoldersMutex); + + if (folder->containerHandler->getTotalSize) { + folder->containerHandler->getTotalSize(folder); + } + + FolderEntry *entry = FolderAddEntry(folder, name, nameBytes, information, id); + ListEntry listEntry = { .entry = entry }; + + for (uintptr_t i = 0; i < folder->attachedInstances.Length(); i++) { + Instance *instance = folder->attachedInstances[i]; + listEntry.selected = instance == selectItem; + InstanceAddSingle(instance, listEntry); + InstanceUpdateStatusString(instance); + } + + if (!mutexAlreadyAcquired) EsMutexRelease(&loadedFoldersMutex); +} + +uint64_t FolderRemoveEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes) { + EsMutexAcquire(&loadedFoldersMutex); + + FolderEntry *entry = (FolderEntry *) HashTableGetLong(&folder->entries, name, nameBytes); + uint64_t id = 0; + + if (entry) { + for (uintptr_t i = 0; i < folder->attachedInstances.Length(); i++) { + InstanceRemoveSingle(folder->attachedInstances[i], entry); + } + + id = entry->id; + HashTableDeleteLong(&folder->entries, name, nameBytes); + FolderEntryCloseHandle(folder, entry); + } + + EsMutexRelease(&loadedFoldersMutex); + return id; +} + +void FolderPathMoved(Instance *instance, String oldPath, String newPath) { + _EsPathAnnouncePathMoved(instance, STRING(oldPath), STRING(newPath)); + + EsMutexAcquire(&loadedFoldersMutex); + + for (uintptr_t i = 0; i < loadedFolders.Length(); i++) { + Folder *folder = loadedFolders[i]; + + if (PathReplacePrefix(&folder->path, oldPath, newPath)) { + for (uintptr_t i = 0; i < folder->attachedInstances.Length(); i++) { + InstanceFolderPathChanged(folder->attachedInstances[i], false); + } + } + } + + EsMutexRelease(&loadedFoldersMutex); + + for (uintptr_t i = 0; i < bookmarks.Length(); i++) { + PathReplacePrefix(&bookmarks[i], oldPath, newPath); + } + + for (uintptr_t i = 0; i < instances.Length(); i++) { + EsListViewInvalidateAll(instances[i]->placesView); + + for (uintptr_t j = 0; j < instances[i]->pathBackwardHistory.Length(); j++) { + HistoryEntry *entry = &instances[i]->pathBackwardHistory[j]; + PathReplacePrefix(&entry->path, oldPath, newPath); + + if (StringStartsWith(oldPath, entry->path) && StringEquals(entry->focusedItem, StringSlice(oldPath, entry->path.bytes, -1))) { + StringDestroy(&entry->focusedItem); + entry->focusedItem = StringDuplicate(StringSlice(newPath, entry->path.bytes, -1)); + } + } + + for (uintptr_t j = 0; j < instances[i]->pathForwardHistory.Length(); j++) { + HistoryEntry *entry = &instances[i]->pathForwardHistory[j]; + PathReplacePrefix(&entry->path, oldPath, newPath); + + if (StringStartsWith(oldPath, entry->path) && StringEquals(entry->focusedItem, StringSlice(oldPath, entry->path.bytes, -1))) { + StringDestroy(&entry->focusedItem); + entry->focusedItem = StringDuplicate(StringSlice(newPath, entry->path.bytes, -1)); + } + } + } + + for (uintptr_t i = 0; i < folderViewSettings.Length(); i++) { + String knownPath = StringFromLiteralWithSize(folderViewSettings[i].path, folderViewSettings[i].pathBytes); + + if (knownPath.bytes - oldPath.bytes + newPath.bytes >= sizeof(folderViewSettings[i].path)) { + continue; + } + + if (!PathHasPrefix(knownPath, oldPath)) { + continue; + } + + String after = StringSlice(knownPath, oldPath.bytes, -1); + folderViewSettings[i].pathBytes = EsStringFormat(folderViewSettings[i].path, sizeof(folderViewSettings[i].path), + "%s%s", STRFMT(newPath), STRFMT(after)); + } + + ConfigurationSave(); +} + +EsError FolderAttachInstance(Instance *instance, String path, bool recurse, Folder **newFolder) { + // TODO Don't modify attachedInstances/attachingInstances/loadedFolders without the message mutex! + // And then we can remove loadedFoldersMutex. + + // (Called on the blocking task thread.) + + Folder *folder = nullptr; + NamespaceHandler *itemHandler = nullptr, *containerHandler = nullptr; + EsError error; + bool driveRemoved = false; + + // Check if we've already loaded the folder. + + EsMutexAcquire(&loadedFoldersMutex); + + for (uintptr_t i = 0; i < loadedFolders.Length(); i++) { + if (StringEquals(loadedFolders[i]->path, path) && loadedFolders[i]->recurse == recurse) { + if (!loadedFolders[i]->refreshing) { + folder = loadedFolders[i]; + goto success; + } else { + driveRemoved = loadedFolders[i]->driveRemoved; + } + } + } + + EsMutexRelease(&loadedFoldersMutex); + + // Find the handler for the path. + + NamespaceFindHandlersForPath(&itemHandler, &containerHandler, path); + + if (!itemHandler || !containerHandler) { + return ES_ERROR_FILE_DOES_NOT_EXIST; + } + + // Load a new folder. + + folder = (Folder *) EsHeapAllocate(sizeof(Folder), true); + + folder->path = StringDuplicate(path); + folder->recurse = recurse; + folder->itemHandler = itemHandler; + folder->containerHandler = containerHandler; + folder->cEmptyMessage = interfaceString_FileManagerEmptyFolderView; + folder->driveRemoved = driveRemoved; + + EsArenaInitialise(&folder->entryArena, 1048576, sizeof(FolderEntry)); + + // TODO Make this asynchronous for some folder providers, or recursive requests + // (that is, immediately present to the user while streaming data in). + error = itemHandler->enumerate(folder); + + folder->driveRemoved = false; + folder->refreshing = false; + + if (error != ES_SUCCESS) { + StringDestroy(&folder->path); + EsHeapFree(folder); + return error; + } + + if (containerHandler->getTotalSize) { + containerHandler->getTotalSize(folder); + } + + EsMutexAcquire(&loadedFoldersMutex); + loadedFolders.Add(folder); + + success:; + + foldersWithNoAttachedInstances.FindAndDeleteSwap(folder, false); + folder->attachingInstances.Add(instance); + + EsMutexRelease(&loadedFoldersMutex); + + *newFolder = folder; + return ES_SUCCESS; +} + +void FolderRefresh(Folder *folder) { + // EsMutexAssertLocked(&loadedFoldersMutex); + + if (folder->refreshing) { + return; + } + + folder->refreshing = true; + + for (uintptr_t i = 0; i < folder->attachedInstances.Length(); i++) { + InstanceLoadFolder(folder->attachedInstances[i], StringDuplicate(folder->path), LOAD_FOLDER_REFRESH); + } +} diff --git a/apps/file_manager/main.cpp b/apps/file_manager/main.cpp new file mode 100644 index 0000000..04dfa04 --- /dev/null +++ b/apps/file_manager/main.cpp @@ -0,0 +1,573 @@ +#define ES_INSTANCE_TYPE Instance +#include +#include + +#include +#include +#define IMPLEMENTATION +#include +#undef IMPLEMENTATION + +// TODO Possible candidates for moving in the core API: +// - String/paths utils +// - Blocking/non-blocking task systems + +// TODO Don't show modals if a folder can't be loaded. +// Instead, show a list view with an error message, +// and disable interactions. + +#define SETTINGS_FILE "|Settings:/Default.ini" + +#define ERROR_LOAD_FOLDER (1) +#define ERROR_NEW_FOLDER (2) +#define ERROR_RENAME_ITEM (3) + +#define PLACES_VIEW_GROUP_BOOKMARKS (0) +#define PLACES_VIEW_GROUP_DRIVES (1) + +#define MESSAGE_BLOCKING_TASK_COMPLETE ((EsMessageType) (ES_MSG_USER_START + 1)) +#define MESSAGE_NON_BLOCKING_TASK_COMPLETE ((EsMessageType) (ES_MSG_USER_START + 2)) + +#define VIEW_DETAILS (0) +#define VIEW_TILES (1) +#define VIEW_THUMBNAILS (2) + +const char *errorTypeStrings[] = { + interfaceString_FileManagerUnknownError, + interfaceString_FileManagerOpenFolderError, + interfaceString_FileManagerNewFolderError, + interfaceString_FileManagerRenameItemError, +}; + +#include "string.cpp" + +EsListViewColumn folderOutputColumns[] = { +#define COLUMN_NAME (0) + { INTERFACE_STRING(FileManagerColumnName), ES_LIST_VIEW_COLUMN_HAS_MENU }, +#define COLUMN_TYPE (1) + { INTERFACE_STRING(FileManagerColumnType), ES_LIST_VIEW_COLUMN_HAS_MENU }, +#define COLUMN_SIZE (2) + { INTERFACE_STRING(FileManagerColumnSize), ES_LIST_VIEW_COLUMN_HAS_MENU | ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED }, +}; + +#define LOAD_FOLDER_BACK (1) +#define LOAD_FOLDER_FORWARD (2) +#define LOAD_FOLDER_START (3) +#define LOAD_FOLDER_REFRESH (4) +#define LOAD_FOLDER_NO_FOCUS (1 << 8) + +struct FolderEntry { + uint16_t handles; + bool isFolder, sizeUnknown; + uint8_t nameBytes, extensionOffset, internalNameBytes; // 0 -> 256. + char *name, *internalName; + EsFileOffset size, previousSize; + uint64_t id; + + inline String GetName() { + return { .text = name, .bytes = nameBytes ?: 256u, .allocated = nameBytes ?: 256u }; + } + + inline String GetInternalName() { + return { .text = internalName, .bytes = internalNameBytes ?: 256u, .allocated = internalNameBytes ?: 256u }; + } + + inline String GetExtension() { + uintptr_t offset = extensionOffset ?: 256u; + return { .text = name + offset, .bytes = (nameBytes ?: 256u) - offset }; + } +}; + +struct ListEntry { + FolderEntry *entry; + bool selected; +}; + +struct Task { + EsGeneric context, context2; + String string, string2; + uint64_t id; + EsError result; + const char *cDescription; + Instance *instance; + + void (*callback)(Instance *instance, Task *task); + void (*then)(Instance *instance, Task *task); // Called on the main thread. +}; + +struct HistoryEntry { + String path; + String focusedItem; +}; + +struct Drive { + const char *prefix; + size_t prefixBytes; + EsVolumeInformation information; +}; + +struct FolderViewSettings { + uint16_t sortColumn; + uint8_t viewType; +}; + +struct FolderViewSettingsEntry { + char path[160]; + FolderViewSettings settings; + uint8_t pathBytes; +}; + +struct Thumbnail { + uint32_t *bits; + uint32_t width, height; + uintptr_t referenceCount; + uint32_t generatingTasksInProgress; +}; + +struct Instance : EsInstance { + // Interface elements. + + EsListView *list; + EsListView *placesView; + EsTextbox *breadcrumbBar; + EsButton *newFolderButton; + EsTextDisplay *status; + + union { + struct { + EsTextbox *textbox; + uintptr_t index; + } rename; + }; + + // Path and history. + + String path; + Array pathBackwardHistory; + Array pathForwardHistory; + + // Commands. + + EsCommand commandGoBackwards, commandGoForwards, commandGoParent; + EsCommand commandNewFolder, commandRename; + EsCommand commandViewDetails, commandViewTiles, commandViewThumbnails; + EsCommand commandRefresh; + + // Active folder. + + struct Folder *folder; + + // Sorted and filtered list contents. + + Array listContents; + + size_t selectedItemCount; + EsFileOffset selectedItemsTotalSize; + + String delayedFocusItem; + + FolderViewSettings viewSettings; + + // Blocking task thread. + // Tasks that block the use of the instance, + // but display progress and can be (optionally) cancelled. + // Shows the dialog after some threshold. +#define BLOCKING_TASK_DIALOG_THRESHOLD_MS (100) + Task blockingTask; + volatile bool blockingTaskInProgress, blockingTaskReachedTimeout; + volatile uint32_t blockingTaskID; +}; + +struct NamespaceHandler { + uint8_t type; + uint8_t rootContainerHandlerType; + + bool (*handlesPath)(String path); + + uint32_t (*getFileType)(String path); + void (*getVisibleName)(EsBuffer *buffer, String path); + void (*getTotalSize)(Folder *folder); // Possibly called on the blocking task thread. + String (*getPathForChildFolder)(Folder *folder, String item); + void (*getDefaultViewSettings)(Folder *folder, FolderViewSettings *settings); + + // Called on the blocking task thread: + EsError (*createChildFolder)(Folder *folder, String *name, bool findUniqueName); // Optional. + EsError (*renameItem)(Folder *folder, String oldName, String name); // Optional. + EsError (*enumerate)(Folder *folder); +}; + +struct Folder { + HashTable entries; + EsArena entryArena; + + Array attachedInstances; + Array attachingInstances; + + String path; + bool recurse; + bool refreshing; + bool driveRemoved; + + EsFileOffset spaceTotal; + EsFileOffset spaceUsed; + + NamespaceHandler *itemHandler, *containerHandler; + + const char *cEmptyMessage; +}; + +void InstanceReportError(struct Instance *instance, int error, EsError code); +bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, int historyMode = 0); +void InstanceUpdateStatusString(Instance *instance); +void InstanceViewSettingsUpdated(Instance *instance); +void InstanceRefreshViewType(Instance *instance); +void InstanceFolderPathChanged(Instance *instance, bool fromLoadFolder); +void InstanceAddContents(struct Instance *instance, HashTable *newEntries); +void InstanceAddSingle(struct Instance *instance, ListEntry newEntry); +void InstanceRemoveContents(struct Instance *instance); +ListEntry InstanceRemoveSingle(Instance *instance, FolderEntry *folderEntry); +ListEntry *InstanceGetSelectedListEntry(Instance *instance); +void ListItemCreated(EsElement *element, uintptr_t index, bool fromFolderRename); +FolderEntry *FolderAddEntry(Folder *folder, const char *_name, size_t nameBytes, EsDirectoryChild *information, uint64_t id = 0); +void FolderAddEntries(Folder *folder, EsDirectoryChild *buffer, size_t entryCount); +uint32_t NamespaceDefaultGetFileType(String); + +Array drives; +EsMutex drivesMutex; + +Array instances; + +Array bookmarks; +#define FOLDER_VIEW_SETTINGS_MAXIMUM_ENTRIES (10000) +Array folderViewSettings; +HashStore thumbnailCache; + +// Non-blocking task thread. + +EsHandle nonBlockingTaskWorkAvailable; +EsMutex nonBlockingTaskMutex; +Array nonBlockingTasks; + +// Styles. + +const EsStyle styleFolderView = { + .inherit = ES_STYLE_LIST_VIEW, + + .metrics = { + .mask = ES_THEME_METRICS_MINIMUM_WIDTH | ES_THEME_METRICS_PREFERRED_WIDTH, + .preferredWidth = 200, + .minimumWidth = 150, + }, +}; + +const EsStyle styleFolderViewTiled = { + .inherit = ES_STYLE_LIST_VIEW, + + .metrics = { + .mask = ES_THEME_METRICS_MINIMUM_WIDTH | ES_THEME_METRICS_PREFERRED_WIDTH | ES_THEME_METRICS_GAP_WRAP | ES_THEME_METRICS_GAP_MINOR, + .preferredWidth = 200, + .minimumWidth = 150, + .gapMinor = 5, + .gapWrap = 5, + }, +}; + +const EsStyle styleFolderItemThumbnail = { + .inherit = ES_STYLE_LIST_ITEM_TILE, + + .metrics = { + .mask = ES_THEME_METRICS_PREFERRED_WIDTH | ES_THEME_METRICS_PREFERRED_HEIGHT + | ES_THEME_METRICS_ICON_SIZE | ES_THEME_METRICS_LAYOUT_VERTICAL | ES_THEME_METRICS_INSETS | ES_THEME_METRICS_TEXT_ALIGN, + .insets = ES_RECT_2(5, 10), + .preferredWidth = 170, + .preferredHeight = 150, + .textAlign = ES_TEXT_H_CENTER | ES_TEXT_V_CENTER | ES_TEXT_ELLIPSIS, + .iconSize = 80, + .layoutVertical = true, + }, +}; + +const EsStyle stylePlacesView = { + .inherit = ES_STYLE_LIST_VIEW, + + .metrics = { + .mask = ES_THEME_METRICS_MINIMUM_WIDTH | ES_THEME_METRICS_PREFERRED_WIDTH | ES_THEME_METRICS_INSETS + | ES_THEME_METRICS_GAP_WRAP | ES_THEME_METRICS_GAP_MAJOR, + .insets = ES_RECT_1(8), + .preferredWidth = 200, + .minimumWidth = 150, + .gapMajor = 16, + .gapWrap = 16, + }, +}; + +void BlockingTaskThread(EsGeneric _instance) { + Instance *instance = (Instance *) _instance.p; + instance->blockingTask.callback(instance, &instance->blockingTask); + EsMessage m = { MESSAGE_BLOCKING_TASK_COMPLETE }; + m.user.context1.p = instance; + m.user.context2.u = instance->blockingTaskID; + EsMessagePost(nullptr, &m); +} + +void BlockingTaskComplete(Instance *instance) { + EsAssert(instance->blockingTaskInProgress); // Task should have been in progress. + instance->blockingTaskInProgress = false; + if (instance->blockingTaskReachedTimeout) EsDialogClose(instance->window); + Task *task = &instance->blockingTask; + if (task->then) task->then(instance, task); +} + +void BlockingTaskQueue(Instance *instance, Task task) { + EsAssert(!instance->blockingTaskInProgress); // Cannot queue a new blocking task if the previous has not finished. + + instance->blockingTask = task; + instance->blockingTaskInProgress = true; + + EsThreadInformation thread; + EsThreadCreate(BlockingTaskThread, &thread, instance); + + ptrdiff_t result = EsWait(&thread.handle, 1, BLOCKING_TASK_DIALOG_THRESHOLD_MS); + EsHandleClose(thread.handle); + + if (result == ES_ERROR_TIMEOUT_REACHED) { + instance->blockingTaskReachedTimeout = true; + EsDialogShowAlert(instance->window, task.cDescription, -1, INTERFACE_STRING(FileManagerOngoingTaskDescription), ES_ICON_TOOLS_TIMER_SYMBOLIC); + // TODO Progress bar; cancelling tasks. + } else { + instance->blockingTaskReachedTimeout = false; + BlockingTaskComplete(instance); + instance->blockingTaskID++; // Prevent the task being completed twice. + } +} + +void NonBlockingTaskThread(EsGeneric) { + while (true) { + EsWait(&nonBlockingTaskWorkAvailable, 1, ES_WAIT_NO_TIMEOUT); + + while (true) { + EsMutexAcquire(&nonBlockingTaskMutex); + + if (!nonBlockingTasks.Length()) { + EsMutexRelease(&nonBlockingTaskMutex); + break; + } + + Task *task = nonBlockingTasks[0]; + nonBlockingTasks.Delete(0); + EsMutexRelease(&nonBlockingTaskMutex); + + task->callback(nullptr, task); + + EsMessage m = { MESSAGE_NON_BLOCKING_TASK_COMPLETE }; + m.user.context2.p = task; + EsMessagePost(nullptr, &m); + } + } +} + +void NonBlockingTaskQueue(Task _task) { + // NOTE We can't store instances in tasks on the non-blocking queue thread, + // because the instances might be destroyed while the task is in progress! + + Task *task = (Task *) EsHeapAllocate(sizeof(Task), false); + EsMemoryCopy(task, &_task, sizeof(Task)); + EsMutexAcquire(&nonBlockingTaskMutex); + nonBlockingTasks.Add(task); + EsMutexRelease(&nonBlockingTaskMutex); + EsEventSet(nonBlockingTaskWorkAvailable); +} + +void NonBlockingTaskComplete(EsMessage *message) { + Task *task = (Task *) message->user.context2.p; + if (task->then) task->then(nullptr, task); + EsHeapFree(task); +} + +void ConfigurationSave() { + EsBuffer buffer = {}; + buffer.canGrow = true; + + EsBufferFormat(&buffer, "[bookmarks]\n"); + + for (uintptr_t i = 0; i < bookmarks.Length(); i++) { + EsBufferFormat(&buffer, "=%s\n", STRFMT(bookmarks[i])); + } + + for (uintptr_t i = 0; i < folderViewSettings.Length(); i++) { + FolderViewSettingsEntry *entry = &folderViewSettings[i]; + EsBufferFormat(&buffer, "\n[@folder]\npath=%z\nsort_column=%d\nview_type=%d\n", + entry->path, entry->settings.sortColumn, entry->settings.viewType); + } + + EsFileWriteAll(EsLiteral(SETTINGS_FILE), buffer.out, buffer.position); + EsHeapFree(buffer.out); +} + +#include "type_database.cpp" +#include "folder.cpp" +#include "commands.cpp" +#include "ui.cpp" + +void DriveRemove(const char *prefix, size_t prefixBytes) { + if (!prefixBytes || prefix[0] == '|') return; + EsMutexAcquire(&drivesMutex); + bool found = false; + + for (uintptr_t index = 0; index < drives.Length(); index++) { + if (0 == EsStringCompareRaw(prefix, prefixBytes, drives[index].prefix, drives[index].prefixBytes)) { + drives.Delete(index); + found = true; + + for (uintptr_t i = 0; i < instances.Length(); i++) { + EsListViewRemove(instances[i]->placesView, PLACES_VIEW_GROUP_DRIVES, index, index); + } + + break; + } + } + + EsAssert(found); + EsMutexRelease(&drivesMutex); + + EsMutexAcquire(&loadedFoldersMutex); + + for (uintptr_t i = 0; i < loadedFolders.Length(); i++) { + Folder *folder = loadedFolders[i]; + + if (folder->itemHandler->type == NAMESPACE_HANDLER_DRIVES_PAGE + || StringStartsWith(folder->path, StringFromLiteralWithSize(prefix, prefixBytes))) { + folder->driveRemoved = true; + FolderRefresh(folder); + } + } + + EsMutexRelease(&loadedFoldersMutex); +} + +void DriveAdd(const char *prefix, size_t prefixBytes) { + if (!prefixBytes || prefix[0] == '|') return; + + EsMutexAcquire(&drivesMutex); + + Drive drive = {}; + drive.prefix = prefix; + drive.prefixBytes = prefixBytes; + EsMountPointGetVolumeInformation(prefix, prefixBytes, &drive.information); + drives.Add(drive); + + for (uintptr_t i = 0; i < instances.Length(); i++) { + EsListViewInsert(instances[i]->placesView, PLACES_VIEW_GROUP_DRIVES, drives.Length(), drives.Length()); + } + + EsMutexRelease(&drivesMutex); + + for (uintptr_t i = 0; i < instances.Length(); i++) { + if (instances[i]->folder->itemHandler->type == NAMESPACE_HANDLER_DRIVES_PAGE + || StringStartsWith(instances[i]->folder->path, StringFromLiteralWithSize(prefix, prefixBytes))) { + FolderRefresh(instances[i]->folder); + } + } +} + +void LoadSettings() { + EsINIState state = { (char *) EsFileReadAll(EsLiteral(SETTINGS_FILE), &state.bytes) }; + FolderViewSettings *folder = nullptr; + + while (EsINIParse(&state)) { + if (state.value && 0 == EsStringCompareRaw(state.section, state.sectionBytes, EsLiteral("bookmarks"))) { + String string = {}; + string.text = state.value, string.bytes = state.valueBytes; + BookmarkAdd(string, false); + } else if (0 == EsStringCompareRaw(state.sectionClass, state.sectionClassBytes, EsLiteral("folder"))) { + if (0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("path"))) { + if (state.keyBytes < sizeof(folderViewSettings[0].path)) { + FolderViewSettingsEntry *entry = folderViewSettings.Add(); + EsMemoryCopy(entry->path, state.value, state.valueBytes); + entry->pathBytes = state.valueBytes; + folder = &entry->settings; + } + } else if (folder && 0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("sort_column"))) { + folder->sortColumn = EsIntegerParse(state.value, state.valueBytes); + } else if (folder && 0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("view_type"))) { + folder->viewType = EsIntegerParse(state.value, state.valueBytes); + } + } + } +} + +void _start() { + _init(); + + AddKnownFileTypes(); + LoadSettings(); + + // Enumerate drives. + + EsMountPointEnumerate([] (const char *prefix, size_t prefixBytes, EsGeneric) { + DriveAdd(prefix, prefixBytes); + }, 0); + + // Start the non-blocking task threads. + + nonBlockingTaskWorkAvailable = EsEventCreate(true /* autoReset */); + EsThreadInformation _nonBlockingTaskThread = {}; + + for (uintptr_t i = 0; i < EsSystemGetConstant(ES_SYSTEM_CONSTANT_OPTIMAL_WORK_QUEUE_THREAD_COUNT); i++) { + EsThreadCreate(NonBlockingTaskThread, &_nonBlockingTaskThread, nullptr); + } + + // Process messages. + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FileManagerTitle)); + instances.Add(instance); + InstanceCreateUI(instance); + } else if (message->type == ES_MSG_INSTANCE_DESTROY) { + // TODO Cleanup/cancel any unfinished non-blocking tasks before we get here! + + Instance *instance = message->instanceDestroy.instance; + InstanceDestroy(instance); + instances.FindAndDeleteSwap(instance, true); + } else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) { + DriveAdd(message->registerFileSystem.mountPoint->prefix, message->registerFileSystem.mountPoint->prefixBytes); + } else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) { + DriveRemove(message->unregisterFileSystem.mountPoint->prefix, message->unregisterFileSystem.mountPoint->prefixBytes); + } else if (message->type == ES_MSG_FILE_MANAGER_FILE_MODIFIED) { + char *_path = (char *) EsHeapAllocate(message->user.context2.u, false); + EsConstantBufferRead(message->user.context1.u, _path); + String fullPath = StringFromLiteralWithSize(_path, message->user.context2.u); + size_t pathSectionCount = PathCountSections(fullPath); + + for (uintptr_t i = 0; i < pathSectionCount; i++) { + String path = PathGetParent(fullPath, i + 1); + String file = PathGetSection(fullPath, i + 1); + String folder = PathGetParent(path); + EsDirectoryChild information = {}; + + if (EsPathQueryInformation(STRING(path), &information)) { + EsMutexAcquire(&loadedFoldersMutex); + + for (uintptr_t i = 0; i < loadedFolders.Length(); i++) { + if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue; + if (EsStringCompareRaw(STRING(loadedFolders[i]->path), STRING(folder))) continue; + FolderAddEntryAndUpdateInstances(loadedFolders[i], file.text, file.bytes, &information, nullptr, true); + } + + EsMutexRelease(&loadedFoldersMutex); + } + } + + EsHandleClose(message->user.context1.u); + EsHeapFree(_path); + } else if (message->type == MESSAGE_BLOCKING_TASK_COMPLETE) { + Instance *instance = (Instance *) message->user.context1.p; + if (message->user.context2.u == instance->blockingTaskID) BlockingTaskComplete(instance); + } else if (message->type == MESSAGE_NON_BLOCKING_TASK_COMPLETE) { + NonBlockingTaskComplete(message); + } + } +} diff --git a/apps/file_manager/string.cpp b/apps/file_manager/string.cpp new file mode 100644 index 0000000..d321641 --- /dev/null +++ b/apps/file_manager/string.cpp @@ -0,0 +1,201 @@ +struct String { + char *text; + size_t bytes, allocated; +}; + +String StringAllocateAndFormat(const char *format, ...) { + String string = {}; + va_list arguments; + va_start(arguments, format); + string.text = EsStringAllocateAndFormatV(&string.bytes, format, arguments); + va_end(arguments); + string.allocated = string.bytes; + return string; +} + +String StringFromLiteral(const char *literal) { + String string = {}; + string.text = (char *) literal; + string.bytes = EsCStringLength(literal); + return string; +} + +String StringFromLiteralWithSize(const char *literal, ptrdiff_t bytes) { + String string = {}; + string.text = (char *) literal; + string.bytes = bytes == -1 ? EsCStringLength(literal) : bytes; + return string; +} + +void StringAppend(String *string, String with) { + if (string->bytes + with.bytes > string->allocated) { + string->allocated = (string->allocated + with.bytes) * 2; + string->text = (char *) EsHeapReallocate(string->text, string->allocated, false); + } + + EsMemoryCopy(string->text + string->bytes, with.text, with.bytes); + string->bytes += with.bytes; +} + +void StringDestroy(String *string) { + EsAssert(string->allocated == string->bytes); // Attempting to free a partial string. + EsHeapFree(string->text); + string->text = nullptr; + string->bytes = string->allocated = 0; +} + +String StringDuplicate(String string) { + String result = {}; + result.bytes = result.allocated = string.bytes; + result.text = (char *) EsHeapAllocate(result.bytes + 1, false); + result.text[result.bytes] = 0; + EsMemoryCopy(result.text, string.text, result.bytes); + return result; +} + +inline bool StringStartsWith(String a, String b) { + return a.bytes >= b.bytes && 0 == EsMemoryCompare(a.text, b.text, b.bytes); +} + +inline bool StringEndsWith(String a, String b) { + return a.bytes >= b.bytes && 0 == EsMemoryCompare(a.text + a.bytes - b.bytes, b.text, b.bytes); +} + +inline bool StringEquals(String a, String b) { + return a.bytes == b.bytes && 0 == EsMemoryCompare(a.text, b.text, a.bytes); +} + +String StringSlice(String string, uintptr_t offset, ptrdiff_t length) { + if (length == -1) { + length = string.bytes - offset; + } + + string.text += offset; + string.bytes = length; + string.allocated = 0; + return string; +} + +#define STRING(x) x.text, x.bytes +#define STRFMT(x) x.bytes, x.text + +uintptr_t PathCountSections(String string) { + ptrdiff_t sectionCount = 0; + + for (uintptr_t i = 0; i < string.bytes; i++) { + if (string.text[i] == '/') { + sectionCount++; + } + } + + return sectionCount; +} + +String PathGetSection(String string, ptrdiff_t index) { + String output = {}; + size_t stringBytes = string.bytes; + char *text = string.text; + + if (index < 0) { + index += PathCountSections(string); + } + + if (index < 0) { + return output; + } + + uintptr_t i = 0, bytes = 0; + + for (; index && i < stringBytes; i++) { + if (text[i] == '/') { + index--; + } + } + + if (index) { + return output; + } + + output.text = text + i; + + for (; i < stringBytes; i++) { + if (text[i] == '/') { + break; + } else { + bytes++; + } + } + + output.bytes = bytes; + + return output; +} + +String PathGetParent(String string, uintptr_t index) { + if (index == PathCountSections(string)) return string; + String section = PathGetSection(string, index); + string.bytes = section.bytes + section.text - string.text + 1; + return string; +} + +String PathGetExtension(String string) { + String extension = {}; + int lastSeparator = 0; + + for (intptr_t i = string.bytes - 1; i >= 0; i--) { + if (string.text[i] == '.') { + lastSeparator = i; + break; + } + } + + if (!lastSeparator && string.text[0] != '.') { + extension.text = string.text + string.bytes; + extension.bytes = 0; + return extension; + } else { + extension.text = string.text + lastSeparator + 1; + extension.bytes = string.bytes - lastSeparator - 1; + return extension; + } +} + +String PathGetParent(String string) { + size_t newPathBytes = 0; + + for (uintptr_t i = 0; i < string.bytes - 1; i++) { + if (string.text[i] == '/') { + newPathBytes = i + 1; + } + } + + String result = {}; + result.bytes = newPathBytes; + result.text = string.text; + + return result; +} + +bool PathHasPrefix(String path, String prefix) { + return StringStartsWith(path, prefix) && path.bytes > prefix.bytes && path.text[prefix.bytes] == '/'; +} + +bool PathReplacePrefix(String *knownPath, String oldPath, String newPath) { + if (PathHasPrefix(*knownPath, oldPath)) { + String after = StringSlice(*knownPath, oldPath.bytes, -1); + String path = StringAllocateAndFormat("%s%s", STRFMT(newPath), STRFMT(after)); + StringDestroy(knownPath); + *knownPath = path; + return true; + } + + return false; +} + +String PathRemoveTrailingSlash(String path) { + if (path.bytes && path.text[path.bytes - 1] == '/') { + path.bytes--; + } + + return path; +} diff --git a/apps/file_manager/type_database.cpp b/apps/file_manager/type_database.cpp new file mode 100644 index 0000000..9f31f3b --- /dev/null +++ b/apps/file_manager/type_database.cpp @@ -0,0 +1,110 @@ +struct FileType { + char *name; + size_t nameBytes; + uint32_t iconID; + int64_t openHandler; + + // TODO Allow applications to register their own thumbnail generators. + bool hasThumbnailGenerator; +}; + +Array knownFileTypes; +HashStore knownFileTypesByExtension; + +void AddKnownFileTypes() { +#define ADD_FILE_TYPE(_extension, _name, _iconID) \ + { \ + FileType type = {}; \ + type.name = (char *) _name; \ + type.iconID = _iconID; \ + uintptr_t index = knownFileTypes.Length(); \ + knownFileTypes.Add(type); \ + *knownFileTypesByExtension.Put(_extension, EsCStringLength(_extension)) = index; \ + } + +#define KNOWN_FILE_TYPE_DIRECTORY (0) + ADD_FILE_TYPE("", interfaceString_CommonItemFolder, ES_ICON_FOLDER); +#define KNOWN_FILE_TYPE_UNKNOWN (1) + ADD_FILE_TYPE("", interfaceString_CommonItemFile, ES_ICON_UNKNOWN); +#define KNOWN_FILE_TYPE_DRIVE_HDD (2) + ADD_FILE_TYPE("", interfaceString_CommonDriveHDD, ES_ICON_DRIVE_HARDDISK); +#define KNOWN_FILE_TYPE_DRIVE_SSD (3) + ADD_FILE_TYPE("", interfaceString_CommonDriveSSD, ES_ICON_DRIVE_HARDDISK_SOLIDSTATE); +#define KNOWN_FILE_TYPE_DRIVE_CDROM (4) + ADD_FILE_TYPE("", interfaceString_CommonDriveCDROM, ES_ICON_MEDIA_OPTICAL); +#define KNOWN_FILE_TYPE_DRIVE_USB_MASS_STORAGE (5) + ADD_FILE_TYPE("", interfaceString_CommonDriveUSBMassStorage, ES_ICON_DRIVE_REMOVABLE_MEDIA_USB); +#define KNOWN_FILE_TYPE_DRIVES_PAGE (6) + ADD_FILE_TYPE("", interfaceString_FileManagerDrivesPage, ES_ICON_COMPUTER_LAPTOP); + + size_t groupCount; + EsSystemConfigurationGroup *groups = EsSystemConfigurationReadAll(&groupCount); + + for (uintptr_t i = 0; i < groupCount; i++) { + EsSystemConfigurationGroup *group = groups + i; + + if (EsStringCompareRaw(group->sectionClass, group->sectionClassBytes, EsLiteral("file_type"))) { + continue; + } + + FileType type = {}; + + type.name = EsSystemConfigurationGroupReadString(group, "name", -1, &type.nameBytes); + type.openHandler = EsSystemConfigurationGroupReadInteger(group, "open", -1); + + char *iconName = EsSystemConfigurationGroupReadString(group, "icon", -1); + + if (iconName) { + type.iconID = EsIconIDFromString(iconName); + EsHeapFree(iconName); + } + + char *extension = EsSystemConfigurationGroupReadString(group, "extension", -1); + + // TODO Proper thumbnail generator registrations. + + if (0 == EsCRTstrcmp(extension, "jpg") || 0 == EsCRTstrcmp(extension, "png") || 0 == EsCRTstrcmp(extension, "bmp")) { + type.hasThumbnailGenerator = true; + } + + uintptr_t index = knownFileTypes.Length(); + knownFileTypes.Add(type); + *knownFileTypesByExtension.Put(extension, EsCStringLength(extension)) = index; + } +} + +FileType *FolderEntryGetType(Folder *folder, FolderEntry *entry) { + if (entry->isFolder) { + if (folder->itemHandler->getFileType != NamespaceDefaultGetFileType) { + String path = StringAllocateAndFormat("%s%s", STRFMT(folder->path), STRFMT(entry->GetInternalName())); + FileType *type = &knownFileTypes[folder->itemHandler->getFileType(path)]; + StringDestroy(&path); + return type; + } else { + return &knownFileTypes[KNOWN_FILE_TYPE_DIRECTORY]; + } + } else { + String extension = entry->GetExtension(); + char buffer[32]; + uintptr_t i = 0; + + for (; i < extension.bytes && i < 32; i++) { + if (EsCRTisupper(extension.text[i])) { + buffer[i] = EsCRTtolower(extension.text[i]); + } else { + buffer[i] = extension.text[i]; + } + } + + uintptr_t index = knownFileTypesByExtension.Get1(buffer, i); + return &knownFileTypes[index ? index : KNOWN_FILE_TYPE_UNKNOWN]; + } +} + +uint32_t IconFromDriveType(uint8_t driveType) { + if (driveType == ES_DRIVE_TYPE_HDD ) return ES_ICON_DRIVE_HARDDISK; + if (driveType == ES_DRIVE_TYPE_SSD ) return ES_ICON_DRIVE_HARDDISK_SOLIDSTATE; + if (driveType == ES_DRIVE_TYPE_CDROM ) return ES_ICON_MEDIA_OPTICAL; + if (driveType == ES_DRIVE_TYPE_USB_MASS_STORAGE) return ES_ICON_DRIVE_REMOVABLE_MEDIA_USB; + return ES_ICON_DRIVE_HARDDISK; +} diff --git a/apps/file_manager/ui.cpp b/apps/file_manager/ui.cpp new file mode 100644 index 0000000..63217dc --- /dev/null +++ b/apps/file_manager/ui.cpp @@ -0,0 +1,1079 @@ +// TODO Custom columns. + +void InstanceFolderPathChanged(Instance *instance, bool fromLoadFolder) { + if (fromLoadFolder) { + // Don't free the old path; it's used in the history stack. + } else { + StringDestroy(&instance->path); + } + + instance->path = StringDuplicate(instance->folder->path); + EsTextboxSelectAll(instance->breadcrumbBar); + EsTextboxInsert(instance->breadcrumbBar, STRING(instance->path)); + + uint8_t _buffer[256]; + EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; + instance->folder->containerHandler->getVisibleName(&buffer, instance->path); + EsWindowSetTitle(instance->window, (char *) buffer.out, buffer.position); + EsWindowSetIcon(instance->window, knownFileTypes[instance->folder->containerHandler->getFileType(instance->path)].iconID); + + EsListViewEnumerateVisibleItems(instance->list, [] (EsListView *, EsElement *item, uint32_t, EsGeneric index) { + ListItemCreated(item, index.u, true); + }); +} + +bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, int historyMode) { + // Check if the path hasn't changed. + + if (instance->folder && !instance->folder->refreshing && StringEquals(path, instance->folder->path)) { + StringDestroy(&path); + return true; + } + + Task task = {}; + + task.context = historyMode; + task.string = path; + task.cDescription = interfaceString_FileManagerOpenFolderTask; + + task.callback = [] (Instance *instance, Task *task) { + Folder *newFolder = nullptr; + task->result = FolderAttachInstance(instance, task->string, false, &newFolder); + task->context2 = newFolder; + StringDestroy(&task->string); + }; + + task.then = [] (Instance *instance, Task *task) { + if (ES_CHECK_ERROR(task->result)) { + EsTextboxSelectAll(instance->breadcrumbBar); + EsTextboxInsert(instance->breadcrumbBar, STRING(instance->path)); + InstanceReportError(instance, ERROR_LOAD_FOLDER, task->result); + return; + } + + int historyMode = task->context.i & 0xFF; + int flags = task->context.i; + Folder *folder = (Folder *) task->context2.p; + + // Add the path to the history array. + + HistoryEntry historyEntry = {}; + historyEntry.path = instance->path; + + EsGeneric focusedIndex; + + if (EsListViewGetFocusedItem(instance->list, nullptr, &focusedIndex)) { + String name = instance->listContents[focusedIndex.u].entry->GetName(); + historyEntry.focusedItem = StringDuplicate(name); + } + + if (historyMode == LOAD_FOLDER_BACK) { + instance->pathForwardHistory.Add(historyEntry); + } else if (historyMode == LOAD_FOLDER_FORWARD) { + instance->pathBackwardHistory.Add(historyEntry); + } else if (historyMode == LOAD_FOLDER_START || historyMode == LOAD_FOLDER_REFRESH) { + } else { + instance->pathBackwardHistory.Add(historyEntry); + + for (int i = 0; i < (int) instance->pathForwardHistory.Length(); i++) { + StringDestroy(&instance->pathForwardHistory[i].path); + StringDestroy(&instance->pathForwardHistory[i].focusedItem); + } + + instance->pathForwardHistory.SetLength(0); + } + + // Update commands. + + EsCommandSetDisabled(&instance->commandGoBackwards, !instance->pathBackwardHistory.Length()); + EsCommandSetDisabled(&instance->commandGoForwards, !instance->pathForwardHistory.Length()); + EsCommandSetDisabled(&instance->commandGoParent, PathCountSections(folder->path) == 1); + EsCommandSetDisabled(&instance->commandNewFolder, !folder->itemHandler->createChildFolder); + EsCommandSetDisabled(&instance->commandRename, true); + EsCommandSetDisabled(&instance->commandRefresh, false); + + // Detach from the old folder. + + EsMutexAcquire(&loadedFoldersMutex); + + InstanceRemoveContents(instance); + FolderDetachInstance(instance); + + // Load the view settings for the folder. + + bool foundViewSettings = false; + + if (folder->path.bytes < sizeof(folderViewSettings[0].path)) { + for (uintptr_t i = 0; i < folderViewSettings.Length(); i++) { + if (folderViewSettings[i].pathBytes == folder->path.bytes + && 0 == EsMemoryCompare(folderViewSettings[i].path, STRING(folder->path))) { + foundViewSettings = true; + FolderViewSettingsEntry entry = folderViewSettings[i]; + instance->viewSettings = entry.settings; + folderViewSettings.Delete(i); + folderViewSettings.Add(entry); // Update the LRU order. + break; + } + } + } + + if (!foundViewSettings) { + if (folder->itemHandler->getDefaultViewSettings) { + folder->itemHandler->getDefaultViewSettings(folder, &instance->viewSettings); + } else { + // TODO Get default from configuration. + instance->viewSettings.sortColumn = COLUMN_NAME; + instance->viewSettings.viewType = VIEW_DETAILS; + } + } + + InstanceRefreshViewType(instance); + + // Attach to the new folder. + + folder->attachingInstances.FindAndDeleteSwap(instance, true); + instance->folder = folder; + folder->attachedInstances.Add(instance); + + EsListViewSetEmptyMessage(instance->list, folder->cEmptyMessage); + InstanceAddContents(instance, &folder->entries); + + EsMutexRelease(&loadedFoldersMutex); + + InstanceFolderPathChanged(instance, true); + + if (~flags & LOAD_FOLDER_NO_FOCUS) { + EsElementFocus(instance->list); + } + + EsListViewInvalidateAll(instance->placesView); + }; + + BlockingTaskQueue(instance, task); + return true; +} + +void InstanceRefreshViewType(Instance *instance) { + if (instance->viewSettings.viewType == VIEW_DETAILS) { + EsCommandSetCheck(&instance->commandViewDetails, ES_CHECK_CHECKED, false); + EsCommandSetCheck(&instance->commandViewTiles, ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandViewThumbnails, ES_CHECK_UNCHECKED, false); + + EsListViewChangeStyles(instance->list, &styleFolderView, ES_STYLE_LIST_ITEM, nullptr, nullptr, ES_LIST_VIEW_COLUMNS, ES_LIST_VIEW_TILED); + EsListViewSetColumns(instance->list, folderOutputColumns, sizeof(folderOutputColumns) / sizeof(folderOutputColumns[0])); + } else if (instance->viewSettings.viewType == VIEW_TILES) { + EsCommandSetCheck(&instance->commandViewTiles, ES_CHECK_CHECKED, false); + EsCommandSetCheck(&instance->commandViewDetails, ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandViewThumbnails, ES_CHECK_UNCHECKED, false); + + EsListViewChangeStyles(instance->list, &styleFolderViewTiled, ES_STYLE_LIST_ITEM_TILE, nullptr, nullptr, ES_LIST_VIEW_TILED, ES_LIST_VIEW_COLUMNS); + } else if (instance->viewSettings.viewType == VIEW_THUMBNAILS) { + EsCommandSetCheck(&instance->commandViewThumbnails, ES_CHECK_CHECKED, false); + EsCommandSetCheck(&instance->commandViewTiles, ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandViewDetails, ES_CHECK_UNCHECKED, false); + + EsListViewChangeStyles(instance->list, &styleFolderViewTiled, &styleFolderItemThumbnail, nullptr, nullptr, ES_LIST_VIEW_TILED, ES_LIST_VIEW_COLUMNS); + } +} + +void InstanceUpdateItemSelectionCountCommands(Instance *instance) { + EsCommandSetDisabled(&instance->commandRename, instance->selectedItemCount != 1 || !instance->folder->itemHandler->renameItem); +} + +int InstanceCompareFolderEntries(FolderEntry *left, FolderEntry *right, uint16_t sortColumn) { + bool descending = sortColumn & (1 << 8); + sortColumn &= 0xFF; + + int result = 0; + + if (!left->isFolder && right->isFolder) { + result = 1; + } else if (!right->isFolder && left->isFolder) { + result = -1; + } else { + if (sortColumn == COLUMN_NAME) { + result = EsStringCompare(STRING(left->GetName()), STRING(right->GetName())); + } else if (sortColumn == COLUMN_TYPE) { + result = EsStringCompare(STRING(left->GetExtension()), STRING(right->GetExtension())); + } else if (sortColumn == COLUMN_SIZE) { + if (right->size < left->size) result = 1; + else if (right->size > left->size) result = -1; + else result = 0; + } + + if (!result && sortColumn != COLUMN_NAME) { + result = EsStringCompare(STRING(left->GetName()), STRING(right->GetName())); + } + + if (!result) { + if ((uintptr_t) right > (uintptr_t) left) result = 1; + else if ((uintptr_t) right < (uintptr_t) left) result = -1; + else result = 0; + } + } + + return descending ? -result : result; +} + +bool InstanceAddInternal(Instance *instance, ListEntry *entry) { + // TODO Filtering. + + entry->entry->handles++; + + if (entry->selected) { + instance->selectedItemCount++; + instance->selectedItemsTotalSize += entry->entry->size; + InstanceUpdateItemSelectionCountCommands(instance); + } + + return true; +} + +void InstanceRemoveInternal(Instance *instance, ListEntry *entry) { + FolderEntryCloseHandle(instance->folder, entry->entry); + + if (entry->selected) { + instance->selectedItemCount--; + instance->selectedItemsTotalSize -= entry->entry->size; + InstanceUpdateItemSelectionCountCommands(instance); + } +} + +void InstanceUpdateStatusString(Instance *instance) { + // TODO Localization. + + char buffer[1024]; + size_t bytes; + + size_t itemCount = instance->listContents.Length(); + + if (instance->selectedItemCount) { + bytes = EsStringFormat(buffer, sizeof(buffer), "Selected %d item%z (%D)", + instance->selectedItemCount, instance->selectedItemCount == 1 ? "" : "s", instance->selectedItemsTotalSize); + } else { + if (itemCount) { + if (instance->folder->spaceUsed) { + if (instance->folder->spaceTotal) { + bytes = EsStringFormat(buffer, sizeof(buffer), "%d item%z " HYPHENATION_POINT " %D out of %D used", + itemCount, itemCount == 1 ? "" : "s", instance->folder->spaceUsed, instance->folder->spaceTotal); + } else { + bytes = EsStringFormat(buffer, sizeof(buffer), "%d item%z (%D)", + itemCount, itemCount == 1 ? "" : "s", instance->folder->spaceUsed); + } + } else { + bytes = EsStringFormat(buffer, sizeof(buffer), "%d item%z", + itemCount, itemCount == 1 ? "" : "s"); + } + } else { + if (instance->folder && instance->folder->itemHandler->type == NAMESPACE_HANDLER_INVALID) { + bytes = EsStringFormat(buffer, sizeof(buffer), "Invalid path"); + } else { + bytes = EsStringFormat(buffer, sizeof(buffer), "Empty folder"); + } + } + } + + EsTextDisplaySetContents(instance->status, buffer, bytes); +} + +void InstanceAddSingle(Instance *instance, ListEntry entry) { + // Call with loadedFoldersMutex and message mutex. + + if (!InstanceAddInternal(instance, &entry)) { + return; // Filtered out. + } + + uintptr_t low = 0, high = instance->listContents.Length(); + + while (low < high) { + uintptr_t middle = (low + high) / 2; + int compare = InstanceCompareFolderEntries(instance->listContents[middle].entry, entry.entry, instance->viewSettings.sortColumn); + + if (compare == 0) { + // The entry is already in the list. + + EsListViewInvalidateContent(instance->list, 0, middle); + InstanceRemoveInternal(instance, &entry); + + ListEntry *existingEntry = &instance->listContents[middle]; + + if (existingEntry->selected) { + instance->selectedItemsTotalSize += existingEntry->entry->size - existingEntry->entry->previousSize; + InstanceUpdateStatusString(instance); + } + + return; + } else if (compare > 0) { + high = middle; + } else { + low = middle + 1; + } + } + + instance->listContents.Insert(entry, low); + EsListViewInsert(instance->list, 0, low, low); + + if (entry.selected) { + EsListViewSelect(instance->list, 0, low); + EsListViewFocusItem(instance->list, 0, low); + } + + InstanceUpdateStatusString(instance); +} + +ES_MACRO_SORT(InstanceSortListContents, ListEntry, { + result = InstanceCompareFolderEntries(_left->entry, _right->entry, context); +}, uint16_t); + +void InstanceAddContents(Instance *instance, HashTable *newEntries) { + // Call with loadedFoldersMutex and message mutex. + + size_t oldListEntryCount = instance->listContents.Length(); + + for (uintptr_t i = 0; i < newEntries->slotCount; i++) { + if (!newEntries->slots[i].key.used) { + continue; + } + + ListEntry entry = {}; + entry.entry = (FolderEntry *) newEntries->slots[i].value; + + if (InstanceAddInternal(instance, &entry)) { + instance->listContents.Add(entry); + } + } + + if (oldListEntryCount) { + EsListViewRemove(instance->list, 0, 0, oldListEntryCount - 1); + } + + InstanceSortListContents(instance->listContents.array, instance->listContents.Length(), instance->viewSettings.sortColumn); + + if (instance->listContents.Length()) { + EsListViewInsert(instance->list, 0, 0, instance->listContents.Length() - 1); + + if (instance->delayedFocusItem.bytes) { + for (uintptr_t i = 0; i < instance->listContents.Length(); i++) { + if (0 == EsStringCompareRaw(STRING(instance->listContents[i].entry->GetName()), STRING(instance->delayedFocusItem))) { + EsListViewSelect(instance->list, 0, i); + EsListViewFocusItem(instance->list, 0, i); + break; + } + } + + StringDestroy(&instance->delayedFocusItem); + } + } + + InstanceUpdateStatusString(instance); +} + +ListEntry InstanceRemoveSingle(Instance *instance, FolderEntry *folderEntry) { + uintptr_t low = 0, high = instance->listContents.Length(); + + while (low <= high) { + uintptr_t middle = (low + high) / 2; + int compare = InstanceCompareFolderEntries(instance->listContents[middle].entry, folderEntry, instance->viewSettings.sortColumn); + + if (compare == 0) { + ListEntry entry = instance->listContents[middle]; + InstanceRemoveInternal(instance, &entry); + EsListViewRemove(instance->list, 0, middle, middle); + instance->listContents.Delete(middle); + InstanceUpdateStatusString(instance); + return entry; + } else if (compare > 0) { + high = middle; + } else { + low = middle + 1; + } + } + + // It wasn't in the list. + return {}; +} + +void InstanceRemoveContents(Instance *instance) { + for (uintptr_t i = 0; i < instance->listContents.Length(); i++) { + InstanceRemoveInternal(instance, &instance->listContents[i]); + } + + EsAssert(instance->selectedItemCount == 0); // After removing all items none should be selected. + + if (instance->listContents.Length()) { + EsListViewRemove(instance->list, 0, 0, instance->listContents.Length() - 1); + EsListViewContentChanged(instance->list); + } + + instance->listContents.Free(); + InstanceUpdateStatusString(instance); +} + +ListEntry *InstanceGetSelectedListEntry(Instance *instance) { + for (uintptr_t i = 0; i < instance->listContents.Length(); i++) { + ListEntry *entry = &instance->listContents[i]; + + if (entry->selected) { + return entry; + } + } + + return nullptr; +} + +void InstanceViewSettingsUpdated(Instance *instance) { + if (!instance->folder) return; // We were called early in initialization of the instance; ignore. + + if (instance->path.bytes < sizeof(folderViewSettings[0].path)) { + bool foundViewSettings = false; + + for (uintptr_t i = 0; i < folderViewSettings.Length(); i++) { + if (folderViewSettings[i].pathBytes == instance->path.bytes + && 0 == EsMemoryCompare(folderViewSettings[i].path, STRING(instance->path))) { + foundViewSettings = true; + folderViewSettings[i].settings = instance->viewSettings; + break; + } + } + + if (!foundViewSettings) { + if (folderViewSettings.Length() == FOLDER_VIEW_SETTINGS_MAXIMUM_ENTRIES) { + folderViewSettings.Delete(0); + } + + FolderViewSettingsEntry *entry = folderViewSettings.Add(); + EsMemoryCopy(entry->path, STRING(instance->path)); + entry->pathBytes = instance->path.bytes; + entry->settings = instance->viewSettings; + } + } + + ConfigurationSave(); +} + +void InstanceChangeSortColumn(EsMenu *menu, EsGeneric context) { + Instance *instance = menu->instance; + instance->viewSettings.sortColumn = context.u; + InstanceViewSettingsUpdated(instance); + InstanceSortListContents(instance->listContents.array, instance->listContents.Length(), instance->viewSettings.sortColumn); + EsListViewContentChanged(instance->list); +} + +__attribute__((optimize("-O3"))) +void ThumbnailResize(uint32_t *bits, uint32_t originalWidth, uint32_t originalHeight, uint32_t targetWidth, uint32_t targetHeight) { + // NOTE Modifies the original bits! + // NOTE It looks like this only gets vectorised in -O3. + // TODO Move into the API. + + float cx = (float) originalWidth / targetWidth; + float cy = (float) originalHeight / targetHeight; + + for (uint32_t i = 0; i < originalHeight; i++) { + uint32_t *output = bits + i * originalWidth; + uint32_t *input = output; + + for (uint32_t j = 0; j < targetWidth; j++) { + uint32_t sumAlpha = 0, sumRed = 0, sumGreen = 0, sumBlue = 0; + uint32_t count = (uint32_t) ((j + 1) * cx) - (uint32_t) (j * cx); + + for (uint32_t k = 0; k < count; k++, input++) { + uint32_t pixel = *input; + sumAlpha += (pixel >> 24) & 0xFF; + sumRed += (pixel >> 16) & 0xFF; + sumGreen += (pixel >> 8) & 0xFF; + sumBlue += (pixel >> 0) & 0xFF; + } + + sumAlpha /= count; + sumRed /= count; + sumGreen /= count; + sumBlue /= count; + + *output = (sumAlpha << 24) | (sumRed << 16) | (sumGreen << 8) | (sumBlue << 0); + output++; + } + } + + for (uint32_t i = 0; i < targetWidth; i++) { + uint32_t *output = bits + i; + uint32_t *input = output; + + for (uint32_t j = 0; j < targetHeight; j++) { + uint32_t sumAlpha = 0, sumRed = 0, sumGreen = 0, sumBlue = 0; + uint32_t count = (uint32_t) ((j + 1) * cy) - (uint32_t) (j * cy); + + for (uint32_t k = 0; k < count; k++, input += originalWidth) { + uint32_t pixel = *input; + sumAlpha += (pixel >> 24) & 0xFF; + sumRed += (pixel >> 16) & 0xFF; + sumGreen += (pixel >> 8) & 0xFF; + sumBlue += (pixel >> 0) & 0xFF; + } + + sumAlpha /= count; + sumRed /= count; + sumGreen /= count; + sumBlue /= count; + + *output = (sumAlpha << 24) | (sumRed << 16) | (sumGreen << 8) | (sumBlue << 0); + output += originalWidth; + } + } + + for (uint32_t i = 0; i < targetHeight; i++) { + for (uint32_t j = 0; j < targetWidth; j++) { + bits[i * targetWidth + j] = bits[i * originalWidth + j]; + } + } +} + +void ListItemGenerateThumbnailTask(Instance *, Task *task) { + EsMessageMutexAcquire(); + Thumbnail *thumbnail = thumbnailCache.Get(&task->id); + bool cancelTask = !thumbnail || thumbnail->referenceCount == 0; + EsMessageMutexRelease(); + + if (cancelTask) { + return; // There are no longer any list items visible for this file. + } + + size_t fileBytes; + void *file = EsFileReadAll(STRING(task->string), &fileBytes); + + if (!file) { + return; // The file could not be loaded. + } + + // TODO Allow applications to register their own thumbnail generators. + uint32_t originalWidth, originalHeight; + uint32_t *originalBits = (uint32_t *) EsImageLoad(file, fileBytes, &originalWidth, &originalHeight, 4); + EsHeapFree(file); + + if (!originalBits) { + return; // The image could not be loaded. + } + + // TODO Determine the best value for these constants -- maybe base it off the current UI scale factor? + uint32_t thumbnailMaximumWidth = 120; + uint32_t thumbnailMaximumHeight = 80; + EsRectangle targetRectangle = EsRectangleFit(ES_RECT_2S(thumbnailMaximumWidth, thumbnailMaximumHeight), ES_RECT_2S(originalWidth, originalHeight), false); + uint32_t targetWidth = ES_RECT_WIDTH(targetRectangle), targetHeight = ES_RECT_HEIGHT(targetRectangle); + uint32_t *targetBits; + + if (targetWidth == originalWidth && targetHeight == originalHeight) { + targetBits = originalBits; + } else { + targetBits = (uint32_t *) EsHeapAllocate(targetWidth * targetHeight * 4, false); + + if (!targetBits) { + EsHeapFree(originalBits); + return; // Allocation failure; could not resize the image. + } + + ThumbnailResize(originalBits, originalWidth, originalHeight, targetWidth, targetHeight); + targetBits = (uint32_t *) EsHeapReallocate(originalBits, targetWidth * targetHeight * 4, false); + } + + EsMessageMutexAcquire(); + + thumbnail = thumbnailCache.Get(&task->id); + + if (thumbnail) { + if (thumbnail->bits) EsHeapFree(thumbnail->bits); + thumbnail->bits = targetBits; + thumbnail->width = targetWidth; + thumbnail->height = targetHeight; + // TODO Submit width/height properties. + } + + EsMessageMutexRelease(); +} + +void ListItemGenerateThumbnailTaskComplete(Instance *, Task *task) { + Thumbnail *thumbnail = thumbnailCache.Get(&task->id); + + if (thumbnail) { + thumbnail->generatingTasksInProgress--; + } + + String parent = PathGetParent(task->string); + + for (uintptr_t i = 0; i < instances.Length(); i++) { + if (StringEquals(parent, instances[i]->path)) { // TODO Support recursive views. + EsListViewInvalidateAll(instances[i]->list); + } + } + + StringDestroy(&task->string); +} + +Thumbnail *ListItemGetThumbnail(EsElement *element) { + Instance *instance = element->instance; + ListEntry *entry = &instance->listContents[EsListViewGetIndexFromItem(element).u]; + Thumbnail *thumbnail = thumbnailCache.Get(&entry->entry->id); + return thumbnail; +} + +void ListItemCreated(EsElement *element, uintptr_t index, bool fromFolderRename) { + Instance *instance = element->instance; + + if (instance->viewSettings.viewType != VIEW_THUMBNAILS && instance->viewSettings.viewType != VIEW_TILES) { + return; // The current view does not display thumbnails. + } + + ListEntry *listEntry = &instance->listContents[index]; + FolderEntry *entry = listEntry->entry; + FileType *fileType = FolderEntryGetType(instance->folder, entry); + + if (!fileType->hasThumbnailGenerator) { + return; // The file type does not support thumbnail generation. + } + + Thumbnail *thumbnail = thumbnailCache.Put(&entry->id); + + if (!fromFolderRename) { + thumbnail->referenceCount++; + } + + // TODO Remove from LRU if needed. + + if ((thumbnail->generatingTasksInProgress && !fromFolderRename) || thumbnail->bits) { + return; // The thumbnail is already being/has already been generated. + } + + thumbnail->generatingTasksInProgress++; + + String path = StringAllocateAndFormat("%s%s", STRFMT(instance->path), STRFMT(entry->GetName())); + + Task task = { + .string = path, + .id = entry->id, + .callback = ListItemGenerateThumbnailTask, + .then = ListItemGenerateThumbnailTaskComplete, + }; + + NonBlockingTaskQueue(task); +} + +int ListItemMessage(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_DESTROY) { + Thumbnail *thumbnail = ListItemGetThumbnail(element); + + if (thumbnail) { + thumbnail->referenceCount--; + + // TODO When the referenceCount drops to 0, put it on a LRU list. + } + } else if (message->type == ES_MSG_PAINT_ICON) { + if (element->instance->viewSettings.viewType == VIEW_THUMBNAILS || element->instance->viewSettings.viewType == VIEW_TILES) { + Thumbnail *thumbnail = ListItemGetThumbnail(element); + + if (thumbnail && thumbnail->bits) { + EsRectangle destination = EsPainterBoundsClient(message->painter); + EsRectangle source = ES_RECT_2S(thumbnail->width, thumbnail->height); + destination = EsRectangleFit(destination, source, false); + // EsDrawBlock(message->painter, EsRectangleAdd(destination, ES_RECT_1(2)), 0x20000000); + EsDrawBitmapScaled(message->painter, destination, source, thumbnail->bits, thumbnail->width * 4, 0xFF); + return ES_HANDLED; + } + } + } + + return 0; +} + +int ListCallback(EsElement *element, EsMessage *message) { + Instance *instance = element->instance; + + if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) { + int column = message->getContent.column, index = message->getContent.index.i; + EsAssert(index < (int) instance->listContents.Length() && index >= 0); + ListEntry *listEntry = &instance->listContents[index]; + FolderEntry *entry = listEntry->entry; + FileType *fileType = FolderEntryGetType(instance->folder, entry); + + if (column == COLUMN_NAME) { + String name = entry->GetName(); + EsBufferFormat(message->getContent.buffer, "%s", name.bytes, name.text); + message->getContent.icon = fileType->iconID; + } else if (column == COLUMN_TYPE) { + EsBufferFormat(message->getContent.buffer, "%z", fileType->name); + } else if (column == COLUMN_SIZE) { + if (!entry->sizeUnknown) { + EsBufferFormat(message->getContent.buffer, "%D", entry->size); + } + } + } else if (message->type == ES_MSG_LIST_VIEW_GET_SUMMARY) { + int index = message->getContent.index.i; + EsAssert(index < (int) instance->listContents.Length() && index >= 0); + ListEntry *listEntry = &instance->listContents[index]; + FolderEntry *entry = listEntry->entry; + FileType *fileType = FolderEntryGetType(instance->folder, entry); + String name = entry->GetName(); + EsBufferFormat(message->getContent.buffer, "%s\n\a2]%z " HYPHENATION_POINT " %D", name.bytes, name.text, fileType->name, entry->size); + message->getContent.icon = fileType->iconID; + message->getContent.richText = true; + } else if (message->type == ES_MSG_LIST_VIEW_SELECT_RANGE) { + for (intptr_t i = message->selectRange.fromIndex.i; i <= message->selectRange.toIndex.i; i++) { + ListEntry *entry = &instance->listContents[i]; + if (entry->selected) { instance->selectedItemCount--; instance->selectedItemsTotalSize -= entry->entry->size; } + entry->selected = message->selectRange.toggle ? !entry->selected : message->selectRange.select; + if (entry->selected) { instance->selectedItemCount++; instance->selectedItemsTotalSize += entry->entry->size; } + } + + InstanceUpdateItemSelectionCountCommands(instance); + StringDestroy(&instance->delayedFocusItem); + InstanceUpdateStatusString(instance); + } else if (message->type == ES_MSG_LIST_VIEW_SELECT) { + ListEntry *entry = &instance->listContents[message->selectItem.index.i]; + if (entry->selected) { instance->selectedItemCount--; instance->selectedItemsTotalSize -= entry->entry->size; } + entry->selected = message->selectItem.isSelected; + if (entry->selected) { instance->selectedItemCount++; instance->selectedItemsTotalSize += entry->entry->size; } + InstanceUpdateItemSelectionCountCommands(instance); + StringDestroy(&instance->delayedFocusItem); + InstanceUpdateStatusString(instance); + } else if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED) { + ListEntry *entry = &instance->listContents[message->selectItem.index.i]; + message->selectItem.isSelected = entry->selected; + } else if (message->type == ES_MSG_LIST_VIEW_CHOOSE_ITEM) { + ListEntry *listEntry = &instance->listContents[message->chooseItem.index.i]; + + if (listEntry) { + FolderEntry *entry = listEntry->entry; + + if (entry->isFolder) { + String path = instance->folder->itemHandler->getPathForChildFolder(instance->folder, entry->GetInternalName()); + InstanceLoadFolder(instance, path); + } else { + FileType *fileType = FolderEntryGetType(instance->folder, entry); + + if (fileType->openHandler) { + String path = StringAllocateAndFormat("%s%s", STRFMT(instance->folder->path), STRFMT(entry->GetInternalName())); + EsApplicationStartupInformation information = {}; + information.id = fileType->openHandler; + information.filePath = path.text; + information.filePathBytes = path.bytes; + EsApplicationStart(&information); + StringDestroy(&path); + } else { + EsDialogShowAlert(instance->window, INTERFACE_STRING(FileManagerOpenFileError), + INTERFACE_STRING(FileManagerNoRegisteredApplicationsForFile), + ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON); + } + } + } + } else if (message->type == ES_MSG_LIST_VIEW_COLUMN_MENU) { + EsMenu *menu = EsMenuCreate(message->columnMenu.source); + uint32_t index = (uint32_t) message->columnMenu.index; + EsMenuAddItem(menu, instance->viewSettings.sortColumn == index ? ES_MENU_ITEM_CHECKED : 0, + INTERFACE_STRING(CommonSortAscending), InstanceChangeSortColumn, index); + EsMenuAddItem(menu, instance->viewSettings.sortColumn == (index | (1 << 8)) ? ES_MENU_ITEM_CHECKED : 0, + INTERFACE_STRING(CommonSortDescending), InstanceChangeSortColumn, index | (1 << 8)); + EsMenuShow(menu); + } else if (message->type == ES_MSG_LIST_VIEW_GET_COLUMN_SORT) { + if (message->getColumnSort.index == (instance->viewSettings.sortColumn & 0xFF)) { + return (instance->viewSettings.sortColumn & (1 << 8)) ? ES_LIST_VIEW_COLUMN_SORT_DESCENDING : ES_LIST_VIEW_COLUMN_SORT_ASCENDING; + } + } else if (message->type == ES_MSG_LIST_VIEW_CREATE_ITEM) { + EsElement *element = message->createItem.item; + element->messageUser = ListItemMessage; + ListItemCreated(element, message->createItem.index.u, false); + } else if (message->type == ES_MSG_MOUSE_RIGHT_CLICK) { + EsMenu *menu = EsMenuCreate(element, ES_MENU_AT_CURSOR); + +#define ADD_SORT_COLUMN_MENU_ITEM(_column, _string) \ + EsMenuAddItem(menu, instance->viewSettings.sortColumn == (_column) ? ES_MENU_ITEM_CHECKED : ES_FLAGS_DEFAULT, \ + INTERFACE_STRING(_string), InstanceChangeSortColumn, _column) + EsMenuAddItem(menu, ES_MENU_ITEM_HEADER, INTERFACE_STRING(CommonSortAscending)); + ADD_SORT_COLUMN_MENU_ITEM(COLUMN_NAME, FileManagerColumnName); + ADD_SORT_COLUMN_MENU_ITEM(COLUMN_TYPE, FileManagerColumnType); + ADD_SORT_COLUMN_MENU_ITEM(COLUMN_SIZE, FileManagerColumnSize); + EsMenuAddSeparator(menu); + EsMenuAddItem(menu, ES_MENU_ITEM_HEADER, INTERFACE_STRING(CommonSortDescending)); + ADD_SORT_COLUMN_MENU_ITEM(COLUMN_NAME | (1 << 8), FileManagerColumnName); + ADD_SORT_COLUMN_MENU_ITEM(COLUMN_TYPE | (1 << 8), FileManagerColumnType); + ADD_SORT_COLUMN_MENU_ITEM(COLUMN_SIZE | (1 << 8), FileManagerColumnSize); +#undef ADD_SORT_COLUMN_MENU_ITEM + + EsMenuNextColumn(menu); + + EsMenuAddItem(menu, ES_MENU_ITEM_HEADER, INTERFACE_STRING(FileManagerListContextActions)); + EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonClipboardPaste), EsCommandByID(instance, ES_COMMAND_PASTE)); + EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonSelectionSelectAll), EsCommandByID(instance, ES_COMMAND_SELECT_ALL)); + EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(FileManagerNewFolderToolbarItem), &instance->commandNewFolder); + EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(FileManagerRefresh), &instance->commandRefresh); + + EsMenuAddSeparator(menu); + +#define ADD_VIEW_TYPE_MENU_ITEM(_command, _string) \ + EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(_string), _command) + EsMenuAddItem(menu, ES_MENU_ITEM_HEADER, INTERFACE_STRING(CommonListViewType)); + ADD_VIEW_TYPE_MENU_ITEM(&instance->commandViewThumbnails, CommonListViewTypeThumbnails); + ADD_VIEW_TYPE_MENU_ITEM(&instance->commandViewTiles, CommonListViewTypeTiles); + ADD_VIEW_TYPE_MENU_ITEM(&instance->commandViewDetails, CommonListViewTypeDetails); +#undef ADD_VIEW_TYPE_MENU_ITEM + + EsMenuShow(menu); + } else { + return 0; + } + + return ES_HANDLED; +} + +int PlacesViewCallback(EsElement *element, EsMessage *message) { + Instance *instance = element->instance; + + if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) { + int group = message->getContent.group; + int index = message->getContent.index.i; + + if (group == PLACES_VIEW_GROUP_DRIVES) { + // TODO Use namespace lookup. + + if (index == 0) { + EsBufferFormat(message->getContent.buffer, "%z", interfaceString_FileManagerPlacesDrives); + message->getContent.icon = ES_ICON_COMPUTER_LAPTOP; + } else { + Drive *drive = &drives[index - 1]; + EsBufferFormat(message->getContent.buffer, "%s", drive->information.labelBytes, drive->information.label); + message->getContent.icon = IconFromDriveType(drive->information.driveType); + } + } else if (group == PLACES_VIEW_GROUP_BOOKMARKS) { + if (index == 0) { + EsBufferFormat(message->getContent.buffer, "%z", interfaceString_FileManagerPlacesBookmarks); + message->getContent.icon = ES_ICON_HELP_ABOUT; + } else { + // TODO The namespace lookup might be expensive. Perhaps these should be cached? + NamespaceGetVisibleName(message->getContent.buffer, bookmarks[index - 1]); + message->getContent.icon = NamespaceGetIcon(bookmarks[index - 1]); + } + } + } else if (message->type == ES_MSG_LIST_VIEW_SELECT && message->selectItem.isSelected) { + if (message->selectItem.group == PLACES_VIEW_GROUP_DRIVES) { + if (message->selectItem.index.i == 0) { + InstanceLoadFolder(instance, StringAllocateAndFormat("%z", interfaceString_FileManagerDrivesPage), LOAD_FOLDER_NO_FOCUS); + } else { + Drive *drive = &drives[message->selectItem.index.i - 1]; + InstanceLoadFolder(instance, StringAllocateAndFormat("%s/", drive->prefixBytes, drive->prefix), LOAD_FOLDER_NO_FOCUS); + } + } else if (message->selectItem.group == PLACES_VIEW_GROUP_BOOKMARKS && message->selectItem.index.i) { + String string = bookmarks[message->selectItem.index.i - 1]; + InstanceLoadFolder(instance, StringAllocateAndFormat("%s", STRFMT(string)), LOAD_FOLDER_NO_FOCUS); + } + } else if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED) { + if (message->selectItem.group == PLACES_VIEW_GROUP_DRIVES) { + if (message->selectItem.index.i == 0) { + message->selectItem.isSelected = 0 == EsStringCompareRaw(INTERFACE_STRING(FileManagerDrivesPage), + instance->path.text, instance->path.bytes); + } else { + Drive *drive = &drives[message->selectItem.index.i - 1]; + message->selectItem.isSelected = 0 == EsStringCompareRaw(drive->prefix, drive->prefixBytes, + instance->path.text, instance->path.bytes - 1); + } + } else if (message->selectItem.group == PLACES_VIEW_GROUP_BOOKMARKS && message->selectItem.index.i) { + String string = bookmarks[message->selectItem.index.i - 1]; + message->selectItem.isSelected = 0 == EsStringCompareRaw(string.text, string.bytes, + instance->path.text, instance->path.bytes); + } + } else if (message->type == ES_MSG_LIST_VIEW_CONTEXT_MENU) { + if (message->selectItem.group == PLACES_VIEW_GROUP_BOOKMARKS && !message->selectItem.index.i) { + bool isCurrentFolderBookmarked = false; + + for (uintptr_t i = 0; i < bookmarks.Length(); i++) { + if (0 == EsStringCompareRaw(STRING(bookmarks[i]), STRING(instance->path))) { + isCurrentFolderBookmarked = true; + break; + } + } + + EsMenu *menu = EsMenuCreate(element, ES_MENU_AT_CURSOR); + + if (isCurrentFolderBookmarked) { + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(FileManagerBookmarksRemoveHere), [] (EsMenu *menu, EsGeneric) { + BookmarkRemove(menu->instance->path); + }); + } else { + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(FileManagerBookmarksAddHere), [] (EsMenu *menu, EsGeneric) { + BookmarkAdd(menu->instance->path); + }); + } + + EsMenuShow(menu); + } + } else { + return 0; + } + + return ES_HANDLED; +} + +int BreadcrumbBarMessage(EsElement *element, EsMessage *message) { + Instance *instance = element->instance; + + if (message->type == ES_MSG_TEXTBOX_ACTIVATE_BREADCRUMB) { + String section = PathGetSection(instance->folder->path, message->activateBreadcrumb); + size_t bytes = section.text + section.bytes - instance->folder->path.text; + + String path = StringAllocateAndFormat("%s%z", + bytes, instance->folder->path.text, + instance->folder->path.text[bytes - 1] != '/' ? "/" : ""); + InstanceLoadFolder(instance, path); + } else if (message->type == ES_MSG_TEXTBOX_EDIT_END) { + String section; + section.text = EsTextboxGetContents(instance->breadcrumbBar, §ion.bytes); + section.allocated = section.bytes; + + String path = StringAllocateAndFormat("%s%z", + section.bytes, section.text, + section.text[section.bytes - 1] != '/' ? "/" : ""); + + if (!InstanceLoadFolder(instance, path)) { + StringDestroy(§ion); + return ES_REJECTED; + } + + StringDestroy(§ion); + } else if (message->type == ES_MSG_TEXTBOX_GET_BREADCRUMB) { + if (!instance->folder || PathCountSections(instance->folder->path) == message->getBreadcrumb.index) { + return ES_REJECTED; + } + + String path = PathGetParent(instance->folder->path, message->getBreadcrumb.index); + NamespaceGetVisibleName(message->getBreadcrumb.buffer, path); + return ES_HANDLED; + } + + return 0; +} + +#define ADD_BUTTON_TO_TOOLBAR(_command, _label, _icon, _accessKey, _name) \ + { \ + _name = EsButtonCreate(toolbar, ES_FLAGS_DEFAULT, 0, _label); \ + EsButtonSetIcon(_name, _icon); \ + EsCommandAddButton(&instance->_command, _name); \ + _name->accessKey = _accessKey; \ + } + +#define ADD_BUTTON_TO_STATUS_BAR(_command, _label, _icon, _accessKey, _name) \ + { \ + _name = EsButtonCreate(statusBar, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_STATUS_BAR, _label); \ + EsButtonSetIcon(_name, _icon); \ + EsCommandAddButton(&instance->_command, _name); \ + _name->accessKey = _accessKey; \ + } + +void InstanceCreateUI(Instance *instance) { + EsButton *button; + + EsWindowSetIcon(instance->window, ES_ICON_SYSTEM_FILE_MANAGER); + InstanceRegisterCommands(instance); + + EsPanel *rootPanel = EsPanelCreate(instance->window, ES_CELL_FILL | ES_PANEL_VERTICAL); + EsSplitter *splitter = EsSplitterCreate(rootPanel, ES_SPLITTER_HORIZONTAL | ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_WITH_STATUS_BAR_CONTENT); + + // Places: + + instance->placesView = EsListViewCreate(splitter, ES_CELL_EXPAND | ES_CELL_COLLAPSABLE | ES_LIST_VIEW_SINGLE_SELECT | ES_CELL_V_FILL, + &stylePlacesView, ES_STYLE_LIST_ITEM, ES_STYLE_LIST_ITEM, nullptr); + instance->placesView->accessKey = 'P'; + instance->placesView->messageUser = PlacesViewCallback; + EsListViewInsertGroup(instance->placesView, PLACES_VIEW_GROUP_BOOKMARKS, ES_LIST_VIEW_GROUP_HAS_HEADER | ES_LIST_VIEW_GROUP_INDENT); + EsListViewInsertGroup(instance->placesView, PLACES_VIEW_GROUP_DRIVES, ES_LIST_VIEW_GROUP_HAS_HEADER | ES_LIST_VIEW_GROUP_INDENT); + if (bookmarks.Length()) EsListViewInsert(instance->placesView, PLACES_VIEW_GROUP_BOOKMARKS, 1, bookmarks.Length()); + EsListViewInsert(instance->placesView, PLACES_VIEW_GROUP_DRIVES, 1, drives.Length()); + + // Main list: + + instance->list = EsListViewCreate(splitter, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_MULTI_SELECT, &styleFolderView); + instance->list->accessKey = 'L'; + instance->list->messageUser = ListCallback; + EsListViewSetColumns(instance->list, folderOutputColumns, sizeof(folderOutputColumns) / sizeof(folderOutputColumns[0])); + EsListViewInsertGroup(instance->list, 0); + + // Toolbar: + + EsElement *toolbar = EsWindowGetToolbar(instance->window); + ADD_BUTTON_TO_TOOLBAR(commandGoBackwards, nullptr, ES_ICON_GO_PREVIOUS_SYMBOLIC, 'B', button); + ADD_BUTTON_TO_TOOLBAR(commandGoForwards, nullptr, ES_ICON_GO_NEXT_SYMBOLIC, 'F', button); + ADD_BUTTON_TO_TOOLBAR(commandGoParent, nullptr, ES_ICON_GO_UP_SYMBOLIC, 'U', button); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT); + instance->breadcrumbBar = EsTextboxCreate(toolbar, ES_CELL_H_FILL | ES_TEXTBOX_EDIT_BASED | ES_TEXTBOX_REJECT_EDIT_IF_LOST_FOCUS, {}); + instance->breadcrumbBar->messageUser = BreadcrumbBarMessage; + EsTextboxUseBreadcrumbOverlay(instance->breadcrumbBar); + ADD_BUTTON_TO_TOOLBAR(commandNewFolder, interfaceString_FileManagerNewFolderToolbarItem, ES_ICON_FOLDER_NEW_SYMBOLIC, 'N', instance->newFolderButton); + + // Status bar: + + EsPanel *statusBar = EsPanelCreate(rootPanel, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_STATUS_BAR); + instance->status = EsTextDisplayCreate(statusBar, ES_CELL_H_FILL); + ADD_BUTTON_TO_STATUS_BAR(commandViewDetails, nullptr, ES_ICON_VIEW_LIST_SYMBOLIC, 0, button); + ADD_BUTTON_TO_STATUS_BAR(commandViewTiles, nullptr, ES_ICON_VIEW_LIST_COMPACT_SYMBOLIC, 0, button); + ADD_BUTTON_TO_STATUS_BAR(commandViewThumbnails, nullptr, ES_ICON_VIEW_GRID_SYMBOLIC, 0, button); + + // Load initial folder: + + const EsApplicationStartupInformation *startupInformation = EsInstanceGetStartupInformation(instance); + String path; + + if (startupInformation && (startupInformation->flags & ES_APPLICATION_STARTUP_MANUAL_PATH)) { + uintptr_t directoryEnd = startupInformation->filePathBytes; + + for (uintptr_t i = 0; i < (uintptr_t) startupInformation->filePathBytes; i++) { + if (startupInformation->filePath[i] == '/') { + directoryEnd = i + 1; + } + } + + instance->delayedFocusItem = StringAllocateAndFormat("%s", startupInformation->filePathBytes - directoryEnd, startupInformation->filePath + directoryEnd); + path = StringAllocateAndFormat("%s", directoryEnd, startupInformation->filePath); + } else { + path = StringAllocateAndFormat("0:/"); + } + + InstanceLoadFolder(instance, path, LOAD_FOLDER_START); +} + +void InstanceReportError(Instance *instance, int error, EsError code) { + EsPrint("FM error %d/%d.\n", error, code); + + // TODO Error messages. + + const char *message = interfaceString_FileManagerGenericError; + + if (code == ES_ERROR_FILE_ALREADY_EXISTS) { + message = interfaceString_FileManagerItemAlreadyExistsError; + } else if (code == ES_ERROR_FILE_DOES_NOT_EXIST) { + message = interfaceString_FileManagerItemDoesNotExistError; + } else if (code == ES_ERROR_FILE_PERMISSION_NOT_GRANTED) { + message = interfaceString_FileManagerPermissionNotGrantedError; + } + + EsDialogShowAlert(instance->window, errorTypeStrings[error], -1, message, -1, + ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON); +} + +void InstanceDestroy(Instance *instance) { + StringDestroy(&instance->path); + StringDestroy(&instance->delayedFocusItem); + + for (uintptr_t i = 0; i < instance->pathBackwardHistory.Length(); i++) { + StringDestroy(&instance->pathBackwardHistory[i].path); + StringDestroy(&instance->pathBackwardHistory[i].focusedItem); + } + + for (uintptr_t i = 0; i < instance->pathForwardHistory.Length(); i++) { + StringDestroy(&instance->pathForwardHistory[i].path); + StringDestroy(&instance->pathForwardHistory[i].focusedItem); + } + + for (uintptr_t i = 0; i < instance->listContents.Length(); i++) { + FolderEntryCloseHandle(instance->folder, instance->listContents[i].entry); + } + + FolderDetachInstance(instance); + + instance->pathBackwardHistory.Free(); + instance->pathForwardHistory.Free(); + instance->listContents.Free(); +} diff --git a/apps/fly.cpp b/apps/fly.cpp new file mode 100644 index 0000000..988c26f --- /dev/null +++ b/apps/fly.cpp @@ -0,0 +1,942 @@ +// TODO Icon. +// TODO Music. +// TODO Draw() with rotation. +// TODO Saving with new file IO. + +#include + +EsInstance *instance; +uint32_t backgroundColor; +int musicIndex; +bool keysPressedSpace, keysPressedEscape, keysPressedX; +uint32_t previousControllerButtons[ES_GAME_CONTROLLER_MAX_COUNT]; +uint32_t *targetBits; +size_t targetWidth, targetHeight, targetStride; +double updateTimeAccumulator; +float gameScale; +uint32_t gameOffsetX, gameOffsetY, gameWidth, gameHeight; + +#define GAME_SIZE (380) +#define BRAND "fly" + +struct Texture { + uint32_t width, height; + uint32_t *bits; +}; + +void Transform(float *destination, float *left, float *right) { + float d[6]; + d[0] = left[0] * right[0] + left[1] * right[3]; + d[1] = left[0] * right[1] + left[1] * right[4]; + d[2] = left[0] * right[2] + left[1] * right[5] + left[2]; + d[3] = left[3] * right[0] + left[4] * right[3]; + d[4] = left[3] * right[1] + left[4] * right[4]; + d[5] = left[3] * right[2] + left[4] * right[5] + left[5]; + destination[0] = d[0]; + destination[1] = d[1]; + destination[2] = d[2]; + destination[3] = d[3]; + destination[4] = d[4]; + destination[5] = d[5]; +} + +__attribute__((optimize("-O2"))) +void Draw(Texture *texture, + float x, float y, float w = -1, float h = -1, + float sx = 0, float sy = 0, float sw = -1, float sh = -1, + float _a = 1, float _r = 1, float _g = 1, float _b = 1, + float rot = 0) { + (void) rot; + + if (sw == -1 && sh == -1) sw = texture->width, sh = texture->height; + if (w == -1 && h == -1) w = sw, h = sh; + if (_a <= 0) return; + + if (x + w < 0 || y + h < 0 || x > GAME_SIZE || y > GAME_SIZE) return; + + x *= gameScale, y *= gameScale, w *= gameScale, h *= gameScale; + + float m[6] = {}; + float m1[6] = { sw / w, 0, 0, 0, sh / h, 0 }; + float m2[6] = { 1, 0, -x * (sw / w), 0, 1, -y * (sh / h) }; + + Transform(m, m2, m1); + + intptr_t yStart = y - 1, yEnd = y + h + 1, xStart = x - 1, xEnd = x + w + 1; + // if (rot) yStart -= h * 0.45f, yEnd += h * 0.45f, xStart -= w * 0.45f, xEnd += w * 0.45f; + if (yStart < 0) yStart = 0; + if (yStart > gameHeight) yStart = gameHeight; + if (yEnd < 0) yEnd = 0; + if (yEnd > gameHeight) yEnd = gameHeight; + if (xStart < 0) xStart = 0; + if (xStart > gameWidth) xStart = gameWidth; + if (xEnd < 0) xEnd = 0; + if (xEnd > gameWidth) xEnd = gameWidth; + m[2] += m[0] * xStart, m[5] += m[3] * xStart; + + uint32_t *scanlineStart = targetBits + (gameOffsetY + yStart) * targetStride / 4 + (gameOffsetX + xStart); + + uint32_t r = _r * 255, g = _g * 255, b = _b * 255, a = _a * 255; + + for (intptr_t y = yStart; y < yEnd; y++, scanlineStart += targetStride / 4) { + uint32_t *output = scanlineStart; + + float tx = m[1] * y + m[2]; + float ty = m[4] * y + m[5]; + + for (intptr_t x = xStart; x < xEnd; x++, output++, tx += m[0], ty += m[3]) { + if (tx + sx < 0 || ty + sy < 0) continue; + uintptr_t txi = tx + sx, tyi = ty + sy; + if (txi < sx || tyi < sy || txi >= sx + sw || tyi >= sy + sh) continue; + uint32_t modified = texture->bits[tyi * texture->width + txi]; + if (!(modified & 0xFF000000)) continue; + uint32_t original = *output; + uint32_t alpha1 = (((modified & 0xFF000000) >> 24) * a) >> 8; + uint32_t alpha2 = (255 - alpha1) << 8; + uint32_t r2 = alpha2 * ((original & 0x00FF0000) >> 16); + uint32_t g2 = alpha2 * ((original & 0x0000FF00) >> 8); + uint32_t b2 = alpha2 * ((original & 0x000000FF) >> 0); + uint32_t r1 = r * alpha1 * ((modified & 0x00FF0000) >> 16); + uint32_t g1 = g * alpha1 * ((modified & 0x0000FF00) >> 8); + uint32_t b1 = b * alpha1 * ((modified & 0x000000FF) >> 0); + *output = 0xFF000000 + | (0x00FF0000 & ((r1 + r2) << 0)) + | (0x0000FF00 & ((g1 + g2) >> 8)) + | (0x000000FF & ((b1 + b2) >> 16)); + } + } +} + +void CreateTexture(Texture *texture, const char *cName) { + size_t dataBytes; + const void *data = EsEmbeddedFileGet(cName, &dataBytes); + texture->bits = (uint32_t *) EsImageLoad(data, dataBytes, &texture->width, &texture->height, 4); + EsAssert(texture->bits); +} + +void ExitGame() { + EsInstanceDestroy(instance); +} + +/////////////////////////////////////////////////////////// + +#define TAG_ALL (-1) +#define TAG_SOLID (-2) +#define TAG_KILL (-3) +#define TAG_WORLD (-4) + +#define TILE_SIZE (16) + +struct Entity { + uint8_t tag; + uint8_t layer; + bool solid, kill, hide; + char symbol; + int8_t frameCount, stepsPerFrame; + Texture *texture; + float texOffX, texOffY, w, h; + int uid; + + void (*create)(Entity *); + void (*destroy)(Entity *); + void (*stepAlways)(Entity *); // Called even if level editing. + void (*step)(Entity *); + void (*draw)(Entity *); + void (*drawAfter)(Entity *); + + float x, y, px, py; + int stepIndex; + bool isUsed, isDestroyed; + + union { + struct { + float cx, cy; + float th, dth; + float dths; + int respawn, respawnGrow, dash; + } player; + + struct { + int random; + } block; + + struct { + float vel; + } moveBlock; + + struct { + float th, cx, cy; + } spin; + + struct { + float vx, vy, th, dth; + int life; + uint32_t col; + } star; + }; + + void Destroy() { + if (isDestroyed) return; + isDestroyed = true; + if (destroy) destroy(this); + } +}; + +Texture textureDashMessage, textureKeyMessage, textureKey, textureControlsMessage, textureWhite; + +Entity typePlayer, typeBlock, typeCheck, typeMoveH, typeStar, typeMoveV, typePowerup, typeShowMessage, typeKey, typeLock, typeSpin, typeEnd; + +// All the entities that can be loaded from the rooms. +Entity *entityTypes[] = { + &typeBlock, &typeCheck, &typeMoveH, &typeMoveV, &typePowerup, &typeKey, &typeLock, &typeSpin, &typeEnd, + nullptr, +}; + +int levelTick; +bool justLoaded = true; + +#define MAX_ENTITIES (1000) + +struct SaveState { + float checkX, checkY; + int roomX, roomY; + bool hasDash, hasKey; + int deathCount; + uint32_t check; +}; + +struct GameState : SaveState { + Entity entities[MAX_ENTITIES]; + int world; + Entity *player; +}; + +GameState state; + +Entity *AddEntity(Entity *templateEntity, float x, float y, int uid = 0) { + for (int i = 0; i < MAX_ENTITIES; i++) { + if (!state.entities[i].isUsed) { + EsMemoryCopy(state.entities + i, templateEntity, sizeof(Entity)); + state.entities[i].isUsed = true; + if (!state.entities[i].frameCount) state.entities[i].frameCount = 1; + if (!state.entities[i].stepsPerFrame) state.entities[i].stepsPerFrame = 1; + state.entities[i].x = state.entities[i].px = x; + state.entities[i].y = state.entities[i].py = y; + if (!state.entities[i].w) state.entities[i].w = state.entities[i].texture->width - 1; + if (!state.entities[i].h) state.entities[i].h = state.entities[i].texture->height / state.entities[i].frameCount - 1; + state.entities[i].uid = uid; + if (state.entities[i].create) state.entities[i].create(state.entities + i); + return state.entities + i; + } + } + + static Entity fake = {}; + return &fake; +} + +Entity *FindEntity(float x, float y, float w, float h, int tag, Entity *exclude) { + for (int i = 0; i < MAX_ENTITIES; i++) { + if (state.entities[i].isUsed && !state.entities[i].isDestroyed + && (state.entities[i].tag == tag + || tag == TAG_ALL + || (tag == TAG_SOLID && state.entities[i].solid) + || (tag == TAG_KILL && state.entities[i].kill) + ) + && state.entities + i != exclude) { + if (x <= state.entities[i].x + state.entities[i].w && state.entities[i].x <= x + w + && y <= state.entities[i].y + state.entities[i].h && state.entities[i].y <= y + h) { + return state.entities + i; + } + } + } + + return nullptr; +} + +char roomName[16]; + +void UpdateRoomName() { + roomName[0] = 'R'; + roomName[1] = (state.roomX / 10) + '0'; + roomName[2] = (state.roomX % 10) + '0'; + roomName[3] = '_'; + roomName[4] = (state.roomY / 10) + '0'; + roomName[5] = (state.roomY % 10) + '0'; + roomName[6] = '.'; + roomName[7] = 'D'; + roomName[8] = 'A'; + roomName[9] = 'T'; + roomName[10] = 0; +} + +#define ROOM_ID ((state.roomX - 7) + (state.roomY - 9) * 6) + +void LoadRoom() { + state.world = 0; + + UpdateRoomName(); + + roomName[6] = '_'; + const uint8_t *buffer = (const uint8_t *) EsEmbeddedFileGet(roomName); + + for (int i = 0; i < MAX_ENTITIES; i++) { + if (!state.entities[i].isUsed || state.entities[i].isDestroyed) continue; + + if (state.entities[i].tag != typePlayer.tag) { + state.entities[i].Destroy(); + } else { + state.entities[i].px = state.entities[i].x; + state.entities[i].py = state.entities[i].y; + } + } + + int p = 0; + int iir = 0; + + while (true) { + uint8_t tag = buffer[p++]; + if (!tag) break; + float x = *(float *) (buffer + p); p += 4; + float y = *(float *) (buffer + p); p += 4; + + if (tag == (uint8_t) TAG_WORLD) { + state.world = x; + } + + for (int i = 0; entityTypes[i]; i++) { + if (entityTypes[i]->tag == tag) { + AddEntity(entityTypes[i], x, y, (state.roomX << 24) | (state.roomY << 16) | iir); + iir++; + } + } + } + + musicIndex = state.world; +} + +void CalculateCheck() { + state.check = 0; + + uint8_t *buffer = (uint8_t *) &state; + uint32_t check = 0x1D471D47; + + for (uintptr_t i = 0; i < sizeof(SaveState); i++) { + check ^= ((uint32_t) buffer[i] + 10) * (i + 100); + } + + state.check = check; +} + +float FadeInOut(float t) { + if (t < 0.3f) return t / 0.3f; + else if (t < 0.7f) return 1; + else return 1 - (t - 0.7f) / 0.3f; +} + +void InitialiseGame() { + state.roomX = 10; + state.roomY = 10; + + CreateTexture(&textureWhite, "white_png"); + CreateTexture(&textureKey, "key_png"); + CreateTexture(&textureDashMessage, "dash_msg_png"); + CreateTexture(&textureKeyMessage, "key_msg_png"); + CreateTexture(&textureControlsMessage, "controls_png"); + + int tag = 1; + + { + static Texture texture; + CreateTexture(&texture, "player_png"); + typePlayer.tag = tag++; + typePlayer.texture = &texture; + typePlayer.frameCount = 6; + typePlayer.stepsPerFrame = 5; + typePlayer.layer = 1; + + typePlayer.step = [] (Entity *entity) { + if (entity->player.respawn) { + if (entity->stepIndex > entity->player.respawn) { + entity->player.respawn = 0; + entity->hide = false; + entity->player.cx = state.checkX; + entity->player.cy = state.checkY; + entity->player.respawnGrow = entity->stepIndex + 20; + entity->player.dash = 0; + } else { + return; + } + } + + if (!entity->player.respawnGrow && !entity->player.dash) { + if (keysPressedSpace) { + entity->player.cx += (entity->x - entity->player.cx) * 2; + entity->player.cy += (entity->y - entity->player.cy) * 2; + entity->player.th += 3.15f; + entity->player.dth = -entity->player.dth; + entity->player.dths = 5; + } else if (keysPressedX && state.hasDash) { + entity->player.dash = 10; + } + } + + float rd = 40; + + if (entity->player.respawnGrow) { + if (entity->stepIndex > entity->player.respawnGrow) { + entity->player.respawnGrow = 0; + } else { + rd *= 1 - (entity->player.respawnGrow - entity->stepIndex) / 20.0f; + } + } + + entity->x = rd * EsCRTcosf(entity->player.th) + entity->player.cx; + entity->y = rd * EsCRTsinf(entity->player.th) + entity->player.cy + 5 * EsCRTsinf(4.71f + entity->stepIndex * 0.1f); + + if (entity->player.dash) { + float pt = entity->player.th - entity->player.dth; + float px = rd * EsCRTcosf(pt) + entity->player.cx; + float py = rd * EsCRTsinf(pt) + entity->player.cy + 5 * EsCRTsinf(4.71f + (entity->stepIndex - 1) * 0.1f); + float dx = entity->x - px; + float dy = entity->y - py; + entity->player.cx += dx * 3.2f; + entity->player.cy += dy * 3.2f; + entity->player.dash--; + AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0xFF; + } else { + entity->player.th += entity->player.dth; + } + + if (entity->player.respawnGrow) { + entity->px = entity->x; + entity->py = entity->y; + } + + if (entity->player.dths) { + entity->player.th += entity->player.dth; + entity->player.dths--; + entity->stepIndex = 5 * 3; + } + + if (FindEntity(entity->x + 5, entity->y + 5, entity->w - 10, entity->h - 10, TAG_KILL, 0)) { + for (int i = 0; i < 20; i++) { + AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0xFF0000; + } + + entity->hide = true; + entity->player.respawn = entity->stepIndex + 20; + state.deathCount++; + } + + if (entity->x > GAME_SIZE - 8) { + entity->x -= GAME_SIZE; + entity->player.cx -= GAME_SIZE; + state.checkX -= GAME_SIZE; + state.roomX++; + LoadRoom(); + } else if (entity->x < -8) { + entity->x += GAME_SIZE; + entity->player.cx += GAME_SIZE; + state.checkX += GAME_SIZE; + state.roomX--; + LoadRoom(); + } + + if (entity->y > GAME_SIZE - 8) { + entity->y -= GAME_SIZE; + entity->player.cy -= GAME_SIZE; + state.checkY -= GAME_SIZE; + state.roomY++; + LoadRoom(); + } else if (entity->y < -8) { + entity->y += GAME_SIZE; + entity->player.cy += GAME_SIZE; + state.checkY += GAME_SIZE; + state.roomY--; + LoadRoom(); + } + }; + + typePlayer.create = [] (Entity *entity) { + state.player = entity; + entity->player.cx = entity->x; + entity->player.cy = entity->y; + entity->player.dth = 0.06f; + }; + } + + { + static Texture texture; + CreateTexture(&texture, "block_png"); + + static Texture block2; + CreateTexture(&block2, "block2_png"); + + typeBlock.tag = tag++; + typeBlock.texture = &texture; + typeBlock.kill = true; + typeBlock.hide = true; + typeBlock.layer = 2; + + typeBlock.create = [] (Entity *entity) { + uint8_t r = EsRandomU8(); + + if (r < 20) { + entity->block.random = 1; + } else if (r < 50) { + entity->block.random = 2; + } else { + entity->block.random = 0; + } + }; + + typeBlock.stepAlways = [] (Entity *entity) { + if (FindEntity(entity->x + 1, entity->y + 1, entity->w - 2, entity->h - 2, entity->tag, entity)) { + entity->Destroy(); + } + }; + + typeBlock.drawAfter = [] (Entity *entity) { + if (!FindEntity(entity->x - 16, entity->y, 1, 1, entity->tag, entity)) { + Draw(&block2, entity->x - 16, entity->y, 16, 16, 0, entity->block.random * 16, 16, 16, 1); + } + + if (!FindEntity(entity->x + 16, entity->y, 1, 1, entity->tag, entity)) { + Draw(&block2, entity->x + 16, entity->y, 16, 16, 32, entity->block.random * 16, 16, 16, 1); + } + + if (!FindEntity(entity->x, entity->y - 16, 1, 1, entity->tag, entity)) { + Draw(&block2, entity->x, entity->y - 16, 16, 16, 16, entity->block.random * 16, 16, 16, 1); + } + + if (!FindEntity(entity->x, entity->y + 16, 1, 1, entity->tag, entity)) { + Draw(&block2, entity->x, entity->y + 16, 16, 16, 48, entity->block.random * 16, 16, 16, 1); + } + }; + } + + { + static Texture check1, check2; + CreateTexture(&check1, "check1_png"); + CreateTexture(&check2, "check2_png"); + typeCheck.tag = tag++; + typeCheck.texture = &check1; + + typeCheck.step = [] (Entity *entity) { + if (state.checkX == entity->x && state.checkY == entity->y) { + entity->texture = &check2; + } else { + entity->texture = &check1; + } + + if (FindEntity(entity->x - 4, entity->y - 4, entity->w + 8, entity->h + 8, typePlayer.tag, 0)) { + if (state.checkX != entity->x || state.checkY != entity->y) { + for (int i = 0; i < 10; i++) AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0xFFFFFF; + } + + state.checkX = entity->x; + state.checkY = entity->y; + + CalculateCheck(); + EsFileWriteAll("|Settings:/Save.dat", -1, &state, sizeof(SaveState)); + } + }; + } + + { + static Texture texture; + CreateTexture(&texture, "moveblock_png"); + typeMoveH.tag = tag++; + typeMoveH.texture = &texture; + typeMoveH.kill = true; + typeMoveH.w = 16; + typeMoveH.h = 16; + typeMoveH.texOffX = -4; + typeMoveH.texOffY = -4; + + typeMoveH.create = [] (Entity *entity) { + entity->moveBlock.vel = -4; + }; + + typeMoveH.step = [] (Entity *entity) { + entity->x += entity->moveBlock.vel; + + if (FindEntity(entity->x, entity->y, entity->w, entity->h, typeBlock.tag, 0)) { + entity->moveBlock.vel = -entity->moveBlock.vel; + } + }; + } + + { + // Removed entity. + tag++; + } + + { + static Texture texture; + CreateTexture(&texture, "star_png"); + typeStar.texture = &texture; + typeStar.tag = tag++; + typeStar.hide = true; // Draw manually. + typeStar.layer = 2; + + typeStar.create = [] (Entity *entity) { + float th = EsRandomU8() / 255.0 * 6.24; + float sp = EsRandomU8() / 255.0 * 0.5 + 0.5; + entity->star.vx = sp * EsCRTcosf(th); + entity->star.vy = sp * EsCRTsinf(th); + entity->star.life = EsRandomU8(); + entity->star.dth = (EsRandomU8() / 255.0f - 0.5f) * 0.2f; + }; + + typeStar.step = [] (Entity *entity) { + entity->x += entity->star.vx; + entity->y += entity->star.vy; + entity->star.th += entity->star.dth; + + if (entity->star.life < entity->stepIndex) { + entity->Destroy(); + } + }; + + typeStar.drawAfter = [] (Entity *entity) { + Draw(entity->texture, entity->x - 4, entity->y - 4, -1, -1, 0, 0, -1, -1, + 1.0 - (float) entity->stepIndex / entity->star.life, + ((entity->star.col >> 16) & 0xFF) / 255.0f, + ((entity->star.col >> 8) & 0xFF) / 255.0f, + ((entity->star.col >> 0) & 0xFF) / 255.0f, + entity->star.th); + }; + } + + { + static Texture texture; + CreateTexture(&texture, "moveblock_png"); + typeMoveV.tag = tag++; + typeMoveV.texture = &texture; + typeMoveV.kill = true; + typeMoveV.w = 16; + typeMoveV.h = 16; + typeMoveV.texOffX = -4; + typeMoveV.texOffY = -4; + + typeMoveV.create = [] (Entity *entity) { + entity->moveBlock.vel = -4; + }; + + typeMoveV.step = [] (Entity *entity) { + entity->y += entity->moveBlock.vel; + + if (FindEntity(entity->x, entity->y, entity->w, entity->h, typeBlock.tag, 0)) { + entity->moveBlock.vel = -entity->moveBlock.vel; + } + }; + } + + { + static Texture texture; + CreateTexture(&texture, "powerup_png"); + typePowerup.tag = tag++; + typePowerup.texture = &texture; + + typePowerup.step = [] (Entity *entity) { + if (state.hasDash) { + entity->Destroy(); + return; + } + + if (FindEntity(entity->x, entity->y, entity->w, entity->h, typePlayer.tag, 0)) { + state.hasDash = true; + AddEntity(&typeShowMessage, 0, 0)->texture = &textureDashMessage; + entity->Destroy(); + } + }; + } + + { + typeShowMessage.texture = &textureKeyMessage; + typeShowMessage.tag = tag++; + typeShowMessage.hide = true; + + typeShowMessage.draw = [] (Entity *entity) { + Draw(entity->texture, entity->x, entity->y, -1, -1, 0, 0, -1, -1, FadeInOut(entity->stepIndex / 180.0)); + if (entity->stepIndex > 180) entity->Destroy(); + }; + } + + { + typeKey.tag = tag++; + typeKey.texture = &textureKey; + + typeKey.step = [] (Entity *entity) { + if (state.hasKey) { + entity->Destroy(); + } else if (FindEntity(entity->x, entity->y, entity->w, entity->h, typePlayer.tag, 0)) { + state.hasKey = true; + AddEntity(&typeShowMessage, 0, 0)->texture = &textureKeyMessage; + entity->Destroy(); + for (int i = 0; i < 10; i++) AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0xFFFFFF; + } + }; + } + + { + static Texture texture; + CreateTexture(&texture, "lock_png"); + typeLock.tag = tag++; + typeLock.texture = &texture; + typeLock.kill = true; + + typeLock.step = [] (Entity *entity) { + if (state.hasKey) { + for (int i = 0; i < 1; i++) AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0x000000; + entity->Destroy(); + } + }; + } + + { + static Texture texture; + CreateTexture(&texture, "moveblock_png"); + typeSpin.tag = tag++; + typeSpin.texture = &texture; + typeSpin.kill = true; + typeSpin.w = 16; + typeSpin.h = 16; + typeSpin.texOffX = -4; + typeSpin.texOffY = -4; + + typeSpin.create = [] (Entity *entity) { + entity->spin.cx = entity->x; + entity->spin.cy = entity->y; + }; + + typeSpin.step = [] (Entity *entity) { + entity->x = 60 * EsCRTcosf(entity->spin.th) + entity->spin.cx; + entity->y = 60 * EsCRTsinf(entity->spin.th) + entity->spin.cy; + entity->spin.th += 0.04f; + }; + } + + { + static Texture msg1, msg2, msg3, num; + CreateTexture(&msg1, "end1_png"); + CreateTexture(&msg2, "end2_png"); + CreateTexture(&msg3, "end3_png"); + CreateTexture(&num, "numbers_png"); + + typeEnd.tag = tag++; + typeEnd.texture = &textureKey; + typeEnd.hide = true; + + typeEnd.create = [] (Entity *) { + state.player->Destroy(); + }; + + typeEnd.draw = [] (Entity *entity) { + float t = entity->stepIndex / 180.0f; + + if (t < 1) { + Draw(&msg1, 40, 150, -1, -1, 0, 0, -1, -1, FadeInOut(t)); + } else if (t < 2) { + Draw(&msg2, 40, 150, -1, -1, 0, 0, -1, -1, FadeInOut(t - 1)); + } else if (t < 3) { + Draw(&msg3, 40, 150, -1, -1, 0, 0, -1, -1, FadeInOut(t - 2)); + + int p = state.deathCount; + char digits[10]; + int dc = 0; + + if (p == 0) { + digits[dc++] = 0; + } else { + while (p) { + digits[dc++] = p % 10; + p /= 10; + } + } + + int w = dc * 16; + + for (int i = dc - 1; i >= 0; i--) { + Draw(&num, 40 + 150 - w / 2 + (dc - 1 - i) * 16, + 150 + 33, 16, 30, 16 * digits[i], 0, 16, 30, FadeInOut(t - 2)); + } + } else { + ExitGame(); + } + }; + } + + state.checkX = GAME_SIZE / 2; + state.checkY = GAME_SIZE / 2 - 20; + + size_t loadedStateBytes; + SaveState *loadedState = (SaveState *) EsFileReadAll("|Settings:/Save.dat", -1, &loadedStateBytes); + bool noSave = true; + + if (loadedStateBytes == sizeof(SaveState)) { + EsMemoryCopy(&state, loadedState, loadedStateBytes); + + uint32_t oldCheck = state.check; + CalculateCheck(); + EsAssert(oldCheck == state.check); + + noSave = false; + } + + LoadRoom(); + + AddEntity(&typePlayer, state.checkX, state.checkY); + + if (noSave) { + AddEntity(&typeShowMessage, 0, GAME_SIZE - 65)->texture = &textureControlsMessage; + } +} + +void UpdateGame() { + if (keysPressedEscape) { + ExitGame(); + } + + for (int i = 0; i < MAX_ENTITIES; i++) { + if (state.entities[i].isUsed) { + state.entities[i].stepIndex++; + + state.entities[i].px += (state.entities[i].x - state.entities[i].px) * 0.5f; + state.entities[i].py += (state.entities[i].y - state.entities[i].py) * 0.5f; + } + } + + for (int i = 0; i < MAX_ENTITIES; i++) if (state.entities[i].isUsed && state.entities[i].stepAlways) state.entities[i].stepAlways(state.entities + i); + + for (int i = 0; i < MAX_ENTITIES; i++) if (state.entities[i].isUsed && state.entities[i].step) { + state.entities[i].step(state.entities + i); + } + + for (int i = 0; i < MAX_ENTITIES; i++) { + if (state.entities[i].isUsed && state.entities[i].isDestroyed) state.entities[i].isUsed = false; + } + + levelTick++; + + state.world %= 3; + + if (state.world == 0) { + backgroundColor = 0xbef1b1; + } else if (state.world == 1) { + backgroundColor = 0xcee5f1; + } else if (state.world == 2) { + backgroundColor = 0xf3bdf6; + } +} + +void RenderGame() { + for (int layer = -1; layer <= 3; layer++) { + for (int i = 0; i < MAX_ENTITIES; i++) { + Entity *entity = state.entities + i; + if (!entity->isUsed) continue; + if (entity->layer != layer) continue; + if (!entity->texture) continue; + if (entity->hide) continue; + + int frame = entity->stepsPerFrame >= 0 ? ((entity->stepIndex / entity->stepsPerFrame) % entity->frameCount) : (-entity->stepsPerFrame - 1); + Draw(entity->texture, (int) (entity->px + entity->texOffX + 0.5f), + (int) (entity->py + entity->texOffY + 0.5f), + entity->texture->width, entity->texture->height / entity->frameCount, + 0, entity->texture->height / entity->frameCount * frame, + entity->texture->width, entity->texture->height / entity->frameCount); + } + } + + for (int i = 0; i < MAX_ENTITIES; i++) if (state.entities[i].isUsed && state.entities[i].draw ) state.entities[i].draw (state.entities + i); + for (int i = 0; i < MAX_ENTITIES; i++) if (state.entities[i].isUsed && state.entities[i].drawAfter ) state.entities[i].drawAfter (state.entities + i); + + if (state.hasKey) { + Draw(&textureKey, GAME_SIZE - 20, 4); + } +} + +/////////////////////////////////////////////////////////// + +int ProcessCanvasMessage(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_ANIMATE) { + message->animate.complete = false; + updateTimeAccumulator += message->animate.deltaMs / 1000.0; + + while (updateTimeAccumulator > 1 / 60.0) { + { + EsGameControllerState state[ES_GAME_CONTROLLER_MAX_COUNT]; + size_t count = EsGameControllerStatePoll(state); + + for (uintptr_t i = 0; i < count; i++) { + if (state[i].buttons & (1 << 0) && (~previousControllerButtons[i] & (1 << 0))) { + keysPressedSpace = true; + } else if (state[i].buttons & (1 << 1) && (~previousControllerButtons[i] & (1 << 1))) { + keysPressedX = true; + } + + previousControllerButtons[i] = state[i].buttons; + } + } + + UpdateGame(); + updateTimeAccumulator -= 1 / 60.0; + keysPressedSpace = keysPressedEscape = keysPressedX = false; + } + + EsElementRepaint(element); + } else if (message->type == ES_MSG_KEY_DOWN && !message->keyboard.repeat) { + if (message->keyboard.scancode == ES_SCANCODE_SPACE || message->keyboard.scancode == ES_SCANCODE_Z) { + keysPressedSpace = true; + } else if (message->keyboard.scancode == ES_SCANCODE_ESCAPE) { + keysPressedEscape = true; + } else if (message->keyboard.scancode == ES_SCANCODE_X) { + keysPressedX = true; + } + } else if (message->type == ES_MSG_PAINT) { + EsPainter *painter = message->painter; + EsPaintTargetStartDirectAccess(painter->target, &targetBits, nullptr, nullptr, &targetStride); + targetBits = (uint32_t *) ((uint8_t *) targetBits + targetStride * painter->offsetY + 4 * painter->offsetX); + targetWidth = painter->width, targetHeight = painter->height; + + gameScale = (float) painter->width / GAME_SIZE; + if (gameScale * GAME_SIZE > painter->height) gameScale = (float) painter->height / GAME_SIZE; + if (gameScale > 1) gameScale = EsCRTfloorf(gameScale); + gameWidth = GAME_SIZE * gameScale, gameHeight = GAME_SIZE * gameScale; + gameOffsetX = painter->width / 2 - gameWidth / 2; + gameOffsetY = painter->height / 2 - gameHeight / 2; + + // TODO Clear margins. + + Draw(&textureWhite, 0, 0, GAME_SIZE, GAME_SIZE, 0, 0, 1, 1, 1, + ((backgroundColor >> 16) & 0xFF) / 255.0f, + ((backgroundColor >> 8) & 0xFF) / 255.0f, + ((backgroundColor >> 0) & 0xFF) / 255.0f); + + RenderGame(); + + EsPaintTargetEndDirectAccess(painter->target); + } + + return 0; +} + +void _start() { + _init(); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + instance = EsInstanceCreate(message, BRAND); + EsWindow *window = instance->window; + EsPanel *container = EsPanelCreate(window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER); + EsElement *canvas = EsCustomElementCreate(container, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE, {}); + canvas->messageUser = ProcessCanvasMessage; + EsElementStartAnimating(canvas); + EsElementFocus(canvas); + InitialiseGame(); + } + } +} diff --git a/apps/fly.ini b/apps/fly.ini new file mode 100644 index 0000000..65ad1f3 --- /dev/null +++ b/apps/fly.ini @@ -0,0 +1,66 @@ +[general] +name=Fly + +[build] +source=apps/fly.cpp + +[embed] +bgm1_mid=res/Fly Assets/bgm1.mid +bgm2_mid=res/Fly Assets/bgm2.mid +bgm3_mid=res/Fly Assets/bgm3.mid +block2_png=res/Fly Assets/block2.png +block_png=res/Fly Assets/block.png +check1_png=res/Fly Assets/check1.png +check2_png=res/Fly Assets/check2.png +controls_png=res/Fly Assets/controls.png +dash_msg_png=res/Fly Assets/dash_msg.png +end1_png=res/Fly Assets/end1.png +end2_png=res/Fly Assets/end2.png +end3_png=res/Fly Assets/end3.png +key_msg_png=res/Fly Assets/key_msg.png +key_png=res/Fly Assets/key.png +lock_png=res/Fly Assets/lock.png +moveblock_png=res/Fly Assets/moveblock.png +numbers_png=res/Fly Assets/numbers.png +player_png=res/Fly Assets/player.png +powerup_png=res/Fly Assets/powerup.png +R07_12_DAT=res/Fly Assets/R07_12.DAT +R07_13_DAT=res/Fly Assets/R07_13.DAT +R07_14_DAT=res/Fly Assets/R07_14.DAT +R07_16_DAT=res/Fly Assets/R07_16.DAT +R07_17_DAT=res/Fly Assets/R07_17.DAT +R07_18_DAT=res/Fly Assets/R07_18.DAT +R08_12_DAT=res/Fly Assets/R08_12.DAT +R08_13_DAT=res/Fly Assets/R08_13.DAT +R08_14_DAT=res/Fly Assets/R08_14.DAT +R08_16_DAT=res/Fly Assets/R08_16.DAT +R08_17_DAT=res/Fly Assets/R08_17.DAT +R08_18_DAT=res/Fly Assets/R08_18.DAT +R09_10_DAT=res/Fly Assets/R09_10.DAT +R09_11_DAT=res/Fly Assets/R09_11.DAT +R09_12_DAT=res/Fly Assets/R09_12.DAT +R09_13_DAT=res/Fly Assets/R09_13.DAT +R09_14_DAT=res/Fly Assets/R09_14.DAT +R09_15_DAT=res/Fly Assets/R09_15.DAT +R09_16_DAT=res/Fly Assets/R09_16.DAT +R09_17_DAT=res/Fly Assets/R09_17.DAT +R09_18_DAT=res/Fly Assets/R09_18.DAT +R10_09_DAT=res/Fly Assets/R10_09.DAT +R10_10_DAT=res/Fly Assets/R10_10.DAT +R10_11_DAT=res/Fly Assets/R10_11.DAT +R10_12_DAT=res/Fly Assets/R10_12.DAT +R10_13_DAT=res/Fly Assets/R10_13.DAT +R10_14_DAT=res/Fly Assets/R10_14.DAT +R10_15_DAT=res/Fly Assets/R10_15.DAT +R10_16_DAT=res/Fly Assets/R10_16.DAT +R11_09_DAT=res/Fly Assets/R11_09.DAT +R11_10_DAT=res/Fly Assets/R11_10.DAT +R11_11_DAT=res/Fly Assets/R11_11.DAT +R11_13_DAT=res/Fly Assets/R11_13.DAT +R11_14_DAT=res/Fly Assets/R11_14.DAT +R11_15_DAT=res/Fly Assets/R11_15.DAT +R12_09_DAT=res/Fly Assets/R12_09.DAT +R12_10_DAT=res/Fly Assets/R12_10.DAT +R12_11_DAT=res/Fly Assets/R12_11.DAT +star_png=res/Fly Assets/star.png +white_png=res/Fly Assets/white.png diff --git a/apps/font_book.cpp b/apps/font_book.cpp new file mode 100644 index 0000000..188facc --- /dev/null +++ b/apps/font_book.cpp @@ -0,0 +1,414 @@ +#define ES_INSTANCE_TYPE Instance +#include + +// TODO Previewing font files from the database. +// TODO Installing fonts. +// TODO Character map. +// TODO Searching/filtering fonts. +// TODO Single instance. + +#include +#define IMPLEMENTATION +#include +#include + +#define SETTINGS_FILE "|Settings:/Default.ini" + +struct Instance : EsInstance { + Array fonts; + + EsPanel *switcher; + + EsListView *fontList; + EsTextbox *fontSizeTextbox; + EsTextbox *previewTextTextbox; + + EsPanel *fontPreview; + uint16_t fontPreviewID; + + EsElement *fontListToolbar; + EsElement *fontPreviewToolbar; + + int fontSize, fontVariant; + char *previewText; + size_t previewTextBytes; +}; + +EsStyle styleFontList = { + .inherit = ES_STYLE_PANEL_FILLED, + + .metrics = { + .mask = ES_THEME_METRICS_GAP_MINOR | ES_THEME_METRICS_GAP_WRAP | ES_THEME_METRICS_INSETS, + .insets = ES_RECT_1(25), + .gapMinor = 15, + .gapWrap = 15, + }, +}; + +EsStyle styleFontItem = { + .inherit = ES_STYLE_PANEL_SHEET, + + .metrics = { + .mask = ES_THEME_METRICS_PREFERRED_WIDTH | ES_THEME_METRICS_PREFERRED_HEIGHT, + .preferredWidth = 300, + .preferredHeight = 250, + }, +}; + +EsStyle styleFontInformationPanel = { + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_GAP_MAJOR, + .insets = ES_RECT_1(15), + .gapMajor = 10, + }, +}; + +EsStyle styleFontName = { + .inherit = ES_STYLE_TEXT_LABEL_SECONDARY, + + .metrics = { + .mask = ES_THEME_METRICS_TEXT_SIZE, + .textSize = 10, + }, +}; + +EsStyle styleFontInformationRow = { + .metrics = { + .mask = ES_THEME_METRICS_GAP_MAJOR, + .gapMajor = 10, + }, +}; + +EsStyle styleFontPreviewPage = { + .inherit = ES_STYLE_PANEL_DOCUMENT, + + .metrics = { + .mask = ES_THEME_METRICS_INSETS, + .insets = ES_RECT_1(20), + }, +}; + +inline int ClampInteger(int low, int high, int integer) { + if (integer < low) return low; + if (integer > high) return high; + return integer; +} + +bool LoadSettings(Instance *instance) { + EsINIState state = {}; + char *file = (char *) EsFileReadAll(EsLiteral(SETTINGS_FILE), &state.bytes); + + if (!state.buffer) { + return false; + } + + while (EsINIParse(&state)) { + if (state.value && 0 == EsStringCompareRaw(state.section, state.sectionBytes, EsLiteral("preview"))) { + if (0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("size"))) { + instance->fontSize = EsIntegerParse(state.value, state.valueBytes); + } else if (0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("variant"))) { + instance->fontVariant = EsIntegerParse(state.value, state.valueBytes); + } else if (0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("text"))) { + instance->previewTextBytes = state.valueBytes; + instance->previewText = (char *) EsHeapAllocate(instance->previewTextBytes, false); + EsMemoryCopy(instance->previewText, state.value, instance->previewTextBytes); + } + } + } + + EsHeapFree(file); + return true; +} + +void SaveSettings(Instance *instance) { + EsBuffer buffer = { .canGrow = true }; + EsBufferFormat(&buffer, "[preview]\nsize=%d\nvariant=%d\ntext=%s\n", + instance->fontSize, instance->fontVariant, instance->previewTextBytes, instance->previewText); + EsFileWriteAll(EsLiteral(SETTINGS_FILE), buffer.out, buffer.position); + EsHeapFree(buffer.out); +} + +int FontPreviewMessage(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_PAINT) { + // TODO Cache the text plan? + EsTextPlanProperties properties = {}; + properties.flags = ES_TEXT_PLAN_SINGLE_USE | ES_TEXT_PLAN_TRIM_SPACES | ES_TEXT_WRAP | ES_TEXT_ELLIPSIS | ES_TEXT_PLAN_NO_FONT_SUBSTITUTION; + EsRectangle bounds = EsPainterBoundsInset(message->painter); + EsTextRun runs[2] = {}; + EsElementGetTextStyle(element, &runs[0].style); + runs[0].style.font.family = element->userData.u; + runs[0].style.font.weight = element->instance->fontVariant % 10; + runs[0].style.font.italic = element->instance->fontVariant / 10; + runs[0].style.size = element->instance->fontSize; + runs[1].offset = element->instance->previewTextBytes; + EsTextPlan *plan = EsTextPlanCreate(&properties, bounds, element->instance->previewText, runs, 1); + EsDrawText(message->painter, plan, bounds); + } + + return 0; +} + +int FontListMessage(EsElement *element, EsMessage *message) { + Instance *instance = element->instance; + + if (message->type == ES_MSG_LIST_VIEW_CREATE_ITEM) { + EsPanel *panel = EsPanelCreate(message->createItem.item, ES_CELL_FILL, &styleFontInformationPanel); + EsFontInformation *font = &instance->fonts[message->createItem.index.u]; + + EsPanel *row = EsPanelCreate(panel, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleFontInformationRow); + // EsIconDisplayCreate(row, ES_FLAGS_DEFAULT, ES_STYLE_ICON_DISPLAY_SMALL, ES_ICON_FONT_X_GENERIC); + EsTextDisplayCreate(row, ES_FLAGS_DEFAULT, &styleFontName, font->name, font->nameBytes); + EsSpacerCreate(row, ES_CELL_H_FILL, ES_STYLE_SEPARATOR_HORIZONTAL); + + EsElement *preview = EsCustomElementCreate(panel, ES_CELL_FILL, ES_STYLE_TEXT_PARAGRAPH); + preview->userData = font->id; + preview->messageUser = FontPreviewMessage; + + size_t variants = 0; + + for (uintptr_t i = 0; i < 16; i++) { + if (font->availableWeightsNormal & (1 << i)) variants++; + if (font->availableWeightsItalic & (1 << i)) variants++; + } + + row = EsPanelCreate(panel, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleFontInformationRow); + + char description[256]; // TODO Localization. + size_t descriptionBytes = EsStringFormat(description, sizeof(description), "%s " HYPHENATION_POINT " %d variant%z", + font->categoryBytes, font->category, variants, variants == 1 ? "" : "s"); + EsTextDisplayCreate(row, ES_CELL_H_FILL | ES_CELL_V_BOTTOM, ES_STYLE_TEXT_LABEL_SECONDARY, description, descriptionBytes); + + EsButton *openButton = EsButtonCreate(row, ES_BUTTON_NOT_FOCUSABLE); + EsButtonSetIcon(openButton, ES_ICON_GO_NEXT_SYMBOLIC); + } + + return 0; +} + +void FontSizeTextboxUpdate(Instance *instance) { + char result[64]; + size_t resultBytes = EsStringFormat(result, sizeof(result), "%d", instance->fontSize); + EsTextboxSelectAll(instance->fontSizeTextbox); + EsTextboxInsert(instance->fontSizeTextbox, result, resultBytes); + EsListViewInvalidateAll(instance->fontList); +} + +int FontSizeTextboxMessage(EsElement *element, EsMessage *message) { + EsTextbox *textbox = (EsTextbox *) element; + Instance *instance = element->instance; + + if (message->type == ES_MSG_TEXTBOX_EDIT_END) { + char *expression = EsTextboxGetContents(textbox); + EsCalculationValue value = EsCalculateFromUserExpression(expression); + EsHeapFree(expression); + + if (value.error) { + return ES_REJECTED; + } else { + instance->fontSize = ClampInteger(6, 300, value.number); + FontSizeTextboxUpdate(instance); + } + } else if (message->type == ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA) { + instance->fontSize = ClampInteger(6, 300, instance->fontSize + message->numberDragDelta.delta * (message->numberDragDelta.fast ? 10 : 1)); + FontSizeTextboxUpdate(instance); + } else { + return 0; + } + + return ES_HANDLED; +} + +int PreviewTextTextboxMessage(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_TEXTBOX_UPDATED) { + EsHeapFree(element->instance->previewText); + element->instance->previewText = EsTextboxGetContents((EsTextbox *) element, &element->instance->previewTextBytes); + EsListViewInvalidateAll(element->instance->fontList); + } else { + return 0; + } + + return ES_HANDLED; +} + +void VariantsPopupCreate(Instance *instance, EsElement *element, EsCommand *) { + EsMenu *menu = EsMenuCreate(element, ES_FLAGS_DEFAULT); + EsPanel *panel = EsPanelCreate(menu, ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_POPUP); + + EsListView *list = EsListViewCreate(panel, ES_LIST_VIEW_CHOICE_SELECT | ES_LIST_VIEW_FIXED_ITEMS, ES_STYLE_LIST_CHOICE_BORDERED); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal100), 1); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal200), 2); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal300), 3); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal400), 4); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal500), 5); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal600), 6); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal700), 7); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal800), 8); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantNormal900), 9); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic100), 11); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic200), 12); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic300), 13); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic400), 14); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic500), 15); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic600), 16); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic700), 17); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic800), 18); + EsListViewInsertFixedItem(list, INTERFACE_STRING(FontBookVariantItalic900), 19); + EsListViewSelectFixedItem(list, instance->fontVariant); + + list->messageUser = [] (EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_LIST_VIEW_SELECT) { + Instance *instance = element->instance; + EsGeneric selected; + + if (EsListViewGetSelectedFixedItem(((EsListView *) element), &selected)) { + instance->fontVariant = selected.i; + EsListViewInvalidateAll(element->instance->fontList); + } + } + + return 0; + }; + + EsMenuShow(menu); +} + +void LoadFontsFromDatabase(Instance *instance) { + EsFontDatabaseEnumerate([] (const EsFontInformation *information, EsGeneric context) { + ((Instance *) context.p)->fonts.AddPointer(information); + }, instance); + + EsSort(instance->fonts.array, instance->fonts.Length(), sizeof(EsFontInformation), [] (const void *left, const void *right, EsGeneric) { + EsFontInformation *fontLeft = (EsFontInformation *) left; + EsFontInformation *fontRight = (EsFontInformation *) right; + int x = EsStringCompare(fontLeft->name, fontLeft->nameBytes, fontRight->name, fontRight->nameBytes); + if (x) return x; + return EsStringCompareRaw(fontLeft->name, fontLeft->nameBytes, fontRight->name, fontRight->nameBytes); + }, 0); + + EsListViewInsert(instance->fontList, 0, 0, instance->fonts.Length() - 1); +} + +void BackCommand(Instance *instance, EsElement *, EsCommand *) { + EsPanelSwitchTo(instance->switcher, instance->fontList, ES_TRANSITION_NONE); + EsWindowSwitchToolbar(instance->window, instance->fontListToolbar, ES_TRANSITION_SLIDE_DOWN); +} + +void _start() { + _init(); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FontBookTitle)); + EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_FONTS); + EsPanel *rootPanel = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER); + + instance->switcher = EsPanelCreate(rootPanel, ES_CELL_FILL | ES_PANEL_SWITCHER); + + // Settings: + + if (!LoadSettings(instance)) { + instance->fontSize = 24; + instance->fontVariant = 4 /* regular */; + instance->previewTextBytes = EsCStringLength(interfaceString_FontBookPreviewTextDefault); + instance->previewText = (char *) EsHeapAllocate(instance->previewTextBytes, false); + EsMemoryCopy(instance->previewText, interfaceString_FontBookPreviewTextDefault, instance->previewTextBytes); + } + + // Font list page: + + uint64_t flags = ES_CELL_FILL | ES_LIST_VIEW_TILED | ES_LIST_VIEW_CENTER_TILES; + EsListView *fontList = EsListViewCreate(instance->switcher, flags, &styleFontList, &styleFontItem); + EsListViewSetMaximumItemsPerBand(fontList, 4); + EsListViewInsertGroup(fontList, 0); + instance->fontList = fontList; + fontList->messageUser = FontListMessage; + fontList->accessKey = 'F'; + LoadFontsFromDatabase(instance); + + EsPanelSwitchTo(instance->switcher, instance->fontList, ES_TRANSITION_NONE); + + // Font preview page: + + instance->fontPreview = EsPanelCreate(instance->switcher, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleFontPreviewPage); + + // Font list toolbar: + + EsElement *toolbar = EsWindowGetToolbar(instance->window, true /* create new */); + instance->fontListToolbar = toolbar; + + EsPanel *section = EsPanelCreate(toolbar, ES_PANEL_HORIZONTAL); + EsTextDisplayCreate(section, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(FontBookTextSize)); + instance->fontSizeTextbox = EsTextboxCreate(section, ES_TEXTBOX_EDIT_BASED, ES_STYLE_TEXTBOX_BORDERED_SINGLE_COMPACT); + instance->fontSizeTextbox->messageUser = FontSizeTextboxMessage; + instance->fontSizeTextbox->accessKey = 'S'; + EsTextboxUseNumberOverlay(instance->fontSizeTextbox, false); + FontSizeTextboxUpdate(instance); + + EsSpacerCreate(toolbar, ES_CELL_H_FILL); + + section = EsPanelCreate(toolbar, ES_PANEL_HORIZONTAL); + EsTextDisplayCreate(section, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(FontBookPreviewText)); + instance->previewTextTextbox = EsTextboxCreate(section, ES_FLAGS_DEFAULT, ES_STYLE_TEXTBOX_BORDERED_SINGLE); + instance->previewTextTextbox->messageUser = PreviewTextTextboxMessage; + instance->previewTextTextbox->accessKey = 'P'; + EsTextboxInsert(instance->previewTextTextbox, instance->previewText, instance->previewTextBytes, false); + + EsSpacerCreate(toolbar, ES_CELL_H_FILL); + + EsButton *button = EsButtonCreate(toolbar, ES_BUTTON_DROPDOWN, {}, INTERFACE_STRING(FontBookVariants)); + button->accessKey = 'V'; + EsButtonOnCommand(button, VariantsPopupCreate); + + // Font preview toolbar: + + toolbar = EsWindowGetToolbar(instance->window, true /* create new */); + instance->fontPreviewToolbar = toolbar; + button = EsButtonCreate(toolbar, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(FontBookNavigationBack)); + button->accessKey = 'B'; + EsButtonSetIcon(button, ES_ICON_GO_PREVIOUS_SYMBOLIC); + EsButtonOnCommand(button, BackCommand); + } else if (message->type == ES_MSG_INSTANCE_OPEN) { + if (!message->instanceOpen.update) { + Instance *instance = message->instanceOpen.instance; + EsFontInformation information = {}; + information.availableWeightsNormal = 1 << 4 /* regular */; + instance->fontPreviewID = EsFontDatabaseInsertFile(&information, message->instanceOpen.file); + // TODO Check that the font is valid. + + EsElementDestroyContents(instance->fontPreview); + + EsPanel *titleRow = EsPanelCreate(instance->fontPreview, ES_CELL_H_CENTER | ES_PANEL_HORIZONTAL, &styleFontInformationRow); + EsIconDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_ICON_DISPLAY, ES_ICON_FONT_X_GENERIC); + EsTextDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_HEADING0, message->instanceOpen.name, message->instanceOpen.nameBytes); + EsSpacerCreate(instance->fontPreview, ES_FLAGS_DEFAULT, 0, 0, 20); + + int sizes[] = { 12, 18, 24, 36, 48, 60, 72, 0 }; + + for (uintptr_t i = 0; sizes[i]; i++) { + EsPanel *row = EsPanelCreate(instance->fontPreview, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleFontInformationRow); + char buffer[64]; + EsTextDisplayCreate(row, ES_FLAGS_DEFAULT, 0, buffer, EsStringFormat(buffer, sizeof(buffer), "%d", sizes[i])); + EsTextDisplay *display = EsTextDisplayCreate(row, ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION); + const char *string = interfaceString_FontBookPreviewTextLongDefault; + EsTextRun runs[2] = {}; + EsElementGetTextStyle(display, &runs[0].style); + runs[0].style.size = sizes[i]; + runs[0].style.font.family = instance->fontPreviewID; + runs[1].offset = EsCStringLength(string); + EsTextDisplaySetStyledContents(display, string, runs, 1); + } + + EsPanelSwitchTo(instance->switcher, instance->fontPreview, ES_TRANSITION_NONE); + EsWindowSwitchToolbar(instance->window, instance->fontPreviewToolbar, ES_TRANSITION_SLIDE_UP); + } + + EsInstanceOpenComplete(message, true); + } else if (message->type == ES_MSG_INSTANCE_DESTROY) { + SaveSettings(message->instanceDestroy.instance); + EsHeapFree(message->instanceDestroy.instance->previewText); + // TODO Remove the font added to the font database. + } + } +} diff --git a/apps/font_book.ini b/apps/font_book.ini new file mode 100644 index 0000000..0abf52e --- /dev/null +++ b/apps/font_book.ini @@ -0,0 +1,14 @@ +[general] +name=Font Book +icon=icon_applications_fonts + +[build] +source=apps/font_book.cpp + +[@handler] +extension=ttf +action=open + +[@handler] +extension=otf +action=open diff --git a/apps/gl_test.c b/apps/gl_test.c new file mode 100644 index 0000000..53fa23e --- /dev/null +++ b/apps/gl_test.c @@ -0,0 +1,282 @@ +// gcc -o tri tri.c -lOSMesa && ./tri +// x86_64-essence-gcc -o root/tri ports/mesa/tri.c -lOSMesa -lstdc++ -lz -g -D ESSENCE_WINDOW -D MODERN_GL + +#include +#include +#include +#include +#include +#include +#include +#include + +#define IMAGE_WIDTH (700) +#define IMAGE_HEIGHT (600) +uint32_t *buffer; + +#ifdef MODERN_GL +static GLenum (*glCheckFramebufferStatus)(GLenum target); +static GLint (*glGetUniformLocation)(GLuint program, const GLchar *name); +static GLuint (*glCreateProgram)(); +static GLuint (*glCreateShader)(GLenum type); +static void (*glAttachShader)(GLuint program, GLuint shader); +static void (*glBindBuffer)(GLenum target, GLuint buffer); +static void (*glBindFramebuffer)(GLenum target, GLuint framebuffer); +static void (*glBindVertexArray)(GLuint array); +static void (*glBufferData)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +static void (*glCompileShader)(GLuint shader); +static void (*glDeleteFramebuffers)(GLsizei n, const GLuint *framebuffers); +static void (*glDrawBuffers)(GLsizei n, const GLenum *bufs); +static void (*glEnableVertexAttribArray)(); +static void (*glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +static void (*glGenBuffers)(GLsizei n, GLuint *buffers); +static void (*glGenFramebuffers)(GLsizei n, GLuint *framebuffers); +static void (*glGenVertexArrays)(GLsizei n, GLuint *arrays); +static void (*glGetProgramInfoLog)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +static void (*glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +static void (*glGetShaderiv)(GLuint shader, GLenum pname, GLint *param); +static void (*glLinkProgram)(GLuint program); +static void (*glShaderSource)(GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length); +static void (*glUniform1f)(GLint location, GLfloat v0); +static void (*glUniform1i)(GLint location, GLint v0); +static void (*glUniform4f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +static void (*glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +static void (*glUseProgram)(GLuint program); +static void (*glValidateProgram)(GLuint program); +static void (*glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); + +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_VERTEX_SHADER 0x8B31 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_TEXTURE0 0x84C0 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_STATIC_DRAW 0x88E4 +#define GL_MULTISAMPLE 0x809D +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_BGRA 0x80E1 +#endif + +#ifdef ESSENCE_WINDOW +#include + +int CanvasCallback(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_PAINT_BACKGROUND) { + *response = ES_HANDLED; + + int ox = message->painter->width / 2 - IMAGE_WIDTH / 2; + int oy = message->painter->height / 2 - IMAGE_HEIGHT / 2; + EsRectangle bounds = { ox, ox + IMAGE_WIDTH, oy, oy + IMAGE_HEIGHT }; + EsDrawBitmap(message->painter, bounds, buffer, IMAGE_WIDTH * 4, ES_DRAW_BITMAP_OPAQUE); + +#if 0 + EsPainter *painter = message->painter; + size_t stride; + uint32_t *bits; + EsPaintTargetStartDirectAccess(painter->target, &bits, NULL, NULL, &stride); + int width = painter->width, height = painter->height; + int ox = width / 2 - IMAGE_WIDTH / 2; + int oy = height / 2 - IMAGE_HEIGHT / 2; + stride /= 4; + + uint32_t *start = bits + painter->offsetX + painter->offsetY * stride; + + for (int i = 0; i < height; i++) { + uint32_t *destination = start + i * stride; + + for (int j = 0; j < width; j++, destination++) { + int sx = j - ox, sy = i - oy; + + if (sy >= 0 && sy < IMAGE_HEIGHT && sx >= 0 && sx < IMAGE_WIDTH) { + *destination = buffer[sy * IMAGE_WIDTH + sx]; + } else { + *destination = 0xFF000000; + } + } + } +#endif + } + + return ES_NOT_HANDLED; +} +#endif + +int main(int argc, char **argv) { +#ifndef MODERN_GL + OSMesaContext context = OSMesaCreateContextExt(OSMESA_RGBA, 16, 0, 0, NULL); + buffer = (uint32_t *) malloc(IMAGE_WIDTH * IMAGE_HEIGHT * 4); + OSMesaMakeCurrent(context, buffer, GL_UNSIGNED_BYTE, IMAGE_WIDTH, IMAGE_HEIGHT); + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + glLoadIdentity(); + glBegin(GL_TRIANGLES); + glColor4f(1, 0, 0, 1); + glVertex2f(-1, -1); + glColor4f(0, 1, 0, 1); + glVertex2f(0, 1); + glColor4f(0, 0, 1, 1); + glVertex2f(1, -1); + glEnd(); +#else + const int contextAttributes[] = { + OSMESA_FORMAT, OSMESA_RGBA, + OSMESA_DEPTH_BITS, 16, + OSMESA_PROFILE, OSMESA_CORE_PROFILE, + OSMESA_CONTEXT_MAJOR_VERSION, 3, + OSMESA_CONTEXT_MINOR_VERSION, 0, + 0 + }; + + OSMesaContext context = OSMesaCreateContextAttribs(contextAttributes, NULL); + buffer = (uint32_t *) malloc(IMAGE_WIDTH * IMAGE_HEIGHT * 4); + OSMesaMakeCurrent(context, buffer, GL_UNSIGNED_BYTE, IMAGE_WIDTH, IMAGE_HEIGHT); + +#define LOADEXT(x) *(void **) &x = (void *) OSMesaGetProcAddress(#x); assert(x); + LOADEXT(glAttachShader); + LOADEXT(glBindBuffer); + LOADEXT(glBindFramebuffer); + LOADEXT(glBindVertexArray); + LOADEXT(glBufferData); + LOADEXT(glCheckFramebufferStatus); + LOADEXT(glCompileShader); + LOADEXT(glCreateProgram); + LOADEXT(glCreateShader); + LOADEXT(glDeleteFramebuffers); + LOADEXT(glDrawBuffers); + LOADEXT(glEnableVertexAttribArray); + LOADEXT(glFramebufferTexture2D); + LOADEXT(glGenBuffers); + LOADEXT(glGenFramebuffers); + LOADEXT(glGenVertexArrays); + LOADEXT(glGetProgramInfoLog); + LOADEXT(glGetShaderInfoLog); + LOADEXT(glGetShaderiv); + LOADEXT(glGetUniformLocation); + LOADEXT(glLinkProgram); + LOADEXT(glShaderSource); + LOADEXT(glUniform1f); + LOADEXT(glUniform1i); + LOADEXT(glUniform4f); + LOADEXT(glUniformMatrix4fv); + LOADEXT(glUseProgram); + LOADEXT(glValidateProgram); + LOADEXT(glVertexAttribPointer); +#undef LOADEXT + + glClearColor(0, 0, 0, 1); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_MULTISAMPLE); + + int squareVBO, squareIBO; + float squareVBOArray[] = { -1, -1, 0.5f, /**/ -1, 1, 0.5f, /**/ 1, 1, 0.5f, /**/ 1, -1, 0.5f }; + unsigned squareIBOArray[] = { 0, 1, 2, 0, 2, 3 }; + glGenBuffers(1, &squareVBO); + glBindBuffer(GL_ARRAY_BUFFER, squareVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(squareVBOArray), squareVBOArray, GL_STATIC_DRAW); + glGenBuffers(1, &squareIBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, squareIBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(squareIBOArray), squareIBOArray, GL_STATIC_DRAW); + + const char *vertexShaderSource = + "#version 330\n" + "layout(location = 0) in vec3 Position;\n" + "uniform mat4 transform;\n" + "out vec2 TexCoord0;\n" + "void main() { \n" + " gl_Position = transform * vec4(Position, 1.0);\n" + "}\n"; + const char *fragmentShaderSource = + "#version 330\n" + "layout(location = 0) out vec4 FragColor;\n" + "in vec2 TexCoord0;\n" + "uniform vec4 blendColor;\n" + "void main() { \n" + " FragColor = blendColor;\n" + "}\n"; + + const char *shaderSources[] = { vertexShaderSource, fragmentShaderSource }; + int shaderSourceLengths[] = { strlen(vertexShaderSource), strlen(fragmentShaderSource) }; + + unsigned shader = glCreateProgram(); + char shaderInfoLog[1024]; + + unsigned vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, shaderSources + 0, shaderSourceLengths + 0); + glCompileShader(vertexShader); + glGetShaderInfoLog(vertexShader, sizeof(shaderInfoLog), NULL, shaderInfoLog); + glAttachShader(shader, vertexShader); + printf("Vertex shader log: '%s'\n", shaderInfoLog); + + unsigned fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, shaderSources + 1, shaderSourceLengths + 1); + glCompileShader(fragmentShader); + glGetShaderInfoLog(fragmentShader, sizeof(shaderInfoLog), NULL, shaderInfoLog); + glAttachShader(shader, fragmentShader); + printf("Fragment shader log: '%s'\n", shaderInfoLog); + + glLinkProgram(shader); + glValidateProgram(shader); + + int shaderBlendColor = glGetUniformLocation(shader, "blendColor"); + int shaderTransform = glGetUniformLocation(shader, "transform"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + unsigned vertexArray; + glGenVertexArrays(1, &vertexArray); + glBindVertexArray(vertexArray); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, squareVBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, squareIBO); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (const GLvoid *) 0); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(shader); + float transform[] = { 0.5f, 0, 0, 0, /**/ 0, 0.5f, 0, 0, /**/ 0, 0, 1, 0, /**/ 0, 0, 0, 1 }; + glUniformMatrix4fv(shaderTransform, 1, GL_TRUE, transform); + glUniform4f(shaderBlendColor, 1, 0, 1, 1); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); +#endif + + glFinish(); + +#ifndef ESSENCE_WINDOW + FILE *out = fopen("test.ppm", "wb"); + fprintf(out, "P6\n%d %d\n255\n", IMAGE_WIDTH, IMAGE_HEIGHT); + + for (int j = 0; j < IMAGE_HEIGHT; j++) { + for (int i = 0; i < IMAGE_WIDTH; i++) { + fwrite(buffer + j * IMAGE_WIDTH + i, 1, 3, out); + } + } + + fclose(out); + + OSMesaDestroyContext(context); +#else + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + EsInstance *instance = EsInstanceCreate(message, "GL Test"); + EsWindowSetTitle(instance->window, "GL Test", -1); + EsCustomElementCreate(instance->window, ES_CELL_FILL, (EsElementProperties) { .callback = CanvasCallback }); + } + } +#endif + + free(buffer); + printf("all done :)\n"); + + return 0; +} diff --git a/apps/gl_test.ini b/apps/gl_test.ini new file mode 100644 index 0000000..339b5fc --- /dev/null +++ b/apps/gl_test.ini @@ -0,0 +1,6 @@ +[general] +name=GL Test + +[build] +custom_compile_command=x86_64-essence-gcc -o "root/Applications/GL Test/Entry.esx" apps/gl_test.c -lOSMesa -lstdc++ -lz -g -D ESSENCE_WINDOW +require=root/Applications/POSIX/lib/libOSMesa.a diff --git a/apps/hello.c b/apps/hello.c new file mode 100644 index 0000000..90f90ac --- /dev/null +++ b/apps/hello.c @@ -0,0 +1,29 @@ +// Include the Essence system header. +#include + +void _start() { + // We're not using the C standard library, + // so we need to initialise global constructors manually. + _init(); + + while (true) { + // Receive a message from the system. + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + // The system wants us to create an instance of our application. + // Call EsInstanceCreate with the message and application name. + EsInstance *instance = EsInstanceCreate(message, "Hello", -1); + + // Create a text display with the "Hello, world!" message. + EsTextDisplayCreate( + instance->window, // Add the text display to the instance's window. + ES_CELL_FILL, // The text display should fill the window. + ES_STYLE_PANEL_WINDOW_BACKGROUND, // Use the window background style. + "Hello, world!", -1); // Pass -1 for a zero-terminated string. + + // Keep receiving messages in a loop, + // so the system can handle input messages for the window. + } + } +} diff --git a/apps/hello.ini b/apps/hello.ini new file mode 100644 index 0000000..513220f --- /dev/null +++ b/apps/hello.ini @@ -0,0 +1,5 @@ +[general] +name=Hello + +[build] +source=apps/hello.c diff --git a/apps/image_editor.cpp b/apps/image_editor.cpp new file mode 100644 index 0000000..3486249 --- /dev/null +++ b/apps/image_editor.cpp @@ -0,0 +1,840 @@ +// TODO Saving. +// TODO Don't use an EsPaintTarget for the bitmap? +// TODO Show brush preview. +// TODO Other tools: text, selection. +// TODO Resize and crop image. +// TODO Clipboard. +// TODO Clearing textbox undo from EsTextboxInsert? +// TODO Handling out of memory. +// TODO Color palette. +// TODO More brushes? +// TODO Grid. +// TODO Zoom and pan with EsCanvasPane. +// TODO Status bar. +// TODO Clearing undo if too much memory is used. + +#define ES_INSTANCE_TYPE Instance +#include + +#include +#include + +#ifdef OS_ESSENCE +#define IMPLEMENTATION +#include +#endif + +#define TILE_SIZE (128) + +struct Tile { + size_t referenceCount; + uint64_t ownerID; + uint32_t bits[TILE_SIZE * TILE_SIZE]; +}; + +struct Image { + Tile **tiles; + size_t tileCountX, tileCountY; + uint64_t id; + uint32_t width, height; +}; + +struct Instance : EsInstance { + EsElement *canvas; + EsColorWell *colorWell; + EsTextbox *brushSize; + + EsPanel *toolPanel; + EsButton *toolDropdown; + + EsPaintTarget *bitmap; + uint32_t bitmapWidth, bitmapHeight; + + Image image; + uint64_t nextImageID; + + EsCommand commandBrush; + EsCommand commandFill; + EsCommand commandRectangle; + EsCommand commandSelect; + EsCommand commandText; + + // Data while drawing: + EsRectangle modifiedBounds; + float previousPointX, previousPointY; + bool dragged; +}; + +const EsStyle styleBitmapSizeTextbox = { + .inherit = ES_STYLE_TEXTBOX_BORDERED_SINGLE_COMPACT, + + .metrics = { + .mask = ES_THEME_METRICS_PREFERRED_WIDTH, + .preferredWidth = 70, + }, +}; + +const EsStyle styleImageMenuTable = { + .metrics = { + .mask = ES_THEME_METRICS_GAP_ALL | ES_THEME_METRICS_INSETS, + .insets = ES_RECT_4(20, 20, 5, 8), + .gapMajor = 6, + .gapMinor = 6, + }, +}; + +Image ImageFork(Instance *instance, Image image, uint32_t newWidth = 0, uint32_t newHeight = 0) { + Image copy = image; + + copy.width = newWidth ?: image.width; + copy.height = newHeight ?: image.height; + copy.tileCountX = newWidth ? (newWidth + TILE_SIZE - 1) / TILE_SIZE : image.tileCountX; + copy.tileCountY = newHeight ? (newHeight + TILE_SIZE - 1) / TILE_SIZE : image.tileCountY; + copy.id = instance->nextImageID++; + copy.tiles = (Tile **) EsHeapAllocate(copy.tileCountX * copy.tileCountY * sizeof(Tile *), true); + + for (uintptr_t y = 0; y < copy.tileCountY; y++) { + for (uintptr_t x = 0; x < copy.tileCountX; x++) { + uintptr_t source = y * image.tileCountX + x; + uintptr_t destination = y * copy.tileCountX + x; + + if (y < image.tileCountY && x < image.tileCountX && image.tiles[source]) { + image.tiles[source]->referenceCount++; + copy.tiles[destination] = image.tiles[source]; + } + } + } + + return copy; +} + +void ImageDelete(Image image) { + for (uintptr_t i = 0; i < image.tileCountX * image.tileCountY; i++) { + image.tiles[i]->referenceCount--; + + if (!image.tiles[i]->referenceCount) { + // EsPrint("free tile %d, %d from image %d\n", i % image.tileCountX, i / image.tileCountX, image.tiles[i]->ownerID); + EsHeapFree(image.tiles[i]); + } + } + + EsHeapFree(image.tiles); +} + +void ImageCopyToPaintTarget(Instance *instance, const Image *image) { + uint32_t *bits; + size_t width, height, stride; + EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride); + + for (int32_t i = 0; i < (int32_t) image->tileCountY; i++) { + for (int32_t j = 0; j < (int32_t) image->tileCountX; j++) { + Tile *tile = image->tiles[i * image->tileCountX + j]; + int32_t copyWidth = TILE_SIZE, copyHeight = TILE_SIZE; + + if (j * TILE_SIZE + copyWidth > (int32_t) width) { + copyWidth = width - j * TILE_SIZE; + } + + if (i * TILE_SIZE + copyHeight > (int32_t) height) { + copyHeight = height - i * TILE_SIZE; + } + + if (tile) { + for (int32_t y = 0; y < copyHeight; y++) { + for (int32_t x = 0; x < copyWidth; x++) { + bits[stride / 4 * (y + i * TILE_SIZE) + (x + j * TILE_SIZE)] = tile->bits[y * TILE_SIZE + x]; + } + } + } else { + for (int32_t y = 0; y < copyHeight; y++) { + for (int32_t x = 0; x < copyWidth; x++) { + bits[stride / 4 * (y + i * TILE_SIZE) + (x + j * TILE_SIZE)] = 0; + } + } + } + } + } + + EsPaintTargetEndDirectAccess(instance->bitmap); +} + +Tile *ImageUpdateTile(Image *image, uint32_t x, uint32_t y, bool copyOldBits) { + EsAssert(x < image->tileCountX && y < image->tileCountY); + Tile **tileReference = image->tiles + y * image->tileCountX + x; + Tile *tile = *tileReference; + + if (!tile || tile->ownerID != image->id) { + if (tile && tile->referenceCount == 1) { + tile->ownerID = image->id; + + // EsPrint("reuse tile %d, %d for image %d\n", x, y, image->id); + } else { + Tile *old = tile; + if (old) old->referenceCount--; + + *tileReference = tile = (Tile *) EsHeapAllocate(sizeof(Tile), false); + tile->referenceCount = 1; + tile->ownerID = image->id; + + if (copyOldBits && old) { + EsMemoryCopy(tile->bits, old->bits, sizeof(old->bits)); + } + + // EsPrint("allocate new tile %d, %d for image %d\n", x, y, image->id); + } + } + + return tile; +} + +void ImageCopyFromPaintTarget(Instance *instance, Image *image, EsRectangle modifiedBounds) { + uint32_t *bits; + size_t width, height, stride; + EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride); + + modifiedBounds = EsRectangleIntersection(modifiedBounds, ES_RECT_4(0, width, 0, height)); + + for (int32_t i = modifiedBounds.t / TILE_SIZE; i <= modifiedBounds.b / TILE_SIZE; i++) { + for (int32_t j = modifiedBounds.l / TILE_SIZE; j <= modifiedBounds.r / TILE_SIZE; j++) { + if ((uint32_t) j >= image->tileCountX || (uint32_t) i >= image->tileCountY) { + continue; + } + + Tile *tile = ImageUpdateTile(image, j, i, false); + + int32_t copyWidth = TILE_SIZE, copyHeight = TILE_SIZE; + + if (j * TILE_SIZE + copyWidth > (int32_t) width) { + copyWidth = width - j * TILE_SIZE; + } + + if (i * TILE_SIZE + copyHeight > (int32_t) height) { + copyHeight = height - i * TILE_SIZE; + } + + for (int32_t y = 0; y < copyHeight; y++) { + for (int32_t x = 0; x < copyWidth; x++) { + tile->bits[y * TILE_SIZE + x] = bits[stride / 4 * (y + i * TILE_SIZE) + (x + j * TILE_SIZE)]; + } + } + } + } + + EsPaintTargetEndDirectAccess(instance->bitmap); +} + +void ImageUndoMessage(const void *item, EsUndoManager *manager, EsMessage *message) { + const Image *image = (const Image *) item; + Instance *instance = EsUndoGetInstance(manager); + + if (message->type == ES_MSG_UNDO_INVOKE) { + EsUndoPush(manager, ImageUndoMessage, &instance->image, sizeof(Image)); + instance->image = *image; + + if (instance->bitmapWidth != image->width || instance->bitmapHeight != image->height) { + instance->bitmapWidth = image->width; + instance->bitmapHeight = image->height; + EsPaintTargetDestroy(instance->bitmap); + instance->bitmap = EsPaintTargetCreate(instance->bitmapWidth, instance->bitmapHeight, false); + EsElementRelayout(EsElementGetLayoutParent(instance->canvas)); + } + + ImageCopyToPaintTarget(instance, image); + EsElementRepaint(instance->canvas); + } else if (message->type == ES_MSG_UNDO_CANCEL) { + ImageDelete(*image); + } +} + +int BrushSizeMessage(EsElement *element, EsMessage *message) { + EsTextbox *textbox = (EsTextbox *) element; + + if (message->type == ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA) { + double oldValue = EsTextboxGetContentsAsDouble(textbox); + double newValue = oldValue + message->numberDragDelta.delta * (message->numberDragDelta.fast ? 1 : 0.1); + + if (newValue < 1) { + newValue = 1; + } else if (newValue > 1000) { + newValue = 1000; + } + + char result[64]; + size_t resultBytes = EsStringFormat(result, sizeof(result), "%d.%d", (int) newValue, (int) (newValue * 10) % 10); + EsTextboxSelectAll(textbox); + EsTextboxInsert(textbox, result, resultBytes); + } + + return 0; +} + +EsRectangle DrawFill(Instance *instance, EsPoint point) { + uint32_t color = 0xFF000000 | EsColorWellGetRGB(instance->colorWell); + EsRectangle modifiedBounds = ES_RECT_4(point.x, point.x, point.y, point.y); + + if ((uint32_t) point.x >= instance->bitmapWidth || (uint32_t) point.y >= instance->bitmapHeight) { + return {}; + } + + uint32_t *bits; + size_t width, height, stride; + EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride); + stride /= 4; + + Array pointsToVisit = {}; + + uint32_t replaceColor = bits[point.y * stride + point.x]; + if (replaceColor != color) pointsToVisit.Add(point); + + while (pointsToVisit.Length()) { + EsPoint startPoint = pointsToVisit.Pop(); + + if (startPoint.y < modifiedBounds.t) { + modifiedBounds.t = startPoint.y; + } + + if (startPoint.y > modifiedBounds.b) { + modifiedBounds.b = startPoint.y; + } + + for (ptrdiff_t delta = -1; delta <= 1; delta += 2) { + EsPoint point = startPoint; + uint32_t *pointer = bits + point.y * stride + point.x; + + bool spaceAbove = false; + bool spaceBelow = false; + + if (delta == 1) { + point.x += delta; + pointer += delta; + + if (point.x == (int32_t) width) { + break; + } + } + + while (true) { + if (*pointer != replaceColor) { + break; + } + + *pointer = color; + + if (point.x < modifiedBounds.l) { + modifiedBounds.l = point.x; + } + + if (point.x > modifiedBounds.r) { + modifiedBounds.r = point.x; + } + + if (point.y) { + if (!spaceAbove && pointer[-stride] == replaceColor) { + spaceAbove = true; + pointsToVisit.Add({ point.x, point.y - 1 }); + } else if (spaceAbove && pointer[-stride] != replaceColor) { + spaceAbove = false; + } + } + + if (point.y != (int32_t) height - 1) { + if (!spaceBelow && pointer[stride] == replaceColor) { + spaceBelow = true; + pointsToVisit.Add({ point.x, point.y + 1 }); + } else if (spaceBelow && pointer[stride] != replaceColor) { + spaceBelow = false; + } + } + + point.x += delta; + pointer += delta; + + if (point.x == (int32_t) width || point.x < 0) { + break; + } + } + } + } + + modifiedBounds.r++, modifiedBounds.b += 2; + pointsToVisit.Free(); + EsPaintTargetEndDirectAccess(instance->bitmap); + EsElementRepaint(instance->canvas, &modifiedBounds); + return modifiedBounds; +} + +EsRectangle DrawLine(Instance *instance, bool force = false) { + EsPoint point = EsMouseGetPosition(instance->canvas); + float brushSize = EsTextboxGetContentsAsDouble(instance->brushSize); + float spacing = brushSize * 0.1f; + uint32_t color = 0xFF000000 | EsColorWellGetRGB(instance->colorWell); + EsRectangle modifiedBounds = ES_RECT_4(instance->bitmapWidth, 0, instance->bitmapHeight, 0); + + uint32_t *bits; + size_t width, height, stride; + EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride); + stride /= 4; + + // Draw the line. + + while (true) { + float dx = point.x - instance->previousPointX; + float dy = point.y - instance->previousPointY; + float distance = EsCRTsqrtf(dx * dx + dy * dy); + + if (distance < spacing && !force) { + break; + } + + int32_t x0 = instance->previousPointX; + int32_t y0 = instance->previousPointY; + + EsRectangle bounds = ES_RECT_4(x0 - brushSize / 2 - 1, x0 + brushSize / 2 + 1, + y0 - brushSize / 2 - 1, y0 + brushSize / 2 + 1); + bounds = EsRectangleIntersection(bounds, ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight)); + modifiedBounds = EsRectangleBounding(modifiedBounds, bounds); + + for (int32_t y = bounds.t; y < bounds.b; y++) { + for (int32_t x = bounds.l; x < bounds.r; x++) { + float distance = (x - x0) * (x - x0) + (y - y0) * (y - y0); + + if (distance < brushSize * brushSize * 0.25f) { + bits[y * stride + x] = color; + } + } + } + + if (force) { + break; + } + + instance->previousPointX += dx / distance * spacing; + instance->previousPointY += dy / distance * spacing; + } + + // Repaint the canvas. + + modifiedBounds.r++, modifiedBounds.b++; + EsPaintTargetEndDirectAccess(instance->bitmap); + EsElementRepaint(instance->canvas, &modifiedBounds); + return modifiedBounds; +} + +int CanvasMessage(EsElement *element, EsMessage *message) { + Instance *instance = element->instance; + + if (message->type == ES_MSG_PAINT) { + EsPainter *painter = message->painter; + EsRectangle bounds = EsPainterBoundsInset(painter); + EsRectangle area = ES_RECT_4(bounds.l, bounds.l + instance->bitmapWidth, bounds.t, bounds.t + instance->bitmapHeight); + EsDrawPaintTarget(painter, instance->bitmap, area, ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight), 0xFF); + + if (instance->commandRectangle.check == ES_CHECK_CHECKED && instance->dragged) { + EsRectangle rectangle = instance->modifiedBounds; + rectangle.l += painter->offsetX, rectangle.r += painter->offsetX; + rectangle.t += painter->offsetY, rectangle.b += painter->offsetY; + EsDrawBlock(painter, rectangle, 0xFF000000 | EsColorWellGetRGB(instance->colorWell)); + } + } else if ((message->type == ES_MSG_MOUSE_LEFT_DRAG || message->type == ES_MSG_MOUSE_MOVED) + && EsMouseIsLeftHeld() && instance->commandBrush.check == ES_CHECK_CHECKED) { + instance->modifiedBounds = EsRectangleBounding(DrawLine(instance), instance->modifiedBounds); + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG && instance->commandRectangle.check == ES_CHECK_CHECKED) { + EsRectangle previous = instance->modifiedBounds; + EsPoint point = EsMouseGetPosition(element); + EsRectangle rectangle; + if (point.x < instance->previousPointX) rectangle.l = point.x, rectangle.r = instance->previousPointX + 1; + else rectangle.l = instance->previousPointX, rectangle.r = point.x + 1; + if (point.y < instance->previousPointY) rectangle.t = point.y, rectangle.b = instance->previousPointY + 1; + else rectangle.t = instance->previousPointY, rectangle.b = point.y + 1; + instance->modifiedBounds = rectangle; + EsRectangle bounding = EsRectangleBounding(rectangle, previous); + EsElementRepaint(element, &bounding); + instance->dragged = true; + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN && instance->commandBrush.check == ES_CHECK_CHECKED) { + EsUndoPush(instance->undoManager, ImageUndoMessage, &instance->image, sizeof(Image)); + instance->image = ImageFork(instance, instance->image); + EsPoint point = EsMouseGetPosition(element); + instance->previousPointX = point.x, instance->previousPointY = point.y; + instance->modifiedBounds = ES_RECT_4(instance->bitmapWidth, 0, instance->bitmapHeight, 0); + DrawLine(instance, true); + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN && instance->commandRectangle.check == ES_CHECK_CHECKED) { + EsPoint point = EsMouseGetPosition(element); + instance->previousPointX = point.x, instance->previousPointY = point.y; + instance->dragged = false; + } else if (message->type == ES_MSG_MOUSE_LEFT_UP && instance->commandBrush.check == ES_CHECK_CHECKED) { + ImageCopyFromPaintTarget(instance, &instance->image, instance->modifiedBounds); + } else if (message->type == ES_MSG_MOUSE_LEFT_UP && instance->commandRectangle.check == ES_CHECK_CHECKED && instance->dragged) { + instance->dragged = false; + EsUndoPush(instance->undoManager, ImageUndoMessage, &instance->image, sizeof(Image)); + instance->image = ImageFork(instance, instance->image); + EsPainter painter = {}; + painter.clip = ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight); + painter.target = instance->bitmap; + EsDrawBlock(&painter, instance->modifiedBounds, 0xFF000000 | EsColorWellGetRGB(instance->colorWell)); + ImageCopyFromPaintTarget(instance, &instance->image, instance->modifiedBounds); + } else if (message->type == ES_MSG_MOUSE_LEFT_UP && instance->commandFill.check == ES_CHECK_CHECKED) { + EsUndoPush(instance->undoManager, ImageUndoMessage, &instance->image, sizeof(Image)); + instance->image = ImageFork(instance, instance->image); + + EsRectangle modifiedBounds = DrawFill(instance, EsMouseGetPosition(element)); + ImageCopyFromPaintTarget(instance, &instance->image, modifiedBounds); + } else if (message->type == ES_MSG_GET_CURSOR) { + message->cursorStyle = ES_CURSOR_CROSS_HAIR_PICK; + } else if (message->type == ES_MSG_GET_WIDTH) { + message->measure.width = instance->bitmapWidth; + } else if (message->type == ES_MSG_GET_HEIGHT) { + message->measure.height = instance->bitmapHeight; + } else { + return 0; + } + + return ES_HANDLED; +} + +void CommandSelectTool(Instance *instance, EsElement *, EsCommand *command) { + if (command->check == ES_CHECK_CHECKED) { + return; + } + + EsCommandSetCheck(&instance->commandBrush, ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandFill, ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandRectangle, ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandSelect, ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandText, ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(command, ES_CHECK_CHECKED, false); + + if (command == &instance->commandBrush) EsButtonSetIcon(instance->toolDropdown, ES_ICON_DRAW_FREEHAND); + if (command == &instance->commandFill) EsButtonSetIcon(instance->toolDropdown, ES_ICON_COLOR_FILL); + if (command == &instance->commandRectangle) EsButtonSetIcon(instance->toolDropdown, ES_ICON_DRAW_RECTANGLE); + if (command == &instance->commandSelect) EsButtonSetIcon(instance->toolDropdown, ES_ICON_OBJECT_GROUP); + if (command == &instance->commandText) EsButtonSetIcon(instance->toolDropdown, ES_ICON_DRAW_TEXT); + + instance->dragged = false; +} + +int BitmapSizeTextboxMessage(EsElement *element, EsMessage *message) { + EsTextbox *textbox = (EsTextbox *) element; + Instance *instance = textbox->instance; + + if (message->type == ES_MSG_TEXTBOX_EDIT_END || message->type == ES_MSG_TEXTBOX_NUMBER_DRAG_END) { + char *expression = EsTextboxGetContents(textbox); + EsCalculationValue value = EsCalculateFromUserExpression(expression); + EsHeapFree(expression); + + if (value.error) { + return ES_REJECTED; + } + + if (value.number < 1) value.number = 1; + else if (value.number > 20000) value.number = 20000; + int newSize = (int) (value.number + 0.5); + char result[64]; + size_t resultBytes = EsStringFormat(result, sizeof(result), "%d", newSize); + EsTextboxSelectAll(textbox); + EsTextboxInsert(textbox, result, resultBytes); + + int oldSize = textbox->userData.i ? instance->bitmapHeight : instance->bitmapWidth; + + if (oldSize == newSize) { + return ES_HANDLED; + } + + EsRectangle clearRegion; + + if (textbox->userData.i) { + instance->bitmapHeight = newSize; + clearRegion = ES_RECT_4(0, instance->bitmapWidth, oldSize, newSize); + } else { + instance->bitmapWidth = newSize; + clearRegion = ES_RECT_4(oldSize, newSize, 0, instance->bitmapHeight); + } + + EsUndoPush(instance->undoManager, ImageUndoMessage, &instance->image, sizeof(Image)); + instance->image = ImageFork(instance, instance->image, instance->bitmapWidth, instance->bitmapHeight); + EsPaintTargetDestroy(instance->bitmap); + instance->bitmap = EsPaintTargetCreate(instance->bitmapWidth, instance->bitmapHeight, false); + ImageCopyToPaintTarget(instance, &instance->image); + + EsPainter painter = {}; + painter.clip = ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight); + painter.target = instance->bitmap; + EsDrawBlock(&painter, clearRegion, 0xFFFFFFFF); + ImageCopyFromPaintTarget(instance, &instance->image, clearRegion); + + EsElementRelayout(EsElementGetLayoutParent(instance->canvas)); + + return ES_HANDLED; + } else if (message->type == ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA) { + int oldValue = EsTextboxGetContentsAsDouble(textbox); + int newValue = oldValue + message->numberDragDelta.delta * (message->numberDragDelta.fast ? 10 : 1); + if (newValue < 1) newValue = 1; + else if (newValue > 20000) newValue = 20000; + char result[64]; + size_t resultBytes = EsStringFormat(result, sizeof(result), "%d", newValue); + EsTextboxSelectAll(textbox); + EsTextboxInsert(textbox, result, resultBytes); + return ES_HANDLED; + } + + return 0; +} + +void ImageTransform(EsMenu *menu, EsGeneric context) { + Instance *instance = menu->instance; + EsUndoPush(instance->undoManager, ImageUndoMessage, &instance->image, sizeof(Image)); + + uint32_t *bits; + size_t width, height, stride; + EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride); + + EsPaintTarget *newTarget = nullptr; + uint32_t *newBits = nullptr; + size_t newStride = 0; + + if (context.i == 1 || context.i == 2) { + instance->image = ImageFork(instance, instance->image, height, width); + newTarget = EsPaintTargetCreate(height, width, false); + EsPaintTargetStartDirectAccess(newTarget, &newBits, &height, &width, &newStride); + } else { + instance->image = ImageFork(instance, instance->image); + } + + if (context.i == 1 /* rotate left */) { + for (uintptr_t i = 0; i < height; i++) { + for (uintptr_t j = 0; j < width; j++) { + newBits[(width - j - 1) * newStride / 4 + i] = bits[i * stride / 4 + j]; + } + } + } else if (context.i == 2 /* rotate right */) { + for (uintptr_t i = 0; i < height; i++) { + for (uintptr_t j = 0; j < width; j++) { + newBits[j * newStride / 4 + (height - i - 1)] = bits[i * stride / 4 + j]; + } + } + } else if (context.i == 3 /* flip horizontally */) { + for (uintptr_t i = 0; i < height; i++) { + for (uintptr_t j = 0; j < width / 2; j++) { + uint32_t temporary = bits[i * stride / 4 + j]; + bits[i * stride / 4 + j] = bits[i * stride / 4 + (width - j - 1)]; + bits[i * stride / 4 + (width - j - 1)] = temporary; + } + } + } else if (context.i == 4 /* flip vertically */) { + for (uintptr_t i = 0; i < height / 2; i++) { + for (uintptr_t j = 0; j < width; j++) { + uint32_t temporary = bits[i * stride / 4 + j]; + bits[i * stride / 4 + j] = bits[(height - i - 1) * stride / 4 + j]; + bits[(height - i - 1) * stride / 4 + j] = temporary; + } + } + } + + EsPaintTargetEndDirectAccess(instance->bitmap); + + if (newTarget) { + EsPaintTargetDestroy(instance->bitmap); + instance->bitmap = newTarget; + size_t width, height; + EsPaintTargetGetSize(instance->bitmap, &width, &height); + instance->bitmapWidth = width; + instance->bitmapHeight = height; + EsElementRelayout(EsElementGetLayoutParent(instance->canvas)); + } + + ImageCopyFromPaintTarget(instance, &instance->image, ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight)); + EsElementRepaint(instance->canvas); +} + +void MenuTools(Instance *instance, EsElement *element, EsCommand *) { + EsMenu *menu = EsMenuCreate(element); + EsMenuAddCommandsFromToolbar(menu, instance->toolPanel); + EsMenuShow(menu); +} + +void MenuImage(Instance *instance, EsElement *element, EsCommand *) { + EsMenu *menu = EsMenuCreate(element); + + EsMenuAddItem(menu, ES_MENU_ITEM_HEADER, INTERFACE_STRING(ImageEditorCanvasSize)); + EsPanel *table = EsPanelCreate(menu, ES_PANEL_HORIZONTAL | ES_PANEL_TABLE, &styleImageMenuTable); + EsPanelSetBands(table, 2, 2); + + char buffer[64]; + size_t bytes; + EsTextbox *textbox; + + bytes = EsStringFormat(buffer, sizeof(buffer), "%d", instance->bitmapWidth); + EsTextDisplayCreate(table, ES_CELL_H_RIGHT, ES_STYLE_TEXT_LABEL, INTERFACE_STRING(ImageEditorPropertyWidth)); + textbox = EsTextboxCreate(table, ES_TEXTBOX_EDIT_BASED, &styleBitmapSizeTextbox); + EsTextboxInsert(textbox, buffer, bytes, false); + textbox->userData.i = 0; + textbox->messageUser = BitmapSizeTextboxMessage; + EsTextboxUseNumberOverlay(textbox, true); + + bytes = EsStringFormat(buffer, sizeof(buffer), "%d", instance->bitmapHeight); + EsTextDisplayCreate(table, ES_CELL_H_RIGHT, ES_STYLE_TEXT_LABEL, INTERFACE_STRING(ImageEditorPropertyHeight)); + textbox = EsTextboxCreate(table, ES_TEXTBOX_EDIT_BASED, &styleBitmapSizeTextbox); + EsTextboxInsert(textbox, buffer, bytes, false); + textbox->userData.i = 1; + textbox->messageUser = BitmapSizeTextboxMessage; + EsTextboxUseNumberOverlay(textbox, true); + + EsMenuAddSeparator(menu); + EsMenuAddItem(menu, ES_MENU_ITEM_HEADER, INTERFACE_STRING(ImageEditorImageTransformations)); + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(ImageEditorRotateLeft), ImageTransform, 1); + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(ImageEditorRotateRight), ImageTransform, 2); + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(ImageEditorFlipHorizontally), ImageTransform, 3); + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(ImageEditorFlipVertically), ImageTransform, 4); + + EsMenuShow(menu); +} + +void InstanceCreate(EsMessage *message) { + Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(ImageEditorTitle)); + EsElement *toolbar = EsWindowGetToolbar(instance->window); + + // Register commands. + + EsCommandRegister(&instance->commandBrush, instance, CommandSelectTool, 1, "N", true); + EsCommandRegister(&instance->commandFill, instance, CommandSelectTool, 2, "Shift+B", true); + EsCommandRegister(&instance->commandRectangle, instance, CommandSelectTool, 3, "Shift+R", true); + EsCommandRegister(&instance->commandSelect, instance, CommandSelectTool, 4, "R", false); + EsCommandRegister(&instance->commandText, instance, CommandSelectTool, 5, "T", false); + + EsCommandSetCheck(&instance->commandBrush, ES_CHECK_CHECKED, false); + + // Create the toolbar. + + EsButton *button; + + button = EsButtonCreate(toolbar, ES_BUTTON_DROPDOWN, ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG, INTERFACE_STRING(ImageEditorImage)); + EsButtonSetIcon(button, ES_ICON_IMAGE_X_GENERIC); + button->accessKey = 'I'; + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT); + EsButtonOnCommand(button, MenuImage); + button = EsButtonCreate(toolbar, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_TOOLBAR_MEDIUM); + EsCommandAddButton(EsCommandByID(instance, ES_COMMAND_UNDO), button); + EsButtonSetIcon(button, ES_ICON_EDIT_UNDO_SYMBOLIC); + button->accessKey = 'U'; + button = EsButtonCreate(toolbar, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_TOOLBAR_MEDIUM); + EsCommandAddButton(EsCommandByID(instance, ES_COMMAND_REDO), button); + EsButtonSetIcon(button, ES_ICON_EDIT_REDO_SYMBOLIC); + button->accessKey = 'R'; + + EsSpacerCreate(toolbar, ES_CELL_FILL); + + button = instance->toolDropdown = EsButtonCreate(toolbar, ES_BUTTON_DROPDOWN, ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG, INTERFACE_STRING(ImageEditorPickTool)); + EsButtonSetIcon(button, ES_ICON_DRAW_FREEHAND); + EsButtonOnCommand(button, MenuTools); + button->accessKey = 'T'; + + instance->toolPanel = EsPanelCreate(toolbar, ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_TOOLBAR); + button = EsButtonCreate(instance->toolPanel, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG, INTERFACE_STRING(ImageEditorToolBrush)); + EsCommandAddButton(&instance->commandBrush, button); + EsButtonSetIcon(button, ES_ICON_DRAW_FREEHAND); + button->accessKey = 'B'; + button = EsButtonCreate(instance->toolPanel, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG, INTERFACE_STRING(ImageEditorToolFill)); + EsCommandAddButton(&instance->commandFill, button); + EsButtonSetIcon(button, ES_ICON_COLOR_FILL); + button->accessKey = 'F'; + button = EsButtonCreate(instance->toolPanel, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG, INTERFACE_STRING(ImageEditorToolRectangle)); + EsCommandAddButton(&instance->commandRectangle, button); + EsButtonSetIcon(button, ES_ICON_DRAW_RECTANGLE); + button->accessKey = 'E'; + button = EsButtonCreate(instance->toolPanel, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG, INTERFACE_STRING(ImageEditorToolSelect)); + EsCommandAddButton(&instance->commandSelect, button); + EsButtonSetIcon(button, ES_ICON_OBJECT_GROUP); + button->accessKey = 'S'; + button = EsButtonCreate(instance->toolPanel, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG, INTERFACE_STRING(ImageEditorToolText)); + EsCommandAddButton(&instance->commandText, button); + EsButtonSetIcon(button, ES_ICON_DRAW_TEXT); + button->accessKey = 'T'; + + EsWindowAddSizeAlternative(instance->window, instance->toolDropdown, instance->toolPanel, 1100, 0); + + EsSpacerCreate(toolbar, ES_CELL_FILL); + + EsPanel *section = EsPanelCreate(toolbar, ES_PANEL_HORIZONTAL); + EsTextDisplayCreate(section, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(ImageEditorPropertyColor)); + instance->colorWell = EsColorWellCreate(section, ES_FLAGS_DEFAULT, 0); + instance->colorWell->accessKey = 'C'; + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, 0, 5, 0); + + section = EsPanelCreate(toolbar, ES_PANEL_HORIZONTAL); + EsTextDisplayCreate(section, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(ImageEditorPropertyBrushSize)); + instance->brushSize = EsTextboxCreate(section, ES_TEXTBOX_EDIT_BASED, ES_STYLE_TEXTBOX_BORDERED_SINGLE_COMPACT); + instance->brushSize->messageUser = BrushSizeMessage; + EsTextboxUseNumberOverlay(instance->brushSize, false); + EsTextboxInsert(instance->brushSize, EsLiteral("5.0")); + instance->brushSize->accessKey = 'Z'; + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, 0, 1, 0); + + // Create the user interface. + + EsWindowSetIcon(instance->window, ES_ICON_MULTIMEDIA_PHOTO_MANAGER); + + EsCanvasPane *canvasPane = EsCanvasPaneCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_BACKGROUND); + instance->canvas = EsCustomElementCreate(canvasPane, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE); + instance->canvas->messageUser = CanvasMessage; + EsElementFocus(instance->canvas, false); + + // Setup the paint target and the image. + + instance->bitmapWidth = 500; + instance->bitmapHeight = 400; + instance->bitmap = EsPaintTargetCreate(instance->bitmapWidth, instance->bitmapHeight, false); + EsPainter painter = {}; + painter.clip = ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight); + painter.target = instance->bitmap; + EsDrawBlock(&painter, painter.clip, 0xFFFFFFFF); + instance->image = ImageFork(instance, {}, instance->bitmapWidth, instance->bitmapHeight); + ImageCopyFromPaintTarget(instance, &instance->image, painter.clip); +} + +void _start() { + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + InstanceCreate(message); + } else if (message->type == ES_MSG_INSTANCE_OPEN) { + Instance *instance = message->instanceOpen.instance; + size_t fileSize; + uint8_t *file = (uint8_t *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize); + + if (!file) { + EsInstanceOpenComplete(message, false); + continue; + } + + uint32_t width, height; + uint8_t *bits = EsImageLoad(file, fileSize, &width, &height, 4); + EsHeapFree(file); + + if (!bits) { + EsInstanceOpenComplete(message, false, INTERFACE_STRING(ImageEditorUnsupportedFormat)); + continue; + } + + EsPaintTargetDestroy(instance->bitmap); + ImageDelete(instance->image); + + instance->bitmapWidth = width; + instance->bitmapHeight = height; + instance->bitmap = EsPaintTargetCreate(instance->bitmapWidth, instance->bitmapHeight, false); + EsPainter painter = {}; + painter.clip = ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight); + painter.target = instance->bitmap; + EsDrawBitmap(&painter, painter.clip, (uint32_t *) bits, width * 4, 0xFF); + instance->image = ImageFork(instance, {}, instance->bitmapWidth, instance->bitmapHeight); + ImageCopyFromPaintTarget(instance, &instance->image, painter.clip); + EsElementRelayout(EsElementGetLayoutParent(instance->canvas)); + + EsHeapFree(bits); + EsInstanceOpenComplete(message, true); + } else if (message->type == ES_MSG_INSTANCE_DESTROY) { + Instance *instance = message->instanceDestroy.instance; + EsPaintTargetDestroy(instance->bitmap); + ImageDelete(instance->image); + } + } +} diff --git a/apps/image_editor.ini b/apps/image_editor.ini new file mode 100644 index 0000000..0e526df --- /dev/null +++ b/apps/image_editor.ini @@ -0,0 +1,15 @@ +[general] +name=Image Editor +icon=icon_multimedia_photo_manager +use_single_process=1 + +[build] +source=apps/image_editor.cpp + +[@handler] +extension=jpg +action=open + +[@handler] +extension=png +action=open diff --git a/apps/irc_client.cpp b/apps/irc_client.cpp new file mode 100644 index 0000000..2f7ab68 --- /dev/null +++ b/apps/irc_client.cpp @@ -0,0 +1,327 @@ +// TODO Don't use EsTextbox for the output.. +// TODO Put the connection settings in a Panel.Popup. + +#define ES_INSTANCE_TYPE Instance +#include + +struct Instance : EsInstance { + EsTextbox *textboxNick; + EsTextbox *textboxAddress; + EsTextbox *textboxPort; + EsTextbox *textboxOutput; + EsTextbox *textboxInput; + EsButton *buttonConnect; + + EsThreadInformation networkingThread; + + EsMutex inputCommandMutex; + char *inputCommand; + size_t inputCommandBytes; +}; + +const EsStyle styleSmallTextbox = { + .inherit = ES_STYLE_TEXTBOX_BORDERED_SINGLE, + + .metrics = { + .mask = ES_THEME_METRICS_PREFERRED_WIDTH, + .preferredWidth = 100, + }, +}; + +const EsStyle styleOutputTextbox = { + .inherit = ES_STYLE_TEXTBOX_NO_BORDER, + + .metrics = { + .mask = ES_THEME_METRICS_FONT_FAMILY, + .fontFamily = ES_FONT_MONOSPACED, + }, +}; + +const EsStyle styleInputTextbox = { + .inherit = ES_STYLE_TEXTBOX_BORDERED_SINGLE, + + .metrics = { + .mask = ES_THEME_METRICS_FONT_FAMILY, + .fontFamily = ES_FONT_MONOSPACED, + }, +}; + +int TextboxInputCallback(EsElement *element, EsMessage *message) { + Instance *instance = element->instance; + + if (message->type == ES_MSG_KEY_DOWN) { + if (message->keyboard.scancode == ES_SCANCODE_ENTER) { + size_t inputCommandBytes = 0; + char *inputCommand = EsTextboxGetContents(instance->textboxInput, &inputCommandBytes); + + if (inputCommandBytes) { + EsMutexAcquire(&instance->inputCommandMutex); + EsHeapFree(instance->inputCommand); + instance->inputCommand = inputCommand; + instance->inputCommandBytes = inputCommandBytes; + EsMutexRelease(&instance->inputCommandMutex); + } else { + EsHeapFree(inputCommand); + } + + EsTextboxClear(instance->textboxInput, false); + return ES_HANDLED; + } + } + + return 0; +} + +void NetworkingThread(EsGeneric argument) { + Instance *instance = (Instance *) argument.p; + + char errorMessage[4096]; + size_t errorMessageBytes = 0; + + char message[4096]; + size_t messageBytes = 0; + + char nick[64]; + size_t nickBytes = 0; + + char *password = nullptr; + size_t passwordBytes = 0; + + char *address = nullptr; + size_t addressBytes = 0; + + char buffer[1024]; + uintptr_t bufferPosition = 0; + + EsConnection connection = {}; + connection.sendBufferBytes = 65536; + connection.receiveBufferBytes = 65536; + + { + EsMessageMutexAcquire(); + address = EsTextboxGetContents(instance->textboxAddress, &addressBytes); + EsMessageMutexRelease(); + EsError error = EsAddressResolve(address, addressBytes, ES_FLAGS_DEFAULT, &connection.address); + + if (error != ES_SUCCESS) { + errorMessageBytes = EsStringFormat(errorMessage, sizeof(errorMessage), + "The address name '%s' could not be found.\n", addressBytes, address); + goto exit; + } + } + + { + EsMessageMutexAcquire(); + size_t portBytes; + char *port = EsTextboxGetContents(instance->textboxPort, &portBytes); + EsMessageMutexRelease(); + connection.address.port = EsIntegerParse(port, portBytes); + EsHeapFree(port); + } + + { + EsMessageMutexAcquire(); + char *_nick = EsTextboxGetContents(instance->textboxNick, &nickBytes); + EsMessageMutexRelease(); + if (nickBytes > sizeof(nick)) nickBytes = sizeof(nick); + EsMemoryCopy(nick, _nick, nickBytes); + EsHeapFree(_nick); + + for (uintptr_t i = 0; i < nickBytes; i++) { + if (nick[i] == ':') { + password = nick + i + 1; + passwordBytes = nickBytes - i - 1; + nickBytes = i; + } + } + } + + { + EsError error = EsConnectionOpen(&connection, ES_CONNECTION_OPEN_WAIT); + + if (error != ES_SUCCESS) { + errorMessageBytes = EsStringFormat(errorMessage, sizeof(errorMessage), + "Could not open the connection (%d).", error); + goto exit; + } + + messageBytes = EsStringFormat(message, sizeof(message), "%z%s%zNICK %s\r\nUSER %s localhost %s :%s\r\n", + password ? "PASS " : "", passwordBytes, password, password ? "\r\n" : "", + nickBytes, nick, nickBytes, nick, addressBytes, address, nickBytes, nick); + EsConnectionWriteSync(&connection, message, messageBytes); + } + + while (true) { + // TODO Ping the server every 2 minutes. + // TODO If we've received no messages for 5 minutes, timeout. + + uintptr_t inputBytes = 0; + + while (true) { + char *inputCommand = nullptr; + size_t inputCommandBytes = 0; + + EsMutexAcquire(&instance->inputCommandMutex); + inputCommand = instance->inputCommand; + inputCommandBytes = instance->inputCommandBytes; + instance->inputCommand = nullptr; + instance->inputCommandBytes = 0; + EsMutexRelease(&instance->inputCommandMutex); + + if (inputCommand) { + messageBytes = EsStringFormat(message, sizeof(message), "%s\r\n", inputCommandBytes, inputCommand); + EsConnectionWriteSync(&connection, message, messageBytes); + EsHeapFree(inputCommand); + } + + size_t bytesRead; + EsError error = EsConnectionRead(&connection, buffer + bufferPosition, sizeof(buffer) - bufferPosition, &bytesRead); + + if (error != ES_SUCCESS) { + errorMessageBytes = EsStringFormat(errorMessage, sizeof(errorMessage), "The connection was lost (%d).", error); + goto exit; + } + + bufferPosition += bytesRead; + + if (bufferPosition >= 2) { + for (uintptr_t i = 0; i < bufferPosition - 1; i++) { + if (buffer[i] == '\r' && buffer[i + 1] == '\n') { + buffer[i] = 0; + inputBytes = i + 2; + goto gotMessage; + } + } + } + + if (bufferPosition == sizeof(buffer)) { + errorMessageBytes = EsStringFormat(errorMessage, sizeof(errorMessage), "The server sent an invalid message."); + goto exit; + } + } + + gotMessage:; + + EsMessageMutexAcquire(); + EsTextboxInsert(instance->textboxOutput, buffer); + EsTextboxInsert(instance->textboxOutput, "\n"); + EsMessageMutexRelease(); + + { + EsPrint("=================\n%z\n", buffer); + + const char *command = nullptr, *user = nullptr, *parameters = nullptr, *text = nullptr; + char *position = buffer; + + if (*position == ':') { + user = ++position; + while (*position && *position != ' ') position++; + if (*position) *position++ = 0; + } else { + user = address; + } + + while (*position && *position == ' ') position++; + command = position; + while (*position && *position != ' ') position++; + if (*position) *position++ = 0; + while (*position && *position == ' ') position++; + + if (*position != ':') { + parameters = position; + while (*position && *position != ' ') position++; + if (*position) *position++ = 0; + } + + while (*position && *position == ' ') position++; + if (*position == ':') text = position + 1; + + if (0 == EsCRTstrcmp(command, "PING")) { + messageBytes = EsStringFormat(message, sizeof(message), "PONG :%z\r\n", text ?: parameters); + EsConnectionWriteSync(&connection, message, messageBytes); + } + + EsPrint("command: '%z'\nuser: '%z'\nparameters: '%z'\ntext: '%z'\n\n", command, user, parameters, text); + } + + EsMemoryMove(buffer + inputBytes, buffer + bufferPosition, -inputBytes, false); + bufferPosition -= inputBytes; + } + + exit:; + + if (connection.handle) { + EsConnectionClose(&connection); + } + + EsMessageMutexAcquire(); + + if (errorMessageBytes) { + EsDialogShowAlert(instance->window, EsLiteral("Connection failed"), errorMessage, errorMessageBytes, + ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON); + } + + EsElementSetDisabled(instance->textboxAddress, false); + EsElementSetDisabled(instance->textboxNick, false); + EsElementSetDisabled(instance->textboxPort, false); + EsElementSetDisabled(instance->textboxInput, true); + EsElementSetDisabled(instance->buttonConnect, false); + + EsMessageMutexRelease(); + + EsHeapFree(address); +} + +void ConnectCommand(Instance *instance, EsElement *, EsCommand *) { + EsElementSetDisabled(instance->textboxAddress, true); + EsElementSetDisabled(instance->textboxNick, true); + EsElementSetDisabled(instance->textboxPort, true); + EsElementSetDisabled(instance->textboxInput, false); + EsElementSetDisabled(instance->buttonConnect, true); + + EsThreadCreate(NetworkingThread, &instance->networkingThread, instance); +} + +void _start() { + _init(); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + // Create an new instance. + + Instance *instance = EsInstanceCreate(message, "IRC Client"); + EsWindow *window = instance->window; + EsWindowSetIcon(window, ES_ICON_INTERNET_CHAT); + + // Create the toolbar. + + EsElement *toolbar = EsWindowGetToolbar(window); + EsPanel *section = EsPanelCreate(toolbar, ES_PANEL_HORIZONTAL); + EsTextDisplayCreate(section, ES_FLAGS_DEFAULT, 0, EsLiteral("Nick:")); + instance->textboxNick = EsTextboxCreate(section, ES_FLAGS_DEFAULT, &styleSmallTextbox); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + section = EsPanelCreate(toolbar, ES_PANEL_HORIZONTAL); + EsTextDisplayCreate(section, ES_FLAGS_DEFAULT, 0, EsLiteral("Address:")); + instance->textboxAddress = EsTextboxCreate(section, ES_FLAGS_DEFAULT, &styleSmallTextbox); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + section = EsPanelCreate(toolbar, ES_PANEL_HORIZONTAL); + EsTextDisplayCreate(section, ES_FLAGS_DEFAULT, 0, EsLiteral("Port:")); + instance->textboxPort = EsTextboxCreate(section, ES_FLAGS_DEFAULT, &styleSmallTextbox); + EsSpacerCreate(toolbar, ES_CELL_H_FILL); + instance->buttonConnect = EsButtonCreate(toolbar, ES_FLAGS_DEFAULT, 0, EsLiteral("Connect")); + EsButtonOnCommand(instance->buttonConnect, ConnectCommand); + + // Create the main area. + + EsPanel *panel = EsPanelCreate(window, ES_PANEL_VERTICAL | ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER); + instance->textboxOutput = EsTextboxCreate(panel, ES_CELL_FILL | ES_TEXTBOX_MULTILINE, &styleOutputTextbox); + EsPanelCreate(panel, ES_CELL_H_FILL, ES_STYLE_SEPARATOR_HORIZONTAL); + EsPanel *inputArea = EsPanelCreate(panel, ES_PANEL_HORIZONTAL | ES_CELL_H_FILL, ES_STYLE_PANEL_FILLED); + instance->textboxInput = EsTextboxCreate(inputArea, ES_CELL_FILL, &styleInputTextbox); + instance->textboxInput->messageUser = TextboxInputCallback; + EsElementSetDisabled(instance->textboxInput); + } + } +} diff --git a/apps/irc_client.ini b/apps/irc_client.ini new file mode 100644 index 0000000..1ed7d78 --- /dev/null +++ b/apps/irc_client.ini @@ -0,0 +1,7 @@ +[general] +name=IRC Client +icon=icon_internet_chat +use_single_process=1 + +[build] +source=apps/irc_client.cpp diff --git a/apps/markdown_viewer.cpp b/apps/markdown_viewer.cpp new file mode 100644 index 0000000..c9149ef --- /dev/null +++ b/apps/markdown_viewer.cpp @@ -0,0 +1,500 @@ +#define ES_INSTANCE_TYPE Instance +#include + +#include +#include + +#include +#define IMPLEMENTATION +#include +#undef IMPLEMENTATION + +// TODO Inline code background? + +// TODO When resizing the window, maintain the scroll position. +// TODO Table of contents/navigation pane. +// TODO Searching. + +// TODO Images. +// TODO Proper link support. + +// TODO Embedding markdown viewers into other applications. + +// #define DEBUG_PARSER_OUTPUT + +struct Span { + bool em, strong, monospaced, link; + uintptr_t offset; +}; + +struct Instance : EsInstance { + EsElement *root; + + EsElement *active; + Array spans; + Array text; + int32_t paddingBefore; + bool inBlockQuote; + int inListDepth; + int tableColumnCount; + + int debugNestDepth; +}; + +#define MAKE_TEXT_STYLE(_textColor, _textSize, _fontFamily, _fontWeight, _isItalic) \ + { \ + .metrics = { \ + .mask = ES_THEME_METRICS_TEXT_COLOR | ES_THEME_METRICS_TEXT_ALIGN | ES_THEME_METRICS_TEXT_SIZE \ + | ES_THEME_METRICS_FONT_FAMILY | ES_THEME_METRICS_FONT_WEIGHT \ + | ES_THEME_METRICS_IS_ITALIC, \ + .textColor = _textColor, \ + .textAlign = ES_TEXT_H_LEFT | ES_TEXT_V_TOP | ES_TEXT_WRAP, \ + .textSize = (int) (_textSize * 0.64 + 0.5), \ + .fontFamily = _fontFamily, \ + .fontWeight = _fontWeight, \ + .isItalic = _isItalic, \ + }, \ + } + +#define PARAGRAPH_PADDING_BEFORE (0) +#define PARAGRAPH_PADDING_AFTER (16) +#define H1_PADDING_BEFORE (16) +#define H1_PADDING_AFTER (16) +#define H2_PADDING_BEFORE (24) +#define H2_PADDING_AFTER (16) +#define H3_PADDING_BEFORE (24) +#define H3_PADDING_AFTER (16) +#define HEADING_UNDERLINE_GAP (7) +#define HR_PADDING_BEFORE (24) +#define HR_PADDING_AFTER (24) +#define QUOTE_PADDING_BEFORE (16) +#define QUOTE_PADDING_AFTER (0) +#define TABLE_PADDING_BEFORE (16) +#define TABLE_PADDING_AFTER (16) + +#define COLOR_BACKGROUND (0xFFFDFDFD) +#define COLOR_GRAY1 (0xFFE1E4E8) +#define COLOR_GRAY2 (0xFFEBEDEF) +#define COLOR_GRAY3 (0xFFF6F8FA) +#define COLOR_TEXT1 (0xFF24292E) +#define COLOR_TEXT2 (0xFF5A636D) +#define COLOR_TEXT_LINK (0xFF0366D6) + +EsStyle styleBackground = { + .appearance = { + .enabled = true, + .backgroundColor = COLOR_BACKGROUND, + }, +}; + +EsStyle styleRoot = { + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_PREFERRED_WIDTH, + .insets = ES_RECT_4(32, 32, 16, 32), + .preferredWidth = 800, + }, +}; + +EsStyle styleQuote = { + .metrics = { + .mask = ES_THEME_METRICS_INSETS, + .insets = ES_RECT_4(20, 16, 0, 0), + }, + + .appearance = { + .enabled = true, + .borderColor = COLOR_GRAY1, + .borderSize = ES_RECT_4(4, 0, 0, 0), + }, +}; + +EsStyle styleList = { + .metrics = { + .mask = ES_THEME_METRICS_GAP_MAJOR, + .gapMajor = 5, + }, +}; + +EsStyle styleHeadingUnderline = { + .metrics = { + .mask = ES_THEME_METRICS_PREFERRED_HEIGHT, + .preferredHeight = 1, + }, + + .appearance = { + .enabled = true, + .backgroundColor = COLOR_GRAY2, + }, +}; + +EsStyle styleCodeBlock = { + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_CLIP_ENABLED, + .insets = ES_RECT_4(16, 16, 10, 10), + .clipEnabled = true, + }, + + .appearance = { + .enabled = true, + .backgroundColor = COLOR_GRAY3, + }, +}; + +EsStyle styleHorizontalRule = { + .metrics = { + .mask = ES_THEME_METRICS_PREFERRED_HEIGHT, + .preferredHeight = 4, + }, + + .appearance = { + .enabled = true, + .backgroundColor = COLOR_GRAY1, + }, +}; + +EsStyle styleTable = { +}; + +EsStyle styleTD = { + .inherit = ES_STYLE_TEXT_PARAGRAPH, + + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_TEXT_SIZE | ES_THEME_METRICS_TEXT_COLOR, + .insets = ES_RECT_4(8, 8, 8, 0), + .textColor = COLOR_TEXT1, + .textSize = (int) (16 * 0.64 + 0.5), + }, +}; + +EsStyle styleTH = { + .inherit = ES_STYLE_TEXT_PARAGRAPH, + + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_TEXT_SIZE | ES_THEME_METRICS_TEXT_COLOR | ES_THEME_METRICS_FONT_WEIGHT, + .insets = ES_RECT_4(8, 8, 0, 4), + .textColor = COLOR_TEXT1, + .textSize = (int) (16 * 0.64 + 0.5), + .fontWeight = 5, + }, + + .appearance = { + .enabled = true, + .borderColor = COLOR_GRAY1, + .borderSize = ES_RECT_4(0, 0, 0, 1), + }, +}; + +EsStyle styleHeading1 = MAKE_TEXT_STYLE(COLOR_TEXT1, 32, ES_FONT_SANS, 6, false); +EsStyle styleHeading2 = MAKE_TEXT_STYLE(COLOR_TEXT1, 24, ES_FONT_SANS, 6, false); +EsStyle styleHeading3 = MAKE_TEXT_STYLE(COLOR_TEXT1, 20, ES_FONT_SANS, 6, false); +EsStyle styleParagraph = MAKE_TEXT_STYLE(COLOR_TEXT1, 16, ES_FONT_SANS, 4, false); +EsStyle styleQuoteParagraph = MAKE_TEXT_STYLE(COLOR_TEXT2, 16, ES_FONT_SANS, 4, false); +EsStyle styleCode = MAKE_TEXT_STYLE(COLOR_TEXT1, 16, ES_FONT_MONOSPACED, 4, false); + +const char *blockTypes[] = { + "MD_BLOCK_DOC", + "MD_BLOCK_QUOTE", + "MD_BLOCK_UL", + "MD_BLOCK_OL", + "MD_BLOCK_LI", + "MD_BLOCK_HR", + "MD_BLOCK_H", + "MD_BLOCK_CODE", + "MD_BLOCK_HTML", + "MD_BLOCK_P", + "MD_BLOCK_TABLE", + "MD_BLOCK_THEAD", + "MD_BLOCK_TBODY", + "MD_BLOCK_TR", + "MD_BLOCK_TH", + "MD_BLOCK_TD", +}; + +const char *spanTypes[] = { + "MD_SPAN_EM", + "MD_SPAN_STRONG", + "MD_SPAN_A", + "MD_SPAN_IMG", + "MD_SPAN_CODE", + "MD_SPAN_DEL", + "MD_SPAN_LATEXMATH", + "MD_SPAN_LATEXMATH_DISPLAY", + "MD_SPAN_WIKILINK", + "MD_SPAN_U", +}; + +const char *textTypes[] = { + "MD_TEXT_NORMAL", + "MD_TEXT_NULLCHAR", + "MD_TEXT_BR", + "MD_TEXT_SOFTBR", + "MD_TEXT_ENTITY", + "MD_TEXT_CODE", + "MD_TEXT_HTML", + "MD_TEXT_LATEXMATH", +}; + +void AddPadding(Instance *instance, int32_t before, int32_t after) { + if (instance->inListDepth) return; + if (before < instance->paddingBefore) before = instance->paddingBefore; + EsSpacerCreate(instance->active, ES_FLAGS_DEFAULT, nullptr, 0, before); + instance->paddingBefore = after; +} + +void CreateStyledTextDisplay(Instance *instance, EsStyle *style, uint64_t flags = ES_CELL_H_FILL) { + EsTextDisplay *display = EsTextDisplayCreate(instance->active, flags, style); + EsTextRun *runs = (EsTextRun *) EsHeapAllocate(sizeof(EsTextRun) * (instance->spans.Length() + 1), false); + + for (uintptr_t i = 0; i < instance->spans.Length(); i++) { + runs[i].offset = instance->spans[i].offset; + EsElementGetTextStyle(display, &runs[i].style); + if (instance->spans[i].link) { runs[i].style.decorations |= ES_TEXT_DECORATION_UNDERLINE; runs[i].style.color = COLOR_TEXT_LINK; } + if (instance->spans[i].em) runs[i].style.font.italic = true; + if (instance->spans[i].strong) runs[i].style.font.weight = 7; + if (instance->spans[i].monospaced) runs[i].style.font.family = ES_FONT_MONOSPACED; + runs[i].style.decorationsColor = runs[i].style.color; + } + + runs[instance->spans.Length()].offset = instance->text.Length(); + EsTextDisplaySetStyledContents(display, instance->text.array, runs, instance->spans.Length()); + EsHeapFree(runs); +} + +#ifdef DEBUG_PARSER_OUTPUT +void ParserOutputPrintIndentation(Instance *instance) { + for (int i = 0; i < instance->debugNestDepth; i++) { + EsPrint(" "); + } +} +#endif + +int ParserEnterBlock(MD_BLOCKTYPE type, void *detail, void *_instance) { + Instance *instance = (Instance *) _instance; +#ifdef DEBUG_PARSER_OUTPUT + ParserOutputPrintIndentation(instance); + EsPrint(">> Enter block %z\n", blockTypes[type]); + instance->debugNestDepth++; +#endif + (void) detail; + + if (instance->inListDepth && instance->text.Length()) { + CreateStyledTextDisplay(instance, &styleParagraph); + } + + instance->text.SetLength(0); + instance->spans.SetLength(0); + + Span span = {}; + instance->spans.Add(span); + + if (type == MD_BLOCK_UL) { + AddPadding(instance, PARAGRAPH_PADDING_BEFORE, PARAGRAPH_PADDING_AFTER); + instance->active = EsListDisplayCreate(instance->active, ES_CELL_H_FILL | ES_LIST_DISPLAY_BULLETED, ES_STYLE_LIST_DISPLAY_DEFAULT); + } else if (type == MD_BLOCK_OL) { + AddPadding(instance, PARAGRAPH_PADDING_BEFORE, PARAGRAPH_PADDING_AFTER); + EsListDisplay *display = EsListDisplayCreate(instance->active, ES_CELL_H_FILL | ES_LIST_DISPLAY_NUMBERED, ES_STYLE_LIST_DISPLAY_DEFAULT); + instance->active = display; + EsListDisplaySetCounterStart(display, ((MD_BLOCK_OL_DETAIL *) detail)->start - 1); + } else if (type == MD_BLOCK_QUOTE) { + AddPadding(instance, QUOTE_PADDING_BEFORE, QUOTE_PADDING_AFTER); + instance->active = EsPanelCreate(instance->active, ES_CELL_H_FILL, &styleQuote); + instance->inBlockQuote = true; + } else if (type == MD_BLOCK_LI) { + instance->active = EsPanelCreate(instance->active, ES_CELL_H_FILL, &styleList); + instance->inListDepth++; + } else if (type == MD_BLOCK_TABLE) { + AddPadding(instance, TABLE_PADDING_BEFORE, TABLE_PADDING_AFTER); + EsPanel *table = EsPanelCreate(instance->active, ES_PANEL_TABLE | ES_PANEL_HORIZONTAL | ES_CELL_H_SHRINK, &styleTable); + instance->active = table; + instance->tableColumnCount = 0; + } + + return 0; +} + +int ParserLeaveBlock(MD_BLOCKTYPE type, void *detail, void *_instance) { + Instance *instance = (Instance *) _instance; +#ifdef DEBUG_PARSER_OUTPUT + instance->debugNestDepth--; + ParserOutputPrintIndentation(instance); + EsPrint(">> Leave block %z\n", blockTypes[type]); +#endif + + if (type == MD_BLOCK_P) { + if (instance->text.Length()) { + if (type == MD_BLOCK_P) { + AddPadding(instance, PARAGRAPH_PADDING_BEFORE, PARAGRAPH_PADDING_AFTER); + } + + CreateStyledTextDisplay(instance, instance->inBlockQuote ? &styleQuoteParagraph : &styleParagraph); + } + } else if (type == MD_BLOCK_LI) { + if (instance->text.Length()) CreateStyledTextDisplay(instance, &styleParagraph); + instance->text.SetLength(0); + instance->spans.SetLength(0); + instance->active = EsElementGetLayoutParent(instance->active); + instance->inListDepth--; + } else if (type == MD_BLOCK_TD || type == MD_BLOCK_TH) { + if (type == MD_BLOCK_TH) instance->tableColumnCount++; + CreateStyledTextDisplay(instance, type == MD_BLOCK_TH ? &styleTH : &styleTD, ES_CELL_H_EXPAND | ES_CELL_V_EXPAND | ES_CELL_H_SHRINK | ES_CELL_V_SHRINK); + instance->text.SetLength(0); + instance->spans.SetLength(0); + } else if (type == MD_BLOCK_H) { + unsigned level = ((MD_BLOCK_H_DETAIL *) detail)->level; + + if (level == 1) AddPadding(instance, H1_PADDING_BEFORE, H1_PADDING_AFTER); + else if (level == 2) AddPadding(instance, H2_PADDING_BEFORE, H2_PADDING_AFTER); + else AddPadding(instance, H3_PADDING_BEFORE, H3_PADDING_AFTER); + + CreateStyledTextDisplay(instance, level == 1 ? &styleHeading1 : level == 2 ? &styleHeading2 : &styleHeading3); + + if (level <= 2) { + EsSpacerCreate(instance->active, ES_FLAGS_DEFAULT, nullptr, 0, HEADING_UNDERLINE_GAP); + EsSpacerCreate(instance->active, ES_CELL_H_FILL, &styleHeadingUnderline, 0, 0); + } + } else if (type == MD_BLOCK_CODE) { + MD_BLOCK_CODE_DETAIL *code = (MD_BLOCK_CODE_DETAIL *) detail; + AddPadding(instance, PARAGRAPH_PADDING_BEFORE, PARAGRAPH_PADDING_AFTER); + EsElement *wrapper = EsPanelCreate(instance->active, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL | ES_PANEL_H_SCROLL_AUTO, &styleCodeBlock); + EsTextDisplay *display = EsTextDisplayCreate(wrapper, ES_TEXT_DISPLAY_PREFORMATTED, &styleCode, instance->text.array, instance->text.Length()); + + if (0 == EsStringCompare(code->lang.text, code->lang.size, EsLiteral("ini"))) { + EsTextDisplaySetupSyntaxHighlighting(display, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI); + } else if (0 == EsStringCompare(code->lang.text, code->lang.size, EsLiteral("c")) + || 0 == EsStringCompare(code->lang.text, code->lang.size, EsLiteral("cpp")) + || 0 == EsStringCompare(code->lang.text, code->lang.size, EsLiteral("c++"))) { + EsTextDisplaySetupSyntaxHighlighting(display, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C); + } + } else if (type == MD_BLOCK_UL || type == MD_BLOCK_OL || type == MD_BLOCK_QUOTE) { + instance->active = EsElementGetLayoutParent(instance->active); + instance->inBlockQuote = false; + } else if (type == MD_BLOCK_HR) { + AddPadding(instance, HR_PADDING_BEFORE, HR_PADDING_AFTER); + EsSpacerCreate(instance->active, ES_CELL_H_FILL, &styleHorizontalRule, 0, 0); + } else if (type == MD_BLOCK_TABLE) { + EsPanel *panel = (EsPanel *) instance->active; + + EsPanelSetBands(panel, instance->tableColumnCount); + EsPanelTableSetChildCells(panel); + + EsPanelBand column = {}; + column.preferredSize = column.minimumSize = column.maximumSize = ES_PANEL_BAND_SIZE_DEFAULT; + column.pull = 1; // Shrink all columns with equal weight. + EsPanelSetBandsAll(panel, &column); + + instance->active = EsElementGetLayoutParent(instance->active); + } else { + // EsPrint("Unhandled block of type %z.\n", blockTypes[type]); + } + + return 0; +} + +int ParserEnterSpan(MD_SPANTYPE type, void *detail, void *_instance) { + Instance *instance = (Instance *) _instance; +#ifdef DEBUG_PARSER_OUTPUT + ParserOutputPrintIndentation(instance); + EsPrint(">> Enter span %z\n", spanTypes[type]); + instance->debugNestDepth++; +#endif + (void) detail; + + if (type == MD_SPAN_EM || type == MD_SPAN_STRONG || type == MD_SPAN_CODE || type == MD_SPAN_A) { + Span span = instance->spans.Last(); + if (type == MD_SPAN_EM) span.em = true; + if (type == MD_SPAN_STRONG) span.strong = true; + if (type == MD_SPAN_CODE) span.monospaced = true; + if (type == MD_SPAN_A) span.link = true; + span.offset = instance->text.Length(); + instance->spans.Add(span); + } + + return 0; +} + +int ParserLeaveSpan(MD_SPANTYPE type, void *detail, void *_instance) { + Instance *instance = (Instance *) _instance; +#ifdef DEBUG_PARSER_OUTPUT + instance->debugNestDepth--; + ParserOutputPrintIndentation(instance); + EsPrint(">> Leave span %z\n", spanTypes[type]); +#endif + (void) detail; + + if (type == MD_SPAN_EM || type == MD_SPAN_STRONG || type == MD_SPAN_CODE || type == MD_SPAN_A) { + Span span = instance->spans.Last(); + if (type == MD_SPAN_EM) span.em = false; + if (type == MD_SPAN_STRONG) span.strong = false; + if (type == MD_SPAN_CODE) span.monospaced = false; + if (type == MD_SPAN_A) span.link = false; + span.offset = instance->text.Length(); + instance->spans.Add(span); + } + + return 0; +} + +int ParserText(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *_instance) { + (void) type; + Instance *instance = (Instance *) _instance; +#ifdef DEBUG_PARSER_OUTPUT + ParserOutputPrintIndentation(instance); + EsPrint(">> Text %z, %x: %s\n", textTypes[type], text, size, text); +#endif + char *buffer = instance->text.InsertMany(instance->text.Length(), size); + EsMemoryCopy(buffer, text, size); + return 0; +} + +void ProcessApplicationMessage(EsMessage *message) { + if (message->type == ES_MSG_INSTANCE_CREATE) { + Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(MarkdownViewerTitle)); + EsInstanceSetClassViewer(instance, nullptr); + EsWindow *window = instance->window; + EsPanel *wrapper = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER); + EsPanel *background = EsPanelCreate(wrapper, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleBackground); + instance->root = EsPanelCreate(background, ES_CELL_H_SHRINK, &styleRoot); + EsWindowSetIcon(window, ES_ICON_TEXT_MARKDOWN); + } else if (message->type == ES_MSG_INSTANCE_OPEN) { + Instance *instance = message->instanceOpen.instance; + + if (message->instanceOpen.update) { + EsElementStartTransition(instance->root, ES_TRANSITION_ZOOM_IN); + } + + EsElementDestroyContents(instance->root); + + size_t fileSize; + char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize); + + if (!file || !EsUTF8IsValid(file, fileSize)) { + EsInstanceOpenComplete(message, false); + return; + } + + MD_PARSER parser = {}; + parser.flags = MD_DIALECT_GITHUB | MD_FLAG_NOHTML; + parser.enter_block = ParserEnterBlock; + parser.leave_block = ParserLeaveBlock; + parser.enter_span = ParserEnterSpan; + parser.leave_span = ParserLeaveSpan; + parser.text = ParserText; + instance->active = instance->root; + int result = md_parse(file, fileSize, &parser, instance); + if (result) EsElementDestroyContents(instance->root); // An error occurred. + EsInstanceOpenComplete(message, result == 0); + EsHeapFree(file); + + EsElementRelayout(instance->root); + instance->spans.Free(); + instance->text.Free(); + } +} + +void _start() { + _init(); + + while (true) { + ProcessApplicationMessage(EsMessageReceive()); + } +} diff --git a/apps/markdown_viewer.ini b/apps/markdown_viewer.ini new file mode 100644 index 0000000..8c25397 --- /dev/null +++ b/apps/markdown_viewer.ini @@ -0,0 +1,11 @@ +[general] +name=Markdown Viewer +icon=icon_text_markdown +use_single_process=1 + +[build] +source=apps/markdown_viewer.cpp + +[@handler] +extension=md +action=open diff --git a/apps/posix_launcher.cpp b/apps/posix_launcher.cpp new file mode 100644 index 0000000..a1c1d32 --- /dev/null +++ b/apps/posix_launcher.cpp @@ -0,0 +1,311 @@ +#include +#include + +#define _GNU_SOURCE +#include +#include +#include +#include + +#define MSG_RECEIVED_OUTPUT ((EsMessageType) (ES_MSG_USER_START + 1)) + +EsInstance *instance; +EsHandle commandEvent; +char outputBuffer[262144]; +uintptr_t outputBufferPosition; +EsMutex mutex; +volatile bool runningCommand; +int stdinWritePipe; +char *command; +EsTextbox *textboxOutput, *textboxInput; + +const EsStyle styleMonospacedTextbox = { + .inherit = ES_STYLE_TEXTBOX_NO_BORDER, + + .metrics = { + .mask = ES_THEME_METRICS_FONT_FAMILY | ES_THEME_METRICS_TEXT_SIZE, + .textSize = 12, + .fontFamily = ES_FONT_MONOSPACED, + }, +}; + +char *ParseArgument(char **position) { + char *start = *position; + + while (*start == ' ') { + start++; + } + + if (!(*start)) { + return nullptr; + } + + char *end = start; + + while ((*end != ' ' || (end != start && end[-1] == '\\')) && *end) { + end++; + } + + if (*end) { + *end = 0; + end++; + } + + *position = end; + return start; +} + +void WriteToOutputTextbox(const char *string, ptrdiff_t stringBytes) { + if (stringBytes == -1) { + stringBytes = EsCRTstrlen(string); + } + + bool done = false, postMessage = false; + + while (true) { + EsMutexAcquire(&mutex); + + if (outputBufferPosition + stringBytes <= sizeof(outputBuffer)) { + EsMemoryCopy(outputBuffer + outputBufferPosition, string, stringBytes); + postMessage = outputBufferPosition == 0; + outputBufferPosition += stringBytes; + done = true; + } + + EsMutexRelease(&mutex); + + if (!done) { + // The main thread is busy. Wait a little bit before trying again. + EsSleep(100); + } else { + break; + } + } + + if (postMessage) { + EsMessage m = {}; + m.type = MSG_RECEIVED_OUTPUT; + EsMessagePost(nullptr, &m); + } +} + +void RunCommandThread() { + char *argv[64]; + int argc = 0; + char executable[4096]; + int status; + int standardOutputPipe[2]; + int standardInputPipe[2]; + pid_t pid; + struct timespec startTime, endTime; + + char *envp[5] = { + (char *) "LANG=en_US.UTF-8", + (char *) "HOME=/", + (char *) "PATH=/Applications/POSIX/bin", + (char *) "TMPDIR=/Applications/POSIX/tmp", + nullptr + }; + + char *commandPosition = command; + + while (argc < 63) { + argv[argc] = ParseArgument(&commandPosition); + if (!argv[argc]) break; + argc++; + } + + if (!argc) { + goto done; + } + + argv[argc] = nullptr; + + if (0 == EsCRTstrcmp(argv[0], "run")) { + if (argc != 2) { + WriteToOutputTextbox("\nUsage: run \n", -1); + } else { + EsApplicationRunTemporary(instance, argv[1], EsCStringLength(argv[1])); + } + + WriteToOutputTextbox("\n----------------\n", -1); + goto done; + } else if (0 == EsCRTstrcmp(argv[0], "cd")) { + if (argc != 2) { + WriteToOutputTextbox("\nUsage: cd \n", -1); + } else { + chdir(argv[1]); + + WriteToOutputTextbox("\nNew working directory:\n", -1); + WriteToOutputTextbox(getcwd(nullptr, 0), -1); + WriteToOutputTextbox("\n", -1); + } + + WriteToOutputTextbox("\n----------------\n", -1); + goto done; + } + + if (argv[0][0] == '/') { + executable[EsStringFormat(executable, sizeof(executable) - 1, "%z", argv[0])] = 0; + } else { + executable[EsStringFormat(executable, sizeof(executable) - 1, "/Applications/POSIX/bin/%z", argv[0])] = 0; + } + + clock_gettime(CLOCK_MONOTONIC, &startTime); + + pipe(standardOutputPipe); + pipe(standardInputPipe); + + pid = vfork(); + + if (pid == 0) { + dup2(standardInputPipe[0], 0); + dup2(standardOutputPipe[1], 1); + dup2(standardOutputPipe[1], 2); + close(standardInputPipe[0]); + close(standardOutputPipe[1]); + execve(executable, argv, envp); + WriteToOutputTextbox("\nThe executable failed to load.\n", -1); + _exit(-1); + } else if (pid == -1) { + // TODO Report the error. + } + + close(standardInputPipe[0]); + close(standardOutputPipe[1]); + + EsMutexAcquire(&mutex); + stdinWritePipe = standardInputPipe[1]; + EsMutexRelease(&mutex); + + while (true) { + char buffer[1024]; + ssize_t bytesRead = read(standardOutputPipe[0], buffer, 1024); + + if (bytesRead <= 0) { + break; + } else { + WriteToOutputTextbox(buffer, bytesRead); + } + } + + EsMutexAcquire(&mutex); + stdinWritePipe = 0; + EsMutexRelease(&mutex); + + close(standardInputPipe[1]); + close(standardOutputPipe[0]); + + wait4(-1, &status, 0, NULL); + + clock_gettime(CLOCK_MONOTONIC, &endTime); + + { + double startTimeS = startTime.tv_sec + startTime.tv_nsec / 1000000000.0; + double endTimeS = endTime.tv_sec + endTime.tv_nsec / 1000000000.0; + char buffer[256]; + size_t bytes = EsStringFormat(buffer, sizeof(buffer), "\nProcess exited with status %d.\nExecution time: %Fs.\n", status >> 8, endTimeS - startTimeS); + WriteToOutputTextbox(buffer, bytes); + WriteToOutputTextbox("\n----------------\n", -1); + } + + done:; + EsHeapFree(command); + __sync_synchronize(); + runningCommand = false; +} + +int ProcessTextboxInputMessage(EsElement *, EsMessage *message) { + if (message->type == ES_MSG_KEY_DOWN) { + if (message->keyboard.scancode == ES_SCANCODE_ENTER + && !message->keyboard.modifiers + && EsTextboxGetLineLength(textboxInput)) { + char *data = EsTextboxGetContents(textboxInput); + + if (!runningCommand) { + runningCommand = true; + command = data; + + EsTextboxInsert(textboxOutput, "\n> ", -1, false); + EsTextboxInsert(textboxOutput, command, -1, false); + EsTextboxInsert(textboxOutput, "\n", -1, false); + EsTextboxEnsureCaretVisible(textboxOutput, false); + + EsEventSet(commandEvent); + } else { + EsTextboxInsert(textboxOutput, data, -1, false); + EsTextboxInsert(textboxOutput, "\n", -1, false); + EsMutexAcquire(&mutex); + + if (stdinWritePipe) { + write(stdinWritePipe, data, EsCStringLength(data)); + write(stdinWritePipe, "\n", 1); + } + + EsMutexRelease(&mutex); + EsHeapFree(data); + } + + EsTextboxClear(textboxInput, false); + return ES_HANDLED; + } + } + + return 0; +} + +void MessageLoopThread(EsGeneric) { + EsMessageMutexAcquire(); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + EsAssert(!instance); + instance = EsInstanceCreate(message, "POSIX Launcher"); + EsWindow *window = instance->window; + EsWindowSetIcon(window, ES_ICON_UTILITIES_TERMINAL); + EsPanel *panel = EsPanelCreate(window, ES_PANEL_VERTICAL | ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_BACKGROUND); + textboxOutput = EsTextboxCreate(panel, ES_TEXTBOX_MULTILINE | ES_CELL_FILL, &styleMonospacedTextbox); + EsSpacerCreate(panel, ES_CELL_H_FILL, ES_STYLE_SEPARATOR_HORIZONTAL); + textboxInput = EsTextboxCreate(panel, ES_CELL_H_FILL, &styleMonospacedTextbox); + textboxInput->messageUser = ProcessTextboxInputMessage; + EsElementFocus(textboxInput); + } else if (message->type == MSG_RECEIVED_OUTPUT) { + EsMutexAcquire(&mutex); + + if (outputBufferPosition) { + // EsPrint("Inserting %d bytes...\n", outputBufferPosition); + EsTextboxMoveCaretRelative(textboxOutput, ES_TEXTBOX_MOVE_CARET_ALL); + EsTextboxInsert(textboxOutput, outputBuffer, outputBufferPosition, false); + EsTextboxEnsureCaretVisible(textboxOutput, false); + outputBufferPosition = 0; + } + + EsMutexRelease(&mutex); + } + } +} + +int main(int argc, char **argv) { + (void) argc; + (void) argv; + + commandEvent = EsEventCreate(true); + EsMessageMutexRelease(); + EsThreadCreate(MessageLoopThread, nullptr, 0); + +#if 0 + runningCommand = true; + command = (char *) EsHeapAllocate(128, true); + EsStringFormat(command, 128, "gcc es/util/build_core.c -g"); + EsEventSet(commandEvent); +#endif + + while (true) { + EsWaitSingle(commandEvent); + RunCommandThread(); + } + + return 0; +} diff --git a/apps/posix_launcher.ini b/apps/posix_launcher.ini new file mode 100644 index 0000000..eee7e16 --- /dev/null +++ b/apps/posix_launcher.ini @@ -0,0 +1,9 @@ +[general] +name=POSIX Launcher +icon=icon_utilities_terminal +permission_posix_subsystem=1 +permission_run_temporary_application=1 + +[build] +source=apps/posix_launcher.cpp +link_flags=-Lroot/Applications/POSIX/lib -lc bin/crtglue.o bin/crt1.o diff --git a/apps/system_monitor.cpp b/apps/system_monitor.cpp new file mode 100644 index 0000000..088ba86 --- /dev/null +++ b/apps/system_monitor.cpp @@ -0,0 +1,497 @@ +#define ES_INSTANCE_TYPE Instance +#include + +#include +#define IMPLEMENTATION +#include +#undef IMPLEMENTATION + +// TODO Single instance. +// TODO Sorting lists. +// TODO Processes: handle/thread count; IO statistics; more memory information. + +struct Instance : EsInstance { + EsPanel *switcher; + EsTextbox *textboxGeneralLog; + EsListView *listViewProcesses; + EsListView *listViewPCIDevices; + EsPanel *panelMemoryStatistics; + int index; + EsCommand commandTerminateProcess; + Array textDisplaysMemory; +}; + +#define REFRESH_INTERVAL (1000) + +#define DISPLAY_PROCESSES (1) +#define DISPLAY_GENERAL_LOG (3) +#define DISPLAY_PCI_DEVICES (6) +#define DISPLAY_MEMORY (12) + +EsListViewColumn listViewProcessesColumns[] = { + { EsLiteral("Name"), 0, 150 }, + { EsLiteral("PID"), ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 150 }, + { EsLiteral("Memory"), ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 150 }, + { EsLiteral("CPU"), ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 150 }, + { EsLiteral("Handles"), ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 150 }, +}; + +EsListViewColumn listViewContextSwitchesColumns[] = { + { EsLiteral("Time stamp (ms)"), ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 150 }, + { EsLiteral("CPU"), ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 150 }, + { EsLiteral("Process"), 0, 150 }, + { EsLiteral("Thread"), 0, 150 }, + { EsLiteral("Count"), 0, 150 }, +}; + +EsListViewColumn listViewPCIDevicesColumns[] = { + { EsLiteral("Driver"), 0, 200 }, + { EsLiteral("Device ID"), 0, 200 }, + { EsLiteral("Class"), 0, 250 }, + { EsLiteral("Subclass"), 0, 250 }, + { EsLiteral("ProgIF"), 0, 150 }, + { EsLiteral("Bus"), 0, 100 }, + { EsLiteral("Slot"), 0, 100 }, + { EsLiteral("Function"), 0, 100 }, + { EsLiteral("Interrupt pin"), 0, 100 }, + { EsLiteral("Interrupt line"), 0, 100 }, + { EsLiteral("BAR0"), 0, 250 }, + { EsLiteral("BAR1"), 0, 250 }, + { EsLiteral("BAR2"), 0, 250 }, + { EsLiteral("BAR3"), 0, 250 }, + { EsLiteral("BAR4"), 0, 250 }, + { EsLiteral("BAR5"), 0, 250 }, +}; + +const EsStyle styleMonospacedTextbox = { + .inherit = ES_STYLE_TEXTBOX_NO_BORDER, + + .metrics = { + .mask = ES_THEME_METRICS_FONT_FAMILY, + .fontFamily = ES_FONT_MONOSPACED, + }, +}; + +const EsStyle stylePanelMemoryStatistics = { + .inherit = ES_STYLE_PANEL_FILLED, + + .metrics = { + .mask = ES_THEME_METRICS_GAP_ALL, + .gapMajor = 5, + .gapMinor = 5, + }, +}; + +const EsStyle stylePanelMemoryCommands = { + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_GAP_ALL, + .insets = ES_RECT_4(0, 0, 0, 5), + .gapMajor = 5, + .gapMinor = 5, + }, +}; + +const char *pciClassCodeStrings[] = { + "Unknown", + "Mass storage controller", + "Network controller", + "Display controller", + "Multimedia controller", + "Memory controller", + "Bridge controller", + "Simple communication controller", + "Base system peripheral", + "Input device controller", + "Docking station", + "Processor", + "Serial bus controller", + "Wireless controller", + "Intelligent controller", + "Satellite communication controller", + "Encryption controller", + "Signal processing controller", +}; + +const char *pciSubclassCodeStrings1[] = { + "SCSI bus controller", + "IDE controller", + "Floppy disk controller", + "IPI bus controller", + "RAID controller", + "ATA controller", + "Serial ATA", + "Serial attached SCSI", + "Non-volatile memory controller", +}; + +const char *pciSubclassCodeStrings12[] = { + "FireWire (IEEE 1394) controller", + "ACCESS bus", + "SSA", + "USB controller", + "Fibre channel", + "SMBus", + "InfiniBand", + "IPMI interface", + "SERCOS interface (IEC 61491)", + "CANbus", +}; + +const char *pciProgIFStrings12_3[] = { + "UHCI", + "OHCI", + "EHCI", + "XHCI", +}; + +struct ProcessItem { + EsSnapshotProcessesItem data; + uintptr_t cpuUsage; +}; + +char generalLogBuffer[256 * 1024]; +char contextSwitchesBuffer[2 * 1024 * 1024]; +EsPCIDevice pciDevices[1024]; +Array processes; +int64_t selectedPID = -2; + +ProcessItem *FindProcessByPID(Array snapshot, int64_t pid) { + for (uintptr_t i = 0; i < snapshot.Length(); i++) { + if (pid == snapshot[i].data.pid) { + return &snapshot[i]; + } + } + + return nullptr; +} + +void UpdateProcesses(Instance *instance) { + Array previous = processes; + processes = {}; + + size_t bufferSize; + EsHandle handle = EsTakeSystemSnapshot(ES_SYSTEM_SNAPSHOT_PROCESSES, &bufferSize); + EsSnapshotProcesses *snapshot = (EsSnapshotProcesses *) EsHeapAllocate(bufferSize, false); + EsConstantBufferRead(handle, snapshot); + EsHandleClose(handle); + + for (uintptr_t i = 0; i < snapshot->count; i++) { + ProcessItem item = {}; + item.data = snapshot->processes[i]; + processes.Add(item); + + if (snapshot->processes[i].isKernel) { + ProcessItem item = {}; + item.data.cpuTimeSlices = snapshot->processes[i].idleTimeSlices; + item.data.pid = -1; + const char *idle = "CPU idle"; + item.data.nameBytes = EsCStringLength(idle); + EsMemoryCopy(item.data.name, idle, item.data.nameBytes); + processes.Add(item); + } + } + + EsHeapFree(snapshot); + + for (uintptr_t i = 0; i < previous.Length(); i++) { + if (!FindProcessByPID(processes, previous[i].data.pid)) { + EsListViewRemove(instance->listViewProcesses, 0, i, i); + previous.Delete(i--); + } + } + + for (uintptr_t i = 0; i < processes.Length(); i++) { + processes[i].cpuUsage = processes[i].data.cpuTimeSlices; + ProcessItem *item = FindProcessByPID(previous, processes[i].data.pid); + if (item) processes[i].cpuUsage -= item->data.cpuTimeSlices; + } + + int64_t totalCPUTimeSlices = 0; + + for (uintptr_t i = 0; i < processes.Length(); i++) { + totalCPUTimeSlices += processes[i].cpuUsage; + } + + int64_t percentageSum = 0; + + for (uintptr_t i = 0; i < processes.Length(); i++) { + processes[i].cpuUsage = processes[i].cpuUsage * 100 / totalCPUTimeSlices; + percentageSum += processes[i].cpuUsage; + } + + while (percentageSum < 100 && percentageSum) { + for (uintptr_t i = 0; i < processes.Length(); i++) { + if (processes[i].cpuUsage && percentageSum < 100) { + processes[i].cpuUsage++, percentageSum++; + } + } + } + + for (uintptr_t i = 0; i < processes.Length(); i++) { + if (!FindProcessByPID(previous, processes[i].data.pid)) { + EsListViewInsert(instance->listViewProcesses, 0, i, i); + } + } + + EsListViewInvalidateAll(instance->listViewProcesses); + EsCommandSetDisabled(&instance->commandTerminateProcess, selectedPID < 0 || !FindProcessByPID(processes, selectedPID)); + + EsTimerSet(REFRESH_INTERVAL, [] (EsGeneric context) { + Instance *instance = (Instance *) context.p; + + if (instance->index == DISPLAY_PROCESSES) { + UpdateProcesses(instance); + } + }, instance); + + previous.Free(); +} + +void UpdateDisplay(Instance *instance, int index) { + instance->index = index; + + if (index != DISPLAY_PROCESSES) { + EsCommandSetDisabled(&instance->commandTerminateProcess, true); + } + + if (index == DISPLAY_PROCESSES) { + UpdateProcesses(instance); + EsPanelSwitchTo(instance->switcher, instance->listViewProcesses, ES_TRANSITION_NONE); + EsElementFocus(instance->listViewProcesses); + } else if (index == DISPLAY_GENERAL_LOG) { + size_t bytes = EsSyscall(ES_SYSCALL_DEBUG_COMMAND, index, (uintptr_t) generalLogBuffer, sizeof(generalLogBuffer), 0); + EsTextboxSelectAll(instance->textboxGeneralLog); + EsTextboxInsert(instance->textboxGeneralLog, generalLogBuffer, bytes); + EsTextboxEnsureCaretVisible(instance->textboxGeneralLog, false); + EsPanelSwitchTo(instance->switcher, instance->textboxGeneralLog, ES_TRANSITION_NONE); + } else if (index == DISPLAY_PCI_DEVICES) { + size_t count = EsSyscall(ES_SYSCALL_DEBUG_COMMAND, index, (uintptr_t) pciDevices, sizeof(pciDevices) / sizeof(pciDevices[0]), 0); + EsListViewRemoveAll(instance->listViewPCIDevices, 0); + EsListViewInsert(instance->listViewPCIDevices, 0, 0, count - 1); + EsPanelSwitchTo(instance->switcher, instance->listViewPCIDevices, ES_TRANSITION_NONE); + } else if (index == DISPLAY_MEMORY) { + EsMemoryStatistics statistics = {}; + EsSyscall(ES_SYSCALL_DEBUG_COMMAND, index, (uintptr_t) &statistics, 0, 0); + + EsPanelSwitchTo(instance->switcher, instance->panelMemoryStatistics, ES_TRANSITION_NONE); + + if (!instance->textDisplaysMemory.Length()) { + EsPanel *panel = EsPanelCreate(instance->panelMemoryStatistics, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &stylePanelMemoryCommands); + EsButton *button; + + button = EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, EsLiteral("Leak 1 MB")); + EsButtonOnCommand(button, [] (Instance *, EsElement *, EsCommand *) { EsMemoryReserve(0x100000); }); + button = EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, EsLiteral("Leak 4 MB")); + EsButtonOnCommand(button, [] (Instance *, EsElement *, EsCommand *) { EsMemoryReserve(0x400000); }); + button = EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, EsLiteral("Leak 16 MB")); + EsButtonOnCommand(button, [] (Instance *, EsElement *, EsCommand *) { EsMemoryReserve(0x1000000); }); + button = EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, EsLiteral("Leak 64 MB")); + EsButtonOnCommand(button, [] (Instance *, EsElement *, EsCommand *) { EsMemoryReserve(0x4000000); }); + button = EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, EsLiteral("Leak 256 MB")); + EsButtonOnCommand(button, [] (Instance *, EsElement *, EsCommand *) { EsMemoryReserve(0x10000000); }); + + EsSpacerCreate(instance->panelMemoryStatistics, ES_CELL_H_FILL); + } + + char buffer[256]; + size_t bytes; + uintptr_t index = 0; +#define ADD_MEMORY_STATISTIC_DISPLAY(label, ...) \ + bytes = EsStringFormat(buffer, sizeof(buffer), __VA_ARGS__); \ + if (instance->textDisplaysMemory.Length() == index) { \ + EsTextDisplayCreate(instance->panelMemoryStatistics, ES_CELL_H_PUSH | ES_CELL_H_RIGHT, 0, EsLiteral(label)); \ + instance->textDisplaysMemory.Add(EsTextDisplayCreate(instance->panelMemoryStatistics, ES_CELL_H_PUSH | ES_CELL_H_LEFT)); \ + } \ + EsTextDisplaySetContents(instance->textDisplaysMemory[index++], buffer, bytes) + + ADD_MEMORY_STATISTIC_DISPLAY("Fixed heap allocation count:", "%d", statistics.fixedHeapAllocationCount); + ADD_MEMORY_STATISTIC_DISPLAY("Fixed heap graphics surfaces:", "%D (%d B)", + statistics.totalSurfaceBytes, statistics.totalSurfaceBytes); + ADD_MEMORY_STATISTIC_DISPLAY("Fixed heap normal size:", "%D (%d B)", + statistics.fixedHeapTotalSize - statistics.totalSurfaceBytes, statistics.fixedHeapTotalSize - statistics.totalSurfaceBytes); + ADD_MEMORY_STATISTIC_DISPLAY("Fixed heap total size:", "%D (%d B)", + statistics.fixedHeapTotalSize, statistics.fixedHeapTotalSize); + ADD_MEMORY_STATISTIC_DISPLAY("Core heap allocation count:", "%d", statistics.coreHeapAllocationCount); + ADD_MEMORY_STATISTIC_DISPLAY("Core heap total size:", "%D (%d B)", statistics.coreHeapTotalSize, statistics.coreHeapTotalSize); + ADD_MEMORY_STATISTIC_DISPLAY("Cached boot FS nodes:", "%d", statistics.cachedNodes); + ADD_MEMORY_STATISTIC_DISPLAY("Cached boot FS directory entries:", "%d", statistics.cachedDirectoryEntries); + ADD_MEMORY_STATISTIC_DISPLAY("Maximum object cache size:", "%D (%d pages)", statistics.maximumObjectCachePages * ES_PAGE_SIZE, + statistics.maximumObjectCachePages); + ADD_MEMORY_STATISTIC_DISPLAY("Approximate object cache size:", "%D (%d pages)", statistics.approximateObjectCacheSize, + statistics.approximateObjectCacheSize / ES_PAGE_SIZE); + ADD_MEMORY_STATISTIC_DISPLAY("Commit (pageable):", "%D (%d pages)", statistics.commitPageable * ES_PAGE_SIZE, statistics.commitPageable); + ADD_MEMORY_STATISTIC_DISPLAY("Commit (fixed):", "%D (%d pages)", statistics.commitFixed * ES_PAGE_SIZE, statistics.commitFixed); + ADD_MEMORY_STATISTIC_DISPLAY("Commit (total):", "%D (%d pages)", (statistics.commitPageable + statistics.commitFixed) * ES_PAGE_SIZE, + statistics.commitPageable + statistics.commitFixed); + ADD_MEMORY_STATISTIC_DISPLAY("Commit limit:", "%D (%d pages)", statistics.commitLimit * ES_PAGE_SIZE, statistics.commitLimit); + ADD_MEMORY_STATISTIC_DISPLAY("Commit fixed limit:", "%D (%d pages)", statistics.commitFixedLimit * ES_PAGE_SIZE, statistics.commitFixedLimit); + ADD_MEMORY_STATISTIC_DISPLAY("Commit remaining:", "%D (%d pages)", statistics.commitRemaining * ES_PAGE_SIZE, statistics.commitRemaining); + + EsTimerSet(REFRESH_INTERVAL, [] (EsGeneric context) { + Instance *instance = (Instance *) context.p; + + if (instance->index == DISPLAY_MEMORY) { + UpdateDisplay(instance, DISPLAY_MEMORY); + } + }, instance); + } +} + +#define GET_CONTENT(...) EsBufferFormat(message->getContent.buffer, __VA_ARGS__) + +int ListViewProcessesCallback(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) { + int column = message->getContent.column, index = message->getContent.index.i; + ProcessItem *item = &processes[index]; + if (column == 0) GET_CONTENT("%s", item->data.nameBytes, item->data.name); + else if (column == 1) { if (item->data.pid == -1) GET_CONTENT("n/a"); else GET_CONTENT("%d", item->data.pid); } + else if (column == 2) GET_CONTENT("%D", item->data.memoryUsage); + else if (column == 3) GET_CONTENT("%d%%", item->cpuUsage); + else if (column == 4) GET_CONTENT("%d", item->data.handleCount); + else EsAssert(false); + } else if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED) { + message->selectItem.isSelected = processes[message->selectItem.index.u].data.pid == selectedPID; + } else if (message->type == ES_MSG_LIST_VIEW_SELECT && message->selectItem.isSelected) { + selectedPID = processes[message->selectItem.index.u].data.pid; + EsCommandSetDisabled(&element->instance->commandTerminateProcess, selectedPID < 0 || !FindProcessByPID(processes, selectedPID)); + } else { + return 0; + } + + return ES_HANDLED; +} + +int ListViewPCIDevicesCallback(EsElement *, EsMessage *message) { + if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) { + int column = message->getContent.column, index = message->getContent.index.i; + + EsPCIDevice *entry = pciDevices + index; + + if (column == 0) { + GET_CONTENT("%s", entry->driverNameBytes, entry->driverName); + } else if (column == 1) { + GET_CONTENT("%x", entry->deviceID); + } else if (column == 2) { + const char *string = entry->classCode < sizeof(pciClassCodeStrings) / sizeof(pciClassCodeStrings[0]) + ? pciClassCodeStrings[entry->classCode] : "Unknown"; + GET_CONTENT("%d - %z", entry->classCode, string); + } else if (column == 3) { + const char *string = + entry->classCode == 1 && entry->subclassCode < sizeof(pciSubclassCodeStrings1) / sizeof(const char *) + ? pciSubclassCodeStrings1 [entry->subclassCode] + : entry->classCode == 12 && entry->subclassCode < sizeof(pciSubclassCodeStrings12) / sizeof(const char *) + ? pciSubclassCodeStrings12[entry->subclassCode] : ""; + GET_CONTENT("%d%z%z", entry->subclassCode, *string ? " - " : "", string); + } else if (column == 4) { + const char *string = + entry->classCode == 12 && entry->subclassCode == 3 && entry->progIF / 0x10 < sizeof(pciProgIFStrings12_3) / sizeof(const char *) + ? pciProgIFStrings12_3[entry->progIF / 0x10] : ""; + GET_CONTENT("%d%z%z", entry->progIF, *string ? " - " : "", string); + } else if (column == 5) { + GET_CONTENT("%d", entry->bus); + } else if (column == 6) { + GET_CONTENT("%d", entry->slot); + } else if (column == 7) { + GET_CONTENT("%d", entry->function); + } else if (column == 8) { + GET_CONTENT("%d", entry->interruptPin); + } else if (column == 9) { + GET_CONTENT("%d", entry->interruptLine); + } else if (column == 10) { + GET_CONTENT("%x, %D", entry->baseAddresses[0], entry->baseAddressesSizes[0]); + } else if (column == 11) { + GET_CONTENT("%x, %D", entry->baseAddresses[1], entry->baseAddressesSizes[1]); + } else if (column == 12) { + GET_CONTENT("%x, %D", entry->baseAddresses[2], entry->baseAddressesSizes[2]); + } else if (column == 13) { + GET_CONTENT("%x, %D", entry->baseAddresses[3], entry->baseAddressesSizes[3]); + } else if (column == 14) { + GET_CONTENT("%x, %D", entry->baseAddresses[4], entry->baseAddressesSizes[4]); + } else if (column == 15) { + GET_CONTENT("%x, %D", entry->baseAddresses[5], entry->baseAddressesSizes[5]); + } else { + EsAssert(false); + } + + return ES_HANDLED; + } + + return 0; +} + +void AddTab(EsElement *toolbar, uintptr_t index, const char *label, bool asDefault = false) { + EsButton *button = EsButtonCreate(toolbar, ES_BUTTON_RADIOBOX, 0, label); + button->userData.u = index; + + EsButtonOnCommand(button, [] (Instance *instance, EsElement *element, EsCommand *) { + if (EsButtonGetCheck((EsButton *) element) == ES_CHECK_CHECKED) { + UpdateDisplay(instance, element->userData.u); + } + }); + + if (asDefault) EsButtonSetCheck(button, ES_CHECK_CHECKED); +} + +void AddListView(EsListView **pointer, EsElement *switcher, EsUICallbackFunction callback, EsListViewColumn *columns, size_t columnsSize, uint64_t additionalFlags) { + *pointer = EsListViewCreate(switcher, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | additionalFlags); + (*pointer)->messageUser = callback; + EsListViewSetColumns(*pointer, columns, columnsSize / sizeof(EsListViewColumn)); + EsListViewInsertGroup(*pointer, 0); +} + +void TerminateProcess(Instance *instance, EsElement *, EsCommand *) { + if (selectedPID == 0 /* Kernel */) { + // Terminating the kernel process is a meaningless action; the closest equivalent is shutting down. + EsSystemShowShutdownDialog(instance); + return; + } + + EsHandle handle = EsProcessOpen(selectedPID); + + if (handle) { + EsProcessTerminate(handle, 1); + } else { + EsRectangle bounds = EsElementGetWindowBounds(instance->listViewProcesses); + EsAnnouncementShow(instance->window, ES_FLAGS_DEFAULT, (bounds.l + bounds.r) / 2, (bounds.t + bounds.b) / 2, EsLiteral("Could not terminate process")); + } +} + +void ProcessApplicationMessage(EsMessage *message) { + if (message->type == ES_MSG_INSTANCE_CREATE) { + Instance *instance = EsInstanceCreate(message, "System Monitor"); + + EsCommandRegister(&instance->commandTerminateProcess, instance, TerminateProcess, 1, "Del", false); + + EsWindow *window = instance->window; + EsWindowSetIcon(window, ES_ICON_UTILITIES_SYSTEM_MONITOR); + EsPanel *switcher = EsPanelCreate(window, ES_CELL_FILL | ES_PANEL_SWITCHER, ES_STYLE_PANEL_WINDOW_DIVIDER); + instance->switcher = switcher; + + instance->textboxGeneralLog = EsTextboxCreate(switcher, ES_TEXTBOX_MULTILINE | ES_CELL_FILL, &styleMonospacedTextbox); + + AddListView(&instance->listViewProcesses, switcher, ListViewProcessesCallback, + listViewProcessesColumns, sizeof(listViewProcessesColumns), ES_LIST_VIEW_SINGLE_SELECT); + AddListView(&instance->listViewPCIDevices, switcher, ListViewPCIDevicesCallback, + listViewPCIDevicesColumns, sizeof(listViewPCIDevicesColumns), ES_FLAGS_DEFAULT); + + instance->panelMemoryStatistics = EsPanelCreate(switcher, + ES_CELL_FILL | ES_PANEL_TABLE | ES_PANEL_HORIZONTAL | ES_PANEL_V_SCROLL_AUTO, &stylePanelMemoryStatistics); + EsPanelSetBands(instance->panelMemoryStatistics, 2 /* columns */); + + EsElement *toolbar = EsWindowGetToolbar(window); + AddTab(toolbar, DISPLAY_PROCESSES, "Processes", true); + AddTab(toolbar, DISPLAY_GENERAL_LOG, "System log"); + AddTab(toolbar, DISPLAY_PCI_DEVICES, "PCI devices"); + AddTab(toolbar, DISPLAY_MEMORY, "Memory"); + } else if (message->type == ES_MSG_INSTANCE_DESTROY) { + processes.Free(); + } +} + +void _start() { + _init(); + + while (true) { + ProcessApplicationMessage(EsMessageReceive()); + } +} diff --git a/apps/system_monitor.ini b/apps/system_monitor.ini new file mode 100644 index 0000000..78a0691 --- /dev/null +++ b/apps/system_monitor.ini @@ -0,0 +1,8 @@ +[general] +name=System Monitor +icon=icon_utilities_system_monitor +permission_manage_processes=1 +permission_shutdown=1 + +[build] +source=apps/system_monitor.cpp diff --git a/apps/test.cpp b/apps/test.cpp new file mode 100644 index 0000000..f82a20d --- /dev/null +++ b/apps/test.cpp @@ -0,0 +1,180 @@ +#include +#include +// #include + +EsTextbox *textbox; + +#if 0 + +char *master; +char **undo; + +void OffsetToLineAndByte(uintptr_t offset, int32_t *_line, int32_t *_byte) { + int32_t line = 0, byte = 0; + + for (uintptr_t i = 0; i < offset; i++) { + if (master[i] == '\n') { + line++; + byte = 0; + } else { + byte++; + } + } + + *_line = line; + *_byte = byte; +} + +void Compare() { + size_t bytes; + char *contents = EsTextboxGetContents(textbox, &bytes); + // EsPrint("\tContents: '%e'\n\tMaster: '%e'\n", bytes, contents, arrlenu(master), master); + EsAssert(bytes == arrlenu(master)); + EsAssert(0 == EsMemoryCompare(master, contents, bytes)); + EsHeapFree(contents); +} + +void FakeUndoItem(const void *, EsUndoManager *manager, EsMessage *message) { + if (message->type == ES_MSG_UNDO_INVOKE) { + EsUndoPush(manager, FakeUndoItem, nullptr, 0); + } +} + +void AddUndoItem() { + char *copy = nullptr; + arrsetlen(copy, arrlenu(master)); + EsMemoryCopy(copy, master, arrlenu(copy)); + arrput(undo, copy); +} + +void Complete() { + EsUndoPush(textbox->instance->undoManager, FakeUndoItem, nullptr, 0); + EsUndoEndGroup(textbox->instance->undoManager); +} + +void Insert(uintptr_t offset, const char *string, size_t stringBytes) { + if (!stringBytes) return; + AddUndoItem(); + // EsPrint("Insert '%e' at %d.\n", stringBytes, string, offset); + int32_t line, byte; + OffsetToLineAndByte(offset, &line, &byte); + EsTextboxSetSelection(textbox, line, byte, line, byte); + EsTextboxInsert(textbox, string, stringBytes); + arrinsn(master, offset, stringBytes); + EsMemoryCopy(master + offset, string, stringBytes); + Compare(); + Complete(); +} + +void Delete(uintptr_t from, uintptr_t to) { + if (from == to) return; + AddUndoItem(); + // EsPrint("Delete from %d to %d.\n", from, to); + int32_t fromLine, fromByte, toLine, toByte; + OffsetToLineAndByte(from, &fromLine, &fromByte); + OffsetToLineAndByte(to, &toLine, &toByte); + EsTextboxSetSelection(textbox, fromLine, fromByte, toLine, toByte); + EsTextboxInsert(textbox, 0, 0); + if (to > from) arrdeln(master, from, to - from); + else arrdeln(master, to, from - to); + Compare(); + Complete(); +} + +void Test() { + EsRandomSeed(10); + EsTextboxSetUndoManager(textbox, textbox->instance->undoManager); + + while (true) { + uint8_t action = EsRandomU8(); + + if (action < 0x70) { + size_t stringBytes = EsRandomU8() & 0x1F; + char string[0x20]; + + for (uintptr_t i = 0; i < stringBytes; i++) { + string[i] = EsRandomU8() < 0x40 ? '\n' : ((EsRandomU8() % 26) + 'a'); + } + + Insert(EsRandomU64() % (arrlenu(master) + 1), string, stringBytes); + } else if (action < 0xE0) { + if (arrlenu(master)) { + Delete(EsRandomU64() % arrlenu(master), EsRandomU64() % arrlenu(master)); + } + } else { + if (!EsUndoIsEmpty(textbox->instance->undoManager, false)) { + // EsPrint("Undo.\n"); + EsUndoInvokeGroup(textbox->instance->undoManager, false); + arrfree(master); + master = arrlast(undo); + arrpop(undo); + Compare(); + } + } + } +} + +#endif + +const EsStyle stylePanel = { + .inherit = ES_STYLE_PANEL_WINDOW_BACKGROUND, + + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_GAP_MAJOR, + .insets = ES_RECT_1(20), + .gapMajor = 1, + }, +}; + +int TestCanvasMessage(EsElement *, EsMessage *message) { + if (message->type == ES_MSG_PAINT) { + size_t dataBytes; + const void *data = EsEmbeddedFileGet("test", &dataBytes); + if (data) EsDrawVectorFile(message->painter, EsPainterBoundsClient(message->painter), data, dataBytes); + } else if (message->type == ES_MSG_GET_WIDTH) { + message->measure.width = 256; + } else if (message->type == ES_MSG_GET_HEIGHT) { + message->measure.height = 256; + } + + return 0; +} + +void InitialiseInstance(EsInstance *instance) { + // EsPanel *panel = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER); + // textbox = EsTextboxCreate(panel, ES_CELL_FILL | ES_TEXTBOX_ALLOW_TABS | ES_TEXTBOX_MULTILINE, ES_STYLE_TEXTBOX_NO_BORDER); + // Test(); + + EsPanel *panel = EsPanelCreate(instance->window, ES_CELL_FILL, &stylePanel); + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Crash"), [] (EsInstance *, EsElement *, EsCommand *) { EsAssert(false); }); + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Hang"), [] (EsInstance *, EsElement *, EsCommand *) { while (true); }); + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(8000); }); + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait, then crash"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(8000); EsAssert(false); }); + + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Announcement 1"), [] (EsInstance *, EsElement *element, EsCommand *) { + EsRectangle bounds = EsElementGetWindowBounds(element); + EsAnnouncementShow(element->window, ES_FLAGS_DEFAULT, (bounds.l + bounds.r) / 2, (bounds.t + bounds.b) / 2, "Hello, world!", -1); + }); + + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Announcement 2"), [] (EsInstance *, EsElement *element, EsCommand *) { + EsRectangle bounds = EsElementGetWindowBounds(element); + EsAnnouncementShow(element->window, ES_FLAGS_DEFAULT, (bounds.l + bounds.r) / 2, (bounds.t + bounds.b) / 2, INTERFACE_STRING(DesktopApplicationStartupError)); + }); + + EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Push"); + EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Push"); + EsTextboxUseNumberOverlay(EsTextboxCreate(panel, ES_TEXTBOX_EDIT_BASED), true); + EsCustomElementCreate(panel)->messageUser = TestCanvasMessage; +} + +void _start() { + _init(); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + InitialiseInstance(EsInstanceCreate(message, "Test App")); + } + } +} diff --git a/apps/test.ini b/apps/test.ini new file mode 100644 index 0000000..cb68016 --- /dev/null +++ b/apps/test.ini @@ -0,0 +1,8 @@ +[general] +name=Test +icon=icon_system_software_install +use_single_process=1 + +[build] +source=apps/test.cpp +link_flags=-Lroot/Applications/POSIX/lib -lc diff --git a/apps/text_editor.cpp b/apps/text_editor.cpp new file mode 100644 index 0000000..fa6dc69 --- /dev/null +++ b/apps/text_editor.cpp @@ -0,0 +1,334 @@ +#define ES_INSTANCE_TYPE Instance +#include + +#include + +// TODO Document save/load model, then merge into API. +// TODO Replace toolbar, then merge into API. +// TODO Merge Format menu into API. +// TODO Word wrap (textbox feature). + +// TODO Possible extension features: +// - Block selection +// - Folding +// - Tab settings and auto-indent +// - Macros +// - Status bar +// - Goto line +// - Find in files +// - Convert case +// - Sort lines +// - Trim trailing space +// - Indent/comment/join/split shortcuts + +const EsStyle styleFormatPopupColumn = { + .metrics = { + .mask = ES_THEME_METRICS_GAP_MAJOR, + .gapMajor = 5, + }, +}; + +const EsInstanceClassEditorSettings editorSettings = { + INTERFACE_STRING(TextEditorNewFileName), + INTERFACE_STRING(TextEditorNewDocument), + ES_ICON_TEXT, +}; + +struct Instance : EsInstance { + EsTextbox *textboxDocument, + *textboxSearch; + + EsElement *toolbarMain, *toolbarSearch; + + EsTextDisplay *displaySearch; + + EsButton *buttonFormat; + + EsCommand commandFindNext, + commandFindPrevious, + commandFind, + commandFormat; + + uint32_t syntaxHighlightingLanguage; +}; + +void Find(Instance *instance, bool backwards) { + EsWindowSwitchToolbar(instance->window, instance->toolbarSearch, ES_TRANSITION_SLIDE_UP); + + size_t needleBytes; + char *needle = EsTextboxGetContents(instance->textboxSearch, &needleBytes); + + int32_t line0, byte0, line1, byte1; + EsTextboxGetSelection(instance->textboxDocument, &line0, &byte0, &line1, &byte1); + + if (backwards) { + if (line1 < line0) { + line0 = line1; + byte0 = byte1; + } else if (line1 == line0 && byte1 < byte0) { + byte0 = byte1; + } + } else { + if (line1 > line0) { + line0 = line1; + byte0 = byte1; + } else if (line1 == line0 && byte1 > byte0) { + byte0 = byte1; + } + } + + bool found = EsTextboxFind(instance->textboxDocument, needle, needleBytes, &line0, &byte0, backwards ? ES_TEXTBOX_FIND_BACKWARDS : ES_FLAGS_DEFAULT); + + if (found) { + EsTextDisplaySetContents(instance->displaySearch, ""); + EsTextboxSetSelection(instance->textboxDocument, line0, byte0, line0, byte0 + needleBytes); + EsTextboxEnsureCaretVisible(instance->textboxDocument, true); + EsElementFocus(instance->textboxDocument); + } else if (!needleBytes) { + EsTextDisplaySetContents(instance->displaySearch, INTERFACE_STRING(CommonSearchPrompt2)); + EsElementFocus(instance->textboxSearch); + } else { + EsTextDisplaySetContents(instance->displaySearch, INTERFACE_STRING(CommonSearchNoMatches)); + EsElementFocus(instance->textboxSearch); + } + + EsHeapFree(needle); +} + +void SetLanguage(Instance *instance, uint32_t newLanguage) { + EsTextStyle textStyle = {}; + EsTextboxGetTextStyle(instance->textboxDocument, &textStyle); + textStyle.font.family = newLanguage ? ES_FONT_MONOSPACED : ES_FONT_SANS; + EsTextboxSetTextStyle(instance->textboxDocument, &textStyle); + + instance->syntaxHighlightingLanguage = newLanguage; + EsTextboxSetupSyntaxHighlighting(instance->textboxDocument, newLanguage); +} + +void FormatPopupCreate(Instance *instance) { + EsMenu *menu = EsMenuCreate(instance->buttonFormat, ES_FLAGS_DEFAULT); + EsPanel *panel = EsPanelCreate(menu, ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_POPUP); + + { + EsPanel *column = EsPanelCreate(panel, ES_FLAGS_DEFAULT, &styleFormatPopupColumn); + EsTextDisplayCreate(column, ES_CELL_H_EXPAND, ES_STYLE_TEXT_LABEL, INTERFACE_STRING(CommonFormatSize)); + EsListView *list = EsListViewCreate(column, ES_LIST_VIEW_CHOICE_SELECT | ES_LIST_VIEW_FIXED_ITEMS, ES_STYLE_LIST_CHOICE_BORDERED); + + const int presetSizes[] = { + 8, 9, 10, 11, 12, 13, + 14, 16, + 18, 24, 30, + 36, 48, 60, + 72, 96, 120, 144, + }; + + for (uintptr_t i = 0; i < sizeof(presetSizes) / sizeof(presetSizes[0]); i++) { + char buffer[64]; + EsListViewInsertFixedItem(list, buffer, EsStringFormat(buffer, sizeof(buffer), "%d pt", presetSizes[i]), presetSizes[i]); + } + + EsTextStyle textStyle = {}; + EsTextboxGetTextStyle(instance->textboxDocument, &textStyle); + EsListViewSelectFixedItem(list, textStyle.size); + + list->messageUser = [] (EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_LIST_VIEW_SELECT) { + Instance *instance = element->instance; + EsGeneric newSize; + + if (EsListViewGetSelectedFixedItem(((EsListView *) element), &newSize)) { + EsTextStyle textStyle = {}; + EsTextboxGetTextStyle(instance->textboxDocument, &textStyle); + textStyle.size = newSize.u; + EsTextboxSetTextStyle(instance->textboxDocument, &textStyle); + } + } + + return 0; + }; + } + + { + EsPanel *column = EsPanelCreate(panel, ES_FLAGS_DEFAULT, &styleFormatPopupColumn); + EsTextDisplayCreate(column, ES_CELL_H_EXPAND, ES_STYLE_TEXT_LABEL, INTERFACE_STRING(CommonFormatLanguage)); + EsListView *list = EsListViewCreate(column, ES_LIST_VIEW_CHOICE_SELECT | ES_LIST_VIEW_FIXED_ITEMS, ES_STYLE_LIST_CHOICE_BORDERED); + EsListViewInsertFixedItem(list, INTERFACE_STRING(CommonFormatPlainText), 0); + EsListViewInsertFixedItem(list, "C/C++", -1, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C); + EsListViewInsertFixedItem(list, "Ini file", -1, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI); + EsListViewSelectFixedItem(list, instance->syntaxHighlightingLanguage); + + list->messageUser = [] (EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_LIST_VIEW_SELECT) { + Instance *instance = element->instance; + EsGeneric newLanguage; + + if (EsListViewGetSelectedFixedItem(((EsListView *) element), &newLanguage)) { + SetLanguage(instance, newLanguage.u); + } + } + + return 0; + }; + } + + EsMenuShow(menu); +} + +void ProcessApplicationMessage(EsMessage *message) { + if (message->type == ES_MSG_INSTANCE_CREATE) { + Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(TextEditorTitle)); + EsInstanceSetClassEditor(instance, &editorSettings); + + EsWindow *window = instance->window; + EsWindowSetIcon(window, ES_ICON_ACCESSORIES_TEXT_EDITOR); + EsButton *button; + + // Commands: + + uint32_t stableID = 1; + + EsCommandRegister(&instance->commandFindNext, instance, [] (Instance *instance, EsElement *, EsCommand *) { + Find(instance, false); + }, stableID++, "F3"); + + EsCommandRegister(&instance->commandFindPrevious, instance, [] (Instance *instance, EsElement *, EsCommand *) { + Find(instance, true); + }, stableID++, "Shift+F3"); + + EsCommandRegister(&instance->commandFind, instance, [] (Instance *instance, EsElement *, EsCommand *) { + EsWindowSwitchToolbar(instance->window, instance->toolbarSearch, ES_TRANSITION_ZOOM_OUT); + EsElementFocus(instance->textboxSearch); + }, stableID++, "Ctrl+F"); + + EsCommandRegister(&instance->commandFormat, instance, [] (Instance *instance, EsElement *, EsCommand *) { + FormatPopupCreate(instance); + }, stableID++, "Ctrl+Alt+T"); + + EsCommandSetDisabled(&instance->commandFindNext, false); + EsCommandSetDisabled(&instance->commandFindPrevious, false); + EsCommandSetDisabled(&instance->commandFind, false); + EsCommandSetDisabled(&instance->commandFormat, false); + + // Content: + + EsPanel *panel = EsPanelCreate(window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER); + instance->textboxDocument = EsTextboxCreate(panel, + ES_CELL_FILL | ES_TEXTBOX_MULTILINE | ES_TEXTBOX_ALLOW_TABS | ES_TEXTBOX_MARGIN, + ES_STYLE_TEXTBOX_NO_BORDER); + instance->textboxDocument->cName = "document"; + EsTextboxSetUndoManager(instance->textboxDocument, instance->undoManager); + EsElementFocus(instance->textboxDocument); + + // Main toolbar: + + EsElement *toolbarMain = instance->toolbarMain = EsWindowGetToolbar(window, true); + + EsToolbarAddFileMenu(toolbarMain); + + button = EsButtonCreate(toolbarMain, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchOpen)); + button->accessKey = 'S'; + EsButtonSetIcon(button, ES_ICON_EDIT_FIND_SYMBOLIC); + + EsButtonOnCommand(button, [] (Instance *instance, EsElement *, EsCommand *) { + EsWindowSwitchToolbar(instance->window, instance->toolbarSearch, ES_TRANSITION_SLIDE_UP); + EsElementFocus(instance->textboxSearch); + }); + + button = EsButtonCreate(toolbarMain, ES_BUTTON_DROPDOWN, {}, INTERFACE_STRING(CommonFormatPopup)); + button->accessKey = 'M'; + EsButtonSetIcon(button, ES_ICON_FORMAT_TEXT_LARGER_SYMBOLIC); + EsCommandAddButton(&instance->commandFormat, button); + instance->buttonFormat = button; + + EsWindowSwitchToolbar(window, toolbarMain, ES_TRANSITION_NONE); + + // Search toolbar: + + EsElement *toolbarSearch = instance->toolbarSearch = EsWindowGetToolbar(window, true); + + button = EsButtonCreate(toolbarSearch, ES_FLAGS_DEFAULT, 0); + button->cName = "go back", button->accessKey = 'X'; + EsButtonSetIcon(button, ES_ICON_GO_FIRST_SYMBOLIC); + + EsButtonOnCommand(button, [] (Instance *instance, EsElement *, EsCommand *) { + EsWindowSwitchToolbar(instance->window, instance->toolbarMain, ES_TRANSITION_SLIDE_DOWN); + }); + + EsPanel *section = EsPanelCreate(toolbarSearch, ES_PANEL_HORIZONTAL); + EsTextDisplayCreate(section, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(CommonSearchPrompt)); + + instance->textboxSearch = EsTextboxCreate(section, ES_FLAGS_DEFAULT, {}); + instance->textboxSearch->cName = "search textbox"; + instance->textboxSearch->accessKey = 'S'; + + instance->textboxSearch->messageUser = [] (EsElement *element, EsMessage *message) { + Instance *instance = element->instance; + + if (message->type == ES_MSG_KEY_DOWN && message->keyboard.scancode == ES_SCANCODE_ENTER) { + EsCommand *command = (message->keyboard.modifiers & ES_MODIFIER_SHIFT) ? &instance->commandFindPrevious : &instance->commandFindNext; + command->callback(instance, element, command); + return ES_HANDLED; + } else if (message->type == ES_MSG_KEY_DOWN && message->keyboard.scancode == ES_SCANCODE_ESCAPE) { + EsWindowSwitchToolbar(instance->window, instance->toolbarMain, ES_TRANSITION_SLIDE_DOWN); + EsElementFocus(instance->textboxDocument); + return ES_HANDLED; + } else if (message->type == ES_MSG_FOCUSED_START) { + EsTextboxSelectAll(instance->textboxSearch); + } + + return 0; + }; + + instance->displaySearch = EsTextDisplayCreate(toolbarSearch, ES_CELL_H_FILL, {}, ""); + + button = EsButtonCreate(toolbarSearch, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchNext)); + button->accessKey = 'N'; + EsCommandAddButton(&instance->commandFindNext, button); + button = EsButtonCreate(toolbarSearch, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchPrevious)); + button->accessKey = 'P'; + EsCommandAddButton(&instance->commandFindPrevious, button); + } else if (message->type == ES_MSG_INSTANCE_OPEN) { + Instance *instance = message->instanceOpen.instance; + + size_t fileSize; + char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize); + + if (!file) { + EsInstanceOpenComplete(message, false); + } else if (!EsUTF8IsValid(file, fileSize)) { + EsInstanceOpenComplete(message, false); + } else { + EsTextboxSelectAll(instance->textboxDocument); + EsTextboxInsert(instance->textboxDocument, file, fileSize); + EsTextboxSetSelection(instance->textboxDocument, 0, 0, 0, 0); + EsElementRelayout(instance->textboxDocument); + + if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".c"), true) + || EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".cpp"), true) + || EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".h"), true)) { + SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C); + } else if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".ini"), true)) { + SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI); + } else { + SetLanguage(instance, 0); + } + + EsInstanceOpenComplete(message, true); + } + } else if (message->type == ES_MSG_INSTANCE_SAVE) { + Instance *instance = message->instanceSave.instance; + size_t byteCount; + char *contents = EsTextboxGetContents(instance->textboxDocument, &byteCount); + EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount); + EsHeapFree(contents); + EsInstanceSaveComplete(message, true); + } +} + +void _start() { + _init(); + + while (true) { + ProcessApplicationMessage(EsMessageReceive()); + } +} diff --git a/apps/text_editor.ini b/apps/text_editor.ini new file mode 100644 index 0000000..45c2025 --- /dev/null +++ b/apps/text_editor.ini @@ -0,0 +1,27 @@ +[general] +name=Text Editor +icon=icon_accessories_text_editor +use_single_process=1 + +[build] +source=apps/text_editor.cpp + +[@handler] +extension=txt +action=open + +[@handler] +extension=cpp +action=open + +[@handler] +extension=h +action=open + +[@handler] +extension=c +action=open + +[@handler] +extension=ini +action=open diff --git a/boot/x86/esfs-stage1.s b/boot/x86/esfs-stage1.s new file mode 100644 index 0000000..3a5ed57 --- /dev/null +++ b/boot/x86/esfs-stage1.s @@ -0,0 +1,178 @@ +[bits 16] +[org 0x7C00] + +%define superblock 0x8000 +%define temporary_load_buffer 0x9000 +%define block_group_descriptor_table 0x10000 +%define directory_load_location 0x1000 +%define stage2_load_location 0x1000 +%define inode_table_load_buffer 0x20000 +%define magic_breakpoint xchg bx,bx +;%define magic_breakpoint + +start: + ; Setup segment registers + cli + mov ax,0 + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + mov ss,ax + mov sp,0x7C00 + jmp 0x0:.continue + .continue: + sti + + ; Save the information passed from the MBR + mov [drive_number],dl + mov [partition_entry],si + mov [use_emu_read],dh + + ; Get drive parameters. + or dh,dh + jz .skip_params + mov ah,0x08 + xor di,di + int 0x13 + mov si,error_cannot_read_disk + jc error + and cx,63 + mov [max_sectors],cx + inc dh + shr dx,8 + mov [max_heads],dx + .skip_params: + + ; Print a startup message + mov si,startup_message + .loop: + lodsb + or al,al + jz .end + mov ah,0xE + int 0x10 + jmp .loop + .end: + + ; Load the second stage + mov cx,15 + mov eax,1 + mov edi,stage2_load_location + call load_sectors + + mov dl,[drive_number] + mov si,[partition_entry] + mov dh,[use_emu_read] + mov bx,[max_sectors] + mov cx,[max_heads] + jmp 0:stage2_load_location + +load_sectors: + ; Load CX sectors from sector EAX to buffer [EDI]. Returns end of buffer in EDI. + pusha + push edi + + ; Add the partition offset to EAX + mov bx,[partition_entry] + mov ebx,[bx + 8] + add eax,ebx + + ; Load 1 sector + mov [read_structure.lba],eax + mov ah,0x42 + mov dl,[drive_number] + mov si,read_structure + cmp byte [use_emu_read],1 + je .use_emu + int 0x13 + jmp .done_read + .use_emu: + call load_sector_emu + .done_read: + + ; Check for error + mov si,error_cannot_read_disk + jc error + + ; Copy the data to its destination + pop edi + mov cx,0x200 + mov eax,edi + shr eax,4 + and eax,0xF000 + mov es,ax + mov si,temporary_load_buffer + rep movsb + + ; Go to the next sector + popa + add edi,0x200 + inc eax + loop load_sectors + ret + +load_sector_emu: + mov di,[read_structure.lba] + xor ax,ax + mov es,ax + mov bx,0x9000 + + ; Calculate cylinder and head. + mov ax,di + xor dx,dx + div word [max_sectors] + xor dx,dx + div word [max_heads] + push dx ; remainder - head + mov ch,al ; quotient - cylinder + shl ah,6 + mov cl,ah + + ; Calculate sector. + mov ax,di + xor dx,dx + div word [max_sectors] + inc dx + or cl,dl + + ; Load the sector. + pop dx + mov dh,dl + mov dl,[drive_number] + mov ax,0x0201 + int 0x13 + + ret + +error: + ; Print an error message + lodsb + or al,al + jz .break + mov ah,0xE + int 0x10 + jmp error + + ; Break indefinitely + .break: + cli + hlt + +startup_message: db "Booting operating system...",10,13,0 + +drive_number: db 0 +use_emu_read: db 0 +partition_entry: dw 0 +max_sectors: dw 0 +max_heads: dw 0 + +read_structure: ; Data for the extended read calls + dw 0x10 + dw 1 + dd temporary_load_buffer + .lba: dq 0 + +error_cannot_read_disk: db "Error: The disk could not be read. (S1)",0 + +times (0x200 - ($-$$)) nop diff --git a/boot/x86/esfs-stage2.s b/boot/x86/esfs-stage2.s new file mode 100644 index 0000000..6bd0d6d --- /dev/null +++ b/boot/x86/esfs-stage2.s @@ -0,0 +1,134 @@ +%macro FilesystemInitialise 0 +%define superblock 0x8000 +%define kernel_file_entry 0x8800 +%endmacro + +%macro FilesystemGetKernelSize 0 +load_kernel: + ; Load the superblock. + mov eax,16 + mov edi,superblock + mov cx,1 + call load_sectors + mov ax,superblock / 16 + mov fs,ax + + ; Check the signature. + mov eax,[fs:0] + cmp eax,0x73734521 + mov si,ErrorBadFilesystem + jne error + + ; Check the read version. + mov ax,[fs:48] + cmp ax,10 + mov si,ErrorBadFilesystem + jg error + + ; Save the OS installation identifier. + mov eax,[fs:152] + mov [os_installation_identifier + 0],eax + mov eax,[fs:156] + mov [os_installation_identifier + 4],eax + mov eax,[fs:160] + mov [os_installation_identifier + 8],eax + mov eax,[fs:164] + mov [os_installation_identifier + 12],eax + + ; Load the kernel's file entry. + mov eax,[fs:184] ; Get the block containing the kernel. + mul dword [fs:64] ; Multiply by block size. + shr eax,9 ; Divide by sector size. + mov cx,2 ; 2 sectors - 1024 bytes. + mov edi,[fs:192] ; The offset into the block. + shr edi,9 ; Divide by sector size. + add eax,edi ; Add to the first sector. + mov edi,kernel_file_entry + call load_sectors + + ; Find the data stream. +FindDataStreamLoop: + mov bx,[KernelDataStreamPosition] + mov eax,[fs:bx] + cmp ax,1 + je SaveKernelSize + shr eax,16 + add [KernelDataStreamPosition],ax + cmp bx,0xC00 + mov si,ErrorUnexpectedFileProblem + jge error + jmp FindDataStreamLoop + + ; Save the size of the kernel. +SaveKernelSize: + mov eax,[fs:0x838] + mov [kernel_size],eax + mov si,error_kernel_too_large + cmp eax,0x300000 + jg error +%endmacro + +%macro FilesystemLoadKernelIntoBuffer 0 + ; Check that the kernel is stored as DATA_INDIRECT file. +CheckForDataIndirect: + mov ax,superblock / 16 + mov fs,ax + mov bx,[KernelDataStreamPosition] + mov ax,[fs:bx+4] + mov si,ErrorUnexpectedFileProblem + cmp al,2 + jne error + + ; Load each extent from the file. +LoadEachExtent: + mov edi,[kernel_buffer] + mov si,[fs:bx+6] + add bx,32 + + ; TODO More than 1 extent. (We don't do the offset correctly). + push si + cmp si,1 + mov si,ErrorUnexpectedFileProblem + jne error + pop si + + ; Load the blocks. + .ExtentLoop: + + ; TODO Other extents than offset = 1, count = 2. + mov al,[fs:bx] + cmp al,0x08 + push si + mov si,ErrorUnexpectedFileProblem + jne error + pop si + + mov eax,[fs:64] + shr eax,9 ; EAX = Sectors per block. + xor ecx,ecx + mov cx,[fs:bx+2] + xchg ch,cl + mul cx + mov cx,ax ; CX = Count. + + xor eax,eax + mov al,[fs:bx+1] + mul dword [fs:64] + shr eax,9 ; EAX = Block. + + xchg bx,bx + + call load_sectors + add bx,4 + + ; Go to the next extent. + sub si,1 + cmp si,0 + jne .ExtentLoop +%endmacro + +%macro FilesystemSpecificCode 0 +KernelDataStreamPosition: dw 0x850 +ErrorBadFilesystem: db "Invalid boot EsFS volume.",0 +ErrorUnexpectedFileProblem: db "The kernel file could not be loaded.",0 +%endmacro diff --git a/boot/x86/loader.s b/boot/x86/loader.s new file mode 100644 index 0000000..ac408b7 --- /dev/null +++ b/boot/x86/loader.s @@ -0,0 +1,913 @@ +[bits 16] +[org 0x1000] + +; This is missing any fileSystem specific macros. +%define vesa_info 0x7000 +%define os_installation_identifier 0x7FF0 +%define temporary_load_buffer 0x9000 +%define page_directory 0x40000 +%define page_directory_length 0x20000 +%define memory_map 0x60000 +%define indirect_block_buffer 0x64000 +; %define magic_breakpoint xchg bx,bx +%define magic_breakpoint + +start: + mov esp,0x7C00 + + ; Save information passed from stage 1 + mov [drive_number],dl + mov [partition_entry],si + mov [use_emu_read],dh + mov [max_sectors],bx + mov [max_heads],cx + + ; @FilesystemSpecific + FilesystemInitialise + +check_pci: + ; Check the computer has PCI + mov ax,0xB101 + xor edi,edi + int 0x1A + mov si,error_no_pci + jc error + or ah,ah + jnz error + +check_cpuid: + ; Check the CPU has CPUID + mov dword [24],.no_cpuid + mov eax,0 + cpuid + jmp .has_cpuid + .no_cpuid: + mov si,error_no_cpuid + jmp error + .has_cpuid: + +check_msr: + ; Check the CPU has MSRs + mov dword [24],.no_msr + mov ecx,0xC0000080 + rdmsr + jmp .has_msr + .no_msr: + mov si,error_no_msr + jmp error + .has_msr: + +enable_a20: + ; Enable the A20 line, if necessary + cli + call check_a20 + jc .a20_enabled + mov ax,0x2401 + int 0x15 + call check_a20 + jc .a20_enabled + mov si,error_cannot_enable_a20_line + jmp error + .a20_enabled: + sti + +identity_paging: + ; Map the first 4MB to itself for the bootloader to do work in protected mode + mov eax,page_directory / 16 + mov es,ax + + ; Clear the page directory + xor eax,eax + mov ecx,0x400 + xor di,di + rep stosd + + ; Recursive map the directory + mov dword [es:0x3FF * 4],page_directory | 3 + + ; Put the first table in the directory + mov dword [es:0],(page_directory + 0x1000) | 3 + + ; Fill the table + mov edi,0x1000 + mov cx,0x400 + mov eax,3 + .loop: + mov [es:edi],eax + add edi,4 + add eax,0x1000 + loop .loop + + ; Set the pointer to the page directory + mov eax,page_directory + mov cr3,eax + +load_gdt: + ; Load the GDT + lgdt [gdt_data.gdt] + +inform_bios_mixed_mode: + mov eax,0xEC00 + mov ebx,3 ; may switch between legacy and long mode + int 0x15 + +load_memory_map: + ; Load the memory map + xor ebx,ebx + + ; Set FS to access the memory map + mov ax,0 + mov es,ax + mov ax,memory_map / 16 + mov fs,ax + + ; Loop through each memory map entry + .loop: + mov di,.entry + mov edx,0x534D4150 + mov ecx,24 + mov eax,0xE820 + mov byte [.acpi],1 + int 0x15 + jc .finished + + ; Check the BIOS call worked + cmp eax,0x534D4150 + jne .fail + +; pusha +; mov di,.entry +; call .print_bytes +; popa + + ; Check if this is usable memory + cmp dword [.type],1 + jne .try_next + cmp dword [.size],0 + je .try_next + cmp dword [.acpi],0 + je .try_next + + ; Check that the region is big enough + mov eax,[.size] + and eax,~0x3FFF + or eax,eax + jz .try_next + + ; Check that the base is above 1MB + cmp dword [.base + 4],0 + jne .base_good + cmp dword [.base],0x100000 + jl .try_next + .base_good: + + ; Align the base to the nearest page + mov eax,[.base] + and eax,0xFFF + or eax,eax + jz .base_aligned + mov eax,[.base] + and eax,~0xFFF + add eax,0x1000 + mov [.base],eax + sub dword [.size],0x1000 + sbb dword [.size + 4],0 + .base_aligned: + + ; Align the size to the nearest page + mov eax,[.size] + and eax,~0xFFF + mov [.size],eax + + ; Convert the size from bytes to 4KB pages + mov eax,[.size] + shr eax,12 + push ebx + mov ebx,[.size + 4] + shl ebx,20 + add eax,ebx + pop ebx + mov [.size],eax + mov dword [.size + 4],0 + + ; Store the entry + push ebx + mov ebx,[.pointer] + mov eax,[.base] + mov [fs:bx],eax + mov eax,[.base + 4] + mov [fs:bx + 4],eax + mov eax,[.size] + mov [fs:bx + 8],eax + add [.total_memory],eax + mov eax,[.size + 4] + adc [.total_memory + 4],eax + mov [fs:bx + 12],eax + add dword [.pointer],16 + pop ebx + + ; Continue to the next entry + .try_next: + or ebx,ebx + jnz .loop + + ; Make sure that there were enough entries + .finished: + mov eax,[.pointer] + shr eax,4 + or eax,eax + jz .fail + + ; Clear the base value for the entry after last + mov ebx,[.pointer] + mov dword [fs:bx],0 + mov dword [fs:bx + 4],0 + + ; Store the total memory + mov eax,[.total_memory] + mov dword [fs:bx + 8],eax + mov eax,[.total_memory + 4] + mov dword [fs:bx + 12],eax + + ; Load the kernel! + jmp load_kernel + + ; Display an error message if we could not load the memory map + .fail: + mov si,error_could_not_get_memory_map + jmp error + + .pointer: dd 0 + .entry: + .base: dq 0 + .size: dq 0 + .type: dd 0 + .acpi: dd 0 + .total_memory: dq 0 + + ; @FilesystemSpecific + FilesystemGetKernelSize + +allocate_kernel_buffer: + ; Switch to protected mode + push ds + push es + push ss + cli + mov eax,cr0 + or eax,0x80000001 + mov cr0,eax + jmp 0x8:.pmode + + ; Set the data segment registers + [bits 32] + .pmode: + mov ax,0x10 + mov ds,ax + mov es,ax + mov ss,ax + + ; Work out the size of memory we'll allocate + mov ecx,[kernel_size] + shr ecx,12 + inc ecx + mov edx,ecx + shl edx,12 + + ; For every memory region + xor ebx,ebx + .memory_region_loop: + + ; Is this the region starting at 1MB? + mov eax,[ebx + memory_map + 4] + or eax,eax + jnz .try_next_memory_region + mov eax,[ebx + memory_map] + cmp eax,0x100000 + jne .try_next_memory_region + + ; Check the region has enough pages remaining + mov eax,[ebx + memory_map + 8] + cmp eax,ecx + jl .try_next_memory_region + + ; Remove ECX pages from the region + mov eax,[ebx + memory_map + 0] + mov [kernel_buffer],eax + add eax,edx + mov [ebx + memory_map + 0],eax + sub dword [ebx + memory_map + 8],ecx + sbb dword [ebx + memory_map + 12],0 + + jmp .found_buffer + + ; Go to the next memory region + .try_next_memory_region: + add ebx,16 + mov eax,[load_memory_map.pointer] + cmp ebx,eax + jne .memory_region_loop + mov si,error_no_memory + jmp error_32 + + .found_buffer: + ; Switch to 16-bit mode + mov eax,cr0 + and eax,0x7FFFFFFF + mov cr0,eax + jmp 0x18:.rmode + + ; Switch to real mode + [bits 16] + .rmode: + mov eax,cr0 + and eax,0x7FFFFFFE + mov cr0,eax + jmp 0x0:.finish + + ; Go to error + .finish: + pop ss + pop es + pop ds + + ; @FilesystemSpecific + FilesystemLoadKernelIntoBuffer + +enable_video_mode: + call vbe_init + jmp enable_video_mode_done +%include "boot/x86/vbe.s" +enable_video_mode_done: + +setup_elf: + ; Switch to protected mode + cli + mov eax,cr0 + or eax,0x80000001 + mov cr0,eax + jmp 0x8:.pmode + + ; Set the data segment registers + [bits 32] + .pmode: + mov ax,0x10 + mov ds,ax + mov es,ax + mov ss,ax + + ; Check the ELF data is correct + mov ebx,[kernel_buffer] + mov esi,error_bad_kernel + cmp dword [ebx + 0],0x464C457F + jne error_32 + cmp byte [ebx + 4],2 + je setup_elf_64 + jne error_32 + +setup_elf_64: + ; Check that the processor is 64-bit + mov ecx,0x80000001 + cpuid + mov esi,error_no_long_mode + test eax,0x20000000 + jnz error_32 + + ; Disable paging + mov eax,cr0 + and eax,0x7FFFFFFF + mov cr0,eax + + ; Identity map the first 4MB + mov dword [page_table_allocation_location],0x5000 + mov ecx,page_directory_length + xor eax,eax + mov edi,page_directory + rep stosb + mov dword [page_directory + 0x1000 - 16],page_directory | 3 + mov dword [page_directory],(page_directory + 0x1000) | 7 + mov dword [page_directory + 0x1000],(page_directory + 0x2000) | 7 + mov dword [page_directory + 0x2000],(page_directory + 0x3000) | 7 + mov dword [page_directory + 0x2000 + 8],(page_directory + 0x4000) | 7 + mov edi,page_directory + 0x3000 + mov eax,0x000003 + mov ebx,0x200003 + mov ecx,0x400 + .identity_loop: + mov [edi],eax + add edi,8 + add eax,0x1000 + loop .identity_loop + mov eax,page_directory + mov cr3,eax + + ; Enable long mode + mov eax,cr4 + or eax,32 + mov cr4,eax + mov ecx,0xC0000080 + rdmsr + or eax,256 + wrmsr + mov eax,cr0 + or eax,0x80000000 + mov cr0,eax + + ; Go to 64-bit mode + jmp 0x48:.start_64_bit_mode +[bits 64] + .start_64_bit_mode: + + mov rax,0x50 + mov ds,rax + mov es,rax + mov ss,rax + + ; Check the ELF data is correct + mov rbx,[kernel_buffer] + mov rsi,error_bad_kernel + cmp byte [rbx + 5],1 + jne error_64 + cmp byte [rbx + 7],0 + jne error_64 + cmp byte [rbx + 16],2 + jne error_64 + cmp byte [rbx + 18],0x3E + jne error_64 + + ; Find the program headers + ; RAX = ELF header, RBX = program headers + mov rax,rbx + mov rbx,[rax + 32] + add rbx,rax + + ; ECX = entries, EDX = size of entry + movzx rcx,word [rax + 56] + movzx rdx,word [rax + 54] + + ; Loop through each program header + .loop_program_headers: + push rax + push rcx + push rdx + push rbx + + ; Only deal with load segments + mov eax,[rbx] + cmp eax,1 + jne .next_entry + + ; Work out how many physical pages we need to allocate + mov rcx,[rbx + 40] + shr rcx,12 + inc rcx + + ; Get the starting virtual address + mov rax,[rbx + 16] + shl rax,16 + shr rax,16 + mov [.target_page],rax + + ; For every frame in the segment + .frame_loop: + xor rbx,rbx + + ; For every memory region + .memory_region_loop: + + ; Check the region has enough pages remaining + mov rax,[rbx + memory_map + 8] + or rax,rax + jz .try_next_memory_region + + ; Remove one page from the region + mov rax,[rbx + memory_map + 0] + mov [.physical_page],rax + add rax,0x1000 + mov [rbx + memory_map + 0],rax + sub qword [rbx + memory_map + 8],1 + + jmp .found_physical_page + + ; Go to the next memory region + .try_next_memory_region: + add rbx,16 + mov eax,[load_memory_map.pointer] + cmp ebx,eax + jne .memory_region_loop + mov si,error_no_memory + jmp error_64 + + ; Map the page into virtual memory + .found_physical_page: + + ; Make sure we have a PDP + mov rax,[.target_page] + shr rax,39 + mov r8,0xFFFFFF7FBFDFE000 + mov rbx,[r8 + rax * 8] + cmp rbx,0 + jne .has_pdp + mov rbx,[page_table_allocation_location] + add rbx,page_directory + or rbx,7 + mov [r8 + rax * 8],rbx + add qword [page_table_allocation_location],0x1000 + mov rax,cr3 + mov cr3,rax + .has_pdp: + + ; Make sure we have a PD + mov rax,[.target_page] + shr rax,30 + mov r8,0xFFFFFF7FBFC00000 + mov rbx,[r8 + rax * 8] + cmp rbx,0 + jne .has_pd + mov rbx,[page_table_allocation_location] + add rbx,page_directory + or rbx,7 + mov [r8 + rax * 8],rbx + add qword [page_table_allocation_location],0x1000 + mov rax,cr3 + mov cr3,rax + .has_pd: + + ; Make sure we have a PT + mov rax,[.target_page] + shr rax,21 + mov r8,0xFFFFFF7F80000000 + mov rbx,[r8 + rax * 8] + cmp rbx,0 + jne .has_pt + mov rbx,[page_table_allocation_location] + add rbx,page_directory + or rbx,7 + mov [r8 + rax * 8],rbx + add qword [page_table_allocation_location],0x1000 + mov rax,cr3 + mov cr3,rax + .has_pt: + + ; Map the page! + mov rax,[.target_page] + shr rax,12 + mov rbx,[.physical_page] + or rbx,0x103 + shl rax,3 + xor r8,r8 + mov r8,0xFFFFFF00 + shl r8,32 + add rax,r8 + mov [rax],rbx + mov rbx,[.target_page] + invlpg [rbx] + + ; Go to the next frame + add qword [.target_page],0x1000 + dec rcx + or rcx,rcx + jnz .frame_loop + + ; Restore the pointer to the segment + pop rbx + push rbx + + ; Clear the memory + mov rcx,[rbx + 40] + xor rax,rax + mov rdi,[rbx + 16] + rep stosb + + ; Copy the memory + mov rcx,[rbx + 32] + mov rsi,[rbx + 8] + add rsi,[kernel_buffer] + mov rdi,[ebx + 16] + rep movsb + + ; Go to the next entry + .next_entry: + pop rbx + pop rdx + pop rcx + pop rax + + add rbx,rdx + dec rcx + or rcx,rcx + jnz .loop_program_headers + + jmp run_kernel64 + + .target_page: dq 0 + .physical_page: dq 0 + +run_kernel64: + ; Get the start address of the kernel + mov rbx,[kernel_buffer] + mov rcx,[rbx + 24] + + ; Let the kernel use the memory that was used to store the executable + xor eax,eax + mov ebx,[load_memory_map.pointer] + mov [memory_map + ebx + 4],eax + mov [memory_map + ebx + 12],eax + mov [memory_map + ebx + 16],eax + mov [memory_map + ebx + 20],eax + mov eax,[memory_map + ebx + 8] + mov [memory_map + ebx + 24],eax + mov eax,[memory_map + ebx + 12] + mov [memory_map + ebx + 28],eax + mov eax,[kernel_buffer] + mov [memory_map + ebx],eax + mov eax,[kernel_size] + shr eax,12 + mov [memory_map + ebx + 8],eax + + ; Map the first MB at 0xFFFFFE0000000000 --> 0xFFFFFE0000100000 + mov rdi,0xFFFFFF7FBFDFE000 + mov rax,[rdi] + mov rdi,0xFFFFFF7FBFDFEFE0 + mov [rdi],rax + mov rax,cr3 + mov cr3,rax + + ; Use the new linear address of the GDT + mov rax,0xFFFFFE0000000000 + add qword [gdt_data.gdt2],rax + lgdt [gdt_data.gdt] + + ; Execute the kernel's _start function + xor rdi,rdi + mov rsi,1 + jmp rcx + +error_64: + jmp far [.error_32_ind] + .error_32_ind: dq error_32 + dd 8 + +[bits 32] +error_32: + ; Switch to 16-bit mode + mov eax,cr0 + and eax,0x7FFFFFFF + mov cr0,eax + jmp 0x18:.rmode + + ; Switch to real mode + [bits 16] + .rmode: + mov eax,cr0 + and eax,0x7FFFFFFE + mov cr0,eax + jmp 0x0:.finish + + ; Go to error + .finish: + mov ax,0 + mov ds,ax + mov es,ax + mov ss,ax + jmp error + +check_a20: + ; Set the carry flag if the A20 line is enabled + mov ax,0 + mov es,ax + mov ax,0xFFFF + mov fs,ax + mov byte [es:0x600],0 + mov byte [fs:0x610],0xFF + cmp byte [es:0x600],0xFF + je .enabled + stc + ret + .enabled: + clc + ret + +error: + ; Print an error message + lodsb + or al,al + jz .break + mov ah,0xE + int 0x10 + jmp error + + ; Break indefinitely + .break: + cli + hlt + +gdt_data: + .null_entry: dq 0 + .code_entry: dd 0xFFFF ; 0x08 + db 0 + dw 0xCF9A + db 0 + .data_entry: dd 0xFFFF ; 0x10 + db 0 + dw 0xCF92 + db 0 + .code_entry_16: dd 0xFFFF ; 0x18 + db 0 + dw 0x0F9A + db 0 + .data_entry_16: dd 0xFFFF ; 0x20 + db 0 + dw 0x0F92 + db 0 + .user_code: dd 0xFFFF ; 0x2B + db 0 + dw 0xCFFA + db 0 + .user_data: dd 0xFFFF ; 0x33 + db 0 + dw 0xCFF2 + db 0 + .tss: dd 0x68 ; 0x38 + db 0 + dw 0xE9 + db 0 + dq 0 + .code_entry64: dd 0xFFFF ; 0x48 + db 0 + dw 0xAF9A + db 0 + .data_entry64: dd 0xFFFF ; 0x50 + db 0 + dw 0xAF92 + db 0 + .user_code64: dd 0xFFFF ; 0x5B + db 0 + dw 0xAFFA + db 0 + .user_data64: dd 0xFFFF ; 0x63 + db 0 + dw 0xAFF2 + db 0 + .user_code64c: dd 0xFFFF ; 0x6B + db 0 + dw 0xAFFA + db 0 + .gdt: dw (gdt_data.gdt - gdt_data - 1) + .gdt2: dq gdt_data + + ; @FilesystemSpecific + FilesystemSpecificCode + +load_sectors: + ; Load CX sectors from sector EAX to EDI + pushad + push edi + + ; Add the partition offset to EAX + mov bx,[partition_entry] + mov ebx,[bx + 8] + add eax,ebx + + ; Load 1 sector + mov [read_structure.lba],eax + mov ah,0x42 + mov dl,[drive_number] + mov si,read_structure + cmp byte [use_emu_read],1 + je .use_emu + int 0x13 + jmp .done_read + .use_emu: + call load_sector_emu + .done_read: + + ; Check for error + mov si,error_cannot_read_disk + jc error + + ; Copy the data to its destination + pop edi + call move_sector_to_target + + ; Go to the next sector + popad + add edi,0x200 + inc eax + loop load_sectors + ret + + ; Move data from the temporary load buffer to EDI +move_sector_to_target: + push ss + push ds + push es + + ; Switch to protected mode + cli + mov eax,cr0 + or eax,0x80000001 + mov cr0,eax + jmp 0x8:.pmode + + ; Set the data segment registers + [bits 32] + .pmode: + mov ax,0x10 + mov ds,ax + mov es,ax + mov ss,ax + + ; Copy the data + mov ecx,0x200 + mov esi,temporary_load_buffer + rep movsb + + ; Switch to 16-bit mode + mov eax,cr0 + and eax,0x7FFFFFFF + mov cr0,eax + jmp 0x18:.rmode + + ; Switch to real mode + [bits 16] + .rmode: + mov eax,cr0 + and eax,0x7FFFFFFE + mov cr0,eax + jmp 0x0:.finish + + ; Return to load_sectors + .finish: + pop es + pop ds + pop ss + sti + ret + +load_sector_emu: + mov di,[read_structure.lba] + xor ax,ax + mov es,ax + mov bx,0x9000 + + ; Calculate cylinder and head. + mov ax,di + xor dx,dx + div word [max_sectors] + xor dx,dx + div word [max_heads] + push dx ; remainder - head + mov ch,al ; quotient - cylinder + shl ah,6 + mov cl,ah + + ; Calculate sector. + mov ax,di + xor dx,dx + div word [max_sectors] + inc dx + or cl,dl + + ; Load the sector. + pop dx + mov dh,dl + mov dl,[drive_number] + mov ax,0x0201 + int 0x13 + + ret + +read_structure: + ; Data for the extended read calls + dw 0x10 + dw 1 + dd temporary_load_buffer + .lba: dq 0 + +drive_number: db 0 +use_emu_read: db 0 +partition_entry: dw 0 +max_sectors: dw 0 +max_heads: dw 0 + +page_table_allocation_location: dq 0 ; Relative to page_directory. + +kernel_buffer: dq 0 +kernel_size: dq 0 + +error_cannot_enable_a20_line: db "Error: Cannot enable the A20 line",0 +error_could_not_get_memory_map: db "Error: Could not get the memory map from the BIOS",0 +error_no_pci: db "Error: Could not find the PCI bus",0 +error_no_cpuid: db "Error: CPU does not have the CPUID instruction",0 +error_no_msr: db "Error: CPU does not have the RDMSR instruction",0 +error_cannot_find_file: db "Error: A file necessary for booting could not found",0 +error_cannot_read_disk: db "Error: The disk could not be read.",0 +error_file_too_large: db "Error: The file was too large to be loaded (more than 256KB).",0 +error_kernel_too_large: db "Error: The kernel was too large for the 3MB buffer.",0 +error_bad_kernel: db "Error: Invalid or unsupported kernel ELF format.",0 +error_no_memory: db "Error: Not enough memory to load kernel" +error_no_long_mode: db "Error: The kernel is compiled for a 64-bit processor but the current processor is 32-bit only.",0 +error_could_not_set_video_mode: db "Error: Could not set video mode 1024x768x24.",0 + +reached_end: db "Reached end of stage 2 bootloader.",0 diff --git a/boot/x86/mbr-emu.s b/boot/x86/mbr-emu.s new file mode 100644 index 0000000..6f711df --- /dev/null +++ b/boot/x86/mbr-emu.s @@ -0,0 +1,144 @@ +[bits 16] +[org 0x600] + +start: + ; Setup segment registers and the stack + cli + mov ax,0 + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + mov ss,ax + mov sp,0x7C00 + sti + + ; Clear the screen + mov ax,0 + int 0x10 + mov ax,3 + int 0x10 + + ; Relocate to 0x600 + cld + mov si,0x7C00 + mov di,0x600 + mov cx,0x200 + rep movsb + jmp 0x0:find_partition + +find_partition: + ; Save the drive number + mov byte [drive_number],dl + + ; Get drive parameters. + mov ah,0x08 + xor di,di + int 0x13 + mov si,error_cannot_read_disk + jc error + and cx,63 + mov [max_sectors],cx + inc dh + shr dx,8 + mov [max_heads],dx + mov si,error_bad_geometry + or cx,cx + jz error + or dx,dx + jz error + + ; Find the bootable flag (0x80) + mov bx,partition_entry_1 + cmp byte [bx],0x80 + je found_partition + mov bx,partition_entry_2 + cmp byte [bx],0x80 + je found_partition + mov bx,partition_entry_3 + cmp byte [bx],0x80 + je found_partition + mov bx,partition_entry_4 + cmp byte [bx],0x80 + je found_partition + + ; No bootable partition + mov si,error_no_bootable_partition + jmp error + +found_partition: + ; Load the first sector of the partition at 0x7C00 + push bx + mov di,[bx + 8] + mov bx,0x7C00 + call load_sector + + ; Jump to the partition's boot sector + mov dl,[drive_number] + pop si + mov dh,0x01 + jmp 0x0:0x7C00 + +error: + ; Print an error message + lodsb + or al,al + jz .break + mov ah,0xE + int 0x10 + jmp error + + ; Break indefinitely + .break: + cli + hlt + +; di - LBA. +; es:bx - buffer +load_sector: + ; Calculate cylinder and head. + mov ax,di + xor dx,dx + div word [max_sectors] + xor dx,dx + div word [max_heads] + push dx ; remainder - head + mov ch,al ; quotient - cylinder + shl ah,6 + mov cl,ah + + ; Calculate sector. + mov ax,di + xor dx,dx + div word [max_sectors] + inc dx + or cl,dl + + ; Load the sector. + pop dx + mov dh,dl + mov dl,[drive_number] + mov ax,0x0201 + int 0x13 + mov si,error_cannot_read_disk + jc error + + ret + +error_cannot_read_disk: db "Error: The disk could not be read. (MBR)",0 +error_no_bootable_partition: db "Error: No bootable partition could be found on the disk.",0 +error_bad_geometry: db 'Error: The BIOS reported invalid disk geometry.',0 + +drive_number: db 0 +max_sectors: dw 0 +max_heads: dw 0 + +times (0x1B4 - ($-$$)) nop + +disk_identifier: times 10 db 0 +partition_entry_1: times 16 db 0 +partition_entry_2: times 16 db 0 +partition_entry_3: times 16 db 0 +partition_entry_4: times 16 db 0 + +dw 0xAA55 diff --git a/boot/x86/mbr.s b/boot/x86/mbr.s new file mode 100644 index 0000000..c480cf3 --- /dev/null +++ b/boot/x86/mbr.s @@ -0,0 +1,106 @@ +[bits 16] +[org 0x600] + +start: + ; Setup segment registers and the stack + cli + mov ax,0 + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + mov ss,ax + mov sp,0x7C00 + sti + + ; Clear the screen + mov ax,0 + int 0x10 + mov ax,3 + int 0x10 + + ; Relocate to 0x600 + cld + mov si,0x7C00 + mov di,0x600 + mov cx,0x200 + rep movsb + jmp 0x0:find_partition + +drive_number: db 0 + +find_partition: + ; Save the drive number + mov byte [drive_number],dl + + ; Find the bootable flag (0x80) + mov bx,partition_entry_1 + cmp byte [bx], 0x80 + je found_partition + mov bx,partition_entry_2 + cmp byte [bx], 0x80 + je found_partition + mov bx,partition_entry_3 + cmp byte [bx], 0x80 + je found_partition + mov bx,partition_entry_4 + cmp byte [bx], 0x80 + je found_partition + + ; No bootable partition + mov si,error_no_bootable_partition + jmp error + +found_partition: + ; Load the first sector of the partition at 0x7C00 + push bx + mov eax,[bx + 8] + mov [read_structure.lba],eax + mov ah,0x42 + mov dl,[drive_number] + push dx + mov si,read_structure + int 0x13 + + ; Check for an error + mov si,error_cannot_read_disk + jc error + + ; Jump to the partition's boot sector + pop dx + pop si + xor dh,dh + jmp 0x0:0x7C00 + +error: + ; Print an error message + lodsb + or al,al + jz .break + mov ah,0xE + int 0x10 + jmp error + + ; Break indefinitely + .break: + cli + hlt + +read_structure: ; Data for the extended read calls + dw 0x10 + dw 1 + dd 0x7C00 + .lba: dq 0 + +error_cannot_read_disk: db "Error: The disk could not be read. (MBR)",0 +error_no_bootable_partition: db "Error: No bootable partition could be found on the disk.",0 + +times (0x1B4 - ($-$$)) nop + +disk_identifier: times 10 db 0 +partition_entry_1: times 16 db 0 +partition_entry_2: times 16 db 0 +partition_entry_3: times 16 db 0 +partition_entry_4: times 16 db 0 + +dw 0xAA55 diff --git a/boot/x86/uefi.c b/boot/x86/uefi.c new file mode 100644 index 0000000..ac5c2f4 --- /dev/null +++ b/boot/x86/uefi.c @@ -0,0 +1,404 @@ +#include +#include + +#define ENTRIES_PER_PAGE_TABLE (512) +#define ENTRIES_PER_PAGE_TABLE_BITS (9) +#define K_PAGE_SIZE (4096) +#define K_PAGE_BITS (12) + +typedef struct __attribute__((packed)) GDTData { + uint16_t length; + uint64_t address; +} GDTData; + +typedef struct MemoryRegion { + uintptr_t base, pages; +} MemoryRegion; + +#define MAX_MEMORY_REGIONS (1024) +MemoryRegion memoryRegions[1024]; +#define KERNEL_BUFFER_SIZE (1048576) +#define kernelBuffer ((char *) 0x200000) +#define IID_BUFFER_SIZE (64) +char iidBuffer[IID_BUFFER_SIZE]; +#define MEMORY_MAP_BUFFER_SIZE (16384) +char memoryMapBuffer[MEMORY_MAP_BUFFER_SIZE]; + +#define VESA_VM_INFO_ONLY +#define ARCH_64 +#include "../../kernel/graphics.cpp" +#include "../../kernel/elf.cpp" + +void ZeroMemory(void *pointer, uint64_t size) { + char *d = (char *) pointer; + + for (uintptr_t i = 0; i < size; i++) { + d[i] = 0; + } +} + +EFI_STATUS EFIAPI efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable) { + UINTN mapKey; + uint32_t *framebuffer, horizontalResolution, verticalResolution, pixelsPerScanline; + InitializeLib(imageHandle, systemTable); + ElfHeader *header; + Print(L"Loading OS...\n"); + + // Make sure 0x100000 -> 0x300000 is identity mapped. + { + EFI_PHYSICAL_ADDRESS address = 0x100000; + + if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->AllocatePages, 4, AllocateAddress, EfiLoaderData, 0x200, &address)) { + Print(L"Error: Could not map 0x100000 -> 0x180000.\n"); + while (1); + } + } + + // Find the RSDP. + { + for (uintptr_t i = 0; i < systemTable->NumberOfTableEntries; i++) { + EFI_CONFIGURATION_TABLE *entry = systemTable->ConfigurationTable + i; + if (entry->VendorGuid.Data1 == 0x8868E871 && entry->VendorGuid.Data2 == 0xE4F1 && entry->VendorGuid.Data3 == 0x11D3 + && entry->VendorGuid.Data4[0] == 0xBC && entry->VendorGuid.Data4[1] == 0x22 && entry->VendorGuid.Data4[2] == 0x00 + && entry->VendorGuid.Data4[3] == 0x80 && entry->VendorGuid.Data4[4] == 0xC7 && entry->VendorGuid.Data4[5] == 0x3C + && entry->VendorGuid.Data4[6] == 0x88 && entry->VendorGuid.Data4[7] == 0x81) { + *((uint64_t *) 0x107FE8) = (uint64_t) entry->VendorTable; + Print(L"The RSDP can be found at 0x%x.\n", entry->VendorTable); + } + } + } + + // Read the kernel, IID and loader files. + { + EFI_GUID loadedImageProtocolGUID = LOADED_IMAGE_PROTOCOL; + EFI_GUID simpleFilesystemProtocolGUID = SIMPLE_FILE_SYSTEM_PROTOCOL; + + EFI_LOADED_IMAGE_PROTOCOL *loadedImageProtocol; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *simpleFilesystemProtocol; + + EFI_FILE *filesystemRoot, *kernelFile, *iidFile, *loaderFile; + + UINTN size; + + if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->OpenProtocol, 6, imageHandle, &loadedImageProtocolGUID, &loadedImageProtocol, imageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)) { + Print(L"Error: Could not open protocol 1.\n"); + while (1); + } + + EFI_HANDLE deviceHandle = loadedImageProtocol->DeviceHandle; + + if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->OpenProtocol, 6, deviceHandle, &simpleFilesystemProtocolGUID, &simpleFilesystemProtocol, imageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)) { + Print(L"Error: Could not open procotol 2.\n"); + while (1); + } + + if (EFI_SUCCESS != uefi_call_wrapper(simpleFilesystemProtocol->OpenVolume, 2, simpleFilesystemProtocol, &filesystemRoot)) { + Print(L"Error: Could not open ESP volume.\n"); + while (1); + } + + if (EFI_SUCCESS != uefi_call_wrapper(filesystemRoot->Open, 5, filesystemRoot, &kernelFile, L"EssenceKernel.esx", EFI_FILE_MODE_READ, 0)) { + Print(L"Error: Could not open EssenceKernel.esx.\n"); + while (1); + } + + size = KERNEL_BUFFER_SIZE; + + if (EFI_SUCCESS != uefi_call_wrapper(kernelFile->Read, 3, kernelFile, &size, kernelBuffer)) { + Print(L"Error: Could not load EssenceKernel.esx.\n"); + while (1); + } + + Print(L"Kernel size: %d bytes\n", size); + + if (size == KERNEL_BUFFER_SIZE) { + Print(L"Kernel too large to fit into buffer.\n"); + while (1); + } + + if (EFI_SUCCESS != uefi_call_wrapper(filesystemRoot->Open, 5, filesystemRoot, &iidFile, L"EssenceIID.dat", EFI_FILE_MODE_READ, 0)) { + Print(L"Error: Could not open EssenceIID.dat.\n"); + while (1); + } + + size = IID_BUFFER_SIZE; + + if (EFI_SUCCESS != uefi_call_wrapper(iidFile->Read, 3, iidFile, &size, iidBuffer)) { + Print(L"Error: Could not load EssenceIID.dat.\n"); + while (1); + } + + if (EFI_SUCCESS != uefi_call_wrapper(filesystemRoot->Open, 5, filesystemRoot, &loaderFile, L"EssenceLoader.bin", EFI_FILE_MODE_READ, 0)) { + Print(L"Error: Could not open EssenceLoader.bin.\n"); + while (1); + } + + size = 0x80000; + + if (EFI_SUCCESS != uefi_call_wrapper(loaderFile->Read, 3, loaderFile, &size, (char *) 0x180000)) { + Print(L"Error: Could not load EssenceLoader.bin.\n"); + while (1); + } + } + +#if 0 + // Print the memory map. + { + UINTN descriptorSize, descriptorVersion, size = MEMORY_MAP_BUFFER_SIZE; + + if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &size, (EFI_MEMORY_DESCRIPTOR *) memoryMapBuffer, &mapKey, &descriptorSize, &descriptorVersion)) { + Print(L"Error: Could not get memory map.\n"); + while (1); + } + + WCHAR *memoryTypes[] = { + L"EfiReservedMemoryType", + L"EfiLoaderCode", + L"EfiLoaderData", + L"EfiBootServicesCode", + L"EfiBootServicesData", + L"EfiRuntimeServicesCode", + L"EfiRuntimeServicesData", + L"EfiConventionalMemory", + L"EfiUnusableMemory", + L"EfiACPIReclaimMemory", + L"EfiACPIMemoryNVS", + L"EfiMemoryMappedIO", + L"EfiMemoryMappedIOPortSpace", + L"EfiPalCode", + L"EfiMaxMemoryType", + }; + + for (uintptr_t i = 0; i < size / descriptorSize; i++) { + EFI_MEMORY_DESCRIPTOR *descriptor = (EFI_MEMORY_DESCRIPTOR *) (memoryMapBuffer + i * descriptorSize); + Print(L"memory %s: %llx -> %llx\n", memoryTypes[descriptor->Type], descriptor->PhysicalStart, descriptor->PhysicalStart + descriptor->NumberOfPages * 0x1000 - 1); + } + } +#endif + + // Get the graphics mode information. + { + EFI_GRAPHICS_OUTPUT_PROTOCOL *graphicsOutputProtocol; + EFI_GUID graphicsOutputProtocolGUID = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + + if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->LocateProtocol, 3, &graphicsOutputProtocolGUID, NULL, &graphicsOutputProtocol)) { + Print(L"Error: Could not open protocol 3.\n"); + while (1); + } + + int32_t desiredMode = -1; + + Print(L"Select a graphics mode:\n"); + + for (uint32_t i = 0; i < graphicsOutputProtocol->Mode->MaxMode; i++) { + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *modeInformation; + UINTN modeInformationSize; + uefi_call_wrapper(graphicsOutputProtocol->QueryMode, 4, graphicsOutputProtocol, i, &modeInformationSize, &modeInformation); + + if (modeInformation->HorizontalResolution >= 800 && modeInformation->VerticalResolution >= 600) { + Print(L" %d: %d by %d\n", i + 1, modeInformation->HorizontalResolution, modeInformation->VerticalResolution); + } + } + + Print(L"> "); + + while (1) { + UINTN index; + uefi_call_wrapper(ST->BootServices->WaitForEvent, 3, 1, &systemTable->ConIn->WaitForKey, &index); + EFI_INPUT_KEY key; + uefi_call_wrapper(systemTable->ConIn->ReadKeyStroke, 2, systemTable->ConIn, &key); + + if (key.UnicodeChar >= '0' && key.UnicodeChar <= '9') { + if (desiredMode == -1) desiredMode = 0; + desiredMode = (desiredMode * 10) + key.UnicodeChar - '0'; + Print(L"%c", key.UnicodeChar); + } else if (key.UnicodeChar == 13) { + break; + } + } + + Print(L"\n"); + + if (desiredMode != -1) { + Print(L"Setting mode %d...\n", desiredMode); + desiredMode--; + + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *modeInformation; + UINTN modeInformationSize; + uefi_call_wrapper(graphicsOutputProtocol->QueryMode, 4, graphicsOutputProtocol, desiredMode, &modeInformationSize, &modeInformation); + + horizontalResolution = modeInformation->HorizontalResolution; + verticalResolution = modeInformation->VerticalResolution; + pixelsPerScanline = modeInformation->PixelsPerScanLine; + + uefi_call_wrapper(graphicsOutputProtocol->SetMode, 2, graphicsOutputProtocol, desiredMode); + } else { + horizontalResolution = graphicsOutputProtocol->Mode->Info->HorizontalResolution; + verticalResolution = graphicsOutputProtocol->Mode->Info->VerticalResolution; + pixelsPerScanline = graphicsOutputProtocol->Mode->Info->PixelsPerScanLine; + } + + framebuffer = (uint32_t *) graphicsOutputProtocol->Mode->FrameBufferBase; + } + + // Get the memory map. + { + UINTN descriptorSize, descriptorVersion, size = MEMORY_MAP_BUFFER_SIZE; + + if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &size, (EFI_MEMORY_DESCRIPTOR *) memoryMapBuffer, &mapKey, &descriptorSize, &descriptorVersion)) { + Print(L"Error: Could not get memory map.\n"); + while (1); + } + + uintptr_t memoryRegionCount = 0; + + for (uintptr_t i = 0; i < size / descriptorSize && memoryRegionCount != MAX_MEMORY_REGIONS - 1; i++) { + EFI_MEMORY_DESCRIPTOR *descriptor = (EFI_MEMORY_DESCRIPTOR *) (memoryMapBuffer + i * descriptorSize); + + if (descriptor->Type == EfiConventionalMemory && descriptor->PhysicalStart >= 0x300000) { + memoryRegions[memoryRegionCount].base = descriptor->PhysicalStart; + memoryRegions[memoryRegionCount].pages = descriptor->NumberOfPages; + memoryRegionCount++; + } + } + + memoryRegions[memoryRegionCount].base = 0; + } + + // Exit boot services. + { + if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->ExitBootServices, 2, imageHandle, mapKey)) { + Print(L"Error: Could not exit boot services.\n"); + while (1); + } + } + + // Identity map the first 3MB for the loader. + { + uint64_t *paging = (uint64_t *) 0x140000; + ZeroMemory(paging, 0x5000); + + paging[0x1FE] = 0x140003; + paging[0x000] = 0x141003; + paging[0x200] = 0x142003; + paging[0x400] = 0x143003; + paging[0x401] = 0x144003; + + for (uintptr_t i = 0; i < 0x400; i++) { + paging[0x600 + i] = (i * 0x1000) | 3; + } + } + + // Copy the installation ID across. + { + uint8_t *destination = (uint8_t *) (0x107FF0); + + for (uintptr_t i = 0; i < 16; i++) { + char c1 = iidBuffer[i * 3 + 0]; + char c2 = iidBuffer[i * 3 + 1]; + if (c1 >= '0' && c1 <= '9') c1 -= '0'; else c1 -= 'A' - 10; + if (c2 >= '0' && c2 <= '9') c2 -= '0'; else c2 -= 'A' - 10; + destination[i] = (c2) | ((c1) << 4); + } + } + + // Copy the graphics information across. + { + struct VESAVideoModeInformation *destination = (struct VESAVideoModeInformation *) (0x107000); + destination->widthPixels = horizontalResolution; + destination->heightPixels = verticalResolution; + destination->bufferPhysical = (uintptr_t) framebuffer; // TODO 64-bit framebuffers. + destination->bytesPerScanlineLinear = pixelsPerScanline * 4; + destination->bitsPerPixel = 32; + } + + // Allocate and map memory for the kernel. + { + uint64_t nextPageTable = 0x1C0000; + + header = (ElfHeader *) kernelBuffer; + ElfProgramHeader *programHeaders = (ElfProgramHeader *) (kernelBuffer + header->programHeaderTable); + uintptr_t programHeaderEntrySize = header->programHeaderEntrySize; + + for (uintptr_t i = 0; i < header->programHeaderEntries; i++) { + ElfProgramHeader *header = (ElfProgramHeader *) ((uint8_t *) programHeaders + programHeaderEntrySize * i); + if (header->type != 1) continue; + + uintptr_t pagesToAllocate = header->segmentSize >> 12; + if (header->segmentSize & 0xFFF) pagesToAllocate++; + uintptr_t physicalAddress = 0; + + for (uintptr_t j = 0; j < MAX_MEMORY_REGIONS; j++) { + MemoryRegion *region = memoryRegions + j; + if (!region->base) break; + if (region->pages < pagesToAllocate) continue; + physicalAddress = region->base; + region->pages -= pagesToAllocate; + region->base += pagesToAllocate << 12; + break; + } + + if (!physicalAddress) { + // TODO Error handling. + *((uint32_t *) framebuffer + 3) = 0xFFFF00FF; + while (1); + } + + for (uintptr_t j = 0; j < pagesToAllocate; j++, physicalAddress += 0x1000) { + uintptr_t virtualAddress = header->virtualAddress + j * K_PAGE_SIZE; + physicalAddress &= 0xFFFFFFFFFFFFF000; + virtualAddress &= 0x0000FFFFFFFFF000; + + uintptr_t indexL4 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3)) & (ENTRIES_PER_PAGE_TABLE - 1); + uintptr_t indexL3 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2)) & (ENTRIES_PER_PAGE_TABLE - 1); + uintptr_t indexL2 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1)) & (ENTRIES_PER_PAGE_TABLE - 1); + uintptr_t indexL1 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 0)) & (ENTRIES_PER_PAGE_TABLE - 1); + + uint64_t *tableL4 = (uint64_t *) 0x140000; + + if (!(tableL4[indexL4] & 1)) { + tableL4[indexL4] = nextPageTable | 7; + ZeroMemory((void *) nextPageTable, K_PAGE_SIZE); + nextPageTable += K_PAGE_SIZE; + } + + uint64_t *tableL3 = (uint64_t *) (tableL4[indexL4] & ~(K_PAGE_SIZE - 1)); + + if (!(tableL3[indexL3] & 1)) { + tableL3[indexL3] = nextPageTable | 7; + ZeroMemory((void *) nextPageTable, K_PAGE_SIZE); + nextPageTable += K_PAGE_SIZE; + } + + uint64_t *tableL2 = (uint64_t *) (tableL3[indexL3] & ~(K_PAGE_SIZE - 1)); + + if (!(tableL2[indexL2] & 1)) { + tableL2[indexL2] = nextPageTable | 7; + ZeroMemory((void *) nextPageTable, K_PAGE_SIZE); + nextPageTable += K_PAGE_SIZE; + } + + uint64_t *tableL1 = (uint64_t *) (tableL2[indexL2] & ~(K_PAGE_SIZE - 1)); + uintptr_t value = physicalAddress | 3; + tableL1[indexL1] = value; + } + } + } + + // Copy the memory regions information across. + { + MemoryRegion *destination = (MemoryRegion *) 0x160000; + + for (uintptr_t i = 0; i < MAX_MEMORY_REGIONS; i++) { + destination[i] = memoryRegions[i]; + } + } + + // Start the loader. + { + ((void (*)()) 0x180000)(); + } + + while (1); + return EFI_SUCCESS; +} diff --git a/boot/x86/uefi_loader.s b/boot/x86/uefi_loader.s new file mode 100644 index 0000000..57efc90 --- /dev/null +++ b/boot/x86/uefi_loader.s @@ -0,0 +1,156 @@ +[bits 64] +[org 0x180000] +[section .text] + +; 0x107000 Graphics info +; 0x107FE8 RSDP address +; 0x107FF0 Installation ID +; 0x140000-0x150000 Identity paging tables +; 0x160000-0x170000 Memory regions +; 0x180000-0x1C0000 Loader (this) +; 0x1C0000-0x1E0000 Kernel paging tables +; 0x1F0000-0x200000 Stack +; 0x200000-0x300000 Kernel + +%define memory_map 0x160000 +%define kernel_buffer 0x200000 + +start: + ; Setup the environment. + lgdt [gdt_data.gdt] + mov rax,0x140000 + mov cr3,rax + mov rax,0x200000 + mov rsp,rax + mov rax,0x50 + mov ds,rax + mov es,rax + mov ss,rax + + ; Find the program headers + ; RAX = ELF header, RBX = program headers + mov rax,kernel_buffer + mov rbx,[rax + 32] + add rbx,rax + + ; ECX = entries, EDX = size of entry + movzx rcx,word [rax + 56] + movzx rdx,word [rax + 54] + + ; Loop through each program header + .loop_program_headers: + push rax + push rcx + + ; Only deal with load segments + mov eax,[rbx] + cmp eax,1 + jne .next_entry + + ; Clear the memory + mov rcx,[rbx + 40] + xor rax,rax + mov rdi,[rbx + 16] + rep stosb + + ; Copy the memory + mov rcx,[rbx + 32] + mov rsi,[rbx + 8] + add rsi,kernel_buffer + mov rdi,[rbx + 16] + rep movsb + + ; Go to the next entry + .next_entry: + pop rcx + pop rax + + add rbx,rdx + dec rcx + or rcx,rcx + jnz .loop_program_headers + + jmp run_kernel64 + +run_kernel64: + ; Get the start address of the kernel + mov rbx,kernel_buffer + mov rcx,[rbx + 24] + + ; Map the first MB at 0xFFFFFE0000000000 --> 0xFFFFFE0000100000 + mov rax,[0xFFFFFF7FBFDFE000] + mov [0xFFFFFF7FBFDFEFE0],rax + mov rax,cr3 + mov cr3,rax + + ; Use the new linear address of the GDT + mov rax,0xFFFFFE0000000000 + add qword [gdt_data.gdt2],rax + lgdt [gdt_data.gdt] + + call set_cs + + ; Execute the kernel's _start function + mov rdi,0x100000 + mov rsi,2 + jmp rcx + +set_cs: + pop rax + push 0x48 + push rax + db 0x48, 0xCB + +gdt_data: + .null_entry: dq 0 + .code_entry: dd 0xFFFF ; 0x08 + db 0 + dw 0xCF9A + db 0 + .data_entry: dd 0xFFFF ; 0x10 + db 0 + dw 0xCF92 + db 0 + .code_entry_16: dd 0xFFFF ; 0x18 + db 0 + dw 0x0F9A + db 0 + .data_entry_16: dd 0xFFFF ; 0x20 + db 0 + dw 0x0F92 + db 0 + .user_code: dd 0xFFFF ; 0x2B + db 0 + dw 0xCFFA + db 0 + .user_data: dd 0xFFFF ; 0x33 + db 0 + dw 0xCFF2 + db 0 + .tss: dd 0x68 ; 0x38 + db 0 + dw 0xE9 + db 0 + dq 0 + .code_entry64: dd 0xFFFF ; 0x48 + db 0 + dw 0xAF9A + db 0 + .data_entry64: dd 0xFFFF ; 0x50 + db 0 + dw 0xAF92 + db 0 + .user_code64: dd 0xFFFF ; 0x5B + db 0 + dw 0xAFFA + db 0 + .user_data64: dd 0xFFFF ; 0x63 + db 0 + dw 0xAFF2 + db 0 + .user_code64c: dd 0xFFFF ; 0x6B + db 0 + dw 0xAFFA + db 0 + .gdt: dw (gdt_data.gdt - gdt_data - 1) + .gdt2: dq gdt_data diff --git a/boot/x86/vbe.s b/boot/x86/vbe.s new file mode 100644 index 0000000..820ab42 --- /dev/null +++ b/boot/x86/vbe.s @@ -0,0 +1,361 @@ +vbe_init: + mov ax,vesa_info >> 4 + mov es,ax + + xor di,di +%ifndef BOOT_USE_VBE + jmp vbe_bad +%endif + + + ; Get EDID information. + mov ax,0x4F15 + mov bl,1 + xor cx,cx + xor dx,dx + xor di,di + int 0x10 + cmp ax,0x4F + jne .no_edid + cmp byte [es:1],0xFF + jne .no_edid + mov al,[es:0x38] + mov ah,[es:0x3A] + shr ah,4 + mov bl,[es:0x3B] + mov bh,[es:0x3D] + shr bh,4 + or ax,ax + jz .no_edid + or bx,bx + jz .no_edid + mov [vbe_best_width],ax + mov [vbe_best_height],bx + mov byte [vbe_has_edid],1 + jmp .no_flat_panel + .no_edid: + ; Get flat panel information. + mov ax,0x4F11 + mov bx,1 + xor di,di + int 0x10 + cmp ax,0x4F + jne .no_flat_panel + mov ax,[es:0x00] + mov bx,[es:0x02] + or ax,ax + jz .no_flat_panel + or bx,bx + jz .no_flat_panel + cmp ax,4096 + ja .no_flat_panel + cmp bx,4096 + ja .no_flat_panel + mov [vbe_best_width],ax + mov [vbe_best_height],bx + .no_flat_panel: + + ; Get SVGA information. + xor di,di + mov ax,0x4F00 + int 0x10 + cmp ax,0x4F + jne vbe_bad + + ; Load the list of available modes. + add di,0x200 + mov eax,[es:14] + cmp eax,0 + je .find_done + mov ax,[es:16] + mov fs,ax + mov si,[es:14] + xor cx,cx + .find_loop: + mov ax,[fs:si] + cmp ax,0xFFFF + je .find_done + mov [es:di],ax + add di,2 + add si,2 + jmp .find_loop + .find_done: + + ; Add standard modes (if necessary). + mov word [es:di],0xFFFF + cmp di,0x200 + jne .added_modes + mov word [es:di + 0],257 + mov word [es:di + 2],259 + mov word [es:di + 4],261 + mov word [es:di + 6],263 + mov word [es:di + 8],273 + mov word [es:di + 10],276 + mov word [es:di + 12],279 + mov word [es:di + 14],282 + mov word [es:di + 16],274 + mov word [es:di + 18],277 + mov word [es:di + 20],280 + mov word [es:di + 22],283 + mov word [es:di + 24],0xFFFF + .added_modes: + + ; Check which of these modes can be used. + mov si,0x200 + mov di,0x200 + .check_loop: + mov cx,[es:si] + mov [es:di],cx + cmp cx,0xFFFF + je .check_done + push di + push si + mov ax,0x4F01 + xor di,di + or cx,(1 << 14) + int 0x10 + pop si + pop di + add si,2 + cmp ax,0x4F ; Interrupt failed. + jne .check_loop + cmp byte [es:0x19],24 ; We only support 24-bit and 32-bit modes currently. + je .valid_bpp + cmp byte [es:0x19],32 + je .valid_bpp + jne .check_loop + .valid_bpp: + cmp word [es:0x14],480 ; We support a minimum vertical resolution of 480 pixels. + jl .check_loop + mov ax,[vbe_best_width] + cmp [es:0x12],ax + jne .not_best_mode + mov ax,[vbe_best_height] + cmp [es:0x14],ax + jne .not_best_mode + mov ax,[es:di] + mov [vbe_best_mode],ax + .not_best_mode: + add di,2 + jmp .check_loop + .check_done: + + ; If we found a best mode, use that. + mov bx,[vbe_best_mode] + or bx,bx + jnz .set_graphics_mode + .no_best_mode: + + ; Print a list of the available modes. + mov si,vbe_s_select_video_mode + call vbe_print_string + mov bx,0x200 + mov cx,1 + .print_loop: + mov dx,[es:bx] + cmp dx,0xFFFF + je .print_done + cmp cx,21 ; Maximum of 20 options. TODO Scrolling! + je .print_done + xor di,di + push cx + mov ax,0x4F01 + mov cx,dx + or cx,(1 << 14) + int 0x10 + pop cx + mov si,vbe_s_left_bracket + call vbe_print_string + mov ax,cx + call vbe_print_decimal + mov si,vbe_s_right_bracket + call vbe_print_string + mov ax,[es:0x12] + call vbe_print_decimal + mov si,vbe_s_by + call vbe_print_string + mov ax,[es:0x14] + call vbe_print_decimal + mov si,vbe_s_space + call vbe_print_string + xor ah,ah + mov al,[es:0x19] + call vbe_print_decimal + mov si,vbe_s_bpp + call vbe_print_string + call vbe_print_newline + inc cx + add bx,2 + jmp .print_loop + .print_done: + + ; Let the user select a mode. + mov dx,cx + dec dx + xor cx,cx + .select_loop: + cmp cx,dx + jb .c1 + mov cx,0 + .c1: + call vbe_set_highlighted_line + xor ax,ax + int 0x16 + shr ax,8 + cmp ax,72 + jne .k11 + dec cx + .k11: + cmp ax,80 + jne .k12 + inc cx + .k12: + cmp ax,28 + jne .select_loop + + ; Set the graphics mode. + mov di,cx + shl di,1 + add di,0x200 + mov bx,[es:di] + .set_graphics_mode: + or bx,(1 << 14) + mov cx,bx + mov ax,0x4F02 + int 0x10 + cmp ax,0x4F + jne vbe_failed + + ; Save information about the mode for the kernel. + mov ax,0x4F01 + xor di,di + int 0x10 + mov byte [es:0],1 ; valid + mov al,[es:0x19] + mov [es:1],al ; bpp + mov ax,[es:0x12] + mov [es:2],ax ; width + mov ax,[es:0x14] + mov [es:4],ax ; height + mov ax,[es:0x10] + mov [es:6],ax ; stride + mov eax,[es:40] + mov [es:8],eax ; buffer + xor eax,eax + mov [es:12],eax + mov ax,0x4F15 + mov bl,1 + xor cx,cx + xor dx,dx + mov di,0x10 + int 0x10 + mov al,[vbe_has_edid] + shl al,1 + or [es:0],al + + ret + +vbe_bad: + mov byte [es:di],0 + ret + +vbe_failed: + mov si,vbe_s_failed + call vbe_print_string + jmp vbe_init.select_loop + +vbe_print_newline: + pusha + mov ah,0xE + mov al,13 + int 0x10 + mov ah,0xE + mov al,10 + int 0x10 + popa + ret + +vbe_print_space: + pusha + mov ah,0xE + mov al,' ' + int 0x10 + popa + ret + +vbe_print_string: ; Input - SI. + pusha + .loop: + lodsb + or al,al + jz .done + mov ah,0xE + int 0x10 + jmp .loop + .done: + popa + ret + +vbe_print_decimal: ; Input - AX. + pusha + mov bx,.buffer + mov cx,10 + .next: + xor dx,dx + div cx + add dx,'0' + mov [bx],dl + inc bx + cmp ax,0 + jne .next + .loop: + dec bx + mov al,[bx] + mov ah,0xE + int 0x10 + cmp bx,.buffer + jne .loop + popa + ret + .buffer: db 0, 0, 0, 0, 0 + +vbe_set_highlighted_line: ; Input - CX + pusha + mov ax,0xB800 + mov fs,ax + mov di,1 + mov dx,(80 * 25) + .clear_loop: + mov byte [fs:di],0x07 + add di,2 + dec dx + cmp dx,0 + jne .clear_loop + mov ax,cx + add ax,2 + mov cx,160 + mul cx + mov dx,80 + mov di,ax + inc di + .highlight_loop: + mov byte [fs:di],0x70 + add di,2 + dec dx + cmp dx,0 + jne .highlight_loop + popa + ret + +vbe_s_select_video_mode: db 'Select a video mode: [use up/down then press enter]',13,10,0 +vbe_s_left_bracket: db '(',0 +vbe_s_right_bracket: db ') ',0 +vbe_s_by: db 'x',0 +vbe_s_space: db ' ',0 +vbe_s_bpp: db 'bpp',0 +vbe_s_failed: db 'This graphics mode could not be selected. Please try a different one.',13,10,0 + +vbe_best_width: dw 0 +vbe_best_height: dw 0 +vbe_best_mode: dw 0 +vbe_has_edid: db 0 diff --git a/desktop/api.cpp b/desktop/api.cpp new file mode 100644 index 0000000..5fd9798 --- /dev/null +++ b/desktop/api.cpp @@ -0,0 +1,1591 @@ +#define ES_API +#define ES_FORWARD(x) x +#define ES_EXTERN_FORWARD extern "C" +#define ES_DIRECT_API +#include + +extern "C" void EsUnimplemented(); +#define alloca __builtin_alloca +#define FT_EXPORT(x) extern "C" x + +#ifdef USE_STB_IMAGE +#define STB_IMAGE_IMPLEMENTATION +#define STBI_MALLOC(sz) EsCRTmalloc(sz) +#define STBI_REALLOC(p,newsz) EsCRTrealloc(p,newsz) +#define STBI_FREE(p) EsCRTfree(p) +#define STBI_NO_STDIO +#define STBI_ONLY_PNG +#define STBI_ONLY_JPEG +#define STBI_NO_LINEAR +#define STB_IMAGE_STATIC +#include +#endif + +#include + +#define SHARED_COMMON_WANT_ALL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IMPLEMENTATION +#include +#undef IMPLEMENTATION + +struct EnumString { const char *cName; int value; }; +#include + +#define ANIMATION_TIME_SCALE (1) + +#define DESKTOP_MSG_SET_TITLE (1) +#define DESKTOP_MSG_SET_ICON (2) +#define DESKTOP_MSG_REQUEST_SAVE (3) +#define DESKTOP_MSG_COMPLETE_SAVE (4) +#define DESKTOP_MSG_SHOW_IN_FILE_MANAGER (5) +#define DESKTOP_MSG_ANNOUNCE_PATH_MOVED (6) +#define DESKTOP_MSG_RUN_TEMPORARY_APPLICATION (7) +#define DESKTOP_MSG_REQUEST_SHUTDOWN (8) +#define DESKTOP_MSG_START_APPLICATION (9) + +extern "C" uintptr_t ProcessorTLSRead(uintptr_t offset); + +struct EsFileStore { +#define FILE_STORE_HANDLE (1) +#define FILE_STORE_PATH (2) + uint8_t type; + + bool operationComplete; + uint32_t handles; + EsError error; + + union { + EsHandle handle; + + struct { + char *path; + size_t pathBytes; + }; + }; +}; + +struct GlobalData { + uint32_t clickChainTimeoutMs; +}; + +struct ThreadLocalStorage { + // This must be the first field. + ThreadLocalStorage *self; + + uint64_t id; +}; + +struct MountPoint : EsMountPoint { + EsVolumeInformation information; + bool removing; +}; + +struct Timer { + EsTimer id; + double afterMs; + EsTimerCallbackFunction callback; + EsGeneric argument; +}; + +EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node); + +struct { + Array systemConfigurationGroups; + Array mountPoints; + bool foundBootFileSystem; + EsProcessStartupInformation *startupInformation; + uint64_t systemConstants[ES_SYSTEM_CONSTANT_COUNT]; + GlobalData *global; + + EsMutex messageMutex; + volatile uintptr_t messageMutexThreadID; + + Array<_EsMessageWithObject> postBox; + EsMutex postBoxMutex; + + Array timers; + EsMutex timersMutex; + EsHandle timersThread; + EsHandle timersEvent; + + EsSpinlock performanceTimerStackLock; +#define PERFORMANCE_TIMER_STACK_SIZE (100) + uint64_t performanceTimerStack[PERFORMANCE_TIMER_STACK_SIZE]; + uintptr_t performanceTimerStackCount; +} api; + +ptrdiff_t tlsStorageOffset; + +#include "syscall.cpp" + +// Miscellanous forward declarations. +void MaybeDestroyElement(EsElement *element); +const char *GetConstantString(const char *key); +void UndoManagerDestroy(EsUndoManager *manager); +int TextGetStringWidth(const EsTextStyle *style, const char *string, size_t stringBytes); +struct APIInstance *InstanceSetup(EsInstance *instance); +EsTextStyle TextPlanGetPrimaryStyle(EsTextPlan *plan); +EsFileStore *FileStoreCreateFromPath(const char *path, size_t pathBytes); + +struct ProcessMessageTiming { + double startLogic, endLogic; + double startLayout, endLayout; + double startPaint, endPaint; + double startUpdate, endUpdate; +}; + +struct EsUndoManager { + EsInstance *instance; + + Array undoStack; + Array redoStack; + +#define UNDO_MANAGER_STATE_NORMAL (0) +#define UNDO_MANAGER_STATE_UNDOING (1) +#define UNDO_MANAGER_STATE_REDOING (2) + int state; +}; + +struct APIInstance { + HashStore commands; + + EsApplicationStartupInformation *startupInformation; + EsHandle mainWindowHandle; + + char *documentPath; + size_t documentPathBytes; + uint32_t instanceClass; + + EsCommand commandDelete, + commandSelectAll, + commandCopy, + commandCut, + commandPaste, + commandUndo, + commandRedo, + commandSave, + commandShowInFileManager; + + const char *applicationName; + size_t applicationNameBytes; + + struct InspectorWindow *attachedInspector; + + EsUndoManager undoManager; + EsUndoManager *activeUndoManager; + + EsFileStore *fileStore; + + union { + EsInstanceClassEditorSettings editorSettings; + EsInstanceClassViewerSettings viewerSettings; + }; +}; + +MountPoint *NodeAddMountPoint(const char *prefix, size_t prefixBytes, EsHandle base, bool queryInformation) { + MountPoint mountPoint = {}; + EsAssert(prefixBytes < sizeof(mountPoint.prefix)); + EsMemoryCopy(mountPoint.prefix, prefix, prefixBytes); + mountPoint.base = base; + mountPoint.prefixBytes = prefixBytes; + + if (queryInformation) { + EsSyscall(ES_SYSCALL_VOLUME_GET_INFORMATION, base, (uintptr_t) &mountPoint.information, 0, 0); + } + + return api.mountPoints.Add(mountPoint); +} + +MountPoint *NodeFindMountPoint(const char *prefix, size_t prefixBytes) { + for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { + MountPoint *mountPoint = &api.mountPoints[i]; + + if (prefixBytes >= mountPoint->prefixBytes + && 0 == EsMemoryCompare(prefix, mountPoint->prefix, mountPoint->prefixBytes) + && !mountPoint->removing) { + return mountPoint; + } + } + + return nullptr; +} + +bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, EsVolumeInformation *information) { + MountPoint *mountPoint = NodeFindMountPoint(prefix, prefixBytes); + if (!mountPoint) return false; + EsMemoryCopy(information, &mountPoint->information, sizeof(EsVolumeInformation)); + return true; +} + +void EsMountPointEnumerate(EsMountPointEnumerationCallbackFunction callback, EsGeneric context) { + for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { + MountPoint *mountPoint = &api.mountPoints[i]; + callback(mountPoint->prefix, mountPoint->prefixBytes, context); + } +} + +EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node) { + EsMountPoint *mountPoint = NodeFindMountPoint(path, pathBytes); + + if (!mountPoint) { + return ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME; + } + + node->handle = mountPoint->base; + path += mountPoint->prefixBytes; + pathBytes -= mountPoint->prefixBytes; + + return EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) path, pathBytes, flags, (uintptr_t) node); +} + +EsSystemConfigurationItem *SystemConfigurationGetItem(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes) { + if (keyBytes == -1) keyBytes = EsCStringLength(key); + + for (uintptr_t i = 0; i < group->itemCount; i++) { + if (0 == EsStringCompareRaw(key, keyBytes, group->items[i].key, group->items[i].keyBytes)) { + return group->items + i; + } + } + + return nullptr; +} + +EsSystemConfigurationGroup *SystemConfigurationGetGroup(const char *section, ptrdiff_t sectionBytes) { + if (sectionBytes == -1) sectionBytes = EsCStringLength(section); + + for (uintptr_t i = 0; i < api.systemConfigurationGroups.Length(); i++) { + if (0 == EsStringCompareRaw(section, sectionBytes, api.systemConfigurationGroups[i].section, api.systemConfigurationGroups[i].sectionBytes)) { + return &api.systemConfigurationGroups[i]; + } + } + + return nullptr; +} + +char *EsSystemConfigurationGroupReadString(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, size_t *valueBytes) { + EsSystemConfigurationItem *item = SystemConfigurationGetItem(group, key, keyBytes); + if (!item) { if (valueBytes) *valueBytes = 0; return nullptr; } + if (valueBytes) *valueBytes = item->valueBytes; + char *copy = (char *) EsHeapAllocate(item->valueBytes + 1, false); + copy[item->valueBytes] = 0; + EsMemoryCopy(copy, item->value, item->valueBytes); + return copy; +} + +int64_t EsSystemConfigurationGroupReadInteger(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, int64_t defaultValue) { + EsSystemConfigurationItem *item = SystemConfigurationGetItem(group, key, keyBytes); + if (!item) return defaultValue; + return EsIntegerParse(item->value, item->valueBytes); +} + +char *EsSystemConfigurationReadString(const char *section, ptrdiff_t sectionBytes, const char *key, ptrdiff_t keyBytes, size_t *valueBytes) { + EsSystemConfigurationGroup *group = SystemConfigurationGetGroup(section, sectionBytes); + if (!group) { if (valueBytes) *valueBytes = 0; return nullptr; } + return EsSystemConfigurationGroupReadString(group, key, keyBytes, valueBytes); +} + +int64_t EsSystemConfigurationReadInteger(const char *section, ptrdiff_t sectionBytes, const char *key, ptrdiff_t keyBytes, int64_t defaultValue) { + EsSystemConfigurationGroup *group = SystemConfigurationGetGroup(section, sectionBytes); + if (!group) return defaultValue; + return EsSystemConfigurationGroupReadInteger(group, key, keyBytes, defaultValue); +} + +void SystemConfigurationLoad(char *file, size_t fileBytes) { + EsINIState s = {}; + s.buffer = file; + s.bytes = fileBytes; + + EsSystemConfigurationGroup *group = nullptr; + + while (EsINIParse(&s)) { + if (!s.keyBytes) { + EsSystemConfigurationGroup _group = {}; + api.systemConfigurationGroups.Add(_group); + group = &api.systemConfigurationGroups.Last(); + group->section = (char *) EsHeapAllocate(s.sectionBytes, false); + EsMemoryCopy(group->section, s.section, (group->sectionBytes = s.sectionBytes)); + group->sectionClass = (char *) EsHeapAllocate(s.sectionClassBytes, false); + EsMemoryCopy(group->sectionClass, s.sectionClass, (group->sectionClassBytes = s.sectionClassBytes)); + } else if (group) { + EsSystemConfigurationItem item = {}; + item.key = (char *) EsHeapAllocate(s.keyBytes, false); + EsMemoryCopy(item.key, s.key, (item.keyBytes = s.keyBytes)); + item.value = (char *) EsHeapAllocate(s.valueBytes + 1, false); + item.value[s.valueBytes] = 0; + EsMemoryCopy(item.value, s.value, (item.valueBytes = s.valueBytes)); + Array items = { group->items }; + items.Add(item); + group->items = items.array; + group->itemCount++; + } + } + + EsHeapFree(file); +} + +EsSystemConfigurationGroup *EsSystemConfigurationReadAll(size_t *groupCount) { + EsMessageMutexCheck(); + *groupCount = api.systemConfigurationGroups.Length(); + return api.systemConfigurationGroups.array; +} + +uint8_t *ApplicationStartupInformationToBuffer(const EsApplicationStartupInformation *information, size_t *dataBytes = nullptr) { + EsApplicationStartupInformation copy = *information; + if (copy.filePathBytes == -1) copy.filePathBytes = EsCStringLength(copy.filePath); + size_t bytes = 1 + sizeof(EsApplicationStartupInformation) + copy.filePathBytes; + uint8_t *buffer = (uint8_t *) EsHeapAllocate(bytes, false); + buffer[0] = DESKTOP_MSG_START_APPLICATION; + EsMemoryCopy(buffer + 1, ©, sizeof(EsApplicationStartupInformation)); + EsMemoryCopy(buffer + 1 + sizeof(EsApplicationStartupInformation), copy.filePath, copy.filePathBytes); + if (dataBytes) *dataBytes = bytes; + return buffer; +} + +void EsApplicationStart(const EsApplicationStartupInformation *information) { + size_t bufferBytes; + uint8_t *buffer = ApplicationStartupInformationToBuffer(information, &bufferBytes); + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) buffer, bufferBytes, 0, 0); +} + +EsApplicationStartupInformation *ApplicationStartupInformationParse(const void *data, size_t dataBytes) { + EsApplicationStartupInformation *startupInformation = (EsApplicationStartupInformation *) data; + + if (sizeof(EsApplicationStartupInformation) <= dataBytes) { + dataBytes -= sizeof(EsApplicationStartupInformation); + if ((size_t) startupInformation->filePathBytes > dataBytes) goto error; + dataBytes -= startupInformation->filePathBytes; + if (dataBytes) goto error; + startupInformation->filePath = (const char *) (startupInformation + 1); + } else { + error:; + EsPrint("Warning: received corrupted startup information.\n"); + return nullptr; + } + + return startupInformation; +} + +void EsInstanceSetClassEditor(EsInstance *_instance, const EsInstanceClassEditorSettings *settings) { + APIInstance *instance = (APIInstance *) _instance->_private; + instance->instanceClass = ES_INSTANCE_CLASS_EDITOR; + instance->editorSettings = *settings; + + if (instance->editorSettings.newDocumentTitleBytes == -1) { + instance->editorSettings.newDocumentTitleBytes = EsCStringLength(instance->editorSettings.newDocumentTitle); + } + + if (instance->editorSettings.newDocumentFileNameBytes == -1) { + instance->editorSettings.newDocumentFileNameBytes = EsCStringLength(instance->editorSettings.newDocumentFileName); + } +} + +void EsInstanceSetClassViewer(EsInstance *_instance, const EsInstanceClassViewerSettings *) { + APIInstance *instance = (APIInstance *) _instance->_private; + instance->instanceClass = ES_INSTANCE_CLASS_VIEWER; +} + +#define CHARACTER_MONO (1) // 1 bit per pixel. +#define CHARACTER_SUBPIXEL (2) // 24 bits per pixel; each byte specifies the alpha of each RGB channel. +#define CHARACTER_IMAGE (3) // 32 bits per pixel, ARGB. +#define CHARACTER_RECOLOR (4) // 32 bits per pixel, AXXX. + +#include "renderer.cpp" +#include "theme.cpp" + +#define TEXT_RENDERER +#include "text.cpp" +#undef TEXT_RENDERER + +#include "gui.cpp" + +#ifndef NO_API_TABLE +const void *const apiTable[] = { +#include +}; +#endif + +extern "C" void _init(); +typedef void (*StartFunction)(); + +const char *EnumLookupNameFromValue(const EnumString *array, int value) { + if (array[0].value == -1) { + return array[value].cName; + } else { + // The values are non-linear, and we have to search the array. + + for (uintptr_t i = 0; array[i].cName; i++) { + if (array[i].value == value) { + return array[i].cName; + } + } + + EsAssert(false); + return nullptr; + } +} + +void EsMessageMutexAcquire() { + EsMutexAcquire(&api.messageMutex); + api.messageMutexThreadID = EsThreadGetID(ES_CURRENT_THREAD); +} + +void EsMessageMutexRelease() { + api.messageMutexThreadID = 0; + EsMutexRelease(&api.messageMutex); +} + +void EsMessageMutexCheck() { + EsAssert(api.messageMutexThreadID == EsThreadGetID(ES_CURRENT_THREAD)); // Expected message mutex to be acquired. +} + +int EsMessageSend(EsElement *element, EsMessage *message) { + int response = 0; + + if (element->messageUser) { + response = element->messageUser(element, message); + } + + bool handledByUser = response; + + if (response == 0 && element->messageClass) { + response = element->messageClass(element, message); + } + + if (element->state & UI_STATE_INSPECTING) { + InspectorNotifyElementEvent(element, "message", "Element processed message '%z' with response %i%z.\n", + EnumLookupNameFromValue(enumStrings_EsMessageType, message->type), response, handledByUser ? " (from user callback)" : ""); + } + + if (message->type >= ES_MSG_STATE_CHANGE_MESSAGE_START && message->type <= ES_MSG_STATE_CHANGE_MESSAGE_END) { + ((EsElement *) element)->MaybeRefreshStyle(); + } + + return response; +} + +void _EsPathAnnouncePathMoved(EsInstance *instance, const char *oldPath, ptrdiff_t oldPathBytes, const char *newPath, ptrdiff_t newPathBytes) { + if (oldPathBytes == -1) oldPathBytes = EsCStringLength(oldPath); + if (newPathBytes == -1) newPathBytes = EsCStringLength(newPath); + size_t bufferBytes = 1 + sizeof(uintptr_t) * 2 + oldPathBytes + newPathBytes; + char *buffer = (char *) EsHeapAllocate(bufferBytes, false); + buffer[0] = DESKTOP_MSG_ANNOUNCE_PATH_MOVED; + EsMemoryCopy(buffer + 1, &oldPathBytes, sizeof(uintptr_t)); + EsMemoryCopy(buffer + 1 + sizeof(uintptr_t), &newPathBytes, sizeof(uintptr_t)); + EsMemoryCopy(buffer + 1 + sizeof(uintptr_t) * 2, oldPath, oldPathBytes); + EsMemoryCopy(buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes, newPath, newPathBytes); + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) buffer, bufferBytes, instance->window->handle, 0); + EsHeapFree(buffer); +} + +void EsApplicationRunTemporary(EsInstance *instance, const char *path, ptrdiff_t pathBytes) { + if (pathBytes == -1) pathBytes = EsCStringLength(path); + char *buffer = (char *) EsHeapAllocate(pathBytes + 1, false); + buffer[0] = DESKTOP_MSG_RUN_TEMPORARY_APPLICATION; + EsMemoryCopy(buffer + 1, path, pathBytes); + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) buffer, pathBytes + 1, instance->window->handle, 0); + EsHeapFree(buffer); +} + +void EsSystemShowShutdownDialog(EsInstance *instance) { + uint8_t message = DESKTOP_MSG_REQUEST_SHUTDOWN; + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) &message, 1, instance->window->handle, 0); +} + +void InstanceSave(EsInstance *_instance) { + APIInstance *instance = (APIInstance *) _instance->_private; + EsAssert(instance->instanceClass == ES_INSTANCE_CLASS_EDITOR); + size_t bufferBytes = instance->editorSettings.newDocumentFileNameBytes + 1; + char *buffer = (char *) EsHeapAllocate(bufferBytes, false); + buffer[0] = DESKTOP_MSG_REQUEST_SAVE; + EsMemoryCopy(buffer + 1, instance->editorSettings.newDocumentFileName, instance->editorSettings.newDocumentFileNameBytes); + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) buffer, bufferBytes, _instance->window->handle, 0); + EsHeapFree(buffer); +} + +void FileStoreCloseHandle(EsFileStore *fileStore) { + EsMessageMutexCheck(); // TODO Remove this limitation? + EsAssert(fileStore->handles < 0x80000000); + + if (--fileStore->handles) { + return; + } + + if (fileStore->type == FILE_STORE_HANDLE) { + if (fileStore->handle) { + EsHandleClose(fileStore->handle); + } + } else if (fileStore->type == FILE_STORE_PATH) { + // The path is stored after the file store allocation. + } + + EsHeapFree(fileStore); +} + +EsFileStore *FileStoreCreateFromPath(const char *path, size_t pathBytes) { + EsFileStore *fileStore = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore) + pathBytes, false); + EsMemoryZero(fileStore, sizeof(EsFileStore)); + fileStore->type = FILE_STORE_PATH; + fileStore->handles = 1; + fileStore->error = ES_SUCCESS; + fileStore->path = (char *) (fileStore + 1); + fileStore->pathBytes = pathBytes; + EsMemoryCopy(fileStore->path, path, pathBytes); + return fileStore; +} + +void InstanceCreateFileStore(APIInstance *instance, EsHandle handle) { + if (instance->fileStore) FileStoreCloseHandle(instance->fileStore); + instance->fileStore = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore), true); + instance->fileStore->type = FILE_STORE_HANDLE; + instance->fileStore->handle = handle; + instance->fileStore->error = ES_SUCCESS; + instance->fileStore->handles = 1; +} + +void InstancePostOpenMessage(EsInstance *_instance, bool update) { + APIInstance *instance = (APIInstance *) _instance->_private; + EsMessage m = { ES_MSG_INSTANCE_OPEN }; + m.instanceOpen.instance = _instance; + m.instanceOpen.name = instance->startupInformation->filePath; + m.instanceOpen.nameBytes = instance->startupInformation->filePathBytes; + m.instanceOpen.file = instance->fileStore; + m.instanceOpen.update = update; + EsMessagePost(nullptr, &m); +} + +APIInstance *InstanceSetup(EsInstance *instance) { + APIInstance *apiInstance = (APIInstance *) EsHeapAllocate(sizeof(APIInstance), true); + + instance->_private = apiInstance; + + instance->undoManager = &apiInstance->undoManager; + instance->undoManager->instance = instance; + apiInstance->activeUndoManager = instance->undoManager; + + EsCommandRegister(&apiInstance->commandDelete, instance, nullptr, ES_COMMAND_DELETE, "Del"); + EsCommandRegister(&apiInstance->commandSelectAll, instance, nullptr, ES_COMMAND_SELECT_ALL, "Ctrl+A"); + EsCommandRegister(&apiInstance->commandCopy, instance, nullptr, ES_COMMAND_COPY, "Ctrl+C|Ctrl+Ins"); + EsCommandRegister(&apiInstance->commandCut, instance, nullptr, ES_COMMAND_CUT, "Ctrl+X|Shift+Del"); + EsCommandRegister(&apiInstance->commandPaste, instance, nullptr, ES_COMMAND_PASTE, "Ctrl+V|Shift+Ins"); + EsCommandRegister(&apiInstance->commandUndo, instance, nullptr, ES_COMMAND_UNDO, "Ctrl+Z"); + EsCommandRegister(&apiInstance->commandRedo, instance, nullptr, ES_COMMAND_REDO, "Ctrl+Y"); + EsCommandRegister(&apiInstance->commandSave, instance, nullptr, ES_COMMAND_SAVE, "Ctrl+S"); + EsCommandRegister(&apiInstance->commandShowInFileManager, instance, nullptr, ES_COMMAND_SHOW_IN_FILE_MANAGER, "Ctrl+Shift+O"); + + EsCommandSetCallback(&apiInstance->commandUndo, [] (EsInstance *instance, EsElement *, EsCommand *) { + EsUndoInvokeGroup(((APIInstance *) instance->_private)->activeUndoManager, false); + }); + + EsCommandSetCallback(&apiInstance->commandRedo, [] (EsInstance *instance, EsElement *, EsCommand *) { + EsUndoInvokeGroup(((APIInstance *) instance->_private)->activeUndoManager, true); + }); + + EsCommandSetCallback(&apiInstance->commandSave, [] (EsInstance *instance, EsElement *, EsCommand *) { + InstanceSave(instance); + }); + + EsCommandSetCallback(&apiInstance->commandShowInFileManager, [] (EsInstance *instance, EsElement *, EsCommand *) { + char buffer[1]; + buffer[0] = DESKTOP_MSG_SHOW_IN_FILE_MANAGER; + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) buffer, 1, instance->window->handle, 0); + }); + + return apiInstance; +} + +EsInstance *_EsInstanceCreate(size_t bytes, EsMessage *message, const char *applicationName, ptrdiff_t applicationNameBytes) { + if (applicationNameBytes == -1) { + applicationNameBytes = EsCStringLength(applicationName); + } + + EsInstance *instance = (EsInstance *) EsHeapAllocate(bytes, true); + EsAssert(bytes >= sizeof(EsInstance)); + APIInstance *apiInstance = InstanceSetup(instance); + apiInstance->applicationName = applicationName; + apiInstance->applicationNameBytes = applicationNameBytes; + + if (message && message->createInstance.data != ES_INVALID_HANDLE && message->createInstance.dataBytes > 1) { + apiInstance->startupInformation = (EsApplicationStartupInformation *) EsHeapAllocate(message->createInstance.dataBytes, false); + + if (apiInstance->startupInformation) { + void *buffer = EsHeapAllocate(message->createInstance.dataBytes, false); + EsConstantBufferRead(message->createInstance.data, buffer); + EsMemoryCopy(apiInstance->startupInformation, (char *) buffer + 1, message->createInstance.dataBytes - 1); + EsHeapFree(buffer); + + if (!ApplicationStartupInformationParse(apiInstance->startupInformation, message->createInstance.dataBytes - 1)) { + EsHeapFree(apiInstance->startupInformation); + apiInstance->startupInformation = nullptr; + } else { + // Duplicate the file path, so that it can be modified in response to ES_MSG_INSTANCE_DOCUMENT_RENAMED messages. + char *filePath = (char *) EsHeapAllocate(apiInstance->startupInformation->filePathBytes, false); + EsMemoryCopy(filePath, apiInstance->startupInformation->filePath, apiInstance->startupInformation->filePathBytes); + apiInstance->startupInformation->filePath = filePath; + } + } + } + + apiInstance->mainWindowHandle = message->createInstance.window; + instance->window = EsWindowCreate(instance, ES_WINDOW_NORMAL); + EsWindowSetTitle(instance->window, nullptr, 0); + + if (apiInstance->startupInformation && apiInstance->startupInformation->readHandle) { + InstanceCreateFileStore(apiInstance, apiInstance->startupInformation->readHandle); + InstancePostOpenMessage(instance, false); + EsWindowSetTitle(instance->window, apiInstance->startupInformation->filePath, apiInstance->startupInformation->filePathBytes); + EsCommandSetDisabled(&apiInstance->commandShowInFileManager, false); + } + + return instance; +} + +const EsApplicationStartupInformation *EsInstanceGetStartupInformation(EsInstance *_instance) { + APIInstance *instance = (APIInstance *) _instance->_private; + return instance->startupInformation; +} + +void EsInstanceDestroy(EsInstance *_instance) { + UndoManagerDestroy(_instance->undoManager); + EsAssert(_instance->window->instance == _instance); + _instance->window->destroyInstanceAfterClose = true; + EsElementDestroy(_instance->window); +} + +EsInstance *InstanceFromWindowID(uint64_t id) { + for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) { + if (EsSyscall(ES_SYSCALL_WINDOW_GET_ID, gui.allWindows[i]->handle, 0, 0, 0) == id) { + return gui.allWindows[i]->instance; + } + } + + return nullptr; +} + +EsError GetMessage(_EsMessageWithObject *message) { + // Process posted messages first, + // so that messages like ES_MSG_WINDOW_DESTROYED are received last. + + bool gotMessage = false; + EsMutexAcquire(&api.postBoxMutex); + + if (api.postBox.Length()) { + *message = api.postBox[0]; + api.postBox.Delete(0); + gotMessage = true; + } + + EsMutexRelease(&api.postBoxMutex); + if (gotMessage) return ES_SUCCESS; + + return EsSyscall(ES_SYSCALL_MESSAGE_GET, (uintptr_t) message, 0, 0, 0); +} + +EsMessage *EsMessageReceive() { + static _EsMessageWithObject message = {}; + EsMessageMutexCheck(); + + while (true) { + TS("Process message\n"); + + if (message.message.type == ES_MSG_INSTANCE_CREATE) { + if (message.message.createInstance.data != ES_INVALID_HANDLE) { + EsHandleClose(message.message.createInstance.data); + } + } else if (message.message.type == ES_MSG_INSTANCE_OPEN) { + // TODO Support multithreaded file operations. + EsAssert(message.message.instanceOpen.file->operationComplete); + } else if (message.message.type == ES_MSG_INSTANCE_SAVE) { + // TODO Support multithreaded file operations. + EsAssert(message.message.instanceSave.file->operationComplete); + FileStoreCloseHandle(message.message.instanceSave.file); + } else if (message.message.type == ES_MSG_APPLICATION_EXIT) { + EsProcessTerminateCurrent(); + } else if (message.message.type == ES_MSG_INSTANCE_DESTROY) { + APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private; + + if (instance->startupInformation && (instance->startupInformation->flags & ES_APPLICATION_STARTUP_SINGLE_INSTANCE_IN_PROCESS)) { + EsMessage m = { ES_MSG_APPLICATION_EXIT }; + EsMessagePost(nullptr, &m); + } + + if (instance->startupInformation) { + EsHeapFree((void *) instance->startupInformation->filePath); + } + + EsHeapFree(instance->startupInformation); + EsHeapFree(instance->documentPath); + + for (uintptr_t i = 0; i < instance->commands.Count(); i++) { + EsCommand *command = instance->commands[i]; + EsAssert(command->registered); + EsAssert(!ArrayLength(command->elements)); + Array elements = { command->elements }; + elements.Free(); + } + + instance->commands.Free(false); + if (instance->fileStore) FileStoreCloseHandle(instance->fileStore); + EsHeapFree(instance); + EsHeapFree(message.message.instanceDestroy.instance); + } else if (message.message.type == ES_MSG_UNREGISTER_FILE_SYSTEM) { + for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { + if (api.mountPoints[i].information.id == message.message.unregisterFileSystem.id) { + EsHandleClose(api.mountPoints[i].base); + api.mountPoints.Delete(i); + } + } + } + + EsMessageMutexRelease(); + + EsError error = GetMessage(&message); + + while (error != ES_SUCCESS) { + if (!gui.animationSleep && gui.animatingElements.Length()) { + EsMessageMutexAcquire(); + ProcessAnimations(); + EsMessageMutexRelease(); + } else { + EsSyscall(ES_SYSCALL_MESSAGE_WAIT, ES_WAIT_NO_TIMEOUT, 0, 0, 0); + } + + error = GetMessage(&message); + } + + EsMessageMutexAcquire(); + + EsMessageType type = message.message.type; + + if (type == ES_MSG_SYSTEM_CONSTANT_UPDATED) { + api.systemConstants[message.message.systemConstantUpdated.index] = message.message.systemConstantUpdated.newValue; + } + + if (type == ES_MSG_EYEDROP_REPORT) { + EsMessageSend((EsElement *) message.object, &message.message); + } else if (type == ES_MSG_TIMER) { + ((EsTimerCallbackFunction) message.message.user.context1.p)(message.message.user.context2); + } else if (type >= ES_MSG_WM_START && type <= ES_MSG_WM_END) { +#if 0 + ProcessMessageTiming timing = {}; + double start = EsTimeStampMs(); + UIProcessWindowManagerMessage((EsWindow *) message.object, &message.message, &timing); + EsPrint("Processed message from WM %x in %Fms (%Fms logic, %Fms layout, %Fms paint, %Fms update screen).\n", + type, EsTimeStampMs() - start, + timing.endLogic - timing.startLogic, + timing.endLayout - timing.startLayout, + timing.endPaint - timing.startPaint, + timing.endUpdate - timing.startUpdate); +#endif + + if (message.object) { + UIProcessWindowManagerMessage((EsWindow *) message.object, &message.message, nullptr); + } + } else if (type == ES_MSG_TAB_INSPECT_UI) { + EsInstance *_instance = InstanceFromWindowID(message.message.tabOperation.id); + + if (_instance) { + APIInstance *instance = (APIInstance *) _instance->_private; + + if (instance->attachedInspector) { + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, instance->attachedInspector->window->handle, 0, 0, ES_WINDOW_PROPERTY_FOCUSED); + } else { + EsWindowCreate(_instance, ES_WINDOW_INSPECTOR); + } + } + } else if (type == ES_MSG_TAB_CLOSE_REQUEST) { + EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id); + if (instance) EsInstanceDestroy(instance); + } else if (type == ES_MSG_INSTANCE_SAVE_RESPONSE) { + EsMessage m = {}; + m.type = ES_MSG_INSTANCE_SAVE; + + m.instanceSave.file = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore), true); + m.instanceSave.file->error = message.message.tabOperation.error; + m.instanceSave.file->handle = message.message.tabOperation.handle; + m.instanceSave.file->type = FILE_STORE_HANDLE; + m.instanceSave.file->handles = 1; + m.instanceSave.instance = InstanceFromWindowID(message.message.tabOperation.id); + + if (m.instanceSave.file->error == ES_SUCCESS) { + EsMemoryCopy(&message.message, &m, sizeof(EsMessage)); + return &message.message; + } else { + EsInstanceSaveComplete(&m, false); + } + + EsMemoryCopy(&message.message, &m, sizeof(EsMessage)); + } else if (type == ES_MSG_INSTANCE_DOCUMENT_RENAMED) { + char *buffer = (char *) EsHeapAllocate(message.message.tabOperation.bytes, false); + EsConstantBufferRead(message.message.tabOperation.handle, buffer); + EsInstance *_instance = InstanceFromWindowID(message.message.tabOperation.id); + + if (_instance) { + APIInstance *instance = (APIInstance *) _instance->_private; + EsHeapFree((void *) instance->startupInformation->filePath); + instance->startupInformation->filePath = buffer; + instance->startupInformation->filePathBytes = message.message.tabOperation.bytes; + EsWindowSetTitle(_instance->window, buffer, message.message.tabOperation.bytes); + } else { + EsHeapFree(buffer); + } + + EsHandleClose(message.message.tabOperation.handle); + } else if (type == ES_MSG_INSTANCE_DOCUMENT_UPDATED) { + EsInstance *_instance = InstanceFromWindowID(message.message.tabOperation.id); + + if (_instance) { + APIInstance *instance = (APIInstance *) _instance->_private; + + InstanceCreateFileStore(instance, message.message.tabOperation.handle); + + if (!message.message.tabOperation.isSource) { + InstancePostOpenMessage(_instance, true); + } + } else { + EsHandleClose(message.message.tabOperation.handle); + } + } else if (type == ES_MSG_REGISTER_FILE_SYSTEM) { + EsMessageRegisterFileSystem *m = &message.message.registerFileSystem; + + int64_t index = 1; // TODO This is incorrect! + + while (true) { + bool seen = false; + + for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { + if (index == EsIntegerParse(api.mountPoints[i].prefix, api.mountPoints[i].prefixBytes)) { + seen = true; + break; + } + } + + if (seen) { + index++; + } else { + break; + } + } + + bool isBootFileSystem = m->isBootFileSystem; + char prefix[16]; + size_t prefixBytes = EsStringFormat(prefix, sizeof(prefix), "%fd:", ES_STRING_FORMAT_SIMPLE, isBootFileSystem ? 0 : index); + + m->mountPoint = NodeAddMountPoint(prefix, prefixBytes, m->rootDirectory, true); + + if (isBootFileSystem) { + api.foundBootFileSystem = true; + } + + return &message.message; + } else if (type == ES_MSG_UNREGISTER_FILE_SYSTEM) { + for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { + if (api.mountPoints[i].information.id == message.message.unregisterFileSystem.id) { + message.message.unregisterFileSystem.mountPoint = &api.mountPoints[i]; + api.mountPoints[i].removing = true; + return &message.message; + } + } + } else { + return &message.message; + } + } +} + +void EsInstanceOpenComplete(EsMessage *message, bool success, const char *errorText, ptrdiff_t errorTextBytes) { + EsInstance *instance = message->instanceOpen.instance; + + if (!success || message->instanceOpen.file->error != ES_SUCCESS) { + if (errorTextBytes) { + EsDialogShowAlert(instance->window, INTERFACE_STRING(FileCannotOpen), + errorText, errorTextBytes, + ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON); + } else { + const char *errorMessage = interfaceString_FileLoadErrorUnknown; + + switch (message->instanceOpen.file->error) { + case ES_ERROR_DRIVE_ERROR_FILE_DAMAGED: + errorMessage = interfaceString_FileLoadErrorCorrupt; + break; + case ES_ERROR_DRIVE_CONTROLLER_REPORTED: + errorMessage = interfaceString_FileLoadErrorDrive; + break; + case ES_ERROR_INSUFFICIENT_RESOURCES: + errorMessage = interfaceString_FileLoadErrorResourcesLow; + break; + } + + EsDialogShowAlert(instance->window, INTERFACE_STRING(FileCannotOpen), + errorMessage, -1, ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON); + } + + // TODO Close the instance. + } else { + if (!message->instanceOpen.update) { + EsUndoClear(instance->undoManager); + } + + EsCommandSetDisabled(EsCommandByID(instance, ES_COMMAND_SAVE), true); + } + + EsAssert(!message->instanceOpen.file->operationComplete); + message->instanceOpen.file->operationComplete = true; +} + +void EsInstanceSaveComplete(EsMessage *message, bool success) { + if (message->instanceSave.file->error != ES_SUCCESS) { + success = false; + } + + if (success) { + message->instanceSave.file->error = EsFileControl(message->instanceSave.file->handle, + ES_FILE_CONTROL_NOTIFY_MONITORS | ES_FILE_CONTROL_FLUSH); + + if (message->instanceSave.file->error != ES_SUCCESS) { + success = false; + } + } + + EsInstance *instance = message->instanceSave.instance; + APIInstance *apiInstance = (APIInstance *) instance->_private; + + if (instance) { + char buffer[1]; + buffer[0] = DESKTOP_MSG_COMPLETE_SAVE; + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) buffer, 1, instance->window->handle, 0); + + if (success) { + EsCommandSetDisabled(EsCommandByID(instance, ES_COMMAND_SAVE), true); + EsRectangle bounds = EsElementGetWindowBounds(instance->window->toolbarSwitcher); + size_t messageBytes; + char *message = EsStringAllocateAndFormat(&messageBytes, "Saved to %s", // TODO Localization. + apiInstance->startupInformation->filePathBytes, apiInstance->startupInformation->filePath); + EsAnnouncementShow(instance->window, ES_FLAGS_DEFAULT, (bounds.l + bounds.r) / 2, bounds.b, message, messageBytes); + EsHeapFree(message); + } else { + const char *errorMessage = interfaceString_FileSaveErrorUnknown; + + switch (message->instanceSave.file->error) { + case ES_ERROR_FILE_DOES_NOT_EXIST: + case ES_ERROR_NODE_DELETED: + case ES_ERROR_FILE_PERMISSION_NOT_GRANTED: + case ES_ERROR_INCORRECT_NODE_TYPE: + errorMessage = interfaceString_FileSaveErrorFileDeleted; + break; + case ES_ERROR_DRIVE_ERROR_FILE_DAMAGED: + errorMessage = interfaceString_FileSaveErrorCorrupt; + break; + case ES_ERROR_DRIVE_CONTROLLER_REPORTED: + errorMessage = interfaceString_FileSaveErrorDrive; + break; + case ES_ERROR_COULD_NOT_RESIZE_FILE: + case ES_ERROR_FILE_TOO_FRAGMENTED: + errorMessage = interfaceString_FileSaveErrorTooLarge; + break; + case ES_ERROR_FILE_IN_EXCLUSIVE_USE: + case ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE: + case ES_ERROR_FILE_HAS_WRITERS: + errorMessage = interfaceString_FileSaveErrorConcurrentAccess; + break; + case ES_ERROR_DRIVE_FULL: + errorMessage = interfaceString_FileSaveErrorDriveFull; + break; + case ES_ERROR_INSUFFICIENT_RESOURCES: + errorMessage = interfaceString_FileSaveErrorResourcesLow; + break; + case ES_ERROR_FILE_ALREADY_EXISTS: + errorMessage = interfaceString_FileSaveErrorAlreadyExists; + break; + } + + EsDialogShowAlert(instance->window, INTERFACE_STRING(FileCannotSave), + errorMessage, -1, ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON); + } + } + + EsAssert(!message->instanceSave.file->operationComplete); + message->instanceSave.file->operationComplete = true; +} + +uint64_t EsSystemGetConstant(uintptr_t index) { + return api.systemConstants[index]; +} + +void ThreadInitialise() { + // TODO Memory leak: this structure is never freed. + // Perhaps the kernel should send a message when a user thread is terminated to its owner process? + + ThreadLocalStorage *local = (ThreadLocalStorage *) EsHeapAllocate(sizeof(ThreadLocalStorage), true); + local->id = EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_THREAD, 0, 0, 0); + local->self = local; + EsSyscall(ES_SYSCALL_PROCESS_SET_TLS, (uintptr_t) local - tlsStorageOffset, 0, 0, 0); +} + +#include "desktop.cpp" + +extern "C" void _start(EsProcessStartupInformation *_startupInformation) { + api.startupInformation = _startupInformation; + bool desktop = api.startupInformation->isDesktop; + +#ifndef NO_API_TABLE + if (desktop) { + // Initialise the API table. + + EsAssert(sizeof(apiTable) <= 0xF000); // API table is too large. + EsMemoryCopy(ES_API_BASE, apiTable, sizeof(apiTable)); + } +#endif + + { + // Initialise the API. + + _init(); + EsSyscall(ES_SYSCALL_SYSTEM_GET_CONSTANTS, (uintptr_t) api.systemConstants, 0, 0, 0); + EsRandomSeed(EsTimeStamp()); + ThreadInitialise(); + EsMessageMutexAcquire(); + + api.global = (GlobalData *) EsObjectMap(EsMemoryOpen(sizeof(GlobalData), EsLiteral("Desktop.Global"), ES_FLAGS_DEFAULT), + 0, sizeof(GlobalData), desktop ? ES_MAP_OBJECT_READ_WRITE : ES_MAP_OBJECT_READ_ONLY); + } + + bool uiProcess = false; + + if (desktop) { + EsPrint("Reached Desktop process.\n"); + + uiProcess = true; + + // Process messages until we find the boot file system. + + while (!api.foundBootFileSystem) { + EsMessage *message = EsMessageReceive(); + DesktopMessage(message); + } + + size_t fileSize; + void *file = EsFileReadAll(K_SYSTEM_CONFIGURATION, -1, &fileSize); + EsAssert(file); + SystemConfigurationLoad((char *) file, fileSize); + + _EsNodeInformation node; + char *path; + + path = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("fonts_path")); + NodeOpen(path, EsCStringLength(path), ES_FLAGS_DEFAULT, &node); + NodeAddMountPoint(EsLiteral("|Fonts:"), node.handle, false); + EsHeapFree(path); + + path = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("themes_path")); + NodeOpen(path, EsCStringLength(path), ES_FLAGS_DEFAULT, &node); + NodeAddMountPoint(EsLiteral("|Themes:"), node.handle, false); + EsHeapFree(path); + + api.global->clickChainTimeoutMs = EsIntegerParse(EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("click_chain_timeout_ms")), -1); + } else { + EsHandle initialMountPointsBuffer = EsSyscall(ES_SYSCALL_PROCESS_GET_CREATION_ARGUMENT, ES_CURRENT_PROCESS, CREATION_ARGUMENT_INITIAL_MOUNT_POINTS, 0, 0); + size_t initialMountPointCount = EsConstantBufferGetSize(initialMountPointsBuffer) / sizeof(EsMountPoint); + EsMountPoint *initialMountPoints = (EsMountPoint *) EsHeapAllocate(initialMountPointCount * sizeof(EsMountPoint), false); + EsConstantBufferRead(initialMountPointsBuffer, initialMountPoints); + + for (uintptr_t i = 0; i < initialMountPointCount; i++) { + NodeAddMountPoint(initialMountPoints[i].prefix, initialMountPoints[i].prefixBytes, initialMountPoints[i].base, true); + + if (0 == EsStringCompareRaw(initialMountPoints[i].prefix, initialMountPoints[i].prefixBytes, EsLiteral("|Themes:"))) { + uiProcess = true; + } + } + + EsHeapFree(initialMountPoints); + EsHandleClose(initialMountPointsBuffer); + + size_t bytes; + EsHandle handle = EsSyscall(ES_SYSCALL_SYSTEM_CONFIGURATION_READ, 0, 0, (uintptr_t) &bytes, 0); + EsAssert(handle); + char *buffer = (char *) EsHeapAllocate(bytes, false); + EsConstantBufferRead(handle, buffer); + EsHandleClose(handle); + SystemConfigurationLoad(buffer, bytes); + } + + if (uiProcess) { + // Initialise the GUI. + + theming.scale = api.systemConstants[ES_SYSTEM_CONSTANT_UI_SCALE] / 100.0f; + + size_t pathBytes, fileBytes; + char *path = EsSystemConfigurationReadString(EsLiteral("ui"), EsLiteral("theme"), &pathBytes); + void *file = EsFileMap(path, pathBytes, &fileBytes, ES_MAP_OBJECT_READ_ONLY); + EsAssert(ThemeLoadData(file, fileBytes)); + EsHeapFree(path); + + theming.cursors.width = ES_THEME_CURSORS_WIDTH; + theming.cursors.height = ES_THEME_CURSORS_HEIGHT; + theming.cursors.stride = ES_THEME_CURSORS_WIDTH * 4; + theming.cursors.bits = EsObjectMap(EsMemoryOpen(theming.cursors.height * theming.cursors.stride, EsLiteral(ES_THEME_CURSORS_NAME), 0), + 0, ES_MAP_OBJECT_ALL, ES_MAP_OBJECT_READ_ONLY); + theming.cursors.fullAlpha = true; + theming.cursors.readOnly = true; + } + + if (desktop) { + DesktopEntry(); + } else { + ((StartFunction) api.startupInformation->applicationStartAddress)(); + } + + EsThreadTerminate(ES_CURRENT_THREAD); +} + +void EsPanic(const char *cFormat, ...) { + char buffer[256]; + va_list arguments; + va_start(arguments, cFormat); + size_t bytes = EsStringFormatV(buffer, sizeof(buffer), cFormat, arguments); + va_end(arguments); + EsPrintDirect(buffer, bytes); + EsSyscall(ES_SYSCALL_PROCESS_CRASH, 0, 0, 0, 0); +} + +void EsAssertionFailure(const char *cFile, int line) { + EsPanic("Assertion failure at %z:%d.\n", cFile, line); +} + +void EsUnimplemented() { + EsAssert(false); +} + +void EsCommandAddButton(EsCommand *command, EsButton *button) { + EsAssert(command->registered); // Command has not been registered. + Array elements = { command->elements }; + elements.Add(button); + command->elements = elements.array; + EsButtonOnCommand(button, command->callback, command); + button->state |= UI_STATE_COMMAND_BUTTON; + EsElementSetDisabled(button, command->disabled); + EsButtonSetCheck(button, command->check); +} + +EsCommand *EsCommandRegister(EsCommand *command, EsInstance *_instance, EsCommandCallbackFunction callback, uint32_t stableID, + const char *cDefaultKeyboardShortcut, bool enabled) { + if (!command) { + command = (EsCommand *) EsHeapAllocate(sizeof(EsCommand), true); + command->allocated = true; + } + + APIInstance *instance = (APIInstance *) _instance->_private; + command->callback = callback; + command->registered = true; + command->stableID = stableID; + command->cKeyboardShortcut = cDefaultKeyboardShortcut; + command->disabled = !enabled; + EsAssert(!instance->commands.Get(&stableID)); // Command already registered. + *instance->commands.Put(&stableID) = command; + return command; +} + +void EsCommandSetDisabled(EsCommand *command, bool disabled) { + EsAssert(command->registered); // Command has not been registered. + + if (disabled != command->disabled) { + command->disabled = disabled; + + for (uintptr_t i = 0; i < ArrayLength(command->elements); i++) { + EsElementSetDisabled(command->elements[i], disabled); + } + } +} + +void EsCommandSetCheck(EsCommand *command, EsCheckState check, bool sendUpdatedMessage) { + EsAssert(command->registered); // Command has not been registered. + + if (check != command->check) { + command->check = check; + + for (uintptr_t i = 0; i < ArrayLength(command->elements); i++) { + EsButtonSetCheck((EsButton *) command->elements[i], check, sendUpdatedMessage); + } + } +} + +void EsCommandSetCallback(EsCommand *command, EsCommandCallbackFunction callback) { + EsAssert(command->registered); // Command has not been registered. + + if (callback != command->callback) { + command->callback = callback; + + for (uintptr_t i = 0; i < ArrayLength(command->elements); i++) { + if (command->elements[i]->state & UI_STATE_COMMAND_BUTTON) { + EsButtonOnCommand((EsButton *) command->elements[i], callback, command); + } + } + } + + if (!callback) { + EsCommandSetDisabled(command, true); + } +} + +EsCommand *EsCommandByID(EsInstance *_instance, uint32_t id) { + APIInstance *instance = (APIInstance *) _instance->_private; + EsCommand *command = instance->commands.Get1(&id); + EsAssert(command); // Invalid command ID. + return command; +} + +void EsPerformanceTimerPush() { + EsSpinlockAcquire(&api.performanceTimerStackLock); + + if (api.performanceTimerStackCount < PERFORMANCE_TIMER_STACK_SIZE) { + api.performanceTimerStack[api.performanceTimerStackCount++] = EsTimeStamp(); + } + + EsSpinlockRelease(&api.performanceTimerStackLock); +} + +double EsPerformanceTimerPop() { + double result = 0; + EsSpinlockAcquire(&api.performanceTimerStackLock); + + if (api.performanceTimerStackCount) { + uint64_t start = api.performanceTimerStack[--api.performanceTimerStackCount]; + result = ((double) (EsTimeStamp() - start) / (double) (api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND])) / 1000000.0; + } + + EsSpinlockRelease(&api.performanceTimerStackLock); + return result; +} + +uint32_t EsIconIDFromString(const char *string, ptrdiff_t stringBytes) { + if (!string) { + return 0; + } + + for (uintptr_t i = 0; i < sizeof(enumStrings_EsStandardIcon) / sizeof(enumStrings_EsStandardIcon[0]) - 1; i++) { + if (0 == EsStringCompare(enumStrings_EsStandardIcon[i].cName + 3, -1, string, stringBytes)) { + return i; + } + } + + return 0; +} + +struct UndoItemFooter { + EsUndoCallback callback; + ptrdiff_t bytes; + bool endOfGroup; +}; + +bool EsUndoPeek(EsUndoManager *manager, EsUndoCallback *callback, const void **item) { + EsMessageMutexCheck(); + Array *stack = manager->state == UNDO_MANAGER_STATE_UNDOING ? &manager->redoStack : &manager->undoStack; + + if (!stack->Length()) { + return false; + } + + UndoItemFooter *footer = (UndoItemFooter *) (stack->array + stack->Length()) - 1; + *callback = footer->callback; + *item = (uint8_t *) footer - footer->bytes; + return true; +} + +void EsUndoPop(EsUndoManager *manager) { + EsMessageMutexCheck(); + EsInstanceSetActiveUndoManager(manager->instance, manager); + Array *stack = manager->state == UNDO_MANAGER_STATE_UNDOING ? &manager->redoStack : &manager->undoStack; + size_t oldLength = stack->Length(); + EsAssert(oldLength); + UndoItemFooter *footer = (UndoItemFooter *) (stack->array + stack->Length()) - 1; + EsMessage m = {}; + m.type = ES_MSG_UNDO_CANCEL; + footer->callback((uint8_t *) footer - footer->bytes, manager, &m); + stack->SetLength(oldLength - footer->bytes - sizeof(UndoItemFooter)); + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_UNDO), !manager->undoStack.Length()); + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_REDO), !manager->redoStack.Length()); +} + +void EsUndoClear(EsUndoManager *manager) { + Array *stack = manager->state == UNDO_MANAGER_STATE_UNDOING ? &manager->redoStack : &manager->undoStack; + + while (stack->Length()) { + EsUndoPop(manager); + } +} + +void EsUndoPush(EsUndoManager *manager, EsUndoCallback callback, const void *item, size_t itemBytes) { + EsMessageMutexCheck(); + EsInstanceSetActiveUndoManager(manager->instance, manager); + + Array *stack = manager->state == UNDO_MANAGER_STATE_UNDOING ? &manager->redoStack : &manager->undoStack; + + UndoItemFooter footer = {}; + footer.callback = callback; + footer.bytes = (itemBytes + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); + + size_t oldLength = stack->Length(); + stack->SetLength(footer.bytes + sizeof(footer) + oldLength); + EsMemoryCopy(stack->array + oldLength, item, itemBytes); + EsMemoryCopy(stack->array + oldLength + footer.bytes, &footer, sizeof(footer)); + + if (manager->state == UNDO_MANAGER_STATE_NORMAL) { + // Clear the redo stack. + manager->state = UNDO_MANAGER_STATE_UNDOING; + EsUndoClear(manager); + manager->state = UNDO_MANAGER_STATE_NORMAL; + } + + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_UNDO), !manager->undoStack.Length()); + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_REDO), !manager->redoStack.Length()); + + if (manager->instance->undoManager == manager) { + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_SAVE), false); + } +} + +void EsUndoContinueGroup(EsUndoManager *manager) { + EsMessageMutexCheck(); + EsAssert(manager->state == UNDO_MANAGER_STATE_NORMAL); + Array stack = manager->undoStack; + if (!stack.Length()) return; + UndoItemFooter *footer = (UndoItemFooter *) (stack.array + stack.Length()) - 1; + footer->endOfGroup = false; +} + +void EsUndoEndGroup(EsUndoManager *manager) { + EsMessageMutexCheck(); + EsAssert(manager->state == UNDO_MANAGER_STATE_NORMAL); + Array stack = manager->undoStack; + if (!stack.Length()) return; + UndoItemFooter *footer = (UndoItemFooter *) (stack.array + stack.Length()) - 1; + footer->endOfGroup = true; +} + +bool EsUndoIsEmpty(EsUndoManager *manager, bool redo) { + EsMessageMutexCheck(); + EsAssert(manager->state == UNDO_MANAGER_STATE_NORMAL); + Array stack = redo ? manager->redoStack : manager->undoStack; + return stack.Length() == 0; +} + +void EsUndoInvokeGroup(EsUndoManager *manager, bool redo) { + EsMessageMutexCheck(); + EsInstanceSetActiveUndoManager(manager->instance, manager); + EsAssert(manager->state == UNDO_MANAGER_STATE_NORMAL); + manager->state = redo ? UNDO_MANAGER_STATE_REDOING : UNDO_MANAGER_STATE_UNDOING; + + Array *stack = redo ? &manager->redoStack : &manager->undoStack; + EsAssert(stack->Length()); + bool first = true; + + while (stack->Length()) { + size_t oldLength = stack->Length(); + UndoItemFooter *footer = (UndoItemFooter *) (stack->array + oldLength) - 1; + + if (!first && footer->endOfGroup) break; + first = false; + + EsMessage m = {}; + m.type = ES_MSG_UNDO_INVOKE; + footer->callback((uint8_t *) footer - footer->bytes, manager, &m); + stack->SetLength(oldLength - footer->bytes - sizeof(UndoItemFooter)); + } + + { + Array stack = redo ? manager->undoStack : manager->redoStack; + EsAssert(stack.Length()); + UndoItemFooter *footer = (UndoItemFooter *) (stack.array + stack.Length()) - 1; + footer->endOfGroup = true; + } + + manager->state = UNDO_MANAGER_STATE_NORMAL; + + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_UNDO), !manager->undoStack.Length()); + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_REDO), !manager->redoStack.Length()); +} + +bool EsUndoInUndo(EsUndoManager *manager) { + EsMessageMutexCheck(); + return manager->state != UNDO_MANAGER_STATE_NORMAL; +} + +void UndoManagerDestroy(EsUndoManager *manager) { + EsMessageMutexCheck(); + + EsAssert(manager->state == UNDO_MANAGER_STATE_NORMAL); + EsUndoClear(manager); + manager->state = UNDO_MANAGER_STATE_UNDOING; + EsUndoClear(manager); + manager->undoStack.Free(); + manager->redoStack.Free(); + manager->state = UNDO_MANAGER_STATE_NORMAL; + + if (((APIInstance *) manager->instance->_private)->activeUndoManager == manager) { + EsInstanceSetActiveUndoManager(manager->instance, manager->instance->undoManager); + } +} + +EsInstance *EsUndoGetInstance(EsUndoManager *manager) { + return manager->instance; +} + +void EsInstanceSetActiveUndoManager(EsInstance *_instance, EsUndoManager *manager) { + EsMessageMutexCheck(); + APIInstance *instance = (APIInstance *) _instance->_private; + + if (instance->activeUndoManager == manager) { + return; + } + + EsUndoEndGroup(instance->activeUndoManager); + instance->activeUndoManager = manager; + + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_UNDO), !manager->undoStack.Length()); + EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_REDO), !manager->redoStack.Length()); +} + +const void *EsEmbeddedFileGet(const char *cName, size_t *byteCount) { + uint64_t name = CalculateCRC64(cName, EsCStringLength(cName)); + + const BundleHeader *header = (const BundleHeader *) BUNDLE_FILE_MAP_ADDRESS; + const BundleFile *files = (const BundleFile *) (header + 1); + + if (header->signature != BUNDLE_SIGNATURE) { + return nullptr; + } + + for (uintptr_t i = 0; i < header->fileCount; i++) { + if (files[i].nameCRC64 == name) { + if (byteCount) { + *byteCount = files[i].bytes; + } + + return (const uint8_t *) header + files[i].offset; + } + } + + return nullptr; +} + +void TimersThread(EsGeneric) { + // TODO Maybe terminate this thread after ~10 seconds of no timers? + + double oldTimeMs = EsTimeStampMs(); + + while (true) { + double newTimeMs = EsTimeStampMs(); + double deltaTimeMs = newTimeMs - oldTimeMs; + oldTimeMs = newTimeMs; + + int64_t waitFor = ES_WAIT_NO_TIMEOUT; + + EsMutexAcquire(&api.timersMutex); + + for (uintptr_t i = 0; i < api.timers.Length(); i++) { + Timer *timer = &api.timers[i]; + timer->afterMs -= deltaTimeMs; // Update time remaining. + + if (timer->afterMs <= 0) { + EsMessage m = { ES_MSG_TIMER }; + m.user.context1.p = (void *) timer->callback; + m.user.context2 = timer->argument; + EsMessagePost(nullptr, &m); + api.timers.DeleteSwap(i); + i--; + } else if (waitFor == ES_WAIT_NO_TIMEOUT || timer->afterMs < waitFor) { + waitFor = timer->afterMs; + } + } + + EsMutexRelease(&api.timersMutex); + + EsWait(&api.timersEvent /* timer set/canceled */, 1, waitFor /* until the next timer */); + } +} + +EsTimer EsTimerSet(uint64_t afterMs, EsTimerCallbackFunction callback, EsGeneric argument) { + EsMutexAcquire(&api.timersMutex); + + static EsTimer _id = 0; + EsTimer id = ++_id; + + Timer timer = { .id = id, .afterMs = (double) afterMs, .callback = callback, .argument = argument }; + + if (!api.timers.Add(timer)) { + id = 0; // Insufficient resources. + } else { + if (!api.timersEvent) { + api.timersEvent = EsEventCreate(true); + } + + if (!api.timersThread) { + EsThreadInformation information; + api.timersThread = EsThreadCreate(TimersThread, &information, 0); + } + + EsEventSet(api.timersEvent); // Wake up the timer thread. + } + + EsMutexRelease(&api.timersMutex); + + return id; +} + +void EsTimerCancel(EsTimer id) { + EsMutexAcquire(&api.timersMutex); + + for (uintptr_t i = 0; i < api.timers.Length(); i++) { + if (api.timers[i].id == id) { + api.timers.DeleteSwap(i); + + if (api.timersEvent) { + EsEventSet(api.timersEvent); // Wake up the timer thread. + } + + break; + } + } + + EsMutexRelease(&api.timersMutex); +} + +#ifndef ENABLE_POSIX_SUBSYSTEM +void EsPOSIXInitialise(int *, char ***) { + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + EsInstance *instance = EsInstanceCreate(message, INTERFACE_STRING(POSIXTitle)); + EsPanel *panel = EsPanelCreate((EsElement *) instance->window, ES_PANEL_VERTICAL | ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_BACKGROUND); + EsTextDisplayCreate(panel, ES_CELL_H_CENTER | ES_CELL_V_FILL | ES_TEXT_DISPLAY_RICH_TEXT, nullptr, INTERFACE_STRING(POSIXUnavailable)); + } + } +} + +long EsPOSIXSystemCall(long, long, long, long, long, long, long) { + EsAssert(false); + return 0; +} + +char *EsPOSIXConvertPath(const char *, size_t *, bool) { + EsAssert(false); + return nullptr; +} +#else +EsProcessStartupInformation *ProcessGetStartupInformation() { + return api.startupInformation; +} +#endif diff --git a/desktop/api.s b/desktop/api.s new file mode 100644 index 0000000..bb08f0b --- /dev/null +++ b/desktop/api.s @@ -0,0 +1,99 @@ +[section .text] + +[global _APISyscall] +_APISyscall: + push rbp + push rbx + push r15 + push r14 + push r13 + push r12 + push r11 + push rcx + mov r12,rsp + syscall + mov rsp,r12 + pop rcx + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + pop rbx + pop rbp + ret + +[global _EsCRTsetjmp] +_EsCRTsetjmp: + mov [rdi + 0x00],rsp + mov [rdi + 0x08],rbp + mov [rdi + 0x10],rbx + mov [rdi + 0x18],r12 + mov [rdi + 0x20],r13 + mov [rdi + 0x28],r14 + mov [rdi + 0x30],r15 + mov rax,[rsp] + mov [rdi + 0x38],rax + xor rax,rax + ret + +[global _EsCRTlongjmp] +_EsCRTlongjmp: + mov rsp,[rdi + 0x00] + mov rbp,[rdi + 0x08] + mov rbx,[rdi + 0x10] + mov r12,[rdi + 0x18] + mov r13,[rdi + 0x20] + mov r14,[rdi + 0x28] + mov r15,[rdi + 0x30] + mov rax,[rdi + 0x38] + mov [rsp],rax + mov rax,rsi + cmp rax,0 + jne .return + mov rax,1 + .return: + ret + +[global EsTimeStamp] +EsTimeStamp: + rdtsc + shl rdx,32 + or rax,rdx + ret + +[global EsCRTsqrt] +EsCRTsqrt: + sqrtsd xmm0,xmm0 + ret + +[global EsCRTsqrtf] +EsCRTsqrtf: + sqrtss xmm0,xmm0 + ret + +[global ProcessorCheckStackAlignment] +ProcessorCheckStackAlignment: + mov rax,rsp + and rax,15 + cmp rax,8 + jne $ + ret + +[global ProcessorTLSRead] +ProcessorTLSRead: + mov rax,[fs:rdi] + ret + +[global ProcessorTLSWrite] +ProcessorTLSWrite: + mov [fs:rdi],rsi + ret + +[global __cyg_profile_func_enter] +__cyg_profile_func_enter: + ret + +[global __cyg_profile_func_exit] +__cyg_profile_func_exit: + ret diff --git a/desktop/crt1.c b/desktop/crt1.c new file mode 100644 index 0000000..85a2897 --- /dev/null +++ b/desktop/crt1.c @@ -0,0 +1,12 @@ +#include + +int main(int argc, char **argv, char **envp); +int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv); + +void _start() { + int argc; + char **argv; + EsPOSIXInitialise(&argc, &argv); + __libc_start_main(main, argc, argv); +} + diff --git a/desktop/crtglue.c b/desktop/crtglue.c new file mode 100644 index 0000000..c7d7bd9 --- /dev/null +++ b/desktop/crtglue.c @@ -0,0 +1,5 @@ +#include + +long OSMakeLinuxSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { + return EsPOSIXSystemCall(n, a1, a2, a3, a4, a5, a6); +} diff --git a/desktop/crti.s b/desktop/crti.s new file mode 100644 index 0000000..0b37e73 --- /dev/null +++ b/desktop/crti.s @@ -0,0 +1,11 @@ +[section .init] +[global _init] +_init: + push rbp + mov rbp, rsp + +[section .fini] +[global _fini] +_fini: + push rbp + mov rbp, rsp diff --git a/desktop/crtn.s b/desktop/crtn.s new file mode 100644 index 0000000..fccb715 --- /dev/null +++ b/desktop/crtn.s @@ -0,0 +1,7 @@ +[section .init] + pop rbp + ret + +[section .fini] + pop rbp + ret diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp new file mode 100644 index 0000000..bd572f6 --- /dev/null +++ b/desktop/desktop.cpp @@ -0,0 +1,1933 @@ +// TODO Tabs: +// - Dragging out of the window. +// - Dragging onto other windows. +// - Keyboard shortcuts. +// - New tab page - search; recent files. +// - Right click menu. +// - Duplicate tabs. +// - If a process exits, its tabs won't close because Desktop has a handle. +// - Also clear any OpenDocument currentWriter fields it owns. + +// TODO Graphical issues: +// - New tab button isn't flush with right border when tab band full. +// - Cursor doesn't update after switching embed window owners. +// - Closing tabs isn't animating. +// - Inactivate windows don't dim outline around tabs. +// - Resizing windows doesn't redraw old shadow sometimes. + +// TODO Task bar: +// - Right click menu. +// - Notification area. + +// TODO Desktop experience: +// - Alt+tab. +// - Changing wallpaper. +// +// TODO Global shortcuts: +// - Restoring closed tabs. +// - Switch to window. +// - Print screen. + +// TODO Only let File Manager read the file_type sections of the system configuration. +// TODO Maybe extend tab hitbox to top of window when maximised? Might need a visual change too. +// TODO Restarting Desktop if it crashes. +// TODO Make sure applications can't delete |Fonts: and |Themes:. + +#define MSG_SETUP_DESKTOP_UI ((EsMessageType) (ES_MSG_USER_START + 1)) + +#define APPLICATION_PERMISSION_ALL_FILES (1 << 0) +#define APPLICATION_PERMISSION_MANAGE_PROCESSES (1 << 1) +#define APPLICATION_PERMISSION_POSIX_SUBSYSTEM (1 << 2) +#define APPLICATION_PERMISSION_RUN_TEMPORARY_APPLICATION (1 << 3) +#define APPLICATION_PERMISSION_SHUTDOWN (1 << 4) + +#define APPLICATION_ID_DESKTOP_BLANK_TAB ((int64_t) 0x8000000000000000L) + +#define CRASHED_TAB_FATAL_ERROR (1) +#define CRASHED_TAB_PROGRAM_NOT_FOUND (2) +#define CRASHED_TAB_INVALID_EXECUTABLE (3) +#define CRASHED_TAB_NOT_RESPONDING (4) + +#define INSTALLATION_STATE_NONE (0) +#define INSTALLATION_STATE_INSTALLER (1) + +struct ReorderItem : EsElement { + double sizeProgress, sizeTarget; + double offsetProgress, offsetTarget; + bool dragging; + int dragOffset, dragPosition; +}; + +struct ReorderList : EsElement { + int targetWidth, extraWidth; + Array items; // By index. +}; + +struct WindowTab : ReorderItem { + struct ContainerWindow *container; + struct ApplicationInstance *applicationInstance; + EsButton *closeButton; +}; + +struct WindowTabBand : ReorderList { + struct ContainerWindow *container; + bool preventNextTabSizeAnimation; +}; + +struct TaskBarButton : ReorderItem { + ContainerWindow *containerWindow; +}; + +struct TaskList : ReorderList { +}; + +struct TaskBar : EsElement { + double enterProgress; + EsRectangle targetBounds; + TaskList taskList; +}; + +struct ContainerWindow { + WindowTabBand *tabBand; + TaskBarButton *taskBarButton; + EsWindow *window; + WindowTab *active; +}; + +struct OpenDocument { + char *path; + size_t pathBytes; + char *temporarySavePath; + size_t temporarySavePathBytes; + EsHandle readHandle; + uint64_t id; + uint64_t currentWriter; +}; + +struct InstalledApplication { + char *cName; + char *cExecutable; + int64_t id; + uint32_t iconID; + bool hidden, useSingleProcess, temporary; + uint64_t permissions; + size_t openInstanceCount; // Only used if useSingleProcess is true. + EsHandle singleProcessHandle; +}; + +struct CrashedTabInstance : EsInstance { +}; + +struct BlankTabInstance : EsInstance { +}; + +struct ApplicationInstance { + WindowTab *tab; + EsInstance *localInstance; + InstalledApplication *application; + uint64_t documentID; + + char title[128]; + size_t titleBytes; + uint32_t iconID; + + uint64_t processID; + EsHandle processHandle; + uint64_t embeddedWindowID; + EsHandle embeddedWindowHandle; + + bool notResponding; + EsHandle restoreEmbeddedWindowHandle; + uint64_t restoreEmbeddedWindowID; +}; + +const EsStyle styleNewTabContent = { + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_GAP_MAJOR, + .insets = ES_RECT_4(50, 50, 50, 50), + .gapMajor = 30, + }, +}; + +const EsStyle styleButtonGroupContainer = { + .inherit = ES_STYLE_BUTTON_GROUP_CONTAINER, + + .metrics = { + .mask = ES_THEME_METRICS_PREFERRED_WIDTH, + .preferredWidth = 400, + }, +}; + +struct { + Array installedApplications; + Array allApplicationInstances; + Array allContainerWindows; + InstalledApplication *fileManager; + uint64_t currentDocumentID; + HashStore openDocuments; + TaskBar taskBar; + EsWindow *wallpaperWindow; + bool shutdownWindowOpen; + bool setupDesktopUIComplete; + int installationState; +} desktop; + +int TaskBarButtonMessage(EsElement *element, EsMessage *message); +ApplicationInstance *ApplicationInstanceCreate(int64_t id, EsApplicationStartupInformation *startupInformation, ContainerWindow *container); +void ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInformation *startupInformation, ApplicationInstance *instance); +void ApplicationInstanceClose(ApplicationInstance *instance); +ApplicationInstance *ApplicationInstanceFindByWindowID(uint64_t windowID, bool remove = false); +void EmbeddedWindowDestroyed(uint64_t id); + +////////////////////////////////////////////////////// +// Reorder lists: +////////////////////////////////////////////////////// + +bool ReorderItemAnimate(ReorderItem *item, uint64_t deltaMs, const char *entranceDuration) { + item->sizeProgress += (item->sizeTarget - item->sizeProgress) + * (1 - EsCRTexp(deltaMs * -3.0f / GetConstantNumber(entranceDuration))); + item->offsetProgress += (item->offsetTarget - item->offsetProgress) + * (1 - EsCRTexp(deltaMs * -3.0f / GetConstantNumber("taskBarButtonMoveDuration"))); + + bool complete = true; + + if (EsCRTfabs(item->sizeTarget - item->sizeProgress) < 1.5) { + item->sizeProgress = item->sizeTarget; + } else { + complete = false; + } + + if (EsCRTfabs(item->offsetTarget - item->offsetProgress) < 1.5) { + item->offsetProgress = item->offsetTarget; + } else { + complete = false; + } + + EsElementRelayout(item->parent); + return complete; +} + +bool ReorderItemDragged(ReorderItem *item, int mouseX) { + ReorderList *list = (ReorderList *) item->parent; + size_t childCount = list->items.Length(); + + if (!item->dragging) { + item->dragOffset = gui.lastClickX - item->offsetX; + item->BringToFront(); + } + + item->dragPosition = mouseX + item->GetWindowBounds().l - item->dragOffset; + + int draggedIndex = (item->dragPosition + list->targetWidth / 2) / list->targetWidth; + if (draggedIndex < 0) draggedIndex = 0; + if (draggedIndex >= (int) childCount) draggedIndex = childCount - 1; + int currentIndex = -1; + + for (uintptr_t i = 0; i < childCount; i++) { + if (list->items[i] == item) { + currentIndex = i; + break; + } + } + + EsAssert(currentIndex != -1); + + bool changed = false; + + if (draggedIndex != currentIndex) { + list->items.Delete(currentIndex); + list->items.Insert(item, draggedIndex); + + for (uintptr_t i = 0, x = list->currentStyle->insets.l; i < childCount; i++) { + ReorderItem *child = (ReorderItem *) list->items[i]; + + if ((int) i != draggedIndex) { + int oldPosition = child->offsetX, newPosition = x + child->offsetProgress; + + if (child->offsetProgress != oldPosition - newPosition) { + child->offsetProgress = oldPosition - newPosition; + child->StartAnimating(); + } + } + + x += child->sizeProgress; + } + + changed = true; + } + + item->dragging = true; + EsElementRelayout(item->parent); + + return changed; +} + +void ReorderItemDragComplete(ReorderItem *item) { + if (!item->dragging) { + return; + } + + ReorderList *list = (ReorderList *) item->parent; + + for (uintptr_t i = 0, x = list->currentStyle->insets.l; i < list->items.Length(); i++) { + if (list->items[i] == item) { + int oldPosition = item->offsetX, newPosition = x + item->offsetProgress; + + if (item->offsetProgress != oldPosition - newPosition) { + item->offsetProgress = oldPosition - newPosition; + item->StartAnimating(); + } + } + + x += item->sizeTarget; + } + + item->dragging = false; +} + +int ReorderListLayout(ReorderList *list, int additionalRightMargin, bool clampDraggedItem, bool preventTabSizeAnimation) { + EsRectangle bounds = list->GetBounds(); + bounds.l += list->currentStyle->insets.l; + bounds.r -= list->currentStyle->insets.r; + bounds.r -= additionalRightMargin; + + size_t childCount = list->items.Length(); + + if (!childCount) { + return 0; + } + + int totalWidth = 0; + + for (uintptr_t i = 0; i < childCount; i++) { + ReorderItem *child = list->items[i]; + totalWidth += child->currentStyle->metrics->maximumWidth + list->currentStyle->metrics->gapMinor; + } + + bool widthClamped = false; + + if (totalWidth > Width(bounds)) { + totalWidth = Width(bounds); + widthClamped = true; + } + + int targetWidth = totalWidth / childCount; + int extraWidth = totalWidth % childCount; + + list->targetWidth = targetWidth; + list->extraWidth = extraWidth; + + for (uintptr_t i = 0; i < childCount; i++) { + ReorderItem *child = list->items[i]; + + int sizeTarget = targetWidth; + if (extraWidth) sizeTarget++, extraWidth--; + + if (preventTabSizeAnimation) { + child->sizeTarget = child->sizeProgress = sizeTarget; + } + + if (child->sizeTarget != sizeTarget) { + child->sizeTarget = sizeTarget; + child->StartAnimating(); + } + } + + int x = bounds.l; + + for (uintptr_t i = 0; i < childCount; i++) { + ReorderItem *child = list->items[i]; + int width = (i == childCount - 1 && widthClamped) ? (totalWidth - x) : child->sizeProgress; + int gap = list->currentStyle->metrics->gapMinor; + + if (child->dragging) { + int p = child->dragPosition; + + if (clampDraggedItem) { + if (p + width > bounds.r) p = bounds.r - width; + if (p < bounds.l) p = bounds.l; + } + + EsElementMove(child, p, 0, width - gap, Height(bounds)); + } else { + EsElementMove(child, x + child->offsetProgress, 0, width - gap, Height(bounds)); + } + + x += width; + } + + return x; +} + +int ReorderListMessage(EsElement *_list, EsMessage *message) { + ReorderList *list = (ReorderList *) _list; + + if (message->type == ES_MSG_LAYOUT) { + ReorderListLayout(list, 0, false, false); + } else if (message->type == ES_MSG_DESTROY) { + list->items.Free(); + } else if (message->type == ES_MSG_ADD_CHILD) { + EsMessage m = { ES_MSG_REORDER_ITEM_TEST }; + + if (ES_HANDLED == EsMessageSend(message->child, &m)) { + list->items.Add((ReorderItem *) message->child); + } + } else if (message->type == ES_MSG_REMOVE_CHILD) { + EsMessage m = { ES_MSG_REORDER_ITEM_TEST }; + + if (ES_HANDLED == EsMessageSend(message->child, &m)) { + list->items.FindAndDelete((ReorderItem *) message->child, true); + } + } + + return 0; +} + +////////////////////////////////////////////////////// +// Container windows: +////////////////////////////////////////////////////// + +void WindowTabActivate(WindowTab *tab) { + if (tab->container->active != tab) { + tab->container->active = tab; + EsElementRelayout(tab->container->tabBand); + tab->container->taskBarButton->Repaint(true); + + // EsPrint("Activating tab %d...\n", tab->tabIndex); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, tab->container->window->handle, (uintptr_t) tab->applicationInstance->embeddedWindowHandle, 0, ES_WINDOW_PROPERTY_EMBED); + } +} + +int ContainerWindowMessage(EsElement *element, EsMessage *message) { + ContainerWindow *container = (ContainerWindow *) element->userData.p; + + if (message->type == ES_MSG_WINDOW_ACTIVATED) { + container->taskBarButton->customStyleState |= THEME_STATE_SELECTED; + container->taskBarButton->MaybeRefreshStyle(); + } else if (message->type == ES_MSG_WINDOW_DEACTIVATED) { + container->taskBarButton->customStyleState &= ~THEME_STATE_SELECTED; + container->taskBarButton->MaybeRefreshStyle(); + } else if (message->type == ES_MSG_KEY_DOWN) { + bool ctrlOnly = message->keyboard.modifiers == ES_MODIFIER_CTRL; + int scancode = message->keyboard.scancode; + + if (((message->keyboard.modifiers & ~ES_MODIFIER_SHIFT) == ES_MODIFIER_CTRL) && message->keyboard.scancode == ES_SCANCODE_TAB) { + int tab = -1; + + for (uintptr_t i = 0; i < container->tabBand->items.Length(); i++) { + if (container->tabBand->items[i] == container->active) { + tab = i; + } + } + + EsAssert(tab != -1); + tab += ((message->keyboard.modifiers & ES_MODIFIER_SHIFT) ? -1 : 1); + if (tab == -1) tab = container->tabBand->items.Length() - 1; + if (tab == (int) container->tabBand->items.Length()) tab = 0; + WindowTabActivate((WindowTab *) container->tabBand->items[tab]); + } else if (ctrlOnly && scancode == ES_SCANCODE_T) { + ApplicationInstanceCreate(APPLICATION_ID_DESKTOP_BLANK_TAB, nullptr, container); + } else if (ctrlOnly && scancode == ES_SCANCODE_W) { + ApplicationInstanceClose(container->active->applicationInstance); + } else if (ctrlOnly && scancode == ES_SCANCODE_N) { + ApplicationInstanceCreate(APPLICATION_ID_DESKTOP_BLANK_TAB, nullptr, nullptr); + } else if (message->keyboard.modifiers == ES_MODIFIER_FLAG && scancode == ES_SCANCODE_UP_ARROW) { + WindowSnap(container->window, false, false, SNAP_EDGE_MAXIMIZE); + } else if (message->keyboard.modifiers == ES_MODIFIER_FLAG && scancode == ES_SCANCODE_DOWN_ARROW) { + if (container->window->isMaximised) { + WindowRestore(container->window); + } else { + EsSyscall(ES_SYSCALL_WINDOW_MOVE, container->window->handle, 0, 0, ES_WINDOW_MOVE_HIDDEN); + } + } else if (message->keyboard.modifiers == ES_MODIFIER_FLAG && scancode == ES_SCANCODE_LEFT_ARROW) { + if (container->window->restoreOnNextMove) { + WindowRestore(container->window); + } else { + WindowSnap(container->window, false, false, SNAP_EDGE_LEFT); + } + } else if (message->keyboard.modifiers == ES_MODIFIER_FLAG && scancode == ES_SCANCODE_RIGHT_ARROW) { + if (container->window->restoreOnNextMove) { + WindowRestore(container->window); + } else { + WindowSnap(container->window, false, false, SNAP_EDGE_RIGHT); + } + } else { + for (uintptr_t i = 0; i < 9; i++) { + if (ctrlOnly && scancode == (int) (ES_SCANCODE_1 + i) && container->tabBand->items.Length() > i) { + WindowTabActivate((WindowTab *) container->tabBand->items[i]); + } + } + } + } else if (message->type == ES_MSG_WINDOW_RESIZED) { + container->tabBand->preventNextTabSizeAnimation = true; + } + + return 0; +} + +int WindowTabMessage(EsElement *element, EsMessage *message) { + WindowTab *tab = (WindowTab *) element; + WindowTabBand *band = (WindowTabBand *) tab->parent; + ApplicationInstance *instance = tab->applicationInstance; + + if (message->type == ES_MSG_PRESSED_START) { + tab->BringToFront(); + WindowTabActivate(tab); + } else if (message->type == ES_MSG_HIT_TEST) { + EsRectangle bounds = tab->GetBounds(); + + if (message->hitTest.x <= 12) { + message->hitTest.inside = (bounds.b - message->hitTest.y) * 14 < message->hitTest.x * bounds.b; + } else if (message->hitTest.x > bounds.r - 12) { + message->hitTest.inside = (bounds.b - message->hitTest.y) * 14 < (bounds.r - message->hitTest.x) * bounds.b; + } + } else if (message->type == ES_MSG_LAYOUT) { + int closeButtonWidth = tab->closeButton->currentStyle->preferredWidth; + Rectangle16 insets = tab->currentStyle->metrics->insets; + EsElementSetHidden(tab->closeButton, tab->currentStyle->gapWrap * 2 + closeButtonWidth >= tab->width); + EsElementMove(tab->closeButton, tab->width - tab->currentStyle->gapWrap - closeButtonWidth, + insets.t, closeButtonWidth, tab->height - insets.t - insets.b); + } else if (message->type == ES_MSG_PAINT) { + EsDrawContent(message->painter, element, ES_RECT_2S(message->painter->width, message->painter->height), + instance->title, instance->titleBytes, instance->iconID); + } else if (message->type == ES_MSG_ANIMATE) { + message->animate.complete = ReorderItemAnimate(tab, message->animate.deltaMs, "windowTabEntranceDuration"); + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + if (band->items.Length() == 1) { + EsPoint screenPosition = EsMouseGetPosition(); + WindowChangeBounds(RESIZE_MOVE, screenPosition.x, screenPosition.y, &gui.lastClickX, &gui.lastClickY, band->window); + } else { + ReorderItemDragged(tab, message->mouseDragged.newPositionX); + } + + EsElementSetDisabled(band->GetChild(0), true); + } else if (message->type == ES_MSG_MOUSE_LEFT_UP) { + ReorderItemDragComplete(tab); + EsElementSetDisabled(band->GetChild(0), false); + } else if (message->type == ES_MSG_MOUSE_RIGHT_CLICK) { + EsMenu *menu = EsMenuCreate(tab, ES_FLAGS_DEFAULT); + + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(DesktopCloseTab), [] (EsMenu *, EsGeneric context) { + ApplicationInstanceClose(((WindowTab *) context.p)->applicationInstance); + }, tab); + + if (EsKeyboardIsShiftHeld() && !instance->localInstance) { + EsAssert(instance->processHandle); + EsMenuAddSeparator(menu); + + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(DesktopInspectUI), [] (EsMenu *, EsGeneric context) { + WindowTab *tab = (WindowTab *) context.p; + ApplicationInstance *instance = tab->applicationInstance; + EsMessage m = { ES_MSG_TAB_INSPECT_UI }; + m.tabOperation.id = instance->embeddedWindowID; + EsMessagePostRemote(instance->processHandle, &m); + }, tab); + } + + EsMenuShow(menu); + } else if (message->type == ES_MSG_MOUSE_MIDDLE_UP && (element->state & UI_STATE_HOVERED)) { + ApplicationInstanceClose(tab->applicationInstance); + } else if (message->type == ES_MSG_REORDER_ITEM_TEST) { + } else { + return 0; + } + + return ES_HANDLED; +} + +WindowTab *WindowTabCreate(ContainerWindow *container, ApplicationInstance *instance) { + WindowTab *tab = (WindowTab *) EsHeapAllocate(sizeof(WindowTab), true); + tab->container = container; + tab->applicationInstance = instance; + tab->Initialise(container->tabBand, ES_CELL_H_SHRINK | ES_CELL_V_BOTTOM, WindowTabMessage, nullptr); + tab->cName = "window tab"; + + tab->closeButton = EsButtonCreate(tab, ES_FLAGS_DEFAULT, ES_STYLE_WINDOW_TAB_CLOSE_BUTTON); + tab->closeButton->userData = tab; + + EsButtonOnCommand(tab->closeButton, [] (EsInstance *, EsElement *element, EsCommand *) { + ApplicationInstanceClose(((WindowTab *) element->userData.p)->applicationInstance); + }); + + return tab; +} + +int WindowTabBandMessage(EsElement *element, EsMessage *message) { + WindowTabBand *band = (WindowTabBand *) element; + + if (message->type == ES_MSG_LAYOUT) { + for (uint16_t i = 0; i < band->items.Length(); i++) { + WindowTab *tab = (WindowTab *) band->items[i]; + tab->SetStyle(tab == tab->container->active ? ES_STYLE_WINDOW_TAB_ACTIVE : ES_STYLE_WINDOW_TAB_INACTIVE); + + if (tab == tab->container->active) { + tab->BringToFront(); + } + } + + int x = ReorderListLayout(band, band->GetChild(0)->currentStyle->preferredWidth + 10, true, band->preventNextTabSizeAnimation); + band->GetChild(0)->InternalMove(band->GetChild(0)->currentStyle->preferredWidth, + band->GetChild(0)->currentStyle->preferredHeight, x + 10, 4); + band->preventNextTabSizeAnimation = false; + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + EsPoint screenPosition = EsMouseGetPosition(); + WindowChangeBounds(RESIZE_MOVE, screenPosition.x, screenPosition.y, &gui.lastClickX, &gui.lastClickY, band->window); + } else if (message->type == ES_MSG_MOUSE_LEFT_UP) { + if (band->window->restoreOnNextMove) { + band->window->resetPositionOnNextMove = true; + } + } else if (message->type == ES_MSG_MOUSE_RIGHT_CLICK) { + EsMenu *menu = EsMenuCreate(band, ES_MENU_AT_CURSOR); + + EsMenuAddItem(menu, band->window->isMaximised ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, + INTERFACE_STRING(DesktopCenterWindow), [] (EsMenu *, EsGeneric context) { + WindowTabBand *band = (WindowTabBand *) context.p; + EsRectangle workArea; + EsSyscall(ES_SYSCALL_SCREEN_WORK_AREA_GET, 0, (uintptr_t) &workArea, 0, 0); + EsRectangle newBounds = EsRectangleCenter(workArea, EsWindowGetBounds(band->window)); + newBounds.t -= 8, newBounds.b -= 8; // Because of the shadow, it looks a little better to be slightly above center :) + EsSyscall(ES_SYSCALL_WINDOW_MOVE, band->window->handle, (uintptr_t) &newBounds, 0, ES_FLAGS_DEFAULT); + }, band); + + EsMenuShow(menu); + } else { + return ReorderListMessage(band, message); + } + + return ES_HANDLED; +} + +ContainerWindow *ContainerWindowCreate() { + ContainerWindow *container = (ContainerWindow *) EsHeapAllocate(sizeof(ContainerWindow), true); + container->window = EsWindowCreate(nullptr, ES_WINDOW_CONTAINER); + desktop.allContainerWindows.Add(container); + container->window->messageUser = ContainerWindowMessage; + container->window->userData = container; + + container->tabBand = (WindowTabBand *) EsHeapAllocate(sizeof(WindowTabBand), true); + container->tabBand->container = container; + container->tabBand->Initialise(container->window, ES_CELL_FILL, WindowTabBandMessage, ES_STYLE_WINDOW_TAB_BAND); + container->tabBand->cName = "window tab band"; + + EsButton *newTabButton = EsButtonCreate(container->tabBand, ES_FLAGS_DEFAULT, ES_STYLE_WINDOW_TAB_BAND_NEW); + + EsButtonOnCommand(newTabButton, [] (EsInstance *, EsElement *element, EsCommand *) { + ApplicationInstanceCreate(APPLICATION_ID_DESKTOP_BLANK_TAB, nullptr, (ContainerWindow *) element->window->userData.p); + }); + + container->taskBarButton = (TaskBarButton *) EsHeapAllocate(sizeof(TaskBarButton), true); + container->taskBarButton->customStyleState = THEME_STATE_SELECTED; + container->taskBarButton->containerWindow = container; + container->taskBarButton->Initialise(&desktop.taskBar.taskList, ES_CELL_FILL, + TaskBarButtonMessage, ES_STYLE_TASK_BAR_BUTTON); + container->taskBarButton->cName = "task bar button"; + + return container; +} + +////////////////////////////////////////////////////// +// Task bar and system modals: +////////////////////////////////////////////////////// + +int TaskBarButtonMessage(EsElement *element, EsMessage *message) { + TaskBarButton *button = (TaskBarButton *) element; + + if (message->type == ES_MSG_PAINT) { + ContainerWindow *containerWindow = button->containerWindow; + ApplicationInstance *instance = containerWindow->active->applicationInstance; + EsDrawContent(message->painter, element, ES_RECT_2S(message->painter->width, message->painter->height), + instance->title, instance->titleBytes, instance->iconID); + } else if (message->type == ES_MSG_MOUSE_LEFT_CLICK) { + if (button->customStyleState & THEME_STATE_SELECTED) { + EsSyscall(ES_SYSCALL_WINDOW_MOVE, button->containerWindow->window->handle, 0, 0, ES_WINDOW_MOVE_HIDDEN); + } else { + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, button->containerWindow->window->handle, 0, 0, ES_WINDOW_PROPERTY_FOCUSED); + } + } else if (message->type == ES_MSG_ANIMATE) { + message->animate.complete = ReorderItemAnimate(button, message->animate.deltaMs, "taskBarButtonEntranceDuration"); + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + ReorderItemDragged(button, message->mouseDragged.newPositionX); + } else if (message->type == ES_MSG_MOUSE_LEFT_UP) { + ReorderItemDragComplete(button); + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + } else if (message->type == ES_MSG_REORDER_ITEM_TEST) { + } else { + return 0; + } + + return ES_HANDLED; +} + +int TaskBarWindowMessage(EsElement *, EsMessage *message) { + if (message->type == ES_MSG_ANIMATE) { + desktop.taskBar.enterProgress += (1 - desktop.taskBar.enterProgress) + * (1 - EsCRTexp(message->animate.deltaMs * -3.0 / GetConstantNumber("taskBarEntranceDuration"))); + + if (EsCRTfabs(1 - desktop.taskBar.enterProgress) < 0.001) { + desktop.taskBar.enterProgress = 1; + message->animate.complete = true; + } else { + message->animate.complete = false; + } + + EsRectangle bounds = desktop.taskBar.targetBounds; + bounds = Translate(bounds, 0, Height(bounds) * (1 - desktop.taskBar.enterProgress)); + EsSyscall(ES_SYSCALL_WINDOW_MOVE, desktop.taskBar.window->handle, (uintptr_t) &bounds, 0, ES_WINDOW_MOVE_UPDATE_SCREEN); + } + + return 0; +} + +int TaskBarMessage(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_LAYOUT) { + EsRectangle bounds = element->GetBounds(); + element->GetChild(0)->InternalMove(Width(bounds), Height(bounds), 0, 0); + } + + return 0; +} + +void ShutdownModalCreate() { + if (desktop.shutdownWindowOpen) { + return; + } + + desktop.shutdownWindowOpen = true; + + // Setup the window. + + EsWindow *window = EsWindowCreate(nullptr, ES_WINDOW_PLAIN); + EsRectangle screen; + EsSyscall(ES_SYSCALL_SCREEN_BOUNDS_GET, 0, (uintptr_t) &screen, 0, 0); + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &screen, 0, ES_WINDOW_MOVE_ALWAYS_ON_TOP); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, (uintptr_t) &screen, 0, ES_WINDOW_PROPERTY_BLUR_BOUNDS); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, ES_WINDOW_SOLID_TRUE, 0, ES_WINDOW_PROPERTY_SOLID); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, 0, 0, ES_WINDOW_PROPERTY_FOCUSED); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, BLEND_WINDOW_MATERIAL_LIGHT_BLUR, 0, ES_WINDOW_PROPERTY_MATERIAL); + + // Setup the UI. + + EsPanel *stack = EsPanelCreate(window, ES_CELL_FILL | ES_PANEL_Z_STACK, ES_STYLE_PANEL_NORMAL_WINDOW_ROOT); + stack->cName = "window stack"; + EsPanelCreate(stack, ES_CELL_FILL, ES_STYLE_PANEL_SHUTDOWN_OVERLAY)->cName = "modal overlay"; + EsPanel *dialog = EsPanelCreate(stack, ES_PANEL_VERTICAL | ES_CELL_CENTER, ES_STYLE_PANEL_DIALOG_ROOT); + dialog->cName = "dialog"; + EsPanel *heading = EsPanelCreate(dialog, ES_PANEL_HORIZONTAL | ES_CELL_H_FILL, ES_STYLE_DIALOG_HEADING); + EsIconDisplayCreate(heading, ES_FLAGS_DEFAULT, {}, ES_ICON_SYSTEM_SHUTDOWN); + EsTextDisplayCreate(heading, ES_CELL_H_FILL | ES_CELL_V_CENTER, ES_STYLE_TEXT_HEADING2, + INTERFACE_STRING(DesktopShutdownTitle))->cName = "dialog heading"; + EsTextDisplayCreate(EsPanelCreate(dialog, ES_PANEL_VERTICAL | ES_CELL_H_FILL, ES_STYLE_DIALOG_CONTENT), + ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(DesktopConfirmShutdown))->cName = "dialog contents"; + EsPanel *buttonArea = EsPanelCreate(dialog, ES_PANEL_HORIZONTAL | ES_PANEL_REVERSE | ES_CELL_H_FILL, ES_STYLE_DIALOG_BUTTON_AREA); + EsButton *cancelButton = EsButtonCreate(buttonArea, ES_BUTTON_DEFAULT, 0, INTERFACE_STRING(CommonCancel)); + EsButton *restartButton = EsButtonCreate(buttonArea, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(DesktopRestartAction)); + EsButton *shutdownButton = EsButtonCreate(buttonArea, ES_FLAGS_DEFAULT, ES_STYLE_PUSH_BUTTON_DANGEROUS, INTERFACE_STRING(DesktopShutdownAction)); + EsElementFocus(cancelButton); + + // Setup command callbacks when the buttons are pressed. + + EsButtonOnCommand(shutdownButton, [] (EsInstance *, EsElement *, EsCommand *) { + EsSyscall(ES_SYSCALL_SHUTDOWN, SHUTDOWN_ACTION_POWER_OFF, 0, 0, 0); + }); + + EsButtonOnCommand(restartButton, [] (EsInstance *, EsElement *, EsCommand *) { + EsSyscall(ES_SYSCALL_SHUTDOWN, SHUTDOWN_ACTION_RESTART, 0, 0, 0); + }); + + EsButtonOnCommand(cancelButton, [] (EsInstance *, EsElement *element, EsCommand *) { + EsElementDestroy(element->window); + desktop.shutdownWindowOpen = false; + }); +} + +////////////////////////////////////////////////////// +// Built-in tabs: +////////////////////////////////////////////////////// + +void InstanceForceQuit(EsInstance *, EsElement *element, EsCommand *) { + ApplicationInstance *instance = (ApplicationInstance *) element->userData.p; + EsProcessTerminate(instance->processHandle, 1); +} + +void InstanceCrashedTabCreate(int reason, ApplicationInstance *_instance) { + EsMessage m = {}; + m.type = ES_MSG_INSTANCE_CREATE; + m.createInstance.window = EsSyscall(ES_SYSCALL_WINDOW_CREATE, ES_WINDOW_NORMAL, 0, 0, 0); + CrashedTabInstance *instance = (CrashedTabInstance *) _EsInstanceCreate(sizeof(CrashedTabInstance), &m, nullptr); + instance->window->toolbarFillMode = true; + if (reason != CRASHED_TAB_NOT_RESPONDING) EsWindowSetIcon(instance->window, ES_ICON_DIALOG_ERROR); + EsElement *toolbar = EsWindowGetToolbar(instance->window); + EsPanel *panel = EsPanelCreate(toolbar, ES_CELL_V_CENTER | ES_CELL_V_PUSH | ES_CELL_H_SHRINK | ES_CELL_H_PUSH | ES_PANEL_VERTICAL, ES_STYLE_PANEL_CRASH_INFO); + + if (reason == CRASHED_TAB_FATAL_ERROR) { + EsTextDisplayCreate(panel, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(DesktopCrashedApplication)); + } else if (reason == CRASHED_TAB_PROGRAM_NOT_FOUND) { + EsTextDisplayCreate(panel, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(DesktopNoSuchApplication)); + EsWindowSetTitle(instance->window, INTERFACE_STRING(CommonErrorTitle)); + } else if (reason == CRASHED_TAB_INVALID_EXECUTABLE) { + EsTextDisplayCreate(panel, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(DesktopApplicationStartupError)); + EsWindowSetTitle(instance->window, INTERFACE_STRING(CommonErrorTitle)); + } else if (reason == CRASHED_TAB_NOT_RESPONDING) { + EsTextDisplayCreate(panel, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(DesktopNotResponding)); + EsButton *button = EsButtonCreate(panel, ES_CELL_H_RIGHT, ES_STYLE_PUSH_BUTTON_DANGEROUS, INTERFACE_STRING(DesktopForceQuit)); + button->userData = _instance; + EsButtonOnCommand(button, InstanceForceQuit); + } + + _instance->embeddedWindowHandle = m.createInstance.window; + _instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, m.createInstance.window, 0, 0, 0); + _instance->localInstance = instance; +} + +void InstanceBlankTabCreate(ApplicationInstance *_instance) { + EsMessage m = {}; + m.type = ES_MSG_INSTANCE_CREATE; + m.createInstance.window = EsSyscall(ES_SYSCALL_WINDOW_CREATE, ES_WINDOW_NORMAL, 0, 0, 0); + EsInstance *instance = _EsInstanceCreate(sizeof(BlankTabInstance), &m, nullptr); + EsWindowSetTitle(instance->window, INTERFACE_STRING(DesktopNewTabTitle)); + EsPanel *windowBackground = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_BACKGROUND); + EsPanel *content = EsPanelCreate(windowBackground, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleNewTabContent); + + { + // Installed applications list. + + EsPanel *buttonGroup = EsPanelCreate(content, ES_PANEL_VERTICAL | ES_CELL_H_SHRINK, &styleButtonGroupContainer); + + buttonGroup->separatorStylePart = ES_STYLE_BUTTON_GROUP_SEPARATOR; + buttonGroup->separatorFlags = ES_CELL_H_FILL; + + for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { + InstalledApplication *application = desktop.installedApplications[i]; + + if (application->hidden) { + continue; + } + + EsButton *button = EsButtonCreate(buttonGroup, ES_CELL_H_FILL | ES_BUTTON_NOT_FOCUSABLE, ES_STYLE_BUTTON_GROUP_ITEM, application->cName); + + button->userData = application; + + EsButtonSetIcon(button, (EsStandardIcon) application->iconID ?: ES_ICON_APPLICATION_DEFAULT_ICON); + + EsButtonOnCommand(button, [] (EsInstance *, EsElement *element, EsCommand *) { + uint64_t tabID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, element->window->handle, 0, 0, 0); + ApplicationInstance *instance = ApplicationInstanceFindByWindowID(tabID); + ApplicationInstanceStart(((InstalledApplication *) element->userData.p)->id, nullptr, instance); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, instance->tab->window->handle, (uintptr_t) instance->embeddedWindowHandle, 0, ES_WINDOW_PROPERTY_EMBED); + EsInstanceDestroy(element->instance); + instance->localInstance = nullptr; + }); + } + } + + _instance->embeddedWindowHandle = m.createInstance.window; + _instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, m.createInstance.window, 0, 0, 0); + _instance->localInstance = instance; +} + +////////////////////////////////////////////////////// +// Application management: +////////////////////////////////////////////////////// + +ApplicationInstance *ApplicationInstanceFindByWindowID(uint64_t windowID, bool remove) { + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if (instance->embeddedWindowID == windowID || (instance->restoreEmbeddedWindowID == windowID && instance->notResponding)) { + if (remove) { + desktop.allApplicationInstances.Delete(i); + } + + return instance; + } + } + + return nullptr; +} + +void ApplicationInstanceClose(ApplicationInstance *instance) { + if (!instance->processID) { + // This is a Desktop owned instance. + if (instance->localInstance) EsInstanceDestroy(instance->localInstance); + instance->localInstance = nullptr; + } else { + // TODO Force closing not responding instances. + EsMessage m = { ES_MSG_TAB_CLOSE_REQUEST }; + m.tabOperation.id = instance->embeddedWindowID; + EsMessagePostRemote(instance->processHandle, &m); + } +} + +void ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInformation *startupInformation, ApplicationInstance *instance) { + EsApplicationStartupInformation _startupInformation = {}; + + if (!startupInformation) { + startupInformation = &_startupInformation; + } + + if (instance->restoreEmbeddedWindowHandle) { + EsHandleClose(instance->restoreEmbeddedWindowHandle); + instance->restoreEmbeddedWindowHandle = ES_INVALID_HANDLE; + } + + if (applicationID == APPLICATION_ID_DESKTOP_BLANK_TAB) { + InstanceBlankTabCreate(instance); + return; + } + + InstalledApplication *application = nullptr; + + for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { + if (desktop.installedApplications[i]->id == applicationID) { + application = desktop.installedApplications[i]; + } + } + + if (!application) { + InstanceCrashedTabCreate(CRASHED_TAB_PROGRAM_NOT_FOUND, instance); + return; + } + + instance->application = application; + + if (application->useSingleProcess && application->singleProcessHandle) { + EsProcessState state; + EsProcessGetState(application->singleProcessHandle, &state); + + if (state.flags & (ES_PROCESS_STATE_ALL_THREADS_TERMINATED | ES_PROCESS_STATE_TERMINATING | ES_PROCESS_STATE_CRASHED)) { + EsHandleClose(application->singleProcessHandle); + application->singleProcessHandle = ES_INVALID_HANDLE; + } + } + + EsHandle process = application->singleProcessHandle; + + if (!application->useSingleProcess || process == ES_INVALID_HANDLE) { + EsProcessInformation information; + EsProcessCreationArguments arguments = {}; + + _EsNodeInformation executableNode; + EsError error = NodeOpen(application->cExecutable, EsCStringLength(application->cExecutable), + ES_FILE_READ | ES_NODE_FAIL_IF_NOT_FOUND, &executableNode); + + if (ES_CHECK_ERROR(error)) { + InstanceCrashedTabCreate(CRASHED_TAB_INVALID_EXECUTABLE, instance); + return; + } + + arguments.executable = executableNode.handle; + arguments.permissions = ES_PERMISSION_WINDOW_MANAGER; + + Array initialMountPoints = {}; + _EsNodeInformation settingsNode = {}; + + if (application->permissions & APPLICATION_PERMISSION_MANAGE_PROCESSES) { + arguments.permissions |= ES_PERMISSION_TAKE_SYSTEM_SNAPSHOT; + arguments.permissions |= ES_PERMISSION_PROCESS_CREATE; + arguments.permissions |= ES_PERMISSION_PROCESS_OPEN; + } + + if (application->permissions & APPLICATION_PERMISSION_POSIX_SUBSYSTEM) { + arguments.permissions |= ES_PERMISSION_PROCESS_OPEN; + arguments.permissions |= ES_PERMISSION_POSIX_SUBSYSTEM; + + MountPoint root = *NodeFindMountPoint(EsLiteral("0:")); + root.write = true; + root.prefixBytes = EsStringFormat(root.prefix, sizeof(root.prefix), "|POSIX:"); + initialMountPoints.Add(root); + } + + if (application->permissions & APPLICATION_PERMISSION_ALL_FILES) { + for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { + initialMountPoints.Add(api.mountPoints[i]); + initialMountPoints[i].write = true; + } + + arguments.permissions |= ES_PERMISSION_GET_VOLUME_INFORMATION; + } else { + initialMountPoints.Add(*NodeFindMountPoint(EsLiteral("|Themes:"))); + initialMountPoints.Add(*NodeFindMountPoint(EsLiteral("|Fonts:"))); + } + + { + size_t settingsPathBytes, settingsFolderBytes; + char *settingsFolder = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("settings_path"), &settingsFolderBytes); + char *settingsPath = EsStringAllocateAndFormat(&settingsPathBytes, "%s/%z", settingsFolderBytes, settingsFolder, application->cName); + error = NodeOpen(settingsPath, settingsPathBytes, ES_NODE_DIRECTORY | ES_NODE_CREATE_DIRECTORIES | _ES_NODE_DIRECTORY_WRITE, &settingsNode); + EsHeapFree(settingsPath); + EsHeapFree(settingsFolder); + + if (error == ES_SUCCESS) { + EsMountPoint settings = {}; + settings.prefixBytes = EsStringFormat(settings.prefix, sizeof(settings.prefix), "|Settings:"); + settings.base = settingsNode.handle; + settings.write = true; + initialMountPoints.Add(settings); + } else { + settingsNode.handle = ES_INVALID_HANDLE; + } + } + + arguments.initialMountPoints = initialMountPoints.array; + arguments.initialMountPointCount = initialMountPoints.Length(); + + error = EsProcessCreate(&arguments, &information); + EsHandleClose(arguments.executable); + + initialMountPoints.Free(); + if (settingsNode.handle) EsHandleClose(settingsNode.handle); + + if (!ES_CHECK_ERROR(error)) { + process = information.handle; + EsHandleClose(information.mainThread.handle); + } else { + InstanceCrashedTabCreate(CRASHED_TAB_INVALID_EXECUTABLE, instance); + return; + } + } + + if (application->useSingleProcess) { + application->singleProcessHandle = process; + } + + instance->processID = EsProcessGetID(process); + instance->processHandle = EsSyscall(ES_SYSCALL_PROCESS_SHARE, process, ES_CURRENT_PROCESS, 0, 0); + + EsMessage m = { ES_MSG_INSTANCE_CREATE }; + + if (~startupInformation->flags & ES_APPLICATION_STARTUP_MANUAL_PATH) { + // Only tell the application the name of the file. + + for (uintptr_t i = 0; i < (size_t) startupInformation->filePathBytes; i++) { + if (startupInformation->filePath[i] == '/') { + startupInformation->filePath += i + 1; + startupInformation->filePathBytes -= i + 1; + i = 0; + } + } + } + + // Share handles to the file and the startup information buffer. + + if (startupInformation->readHandle) { + startupInformation->readHandle = EsSyscall(ES_SYSCALL_NODE_SHARE, startupInformation->readHandle, process, 0, 0); + } + + if (!application->useSingleProcess) { + startupInformation->flags |= ES_APPLICATION_STARTUP_SINGLE_INSTANCE_IN_PROCESS; + } + + uint8_t *createInstanceDataBuffer = ApplicationStartupInformationToBuffer(startupInformation, &m.createInstance.dataBytes); + m.createInstance.data = EsConstantBufferCreate(createInstanceDataBuffer, m.createInstance.dataBytes, process); + EsHeapFree(createInstanceDataBuffer); + + EsHandle handle = EsSyscall(ES_SYSCALL_WINDOW_CREATE, ES_WINDOW_NORMAL, 0, 0, 0); + instance->embeddedWindowHandle = handle; + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, handle, 0xFF000000 | GetConstantNumber("windowFillColor"), 0, ES_WINDOW_PROPERTY_RESIZE_CLEAR_COLOR); + instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, handle, 0, 0, 0); + m.createInstance.window = EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, handle, process, 0, ES_WINDOW_PROPERTY_EMBED_OWNER); + EsMessagePostRemote(process, &m); + + if (!application->useSingleProcess) { + EsHandleClose(process); + } else { + application->openInstanceCount++; + } +} + +ApplicationInstance *ApplicationInstanceCreate(int64_t id, EsApplicationStartupInformation *startupInformation, ContainerWindow *container) { + ApplicationInstance *instance = (ApplicationInstance *) EsHeapAllocate(sizeof(ApplicationInstance), true); + WindowTab *tab = WindowTabCreate(container ?: ContainerWindowCreate(), instance); + instance->title[0] = ' '; + instance->titleBytes = 1; + desktop.allApplicationInstances.Add(instance); + instance->tab = tab; + ApplicationInstanceStart(id, startupInformation, instance); + WindowTabActivate(tab); + return instance; +} + +void ApplicationTemporaryDestroy(InstalledApplication *application) { + if (!application->temporary) return; + EsAssert(!application->singleProcessHandle); + + for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { + if (desktop.installedApplications[i] == application) { + desktop.installedApplications.Delete(i); + EsHeapFree(application->cName); + EsHeapFree(application->cExecutable); + EsHeapFree(application); + // TODO Delete the settings folder. + return; + } + } + + EsAssert(false); +} + +void ApplicationInstanceCrashed(EsMessage *message) { + EsProcessState state; + EsProcessGetState(message->crash.process, &state); + const char *fatalErrorString = state.crashReason.errorCode >= ES_FATAL_ERROR_COUNT ? "[unknown]" + : EnumLookupNameFromValue(enumStrings_EsFatalError, state.crashReason.errorCode); + const char *systemCallString = state.crashReason.duringSystemCall == -1 ? "[none]" + : EnumLookupNameFromValue(enumStrings_EsSyscallType, state.crashReason.duringSystemCall); + EsPrint("Process %d has crashed with error %z, during system call %z.\n", state.id, fatalErrorString, systemCallString); + + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if (instance->processID != message->crash.pid) { + continue; + } + + if (instance->notResponding) { + instance->notResponding = false; + instance->embeddedWindowHandle = instance->restoreEmbeddedWindowHandle; + instance->restoreEmbeddedWindowHandle = ES_INVALID_HANDLE; + instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, instance->embeddedWindowHandle, 0, 0, 0); + EsInstanceDestroy(instance->localInstance); + instance->localInstance = nullptr; + } + + instance->processID = 0; + EsHandleClose(instance->embeddedWindowHandle); + InstanceCrashedTabCreate(CRASHED_TAB_FATAL_ERROR, instance); + + ContainerWindow *container = instance->tab->container; + + if (instance->tab == container->active) { + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, container->window->handle, (uintptr_t) instance->embeddedWindowHandle, 0, ES_WINDOW_PROPERTY_EMBED); + } + } + + for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { + if (desktop.installedApplications[i]->useSingleProcess && desktop.installedApplications[i]->singleProcessHandle + && EsProcessGetID(desktop.installedApplications[i]->singleProcessHandle) == message->crash.pid) { + EsHandleClose(desktop.installedApplications[i]->singleProcessHandle); + desktop.installedApplications[i]->singleProcessHandle = ES_INVALID_HANDLE; + desktop.installedApplications[i]->openInstanceCount = 0; + ApplicationTemporaryDestroy(desktop.installedApplications[i]); + break; + } + } + + EsProcessTerminate(message->crash.process, 1); + EsHandleClose(message->crash.process); +} + +void ApplicationProcessTerminated(uint64_t pid) { + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if (instance->processID != pid) { + continue; + } + + if (instance->notResponding) { + instance->notResponding = false; + instance->embeddedWindowHandle = instance->restoreEmbeddedWindowHandle; + instance->restoreEmbeddedWindowHandle = ES_INVALID_HANDLE; + instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, instance->embeddedWindowHandle, 0, 0, 0); + EsInstanceDestroy(instance->localInstance); + instance->localInstance = nullptr; + } + + EmbeddedWindowDestroyed(instance->embeddedWindowID); + } + + for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { + if (desktop.installedApplications[i]->useSingleProcess && desktop.installedApplications[i]->singleProcessHandle + && EsProcessGetID(desktop.installedApplications[i]->singleProcessHandle) == pid) { + EsHandleClose(desktop.installedApplications[i]->singleProcessHandle); + desktop.installedApplications[i]->singleProcessHandle = ES_INVALID_HANDLE; + desktop.installedApplications[i]->openInstanceCount = 0; + ApplicationTemporaryDestroy(desktop.installedApplications[i]); + break; + } + } +} + +////////////////////////////////////////////////////// +// Document management: +////////////////////////////////////////////////////// + +void OpenDocumentWithApplication(EsApplicationStartupInformation *startupInformation) { + bool foundDocument = false; + uint64_t documentID; + + for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) { + OpenDocument *document = &desktop.openDocuments[i]; + + if (document->pathBytes == (size_t) startupInformation->filePathBytes + && 0 == EsMemoryCompare(document->path, startupInformation->filePath, document->pathBytes)) { + foundDocument = true; + startupInformation->readHandle = document->readHandle; + documentID = document->id; + break; + } + } + + if (!foundDocument) { + EsFileInformation file = EsFileOpen(startupInformation->filePath, startupInformation->filePathBytes, + ES_FILE_READ_SHARED | ES_NODE_FAIL_IF_NOT_FOUND); + + if (file.error != ES_SUCCESS) { + // TODO Report error? + return; + } + + OpenDocument document = {}; + document.path = (char *) EsHeapAllocate(startupInformation->filePathBytes, false); + document.pathBytes = startupInformation->filePathBytes; + document.readHandle = file.handle; + document.id = ++desktop.currentDocumentID; + documentID = document.id; + EsMemoryCopy(document.path, startupInformation->filePath, startupInformation->filePathBytes); + *desktop.openDocuments.Put(&document.id) = document; + + startupInformation->readHandle = document.readHandle; + } + + ApplicationInstance *instance = ApplicationInstanceCreate(startupInformation->id, startupInformation, nullptr); + + if (instance) { + instance->documentID = documentID; + } +} + +void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *newName, size_t newNameBytes) { + if (!instance->processHandle) return; + + EsMessage m = {}; + m.type = ES_MSG_INSTANCE_SAVE_RESPONSE; + m.tabOperation.id = instance->embeddedWindowID; + + if (!instance->documentID) { + size_t folderBytes; + char *folder = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("default_user_documents_path"), &folderBytes); + char *name = (char *) EsHeapAllocate(folderBytes + newNameBytes + 32, false); + EsMemoryCopy(name, folder, folderBytes); + EsMemoryCopy(name + folderBytes, newName, newNameBytes); + EsHeapFree(folder); + size_t nameBytes = EsPathFindUniqueName(name, folderBytes + newNameBytes, folderBytes + newNameBytes + 32); + + if (!nameBytes) { + EsHeapFree(name); + m.tabOperation.error = ES_ERROR_FILE_ALREADY_EXISTS; + EsMessagePostRemote(instance->processHandle, &m); + return; + } + + EsFileInformation file = EsFileOpen(name, nameBytes, ES_FILE_READ_SHARED | ES_NODE_FAIL_IF_FOUND); + + if (file.error != ES_SUCCESS) { + EsHeapFree(name); + m.tabOperation.error = file.error; + EsMessagePostRemote(instance->processHandle, &m); + return; + } + + OpenDocument document = {}; + document.path = name; + document.pathBytes = nameBytes; + document.readHandle = file.handle; + document.id = ++desktop.currentDocumentID; + *desktop.openDocuments.Put(&document.id) = document; + + instance->documentID = document.id; + + { + // Tell the instance the chosen name for the document. + + uintptr_t nameOffset = 0; + + for (uintptr_t i = 0; i < nameBytes; i++) { + if (name[i] == '/') { + nameOffset = i + 1; + } + } + + EsMessage m = { ES_MSG_INSTANCE_DOCUMENT_RENAMED }; + m.tabOperation.id = instance->embeddedWindowID; + m.tabOperation.handle = EsConstantBufferCreate(name + nameOffset, nameBytes - nameOffset, instance->processHandle); + m.tabOperation.bytes = nameBytes - nameOffset; + EsMessagePostRemote(instance->processHandle, &m); + } + } + + OpenDocument *document = desktop.openDocuments.Get(&instance->documentID); + + if (!document) { + return; + } + + if (document->currentWriter) { + m.tabOperation.error = ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE; + } else { + char temporaryFileName[32]; + + for (uintptr_t i = 0; i < sizeof(temporaryFileName); i++) { + temporaryFileName[i] = (EsRandomU8() % 26) + 'a'; + } + + size_t temporaryFolderBytes; + char *temporaryFolder = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("temporary_path"), &temporaryFolderBytes); + char *temporaryFilePath = (char *) EsHeapAllocate(temporaryFolderBytes + 1 + sizeof(temporaryFileName), false); + size_t temporaryFilePathBytes = EsStringFormat(temporaryFilePath, ES_STRING_FORMAT_ENOUGH_SPACE, "%s/%s", + temporaryFolderBytes, temporaryFolder, sizeof(temporaryFileName), temporaryFileName); + + EsFileInformation file = EsFileOpen(temporaryFilePath, temporaryFilePathBytes, + ES_FILE_WRITE_EXCLUSIVE | ES_NODE_FAIL_IF_FOUND | ES_NODE_CREATE_DIRECTORIES); + + EsHeapFree(temporaryFolder); + + if (file.error != ES_SUCCESS) { + m.tabOperation.error = file.error; + EsHeapFree(temporaryFilePath); + } else { + m.tabOperation.handle = EsSyscall(ES_SYSCALL_NODE_SHARE, file.handle, instance->processHandle, 0, 0); + m.tabOperation.error = ES_SUCCESS; + document->currentWriter = instance->embeddedWindowID; + document->temporarySavePath = temporaryFilePath; + document->temporarySavePathBytes = temporaryFilePathBytes; + EsHandleClose(file.handle); + } + } + + EsMessagePostRemote(instance->processHandle, &m); +} + +void InstanceAnnouncePathMoved(ApplicationInstance *fromInstance, const uint8_t *buffer, size_t embedWindowMessageBytes) { + // TODO Update the location of installed applications and other things in the configuration. + + uintptr_t oldPathBytes, newPathBytes; + EsMemoryCopy(&oldPathBytes, buffer + 1, sizeof(uintptr_t)); + EsMemoryCopy(&newPathBytes, buffer + 1 + sizeof(uintptr_t), sizeof(uintptr_t)); + + if (oldPathBytes >= 0x4000 || newPathBytes >= 0x4000 + || oldPathBytes + newPathBytes + sizeof(uintptr_t) * 2 + 1 != embedWindowMessageBytes) { + return; + } + + const char *oldPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2; + const char *newPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes; + + uint64_t documentID = 0; + + for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) { + OpenDocument *document = &desktop.openDocuments[i]; + + if (document->pathBytes >= oldPathBytes + && 0 == EsMemoryCompare(document->path, oldPath, oldPathBytes) + && (oldPathBytes == document->pathBytes || document->path[oldPathBytes] == '/')) { + if (document->pathBytes == oldPathBytes) documentID = document->id; + char *newDocumentPath = (char *) EsHeapAllocate(document->pathBytes - oldPathBytes + newPathBytes, false); + EsMemoryCopy(newDocumentPath, newPath, newPathBytes); + EsMemoryCopy(newDocumentPath + newPathBytes, document->path + oldPathBytes, document->pathBytes - oldPathBytes); + document->pathBytes += newPathBytes - oldPathBytes; + EsHeapFree(document->path); + document->path = newDocumentPath; + } + } + + if (!documentID) { + return; + } + + uintptr_t newNameOffset = 0; + + for (uintptr_t i = 0; i < newPathBytes; i++) { + if (newPath[i] == '/') { + newNameOffset = i + 1; + } + } + + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if (instance->documentID != documentID) continue; + if (instance->application == fromInstance->application) continue; + if (!instance->processHandle) continue; + + EsMessage m = { ES_MSG_INSTANCE_DOCUMENT_RENAMED }; + m.tabOperation.id = instance->embeddedWindowID; + m.tabOperation.handle = EsConstantBufferCreate(newPath + newNameOffset, newPathBytes - newNameOffset, instance->processHandle); + m.tabOperation.bytes = newPathBytes - newNameOffset; + EsMessagePostRemote(instance->processHandle, &m); + } +} + +void ApplicationInstanceCompleteSave(ApplicationInstance *fromInstance) { + OpenDocument *document = desktop.openDocuments.Get(&fromInstance->documentID); + + if (!document || fromInstance->embeddedWindowID != document->currentWriter) { + return; + } + + // Move the temporary file to its target destination. + // TODO Handling errors. + // TODO What should happen if the old file is deleted, but the new file isn't moved? + + EsPathDelete(document->path, document->pathBytes); + EsPathMove(document->temporarySavePath, document->temporarySavePathBytes, document->path, document->pathBytes); + + // Re-open the read handle. + + EsFileInformation file = EsFileOpen(document->path, document->pathBytes, ES_FILE_READ_SHARED | ES_NODE_FAIL_IF_NOT_FOUND); + + if (file.error != ES_SUCCESS) { + // TODO What now? + } else { + EsHandleClose(document->readHandle); + document->readHandle = file.handle; + } + + document->currentWriter = 0; + + if (desktop.fileManager->singleProcessHandle) { + EsMessage m = {}; + m.type = ES_MSG_FILE_MANAGER_FILE_MODIFIED; + m.user.context1 = EsConstantBufferCreate(document->path, document->pathBytes, desktop.fileManager->singleProcessHandle); + m.user.context2 = document->pathBytes; + EsMessagePostRemote(desktop.fileManager->singleProcessHandle, &m); + } + + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if (instance->documentID != document->id) continue; + if (!instance->processHandle) continue; + + EsMessage m = { ES_MSG_INSTANCE_DOCUMENT_UPDATED }; + m.tabOperation.isSource = instance == fromInstance; + m.tabOperation.id = instance->embeddedWindowID; + m.tabOperation.handle = EsSyscall(ES_SYSCALL_NODE_SHARE, document->readHandle, instance->processHandle, 0, 0); + EsMessagePostRemote(instance->processHandle, &m); + } +} + +////////////////////////////////////////////////////// +// Configuration file management: +////////////////////////////////////////////////////// + +void ConfigurationLoad() { + for (uintptr_t i = 0; i < api.systemConfigurationGroups.Length(); i++) { + // Load information about installed applications. + + EsSystemConfigurationGroup *group = &api.systemConfigurationGroups[i]; + + if (0 != EsStringCompareRaw(group->sectionClass, group->sectionClassBytes, EsLiteral("application"))) { + continue; + } + + InstalledApplication *application = (InstalledApplication *) EsHeapAllocate(sizeof(InstalledApplication), true); + + application->cName = EsSystemConfigurationGroupReadString(group, EsLiteral("name")); + size_t executableBytes = 0; + char *icon = EsSystemConfigurationGroupReadString(group, EsLiteral("icon")); + application->iconID = EsIconIDFromString(icon); + EsHeapFree(icon); + char *executable = EsSystemConfigurationGroupReadString(group, EsLiteral("executable"), &executableBytes); + application->cExecutable = (char *) EsHeapAllocate(executableBytes + 1, false); + EsMemoryCopy(application->cExecutable, executable, executableBytes); + application->cExecutable[executableBytes] = 0; + EsHeapFree(executable); + application->useSingleProcess = EsSystemConfigurationGroupReadInteger(group, EsLiteral("use_single_process"), true); + application->hidden = EsSystemConfigurationGroupReadInteger(group, EsLiteral("hidden"), false); + application->id = EsIntegerParse(group->section, group->sectionBytes); + +#define READ_PERMISSION(x, y) if (EsSystemConfigurationGroupReadInteger(group, EsLiteral(x), 0)) application->permissions |= y + READ_PERMISSION("permission_all_files", APPLICATION_PERMISSION_ALL_FILES); + READ_PERMISSION("permission_manage_processes", APPLICATION_PERMISSION_MANAGE_PROCESSES); + READ_PERMISSION("permission_posix_subsystem", APPLICATION_PERMISSION_POSIX_SUBSYSTEM); + READ_PERMISSION("permission_run_temporary_application", APPLICATION_PERMISSION_RUN_TEMPORARY_APPLICATION); + READ_PERMISSION("permission_shutdown", APPLICATION_PERMISSION_SHUTDOWN); + + desktop.installedApplications.Add(application); + + if (EsSystemConfigurationGroupReadInteger(group, EsLiteral("is_file_manager"))) { + desktop.fileManager = application; + } + } + + EsSort(desktop.installedApplications.array, desktop.installedApplications.Length(), + sizeof(InstalledApplication *), [] (const void *_left, const void *_right, EsGeneric) { + InstalledApplication *left = *(InstalledApplication **) _left; + InstalledApplication *right = *(InstalledApplication **) _right; + return EsStringCompare(left->cName, EsCStringLength(left->cName), right->cName, EsCStringLength(right->cName)); + }, 0); + + // Set the system configuration for other applications to read. + + // TODO Enforce a limit of 4MB on the size of the system configuration. + // TODO Alternatively, replace this with a growable EsBuffer. + const size_t bufferSize = 4194304; + char *buffer = (char *) EsHeapAllocate(bufferSize, false); + size_t position = 0; + + for (uintptr_t i = 0; i < api.systemConfigurationGroups.Length(); i++) { + EsSystemConfigurationGroup *group = &api.systemConfigurationGroups[i]; + + if (EsStringCompareRaw(group->sectionClass, group->sectionClassBytes, EsLiteral("font")) + && EsStringCompareRaw(group->sectionClass, group->sectionClassBytes, EsLiteral("file_type")) + && EsStringCompareRaw(group->section, group->sectionBytes, EsLiteral("ui"))) { + continue; + } + + EsINIState s = {}; + s.sectionClass = group->sectionClass, s.sectionClassBytes = group->sectionClassBytes; + s.section = group->section, s.sectionBytes = group->sectionBytes; + position += EsINIFormat(&s, buffer + position, bufferSize - position); + + for (uintptr_t i = 0; i < group->itemCount; i++) { + EsSystemConfigurationItem *item = group->items + i; + + if (!item->keyBytes || item->key[0] == ';') { + continue; + } + + s.key = item->key, s.keyBytes = item->keyBytes; + s.value = item->value, s.valueBytes = item->valueBytes; + position += EsINIFormat(&s, buffer + position, bufferSize - position); + } + } + + EsSyscall(ES_SYSCALL_SYSTEM_CONFIGURATION_WRITE, (uintptr_t) buffer, position, 0, 0); + EsHeapFree(buffer); +} + +////////////////////////////////////////////////////// +// Image utilities: +////////////////////////////////////////////////////// + +void WallpaperLoad(EsGeneric) { + size_t pathBytes; + char *path = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("wallpaper"), &pathBytes); + + if (path) { + void *buffer = EsHeapAllocate(desktop.wallpaperWindow->windowWidth * desktop.wallpaperWindow->windowHeight * 4, false); + LoadImage(path, pathBytes, buffer, desktop.wallpaperWindow->windowWidth, desktop.wallpaperWindow->windowHeight, false); + EsHeapFree(path); + + EsRectangle region = ES_RECT_2S(desktop.wallpaperWindow->windowWidth, desktop.wallpaperWindow->windowHeight); + EsSyscall(ES_SYSCALL_WINDOW_SET_BITS, desktop.wallpaperWindow->handle, (uintptr_t) ®ion, (uintptr_t) buffer, 0); + EsSyscall(ES_SYSCALL_SCREEN_FORCE_UPDATE, true, 0, 0, 0); + + // Work out the most common hue on the wallpaper, and set the system hue. + + uint32_t hueBuckets[36] = {}; + uint32_t hueSelected = 0; + + for (uintptr_t i = 0; i < desktop.wallpaperWindow->windowWidth * desktop.wallpaperWindow->windowHeight; i += 7) { + float h, s, v; + EsColorConvertToHSV(((uint32_t *) buffer)[i], &h, &s, &v); + uintptr_t bucket = (uintptr_t) (h * 6); + hueBuckets[bucket] += 2; + hueBuckets[bucket == 35 ? 0 : (bucket + 1)] += 1; + hueBuckets[bucket == 0 ? 35 : (bucket - 1)] += 1; + } + + for (uintptr_t i = 1; i < 36; i++) { + if (hueBuckets[i] > hueBuckets[hueSelected]) { + hueSelected = i; + } + } + + theming.systemHue = hueSelected / 6.0f; + if (theming.systemHue < 0) theming.systemHue += 6.0f; + + EsHeapFree(buffer); + + // Tell all container windows to redraw with the new system hue. + + EsMessageMutexAcquire(); + + for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) { + if (gui.allWindows[i]->windowStyle == ES_WINDOW_CONTAINER) { + gui.allWindows[i]->Repaint(true); + UIWindowNeedsUpdate(gui.allWindows[i]); + } + } + + EsMessageMutexRelease(); + } + + // TODO Fade wallpaper in. +} + +////////////////////////////////////////////////////// +// General Desktop: +////////////////////////////////////////////////////// + +void CheckForegroundWindowResponding(EsGeneric) { + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if ((~instance->tab->container->taskBarButton->customStyleState & THEME_STATE_SELECTED) + || instance->tab->container->active != instance->tab + || !instance->processID || !instance->processHandle) { + continue; + } + + EsProcessState state; + EsProcessGetState(instance->processHandle, &state); + + WindowTab *tab = instance->tab; + + if (state.flags & ES_PROCESS_STATE_PINGED) { + if (instance->notResponding) { + // Tab is already in a non-responding state. + } else { + instance->notResponding = true; + instance->restoreEmbeddedWindowHandle = instance->embeddedWindowHandle; + instance->restoreEmbeddedWindowID = instance->embeddedWindowID; + InstanceCrashedTabCreate(CRASHED_TAB_NOT_RESPONDING, instance); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, tab->container->window->handle, instance->embeddedWindowHandle, 0, ES_WINDOW_PROPERTY_EMBED); + } + } else { + if (instance->notResponding) { + instance->notResponding = false; + instance->embeddedWindowHandle = instance->restoreEmbeddedWindowHandle; + instance->restoreEmbeddedWindowHandle = ES_INVALID_HANDLE; + instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, instance->embeddedWindowHandle, 0, 0, 0); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, tab->container->window->handle, instance->embeddedWindowHandle, 0, ES_WINDOW_PROPERTY_EMBED); + tab->Repaint(true); + tab->container->taskBarButton->Repaint(true); + EsAssert(instance->localInstance); + EsInstanceDestroy(instance->localInstance); + instance->localInstance = nullptr; + } else { + EsMessage m; + EsMemoryZero(&m, sizeof(EsMessage)); + m.type = ES_MSG_PING; + EsMessagePostRemote(instance->processHandle, &m); + } + } + + break; + } + + EsTimerSet(2500, CheckForegroundWindowResponding, 0); +} + +void DesktopSetup() { + if (!desktop.setupDesktopUIComplete) { + // Get the installation state. + desktop.installationState = EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("installation_state")); + } + + if (!desktop.setupDesktopUIComplete) { + // Load the theme bitmap. + + EsHandle handle = EsMemoryOpen(ES_THEME_CURSORS_WIDTH * ES_THEME_CURSORS_HEIGHT * 4, EsLiteral(ES_THEME_CURSORS_NAME), ES_FLAGS_DEFAULT); + void *destination = EsObjectMap(handle, 0, ES_THEME_CURSORS_WIDTH * ES_THEME_CURSORS_HEIGHT * 4, ES_MAP_OBJECT_READ_WRITE); + LoadImage(theming.system.in + theming.system.bytes - theming.header->bitmapBytes, theming.header->bitmapBytes, + destination, ES_THEME_CURSORS_WIDTH, ES_THEME_CURSORS_HEIGHT, true); + EsObjectUnmap(destination); + EsHandleClose(handle); + } + + { + // Create the wallpaper window. + + if (!desktop.wallpaperWindow) desktop.wallpaperWindow = EsWindowCreate(nullptr, ES_WINDOW_PLAIN); + EsRectangle screen; + EsSyscall(ES_SYSCALL_SCREEN_BOUNDS_GET, 0, (uintptr_t) &screen, 0, 0); + EsSyscall(ES_SYSCALL_WINDOW_MOVE, desktop.wallpaperWindow->handle, (uintptr_t) &screen, 0, ES_WINDOW_MOVE_AT_BOTTOM); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, desktop.wallpaperWindow->handle, (uintptr_t) &screen, 0, ES_WINDOW_PROPERTY_OPAQUE_BOUNDS); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, desktop.wallpaperWindow->handle, + ES_WINDOW_SOLID_TRUE | ES_WINDOW_SOLID_NO_BRING_TO_FRONT, 0, ES_WINDOW_PROPERTY_SOLID); + desktop.wallpaperWindow->windowWidth = Width(screen); + desktop.wallpaperWindow->windowHeight = Height(screen); + desktop.wallpaperWindow->doNotPaint = true; + EsThreadCreate(WallpaperLoad, nullptr, 0); + } + + if (desktop.installationState == INSTALLATION_STATE_NONE) { + // Create the taskbar. + + EsWindow *window = desktop.setupDesktopUIComplete ? desktop.taskBar.window : EsWindowCreate(nullptr, ES_WINDOW_PLAIN); + window->messageUser = TaskBarWindowMessage; + window->StartAnimating(); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, ES_WINDOW_SOLID_TRUE | ES_WINDOW_SOLID_NO_ACTIVATE, 0, ES_WINDOW_PROPERTY_SOLID); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, BLEND_WINDOW_MATERIAL_GLASS, 0, ES_WINDOW_PROPERTY_MATERIAL); + + if (!desktop.setupDesktopUIComplete) desktop.taskBar.Initialise(window, ES_CELL_FILL, TaskBarMessage, ES_STYLE_TASK_BAR_BAR); + desktop.taskBar.cName = "task bar"; + EsThemeMetrics metrics = EsElementGetMetrics(&desktop.taskBar); + window->userData = &desktop.taskBar; + + EsRectangle screen; + EsSyscall(ES_SYSCALL_SCREEN_BOUNDS_GET, 0, (uintptr_t) &screen, 0, 0); + + EsRectangle bounds = screen; + bounds.t = bounds.b - metrics.preferredHeight; + desktop.taskBar.targetBounds = bounds; + + screen.b = bounds.t; + EsSyscall(ES_SYSCALL_SCREEN_WORK_AREA_SET, 0, (uintptr_t) &screen, 0, 0); + + bounds.r -= bounds.l, bounds.b -= bounds.t; + bounds.l = bounds.t = 0; + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, (uintptr_t) &bounds, 0, ES_WINDOW_PROPERTY_BLUR_BOUNDS); + + if (!desktop.setupDesktopUIComplete) { + EsPanel *panel = EsPanelCreate(&desktop.taskBar, ES_PANEL_HORIZONTAL | ES_CELL_FILL, {}); + + EsButton *newWindowButton = EsButtonCreate(panel, ES_FLAGS_DEFAULT, ES_STYLE_TASK_BAR_NEW_WINDOW); + + EsButtonOnCommand(newWindowButton, [] (EsInstance *, EsElement *, EsCommand *) { + ApplicationInstanceCreate(APPLICATION_ID_DESKTOP_BLANK_TAB, nullptr, nullptr); + }); + + desktop.taskBar.taskList.Initialise(panel, ES_CELL_FILL, ReorderListMessage, nullptr); + desktop.taskBar.taskList.cName = "task list"; + + EsButton *shutdownButton = EsButtonCreate(panel, ES_FLAGS_DEFAULT, ES_STYLE_TASK_BAR_EXTRA); + EsButtonSetIcon(shutdownButton, ES_ICON_SYSTEM_SHUTDOWN_SYMBOLIC); + + EsButtonOnCommand(shutdownButton, [] (EsInstance *, EsElement *, EsCommand *) { + ShutdownModalCreate(); + }); + + } + } + + if (!desktop.setupDesktopUIComplete) { + // Launch the first application. + + char *firstApplication = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("first_application")); + + if (firstApplication && firstApplication[0]) { + for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { + if (0 == EsCRTstrcmp(desktop.installedApplications[i]->cName, firstApplication)) { + ApplicationInstanceCreate(desktop.installedApplications[i]->id, nullptr, nullptr); + } + } + } + + EsHeapFree(firstApplication); + } + +#ifdef CHECK_FOR_NOT_RESPONDING + if (!desktop.setupDesktopUIComplete) { + // Setup the timer callback to check if the foreground window is responding. + EsTimerSet(2500, CheckForegroundWindowResponding, 0); + } +#endif + + if (desktop.setupDesktopUIComplete) { + } else if (desktop.installationState == INSTALLATION_STATE_NONE) { +#if 0 + // Play the startup sound. + + EsThreadCreate([] (EsGeneric) { + size_t pathBytes; + char *path = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("startup_sound"), &pathBytes); + + if (path) { + PlaySound(path, pathBytes); + EsHeapFree(path); + } + }, nullptr, 0); +#endif + } else if (desktop.installationState == INSTALLATION_STATE_INSTALLER) { + // Start the installer. + + EsWindow *window = EsWindowCreate(nullptr, ES_WINDOW_PLAIN); + + EsRectangle screen; + EsSyscall(ES_SYSCALL_SCREEN_BOUNDS_GET, 0, (uintptr_t) &screen, 0, 0); + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &screen, 0, ES_WINDOW_MOVE_ALWAYS_ON_TOP); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, ES_WINDOW_SOLID_TRUE, 0, ES_WINDOW_PROPERTY_SOLID); + + EsPanel *root = EsPanelCreate(window, ES_PANEL_VERTICAL | ES_CELL_PUSH | ES_CELL_CENTER, ES_STYLE_INSTALLER_ROOT); + EsTextDisplayCreate(root, ES_CELL_H_FILL, ES_STYLE_TEXT_HEADING0, EsLiteral("Essence Installation")); + + // TODO. + } + + desktop.setupDesktopUIComplete = true; +} + +void DesktopMessage2(EsMessage *message, uint8_t *buffer) { + ApplicationInstance *instance = ApplicationInstanceFindByWindowID(message->desktop.windowID); + + if (buffer[0] == DESKTOP_MSG_START_APPLICATION) { + EsApplicationStartupInformation *information = ApplicationStartupInformationParse(buffer + 1, message->desktop.bytes - 1); + if (information) OpenDocumentWithApplication(information); + } else if (!instance) { + // ------------------------------------------------- + // | Messages below here require a valid instance. | + // ------------------------------------------------- + } else if (buffer[0] == DESKTOP_MSG_SET_TITLE || buffer[0] == DESKTOP_MSG_SET_ICON) { + if (buffer[0] == DESKTOP_MSG_SET_TITLE) { + instance->titleBytes = EsStringFormat(instance->title, sizeof(instance->title), "%s", + message->desktop.bytes - 1, buffer + 1); + } else { + if (message->desktop.bytes == 5) { + EsMemoryCopy(&instance->iconID, buffer + 1, sizeof(uint32_t)); + } + } + + instance->tab->Repaint(true); + + if (instance->tab == instance->tab->container->active) { + instance->tab->container->taskBarButton->Repaint(true); + } + } else if (buffer[0] == DESKTOP_MSG_REQUEST_SAVE) { + ApplicationInstanceRequestSave(instance, (const char *) buffer + 1, message->desktop.bytes - 1); + } else if (buffer[0] == DESKTOP_MSG_COMPLETE_SAVE) { + ApplicationInstanceCompleteSave(instance); + } else if (buffer[0] == DESKTOP_MSG_SHOW_IN_FILE_MANAGER) { + // TODO Don't open a new instance if the folder is already open? + OpenDocument *document = desktop.openDocuments.Get(&instance->documentID); + + if (document) { + EsApplicationStartupInformation startupInformation = {}; + startupInformation.flags = ES_APPLICATION_STARTUP_MANUAL_PATH; + startupInformation.filePath = document->path; + startupInformation.filePathBytes = document->pathBytes; + ApplicationInstanceCreate(desktop.fileManager->id, &startupInformation, instance->tab->container); + } + } else if (buffer[0] == DESKTOP_MSG_ANNOUNCE_PATH_MOVED + && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) + && message->desktop.bytes > 1 + sizeof(uintptr_t) * 2) { + InstanceAnnouncePathMoved(instance, buffer, message->desktop.bytes); + } else if (buffer[0] == DESKTOP_MSG_RUN_TEMPORARY_APPLICATION) { + if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_RUN_TEMPORARY_APPLICATION)) { + InstalledApplication *application = (InstalledApplication *) EsHeapAllocate(sizeof(InstalledApplication), true); + application->temporary = true; + application->hidden = true; + application->useSingleProcess = true; + application->cExecutable = (char *) EsHeapAllocate(message->desktop.bytes, false); + EsMemoryCopy(application->cExecutable, buffer + 1, message->desktop.bytes - 1); + application->cExecutable[message->desktop.bytes - 1] = 0; + static int64_t nextTemporaryID = -1; + application->id = nextTemporaryID--; + application->cName = (char *) EsHeapAllocate(32, false); + for (int i = 1; i < 31; i++) application->cName[i] = (EsRandomU8() % 26) + 'a'; + application->cName[0] = '_', application->cName[31] = 0; + desktop.installedApplications.Add(application); + ApplicationInstanceCreate(application->id, nullptr, nullptr); + } + } else if (buffer[0] == DESKTOP_MSG_REQUEST_SHUTDOWN) { + if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_SHUTDOWN)) { + ShutdownModalCreate(); + } + } +} + +void EmbeddedWindowDestroyed(uint64_t id) { + // TODO Close open documents. + + EsMenuCloseAll(); + ApplicationInstance *instance = ApplicationInstanceFindByWindowID(id, true /* remove if found */); + if (!instance) return; + + ContainerWindow *container = instance->tab->container; + if (instance->processID && !instance->notResponding) EsHandleClose(instance->embeddedWindowHandle); + if (instance->processHandle) EsHandleClose(instance->processHandle); + if (instance->restoreEmbeddedWindowHandle) EsHandleClose(instance->restoreEmbeddedWindowHandle); + instance->embeddedWindowID = 0; + + InstalledApplication *application = instance->application; + + if (application && application->singleProcessHandle && instance->processID) { + EsAssert(application->openInstanceCount); + application->openInstanceCount--; + + if (!application->openInstanceCount && application->useSingleProcess) { + EsMessage m = { ES_MSG_APPLICATION_EXIT }; + EsMessagePostRemote(application->singleProcessHandle, &m); + EsHandleClose(application->singleProcessHandle); + application->singleProcessHandle = ES_INVALID_HANDLE; + ApplicationTemporaryDestroy(application); + application = nullptr; + } + } + + if (container->tabBand->items.Length() == 1) { + EsElementDestroy(container->window); + EsElementDestroy(container->taskBarButton); + desktop.allContainerWindows.FindAndDeleteSwap(container, true); + } else { + if (container->active == instance->tab) { + container->active = nullptr; + + for (uintptr_t i = 0; i < container->tabBand->items.Length(); i++) { + if (container->tabBand->items[i] != instance->tab) continue; + WindowTabActivate((WindowTab *) container->tabBand->items[i ? (i - 1) : 1]); + break; + } + } + + EsElementDestroy(instance->tab); + } + + EsHeapFree(instance); +} + +void DesktopMessage(EsMessage *message) { + if (message->type == ES_MSG_POWER_BUTTON_PRESSED) { + ShutdownModalCreate(); + } else if (message->type == ES_MSG_EMBEDDED_WINDOW_DESTROYED) { + EmbeddedWindowDestroyed(message->desktop.windowID); + } else if (message->type == ES_MSG_DESKTOP) { + if (message->desktop.bytes <= 0x4000) { + uint8_t *buffer = (uint8_t *) EsHeapAllocate(message->desktop.bytes, false); + if (!buffer) return; + EsConstantBufferRead(message->desktop.buffer, buffer); + DesktopMessage2(message, buffer); + EsHeapFree(buffer); + } + + EsHandleClose(message->desktop.buffer); + } else if (message->type == ES_MSG_APPLICATION_CRASH) { + ApplicationInstanceCrashed(message); + } else if (message->type == ES_MSG_PROCESS_TERMINATED) { + ApplicationProcessTerminated(message->crash.pid); + } else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) { + EsHandle rootDirectory = message->registerFileSystem.rootDirectory; + + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) && instance->processHandle) { + message->registerFileSystem.rootDirectory = EsSyscall(ES_SYSCALL_NODE_SHARE, rootDirectory, instance->processHandle, 0, 0); + EsMessagePostRemote(instance->processHandle, message); + } + } + } else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) { + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) && instance->processHandle) { + EsMessagePostRemote(instance->processHandle, message); + } + } + } else if (message->type == ES_MSG_SET_SCREEN_RESOLUTION) { + if (desktop.setupDesktopUIComplete) { + DesktopSetup(); // Refresh desktop UI. + } else { + // The screen resolution will be correctly queried in DesktopSetup. + } + } else if (message->type == MSG_SETUP_DESKTOP_UI) { + DesktopSetup(); + } +} + +void DesktopEntry() { + ConfigurationLoad(); + + EsMessage m = { MSG_SETUP_DESKTOP_UI }; + EsMessagePost(nullptr, &m); + + while (true) { + EsMessage *message = EsMessageReceive(); + DesktopMessage(message); + } +} diff --git a/desktop/docs.md b/desktop/docs.md new file mode 100644 index 0000000..534fede --- /dev/null +++ b/desktop/docs.md @@ -0,0 +1,458 @@ +# Random number generator + +## Definitions + +```c +uint8_t EsRandomU8(); +uint64_t EsRandomU64(); +void EsRandomAddEntropy(uint64_t x); +void EsRandomSeed(uint64_t x); +``` + +## Description + +Used to generate pseudo-random numbers. **Note**: the algorithm used is not suitable for cryptographic or statistical applications. These functions are thread-safe. + +`EsRandomU8` generates a single byte of random data, and `EsRandomU64` generates a random `uint64_t`. + +`EsRandomSeed` begins a new sequence of random numbers. For a given seed, subsequent calls to `EsRandomU64` will form the same sequence every time. + +`EsRandomAddEntropy` is used to move to a different point in the sequence of numbers, where there is no obvious link between the input value and the new sequence position. + +## Example + +```c +EsPrint("A random number between 1 and 100 is:\n", 1 + (EsRandomU64() % 100)); +``` + +# Performance timers + +## Definitions + +```c +void EsPerformanceTimerPush(); +double EsPerformanceTimerPop(); +``` + +## Description + +Used to accurately time sections of code. + +`EsPerformanceTimerPush` pushes the current time onto a stack. `EsPerformanceTimerPop` removes the top item, and returns the elapsed time since that item was added. + +The stack must not exceed more than 100 items. + +## Example + +```c +EsPerformanceTimerPush(); + +EsPerformanceTimerPush(); +PerformStep1(); +double timeStep1 = EsPerformanceTimerPop(); + +EsPerformanceTimerPush(); +PerformStep2(); +double timeStep2 = EsPerformanceTimerPop(); + +double timeTotal = EsPerformanceTimerPop(); + +EsPrint("Total time: %F seconds.\n", timeTotal); +EsPrint("\tStep 1 took %F seconds.\n", timeStep1); +EsPrint("\tStep 2 took %F seconds.\n", timeStep2); +``` + +# Threads + +## Definitions + +```c +struct EsThreadInformation { + EsHandle handle; + uint64_t tid; +} + +#define ES_CURRENT_THREAD ((EsHandle) (0x10)) + +typedef void (*EsThreadEntryFunction)(EsGeneric argument); + +EsError EsThreadCreate(EsThreadEntryFunction entryFunction, EsThreadInformation *information, EsGeneric argument); +uint64_t EsThreadGetID(EsHandle thread); +void EsThreadTerminate(EsHandle thread); +``` + +## Description + +Threads are used to execute code in parallel. Threads can be created and terminated. A process can manipulate threads via handles. A handle to a thread can be closed with `EsHandleClose`. Each thread has a unique ID. A thread ID will not be reused until all handles to the thread that previously used the ID have been closed. Threads may not necessarily execute in parallel; the system may simulate the effect of parallel execution by causing the CPU to switch rapidly between which thread it is executing. + +`EsThreadCreate` creates a new thread, starting at the provided `entryFunction`, which will be passed `argument`. After the call, `information` will be filled with a `handle` to the newly created thread, and the thread's unique ID in `tid`. This function returns `ES_SUCCESS` if the thread was successfully created. + +`EsThreadGetID` gets the ID of a thread from its handle. + +`EsThreadTerminate` instructs a thread to terminate. If the thread is executing privileged code at the time of the request, it will complete the prviledged code before terminating. If a thread is waiting on a synchronisation object, such as a mutex or event, it will stop waiting and terminate regardless. **Note**: if a thread owns a mutex or spinlock when it is terminated, it will **not** release the object. + +A thread can always use the handle `ES_CURRENT_THREAD` to access itself. This handle should not be closed. + +## Example + +```c +void MyThread(EsGeneric number) { + while (true) { + EsPrint("Thread %d has ID %d!\n", number.i, EsThreadGetID(ES_CURRENT_THREAD)); + } +} + +for (uintptr_t number = 1; number <= 5; i++) { + EsThreadInformation information; + EsError error = EsThreadCreate(MyThread, &information, number); + + if (error != ES_SUCCESS) { + EsPrint("Thread %d could not be created.\n", number); + } else { + EsPrint("Started thread %d with ID %d.\n", number, information.tid); + + // Close the handle to the thread. + EsHandleClose(information.handle): + } +} +``` + +# Mutexes + +## Definitions + +```c +void EsMutexAcquire(EsMutex *mutex); +void EsMutexDestroy(EsMutex *mutex); +void EsMutexRelease(EsMutex *mutex); +``` + +## Description + +A mutex is a synchronisation primitive. Threads can *acquire* and *release* it. Only one thread can have acquired the mutex at a time. Before another thread can acquire it, the original thread must release it. When a thread tries to acquire an already-acquired mutex, it will wait until the mutex is released, and then proceed to acquire it. + +The `EsMutex` structure contains a mutex. It should be initialised to zero. When the mutex is no longer needed, it can be destroyed with `EsMutexDestroy`. A mutex must not be acquired when it is destroyed. + +To acquire a mutex, call `EsMutexAcquire` with a pointer to the mutex. To release a mutex, call `EsMutexRelease`. A thread must not attempt to acquire a mutex it already owns, and it must not attempt to release a mutex it does not own. + +## Example + +In this example, the function `IncrementCount` can safely be called on different threads at the same time. + +```c +EsMutex mutex; +#define INITIAL_COUNT (10) + +void IncrementCount(int *count) { + EsMutexAcquire(&mutex); + + if (count == 0) { + // count is uninitialised, so initialise it now. + *count = INITIAL_COUNT; + } + + count++; + + EsMutexRelease(&mutex); +} +``` + +Without the mutex, unexpected behaviour may occur, as the effective operation of threads may be arbitrarily interleaved. + +Consider two threads, A and B, that both call `IncrementCount`: +- Thread A enters IncrementCount and sees that `count = 0`. +- Thread B enters IncrementCount and sees that `count = 0`. +- Thread A sets `count` to `10`. +- Thread A increments `count` by `1` to `11`. +- Thread B sets `count` to `10`. +- Thread B increments `count` by `1` to `11`. + +Despite `IncrementCount` being called twice, the count is only incremented once. + +Another possibility is: +- Thread A enters IncrementCount and reads `count` into a register; it has the value `10`. +- Thread A adds `1` to the register, giving `11`. +- Thread B enters IncrementCount and reads `count` into a register; it has the value `10`. +- Thread B adds `1` to the register, giving `11`. +- Thread A stores the value in its register into `count`, `11`. +- Thread B stores the value in its register into `count`, `11`. + +Again, despite `IncrementCount` being called twice, the count is only incremented once. + +## Deadlock + +Mutexes must be acquired in a consistent order. For example, if the following pattern appears in your code: + +1. Acquire mutex X. +2. Acquire mutex Y. +3. Release mutex Y. +4. Release mutex X. + +Then the following pattern must not occur: + +1. Acquire mutex Y. +2. Acquire mutex X. +3. Release mutex X. +4. Release mutex Y. + +To explain why, suppose thread A executes the first pattern and thread B executes the second. +- Thread A acquires mutex X. +- Thread B acquires mutex Y. +- Thread A attempts to acquire mutex Y. Mutex Y is owned by thread B, so thread A starts waiting for thread B to release it. +- Thread B attempts to acquire mutex X. Mutex X is owned by thread A, so thread B starts waiting for thread A to release it. +- Both threads will continue to wait indefinitely for the other to perform an operation. + +# INI files + +## Definitions + +```c +struct EsINIState { + char *buffer, *sectionClass, *section, *key, *value; + size_t bytes, sectionClassBytes, sectionBytes, keyBytes, valueBytes; +}; + +bool EsINIParse(EsINIState *s); +bool EsINIPeek(EsINIState *s); +size_t EsINIFormat(EsINIState *s, char *buffer, size_t bytes); +void EsINIZeroTerminate(EsINIState *s); +``` + +## Description + +To parse an INI file, first initialise a blank EsINIState structure. Set `buffer` to point to the INI data, and set `bytes` to the byte count of the data. Then, call `EsINIParse` repeatedly, until it returns false, indicating it has reached the end of the data. After each call to `EsINIParse`, the fields of `EsINIState` are updated to give the information about the last parsed line in the INI file. `EsINIPeek` is the same as `EsINIParse` except it does not advance to the next line in the INI data. Fields in `EsINIState` that are not applicable to the parsed line are set to empty strings. Comment lines set `key` to `;` and `value` contains the comment itself. Aside for empty strings, the fields in `EsINIState` will always point into the provided buffer. + +For example, the line `[@hello world]` will set `sectionClass` to `"hello"`, `section` to `"world"`, and `key` and `value` to empty strings. When followed by the line `k=v`, `sectionClass` and `section` will retain their previous values, and `key` will be set to `"k"` and `value` will be set to `"v"`. + +`EsINIFormat` formats the contents of `EsINIState` into a buffer. `bytes` gives the size of `buffer`. The return value gives the number of bytes written to `buffer`; this is clipped to the end of the buffer. + +`EsINIZeroTerminate` zero-terminates `sectionClass`, `section`, `key` and `value` in the `EsINIState`. It cannot be used after calling `EsINIPeek`. + +## Example + +```c +size_t fileBytes; +void *file = EsFileReadAll(EsLiteral("|Settings:/Default.ini"), &fileBytes); + +EsINIState s = {}; +s.buffer = file; +s.bytes = fileBytes; + +while (EsINIParse(&s)) { + EsINIZeroTerminate(&s); + EsPrint("section = %z, key = %z, value = %z\n", s.section, s.key, s.value); +} + +EsHeapFree(file); +``` + +# Heap allocator + +## Definitions + +```c +void *EsHeapAllocate(size_t size, bool zeroMemory, EsHeap *heap = ES_NULL); +void EsHeapFree(void *address, size_t expectedSize = 0, EsHeap *heap = ES_NULL); +void *EsHeapReallocate(void *oldAddress, size_t newAllocationSize, bool zeroNewSpace, EsHeap *heap = ES_NULL); +void EsHeapValidate(); +``` + +## Description + +The heap allocator is a general-purpose allocator. It is thread-safe. It is designed to handle regions of memory of arbitrary size, and arbitrary lifetime. + +To allocate memory, call `EsHeapAllocate`. Set `size` to be the size of the region in bytes. Set `zeroMemory` to `true` for the contents of the region to be automatically zeroed, otherwise `false`. Set `heap` to `NULL`; this parameter is reserved. The return value is the address of the start of allocated region. It will be suitably aligned, given the specified region size and current processor architecture. If `size` is `0`, then `NULL` is returned. + +To free memory, call `EsHeapFree`. Set `address` to be the start of the previously allocated region. Optionally, set `expectedSize` to be the size of the allocated region; if non-zero, the system will assert that this value is correct. Set `heap` to `NULL`; this parameter is reserved. If `address` is `NULL`, this function will do nothing. + +To grow or shrink an existing region, call `EsHeapReallocate`. Set `oldAddress` to be the start of the previously allocated region. Set `newAllocationSize` to be new the size of the region. Set `heap` to `NULL`; this parameter is reserved. If `oldAddress` is `NULL`, this call is equivalent to `EsHeapAllocate`. If `newAllocationSize` is `0`, this call is equivalent to `EsHeapFree`. The return value gives the new start address of the region. This may be the same as `oldAddress`, if the region was able to change size in place. If the region was not able to change size in place, the old contents will be copied to the new region. If `zeroNewSpace` is set, and `newAllocationSize` is greater than the previous size of the region, then the newly accessible bytes at the end of the region will be cleared to zero. + +`EsHeapValidate` will check the current process's heap for errors. If it finds an error, it will crash the process. Do not rely on any behaviour of this function. It is only intended to aid debugging memory errors. + +## Example + +```c +int *array = (int *) EsHeapAllocate(sizeof(int) * 10, true); + +for (int i = 0; i < 5; i++) { + array[i] = i + 1; +} + +for (int i = 0; i < 10; i++) { + EsPrint("%d ", array[i]); // Prints 1 2 3 4 5 0 0 0 0 0. +} + +EsPrint("\n"); + +array = (int *) EsHeapReallocate(array, sizeof(int) * 15, true); + +for (int i = 0; i < 15; i++) { + EsPrint("%d ", array[i]); // Prints 1 2 3 4 5 0 0 0 0 0 0 0 0 0 0. +} + +EsHeapFree(array); +``` + +# Rectangles + +## Definitions + +```c +struct EsRectangle { + int32_t l; + int32_t r; + int32_t t; + int32_t b; +}; + +#define ES_RECT_1(x) ((EsRectangle) { (int32_t) (x), (int32_t) (x), (int32_t) (x), (int32_t) (x) }) +#define ES_RECT_1I(x) ((EsRectangle) { (int32_t) (x), (int32_t) -(x), (int32_t) (x), (int32_t) -(x) }) +#define ES_RECT_2(x, y) ((EsRectangle) { (int32_t) (x), (int32_t) (x), (int32_t) (y), (int32_t) (y) }) +#define ES_RECT_2I(x, y) ((EsRectangle) { (int32_t) (x), (int32_t) -(x), (int32_t) (y), (int32_t) -(y) }) +#define ES_RECT_2S(x, y) ((EsRectangle) { 0, (int32_t) (x), 0, (int32_t) (y) }) +#define ES_RECT_4(x, y, z, w) ((EsRectangle) { (int32_t) (x), (int32_t) (y), (int32_t) (z), (int32_t) (w) }) +#define ES_RECT_4PD(x, y, w, h) ((EsRectangle) { (int32_t) (x), (int32_t) ((x) + (w)), (int32_t) (y), (int32_t) ((y) + (h)) }) +#define ES_RECT_WIDTH(_r) ((_r).r - (_r).l) +#define ES_RECT_HEIGHT(_r) ((_r).b - (_r).t) +#define ES_RECT_TOTAL_H(_r) ((_r).r + (_r).l) +#define ES_RECT_TOTAL_V(_r) ((_r).b + (_r).t) +#define ES_RECT_ALL(_r) (_r).l, (_r).r, (_r).t, (_r).b +#define ES_RECT_VALID(_r) (ES_RECT_WIDTH(_r) > 0 && ES_RECT_HEIGHT(_r) > 0) + +EsRectangle EsRectangleAdd(EsRectangle a, EsRectangle b); +EsRectangle EsRectangleAddBorder(EsRectangle rectangle, EsRectangle border); +EsRectangle EsRectangleBounding(EsRectangle a, EsRectangle b); +EsRectangle EsRectangleCenter(EsRectangle parent, EsRectangle child); +EsRectangle EsRectangleCut(EsRectangle a, int32_t amount, char side); +EsRectangle EsRectangleFit(EsRectangle parent, EsRectangle child, bool allowScalingUp); +EsRectangle EsRectangleIntersection(EsRectangle a, EsRectangle b); +EsRectangle EsRectangleSplit(EsRectangle *a, int32_t amount, char side, int32_t gap = 0); +EsRectangle EsRectangleSubtract(EsRectangle a, EsRectangle b); +EsRectangle EsRectangleTranslate(EsRectangle a, EsRectangle b); +bool EsRectangleEquals(EsRectangle a, EsRectangle b); +bool EsRectangleContains(EsRectangle a, int32_t x, int32_t y); +``` + +## Description + +`EsRectangle` is used to store an integral rectangular region. `l` gives the offset of the left edge, `r` the right edge, `t` the top edge, and `b` the bottom edge. Note that this means the rectangle does not contain the pixels with x coordinate `r` and y coordinate `b`. The edges are stored are 32-bit signed integers. TODO Diagram. + +`EsRectangleAdd` performs a component-wise sum of two rectangles. + +`EsRectangleAddBorder` is similar to `EsRectangleAdd`, but it negates the `r` and `b` fields of `border` before the addition. TODO Diagram. + +`EsRectangleSubtract` is similar to `EsRectangleAdd`, but it negates all fields of the second rectangle before the addition. TODO Diagram. + +`EsRectangleTranslate` is similar to `EsRectangleAdd`, but it sets `r` to `l` and `b` to `t` in the second rectangle before the addition. TODO Diagram. + +`EsRectangleBounding` computes the smallest possible rectangle that contains both parameters. TODO Diagram. + +`EsRectangleCenter` centers the `child` rectangle within the `parent` rectangle. The origin of `child` is ignored; only its dimensions matter. TODO Diagram. + +`EsRectangleCut` cuts a slice of a rectangle, by moving one of the edges of the input rectangle. The returned rectangle is the slice that was cut off. `side` determines the edge; it is a single character, set to be the same as the name of the field that will be modified. If `amount` is positive, then the edge will be moved inwards by that amount. If `amount` is negative, then the edge will be moved outwards by the absolute value. TODO Diagram. + +`EsRectangleSplit` is similar to `EsRectangleCut`, except it modifies the input rectangle so that it contains the modified rectangle after a side is moved. `gap` may be optionally specified to change the distance between the two returned rectangles. TODO Diagram. + +`EsRectangleFit` resizes and moves the `child` rectangle, while preserving its aspect ratio, so that it fits in, and is centered in, `parent`. If `allowScalingUp` is set to `false`, the function will never resize `child` to a larger size. TODO Diagram. + +`EsRectangleIntersection` computes the intersection of the two parameters. TODO Diagram. + +`EsRectangleEquals` returns `true` if the rectangles are identical, otherwise `false`. + +`EsRectangleContains` returns `true` if the rectangle contains the specified point, otherwise `false`. Recall, as noted above, if `x` is `r` or larger, the point is considered to not be inside the rectangle, and similarly if `y` is `b` or larger. + +`ES_RECT_1` creates a rectangle where all fields are the same value. `ES_RECT_1I` creates a rectangle similarly, except `r` and `b` are negated. + +`ES_RECT_2` creates a rectangle where `l` and `r` are the same value, and `t` and `b` are the same value. `ES_RECT_2I` creates a rectangle similarly, except `r` and `b` are negated. `ES_RECT_2S` creates a rectangle with its top-left corner at `(0, 0)`, with the specified width and height. + +`ES_RECT_4` creates a rectangle with the specified values of `l`, `r`, `t` and `b`. `ES_RECT_4PD` creates a rectangle with its top-left corner at `(x, y)` and a width of `w` and height of `h`. + +`ES_RECT_WIDTH` returns the width of a rectangle. `ES_RECT_HEIGHT` returns the height. `ES_RECT_TOTAL_H` returns the sum of the left and right components. `ES_RECT_TOTAL_V` returns the sum of the top and bottom coponents. + +`ES_RECT_ALL` splits a rectangle into its four components, separated by commas. + +`ES_RECT_VALID` returns `true` if the rectangle has positive width and height, otherwise `false`. + +# Text plans + +## Definitions + +```c +struct EsTextRun { + EsTextStyle style; + uint32_t offset; +}; + +struct EsTextPlanProperties { + EsCString cLanguage; + uint32_t flags; + int maxLines; +}; + +#define ES_TEXT_H_LEFT (1 << 0) +#define ES_TEXT_H_CENTER (1 << 1) +#define ES_TEXT_H_RIGHT (1 << 2) +#define ES_TEXT_V_TOP (1 << 3) +#define ES_TEXT_V_CENTER (1 << 4) +#define ES_TEXT_V_BOTTOM (1 << 5) +#define ES_TEXT_ELLIPSIS (1 << 6) +#define ES_TEXT_WRAP (1 << 7) +#define ES_TEXT_PLAN_SINGLE_USE (1 << 8) +#define ES_TEXT_PLAN_TRIM_SPACES (1 << 9) +#define ES_TEXT_PLAN_RTL (1 << 10) +#define ES_TEXT_PLAN_CLIP_UNBREAKABLE_LINES (1 << 11) + +EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *textRuns, size_t textRunCount); + +int EsTextPlanGetWidth(EsTextPlan *plan); +int EsTextPlanGetHeight(EsTextPlan *plan); +size_t EsTextPlanGetLineCount(EsTextPlan *plan); + +void EsTextPlanDestroy(EsTextPlan *plan); + +void EsTextPlanReplaceStyleRenderProperties(EsTextPlan *plan, EsTextStyle *style); +``` + +## Description + +Before you can draw text, you first need to create a *text plan*, which contains all the necessary information to draw the text. The advantage of using text plans is that it enables you to draw the same block of text multiple times without needing the text shaping and layout to be recalculated. + +To create a text plan, use `EsTextPlanCreate`. +- `properties`: Contains properties to apply while laying out the text. `cLanguage` is the BCP 47 language tag as a string; if `NULL`, the default language is used. `maxLines` contains the maximum number of lines allowed in the layout, after which lines will be clipped; if `0`, the number of lines will be unlimited. `flags` contains any combination of the following constants: + - `ES_TEXT_H/V_...`: Sets the alignment of the text in the bounds. + - `ES_TEXT_WRAP`: The text is allowed to wrap when it reaches the end of a line. + - `ES_TEXT_ELLIPSIS`: If the text is to be truncated, an ellipsis will be inserted. + - `ES_TEXT_PLAN_SINGLE_USE`: Set to automatically destroy the text plan after the first time it is drawn. + - `ES_TEXT_PLAN_TRIM_SPACES`: Removes any leading and trailing spaces from each line. + - `ES_TEXT_PLAN_RTL`: Sets the default text direction to right-to-left. + - `ES_TEXT_PLAN_CLIP_UNBREAKABLE_LINES`: If a word is to long to be word-wrapped, prevent it being from being wrapped regardless, and clip it instead. + - `ES_TEXT_PLAN_NO_FONT_SUBSTITUTION`: Prevents font substitution. Otherwise, glyphs missing from the selected font will be drawn in an automatically-selected font that does support them. +- `bounds`: Gives the width and height of the bounds in which the text will be drawn. Only the dimensions of this rectangle matters. It is unused if word wrapping is disabled, and no text alignment flags are specified. +- `string`: Gives the text string, in UTF-8. This string should remain accessible until the text plan is destroyed. +- `textRuns`: An array of text runs, describing the offset and style of each run in the text. The length of each run is automatically calculated as the difference between its offset and the offset of the next run in the array. The first run should have an offset of `0`. The last item in the array should have its `offset` field set to be the total length of the input string, i.e. the end of the last run. The `style` field of the last item is ignored. +- `textRunCount`: The number of text runs in the array. **Note** that the last item in the array should not be included in this count, because it itself does not describe a run, it is only used to indicate the end position of the actual last run. + +Once a text plan has been created, it can be drawn with `EsDrawText`. Information about the calculated text layout can be accessed with `EsTextPlanGetWidth` (returns the horizontal size of the layout), `EsTextPlanGetHeight` (returns the vertical size), and `EsTextPlanGetLineCount` (returns the number of lines in the layout, including lines containing wrapped text). The text plan can be destroyed with `EsTextPlanDestroy`. + +After a text plan is created, some of the style properties can be replaced. These are called the *render properties*, because they only are used when the text is rendered, and do not affect the layout. These are the `color`, `blur`, `decorations` and `decorationsColor` fields in `EsTextStyle`. They can be replaced using `EsTextPlanReplaceStyleRenderProperties`. Note that this replaces the properties for all text runs in the text plan. + +## Example + +```c +void DrawElementText(EsElement *element, EsRectangle bounds, const char *string, size_t stringBytes) { + EsTextRun textRun[2] = {}; + EsElementGetTextStyle(element, &textRun[0].style); + textRun[0].offset = 0; + textRun[1].offset = stringBytes; + EsTextPlanProperties properties = {}; + EsTextPlan *plan = EsTextPlanCreate(&properties, bounds, string, textRun, 1); + EsDrawText(painter, plan, bounds, nullptr, nullptr); + EsTextPlanDestroy(plan); +} +``` + +# CRT functions + +## Description + +The Essence API provides a number of functions from the C standard library which may be used without requiring the POSIX subsystem. See the API header file for an authoritative list of which functions are available. Please note that the functions may not be fully compliant with standards where it would cause unwanted complexity. The functions are prefixed with `EsCRT`; to use the functions without needing this prefix, define `ES_CRT_WITHOUT_PREFIX` before including the API header. diff --git a/desktop/gui.cpp b/desktop/gui.cpp new file mode 100644 index 0000000..8029490 --- /dev/null +++ b/desktop/gui.cpp @@ -0,0 +1,7259 @@ +// TODO Styling features: +// - Specifying aspect ratio of element. +// - Animation parts (list of keyframes). +// - Ripple animations. +// - Exiting animations. +// - Morph from/to entrance/exit animations. +// TODO Close menus within menus (bug). +// TODO Keyboard navigation - menus; escape to restore default focus. +// TODO Middle click panning. +// TODO Scrollbar middle click and zooming; scroll wheel. +// TODO Textboxes: date/time overlays, keyboard shortcut overlay, custom overlays. +// TODO Breadcrumb bar overflow menu; keep hover after recreating UI. +// TODO Textbox embedded objects. +// TODO Closing windows in menu/access key mode. +// TODO Ignore ES_MSG_LAYOUT in panels if layout.sizeChanged is false? + +// Behaviour of activation clicks. --> Only ignore activation clicks from menus. +// Behaviour of the scroll wheel with regards to focused/hovered elements --> Scroll the hovered element only. + +#define WINDOW_INSET ((int) api.systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET]) +#define CONTAINER_TAB_BAND_HEIGHT ((int) api.systemConstants[ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT]) +#define BORDER_THICKNESS ((int) api.systemConstants[ES_SYSTEM_CONSTANT_BORDER_THICKNESS]) + +// #define TRACE_LAYOUT + +struct AccessKeyEntry { + char character; + int number; + EsElement *element; + int x, y; +}; + +struct { + // Animations. + EsTimer animationSleepTimer; + bool animationSleep; + Array animatingElements; + + // Input. + bool draggingStarted, mouseButtonDown; + uint8_t leftModifiers, rightModifiers; + int lastClickX, lastClickY, lastClickButton, resizeType; + + // Menus. + bool menuMode; + + // Access keys. + bool accessKeyMode, unhandledAltPress; + + struct { + Array entries; + int numbers[26]; + struct UIStyle *hintStyle; + EsWindow *window; + char typedCharacter; + } accessKeys; + + // Misc. + Array allWindows; + HashTable keyboardShortcutNames; + EsCursorStyle resizeCursor; + bool resizing; + EsElement *insertAfter; + + // Click chains. + double clickChainStartMs; + int clickChainCount; + EsElement *clickChainElement; +} gui; + +struct TableCell { + uint16_t from[2], to[2]; +}; + +// Miscellanous forward declarations. +void UIWindowPaintNow(EsWindow *window, ProcessMessageTiming *timing, bool afterResize); +EsElement *WindowGetMainPanel(EsWindow *window); +int AccessKeyLayerMessage(EsElement *element, EsMessage *message); +void AccessKeyModeExit(); +int ProcessButtonMessage(EsElement *element, EsMessage *message); +void UIMousePressReleased(EsWindow *window, EsMessage *message, bool sendClick); +void UIMaybeRemoveFocusedElement(EsWindow *window); +EsTextStyle TextPlanGetPrimaryStyle(EsTextPlan *plan); +EsElement *UIFindHoverElementRecursively(EsElement *element, int offsetX, int offsetY, EsPoint position); +const EsStyle *UIGetDefaultStyleVariant(const EsStyle *style, EsElement *parent); + +void InspectorSetup(EsWindow *window); +void InspectorNotifyElementEvent(EsElement *element, const char *cCategory, const char *cFormat, ...); +void InspectorNotifyElementCreated(EsElement *element); +void InspectorNotifyElementDestroyed(EsElement *element); +void InspectorNotifyElementMoved(EsElement *element, EsRectangle takenBounds); +void InspectorNotifyElementPainted(EsElement *element, EsPainter *painter); +void InspectorNotifyElementContentChanged(EsElement *element); + +#define UI_STATE_RELAYOUT (1 << 2) +#define UI_STATE_RELAYOUT_CHILD (1 << 3) +#define UI_STATE_DESTROYING (1 << 4) +#define UI_STATE_DESTROYING_CHILD (1 << 5) + +#define UI_STATE_HOVERED (1 << 6) +#define UI_STATE_PRESSED (1 << 7) +#define UI_STATE_STRONG_PRESSED (1 << 8) +#define UI_STATE_FOCUS_WITHIN (1 << 9) +#define UI_STATE_FOCUSED (1 << 10) +#define UI_STATE_LOST_STRONG_FOCUS (1 << 11) +#define UI_STATE_MENU_SOURCE (1 << 12) + +#define UI_STATE_ANIMATING (1 << 13) +#define UI_STATE_ENTERED (1 << 14) +#define UI_STATE_EXITING (1 << 15) +#define UI_STATE_BLOCK_INTERACTION (1 << 16) + +#define UI_STATE_TEMP (1 << 17) +#define UI_STATE_Z_STACK (1 << 18) +#define UI_STATE_COMMAND_BUTTON (1 << 19) +#define UI_STATE_USE_MEASUREMENT_CACHE (1 << 20) +#define UI_STATE_CHECK_VISIBLE (1 << 21) +#define UI_STATE_INSPECTING (1 << 22) + +struct EsElement : EsElementPublic { + EsUICallbackFunction messageClass; + EsElement *parent; + Array children; + uint32_t state; + + uint8_t transitionType; + uint16_t customStyleState; // ORed to the style state in RefreshStyle. + uint16_t previousStyleState; // Set by RefreshStyleState. + uint16_t transitionDurationMs, transitionTimeMs; + uint64_t lastTimeStamp; + UIStyle *currentStyle; + UIStyleKey currentStyleKey; + ThemeAnimation animation; + EsPaintTarget *previousTransitionFrame; + + int width, height, offsetX, offsetY; + uint8_t internalOffsetLeft, internalOffsetRight, internalOffsetTop, internalOffsetBottom; + TableCell tableCell; + + void Destroy(bool manual = true); + void PrintTree(int depth = 0); + + inline size_t GetChildCount() { + return children.Length(); + } + + inline EsElement *GetChild(uintptr_t index) { + EsAssert(index < children.Length()); // Invalid child index. + return children[index]; + } + + inline EsElement *GetChildByZ(uintptr_t index) { + EsMessage m = { ES_MSG_Z_ORDER }; + m.zOrder.index = index, m.zOrder.child = GetChild(index); + if (m.zOrder.child->flags & ES_ELEMENT_NON_CLIENT) return m.zOrder.child; + if (ES_REJECTED == EsMessageSend(this, &m)) return nullptr; + EsAssert(!m.zOrder.child || m.zOrder.child->parent == this); // Child obtained from ES_MSG_Z_ORDER had different parent. + return m.zOrder.child; + } + + void BringToFront() { + for (uintptr_t i = 0; i < parent->children.Length(); i++) { + if (parent->children[i] == this) { + InspectorNotifyElementDestroyed(this); + EsElement *swap = parent->children.Last(); + parent->children.Last() = this; + parent->children[i] = swap; + InspectorNotifyElementCreated(this); + return; + } + } + + EsAssert(false); + } + + bool IsFocusable() { + if ((~flags & ES_ELEMENT_FOCUSABLE) || (flags & ES_ELEMENT_DISABLED) || (state & UI_STATE_DESTROYING)) { + return false; + } + + EsElement *element = this; + + while (element) { + if ((element->flags & ES_ELEMENT_BLOCK_FOCUS) || (element->state & UI_STATE_BLOCK_INTERACTION) || (element->flags & ES_ELEMENT_HIDDEN)) { + return false; + } + + element = element->parent; + } + + return true; + } + + bool RefreshStyleState(); // Returns true if any observed bits have changed. + void RefreshStyle(UIStyleKey *oldStyleKey = nullptr, bool alreadyRefreshStyleState = false, bool force = false); + bool StartAnimating(); + void SetStyle(const EsStyle *stylePart, bool refreshIfChanged = true); + + inline void MaybeRefreshStyle() { + if (RefreshStyleState()) { + RefreshStyle(nullptr, true); + } + } + + inline EsRectangle GetWindowBounds(bool client = true) { return EsElementGetWindowBounds(this, client); } + inline EsRectangle GetScreenBounds(bool client = true) { return EsElementGetScreenBounds(this, client); } + inline EsRectangle GetBounds() { return ES_RECT_2S(width - internalOffsetLeft - internalOffsetRight, height - internalOffsetTop - internalOffsetBottom); } + +#define PAINT_SHADOW (1 << 0) // Paint the shadow layers. +#define PAINT_NO_OFFSET (1 << 1) // Don't add the element's offset to the painter. +#define PAINT_NO_TRANSITION (1 << 2) // Ignore entrance/exit transitions. +#define PAINT_OVERLAY (1 << 3) // Paint the overlay layers. + void InternalPaint(EsPainter *painter, int flags); + + void InternalMove(int _width, int _height, int _offsetX, int _offsetY); // Non-client offset. + void InternalCalculateRepaintRegion(int x, int y, bool forwards, bool overlappedBySibling = false); + bool InternalDestroy(); // Called after processing each message, to destroy any elements marked by ::Destroy. + + int GetWidth(int height); + int GetHeight(int width); + + void Repaint(bool all, EsRectangle region = ES_RECT_1(0) /* client coordinates */); + + void Initialise(EsElement *_parent, uint64_t _flags, EsUICallbackFunction _classCallback, const EsStyle *style); +}; + +struct MeasurementCache { + int width0, width2, width2Height; + int height0, height2, height2Width; + + bool Get(EsMessage *message, uint32_t *state) { + if (~(*state) & UI_STATE_USE_MEASUREMENT_CACHE) { + width0 = 0, width2 = 0, width2Height = 0; + height0 = 0, height2 = 0, height2Width = 0; + *state |= UI_STATE_USE_MEASUREMENT_CACHE; + } + + if (message->type == ES_MSG_GET_WIDTH) { + if (message->measure.height && message->measure.height == width2Height) { + message->measure.width = width2; + } else if (!message->measure.height && width0) { + message->measure.width = width0; + } else { + return false; + } + } else { + if (message->measure.width && message->measure.width == height2Width) { + message->measure.height = height2; + } else if (!message->measure.width && height0) { + message->measure.height = height0; + } else { + return false; + } + } + + return true; + } + + void Store(EsMessage *message) { + if (message->type == ES_MSG_GET_WIDTH) { + if (message->measure.height) { + width2 = message->measure.width; + width2Height = message->measure.height; + } else { + width0 = message->measure.width; + } + } else { + if (message->measure.width) { + height2Width = message->measure.width; + height2 = message->measure.height; + } else { + height0 = message->measure.height; + } + } + } +}; + +struct EsButton : EsElement { + char *label; + size_t labelBytes; + EsGeneric menuItemContext; + uint32_t iconID; + MeasurementCache measurementCache; + EsCommand *command; + EsCommandCallbackFunction onCommand; + EsElement *checkBuddy; +}; + +struct ScrollPane { + EsElement *parent, *pad; + EsScrollbar *bar[2]; + double position[2]; + int64_t limit[2]; + int32_t fixedViewport[2]; + bool dragScrolling; + +#define SCROLL_MODE_NONE (0) // No scrolling takes place on this axis. +#define SCROLL_MODE_HIDDEN (1) // Scrolling takes place, but there is no visible scrollbar. +#define SCROLL_MODE_FIXED (2) // The scrollbar is always visible. +#define SCROLL_MODE_AUTO (3) // The scrollbar is only visible if the content is larger than the viewport. + uint8_t mode[2]; +#define SCROLL_X_DRAG (1 << 0) +#define SCROLL_Y_DRAG (1 << 1) + uint16_t flags; + + void Setup(EsElement *parent, uint8_t xMode, uint8_t yMode, uint16_t flags); + void SetPosition(int axis, double newPosition, bool sendMovedMessage = true); + void Refresh(); + void ReceivedMessage(EsMessage *message); + + inline void SetX(double scrollX, bool sendMovedMessage = true) { SetPosition(0, scrollX, sendMovedMessage); } + inline void SetY(double scrollY, bool sendMovedMessage = true) { SetPosition(1, scrollY, sendMovedMessage); } + + // Internal. + bool RefreshLimit(int axis, int64_t *content); +}; + +struct PanelMovementItem { + EsElement *element; + EsRectangle oldBounds; +}; + +struct EsPanel : EsElement { + // TODO Make this structure smaller? + + ScrollPane scroll; + + const EsStyle *separatorStylePart; + bool addingSeparator; + uint64_t separatorFlags; + + uint16_t bandCount[2]; + EsPanelBand *bands[2]; + uintptr_t tableIndex; + + uint16_t transitionType; + uint32_t transitionTimeMs, + transitionLengthMs; + + bool destroyPreviousAfterTransitionCompletes; + EsElement *switchedTo, + *switchedFrom; + + Array movementItems; + + MeasurementCache measurementCache; + + int GetGapMajor() { + return currentStyle->gapMajor; + } + + int GetGapMinor() { + return currentStyle->gapMinor; + } + + EsRectangle GetInsets() { + return currentStyle->insets; + } + + int GetInsetWidth() { + EsRectangle insets = GetInsets(); + return insets.l + insets.r; + } + + int GetInsetHeight() { + EsRectangle insets = GetInsets(); + return insets.t + insets.b; + } +}; + +struct EsTextDisplay : EsElement { + EsTextPlanProperties properties; + EsTextRun *textRuns; + size_t textRunCount; + char *contents; + + bool usingSyntaxHighlighting; + + MeasurementCache measurementCache; + EsTextPlan *plan; + int planWidth, planHeight; +}; + +struct ColorPickerHost { + struct EsElement *well; + bool *indeterminate; + bool hasOpacity; +}; + +void ColorPickerCreate(EsElement *parent, ColorPickerHost host, uint32_t initialColor, bool showTextbox); + +void HeapDuplicate(void **pointer, const void *data, size_t bytes) { + if (*pointer) { + EsHeapFree(*pointer); + } + + if (!data && !bytes) { + *pointer = nullptr; + } else { + void *buffer = EsHeapAllocate(bytes, false); + EsMemoryCopy(buffer, data, bytes); + *pointer = buffer; + } +} + +// --------------------------------- Windows. + +struct EsWindow : EsElement { + EsHandle handle; + uint32_t windowWidth, windowHeight; + + bool willUpdate, toolbarFillMode, destroyInstanceAfterClose, hasDialog, doNotPaint; + bool restoreOnNextMove, resetPositionOnNextMove, receivedFirstResize, isMaximised; + bool hovering, activated; + bool visualizeRepaints, visualizeLayoutBounds, visualizePaintSteps; // Inspector properties. + + EsPoint mousePosition; + + EsElement *mainPanel, *toolbar; + EsPanel *toolbarSwitcher; + + EsElement *hovered, + *pressed, + *focused, + *inactiveFocus, + *dragged, + *ensureVisible; + + EsButton *enterButton, + *escapeButton, + *defaultEnterButton; + + // An array of elements that we check are visible after every layout. + // e.g. image displays that want to unload the decoded bitmap when they are scrolled off-screen. + // TODO Support a more advanced queueing system for scroll panes asynchronous tasks. + Array checkVisible; + bool processCheckVisible; + + EsElement *dialogOverlay, *dialogPanel; + EsWindowStyle windowStyle; + EsRectangle beforeMaximiseBounds; + + EsRectangle updateRegion; + EsRectangle updateRegionInProgress; // For visualizePaintSteps. + + Array sizeAlternatives; + + EsElement *source; // Menu source. + EsWindow *targetMenu; // The menu that keyboard events should be sent to. + + int32_t announcementBaseY; + double announcementTimeMs; +}; + +struct SizeAlternative { + EsElement *small, *big; + int widthThreshold, heightThreshold; +}; + +// --------------------------------- Container windows. + +#define RESIZE_LEFT (1) +#define RESIZE_RIGHT (2) +#define RESIZE_TOP (4) +#define RESIZE_BOTTOM (8) +#define RESIZE_TOP_LEFT (5) +#define RESIZE_TOP_RIGHT (6) +#define RESIZE_BOTTOM_LEFT (9) +#define RESIZE_BOTTOM_RIGHT (10) +#define RESIZE_MOVE (0) + +#define SNAP_EDGE_MAXIMIZE (1) +#define SNAP_EDGE_LEFT (2) +#define SNAP_EDGE_RIGHT (3) + +void WindowSnap(EsWindow *window, bool restored, bool dragging, uint8_t edge) { + if (window->isMaximised) { + return; + } + + EsRectangle screen; + EsSyscall(ES_SYSCALL_SCREEN_WORK_AREA_GET, 0, (uintptr_t) &screen, 0, 0); + + if (!window->restoreOnNextMove && !restored) { + window->beforeMaximiseBounds = EsWindowGetBounds(window); + } + + window->restoreOnNextMove = true; + window->isMaximised = edge == SNAP_EDGE_MAXIMIZE; + + EsRectangle bounds; + + if (edge == SNAP_EDGE_MAXIMIZE) { + bounds.t = screen.t - 16 * theming.scale; + bounds.b = screen.b + 19 * theming.scale; + bounds.l = screen.l - 19 * theming.scale; + bounds.r = screen.r + 19 * theming.scale; + } else if (edge == SNAP_EDGE_LEFT) { + bounds.t = screen.t; + bounds.b = screen.b; + bounds.l = screen.l; + bounds.r = (screen.r + screen.l) / 2; + } else if (edge == SNAP_EDGE_RIGHT) { + bounds.t = screen.t; + bounds.b = screen.b; + bounds.l = (screen.r + screen.l) / 2; + bounds.r = screen.r; + } + + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &bounds, 0, + ES_WINDOW_MOVE_DYNAMIC | (edge == SNAP_EDGE_MAXIMIZE ? ES_WINDOW_MOVE_MAXIMISED : 0)); + + if (!dragging) { + window->resetPositionOnNextMove = true; + } +} + +void WindowRestore(EsWindow *window) { + if (!window->restoreOnNextMove) { + return; + } + + window->isMaximised = false; + window->restoreOnNextMove = false; + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &window->beforeMaximiseBounds, 0, ES_WINDOW_MOVE_DYNAMIC); +} + +void WindowChangeBounds(int direction, int newX, int newY, int *originalX, int *originalY, EsWindow *window) { + EsRectangle bounds = EsWindowGetBounds(window), bounds2; + bounds2 = bounds; + + int oldWidth = bounds.r - bounds.l; + int oldHeight = bounds.b - bounds.t; + bool restored = false, canSnap = true; + + if (window->restoreOnNextMove) { + window->restoreOnNextMove = false; + oldWidth = window->beforeMaximiseBounds.r - window->beforeMaximiseBounds.l; + oldHeight = window->beforeMaximiseBounds.b - window->beforeMaximiseBounds.t; + restored = true; + } + + if (direction & RESIZE_LEFT) bounds.l = newX + BORDER_THICKNESS / 2 - WINDOW_INSET; + if (direction & RESIZE_RIGHT) bounds.r = newX - BORDER_THICKNESS / 2 + WINDOW_INSET; + if (direction & RESIZE_TOP) bounds.t = newY + BORDER_THICKNESS / 2 - WINDOW_INSET; + if (direction & RESIZE_BOTTOM) bounds.b = newY - BORDER_THICKNESS / 2 + WINDOW_INSET; + + EsRectangle screen; + EsSyscall(ES_SYSCALL_SCREEN_WORK_AREA_GET, 0, (uintptr_t) &screen, 0, 0); + + int newWidth = bounds.r - bounds.l; + int newHeight = bounds.b - bounds.t; + + int windowSnapRange = GetConstantNumber("windowSnapRange"); + int windowMinimumWidth = GetConstantNumber("windowMinimumWidth"); + int windowMinimumHeight = GetConstantNumber("windowMinimumHeight"); + int windowRestoreDragYPosition = GetConstantNumber("windowRestoreDragYPosition"); + + window->isMaximised = false; + + if (newWidth < windowMinimumWidth && direction & RESIZE_LEFT) bounds.l = bounds.r - windowMinimumWidth; + if (newWidth < windowMinimumWidth && direction & RESIZE_RIGHT) bounds.r = bounds.l + windowMinimumWidth; + if (newHeight < windowMinimumHeight && direction & RESIZE_TOP) bounds.t = bounds.b - windowMinimumHeight; + if (newHeight < windowMinimumHeight && direction & RESIZE_BOTTOM) bounds.b = bounds.t + windowMinimumHeight; + + if (direction == RESIZE_MOVE) { + if (newY < screen.t + windowSnapRange && canSnap) { + WindowSnap(window, restored, true, SNAP_EDGE_MAXIMIZE); + return; + } else if (newX < screen.l + windowSnapRange && canSnap) { + WindowSnap(window, restored, true, SNAP_EDGE_LEFT); + return; + } else if (newX >= screen.r - windowSnapRange && canSnap) { + WindowSnap(window, restored, true, SNAP_EDGE_RIGHT); + return; + } else { + if (restored && window->resetPositionOnNextMove) { + // The user previously snapped/maximised the window in a previous operation. + // Therefore, the movement anchor won't be what the user expects. + // Try to put it in the center. + int positionAlongWindow = *originalX - bounds2.l; + int maxPosition = bounds2.r - bounds2.l; + if (positionAlongWindow > maxPosition - oldWidth / 2) *originalX = gui.lastClickX = positionAlongWindow - maxPosition + oldWidth; + else if (positionAlongWindow > oldWidth / 2) *originalX = gui.lastClickX = oldWidth / 2; + *originalY = gui.lastClickY = windowRestoreDragYPosition; + window->resetPositionOnNextMove = false; + } + + bounds.l = newX - *originalX; + bounds.t = newY - *originalY; + bounds.r = bounds.l + oldWidth; + bounds.b = bounds.t + oldHeight; + } + } else { + window->resetPositionOnNextMove = window->restoreOnNextMove = false; + } + + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &bounds, 0, ES_WINDOW_MOVE_DYNAMIC); +} + +int ProcessWindowBorderMessage(EsWindow *window, EsMessage *message, EsRectangle bounds, int from, int to) { + if (message->type == ES_MSG_GET_CURSOR) { + EsPoint position = EsMouseGetPosition(window); + message->cursorStyle = ES_CURSOR_NORMAL; + + if (window->isMaximised) { + gui.resizeType = 0; + gui.resizeCursor = message->cursorStyle; + } else { + bool left = position.x < to, right = position.x >= bounds.r - to, + top = position.y < to, bottom = position.y >= bounds.b - to; + + if (gui.resizing) { + message->cursorStyle = gui.resizeCursor; + } else if (position.x < from || position.y < from + || position.x >= bounds.r - from || position.y >= bounds.b - from) { + } else if ((right && top) || (bottom && left)) { + message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_1; + } else if ((left && top) || (bottom && right)) { + message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_2; + } else if (left || right) { + message->cursorStyle = ES_CURSOR_RESIZE_HORIZONTAL; + } else if (top || bottom) { + message->cursorStyle = ES_CURSOR_RESIZE_VERTICAL; + } + + if (!window->pressed && !gui.mouseButtonDown) { + gui.resizeType = (left ? RESIZE_LEFT : 0) | (right ? RESIZE_RIGHT : 0) | (top ? RESIZE_TOP : 0) | (bottom ? RESIZE_BOTTOM : 0); + gui.resizeCursor = message->cursorStyle; + } + } + + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + EsPoint screenPosition = EsMouseGetPosition(nullptr); + + if (!window->isMaximised || gui.resizeType == RESIZE_MOVE) { + WindowChangeBounds(gui.resizeType, + screenPosition.x, screenPosition.y, + &gui.lastClickX, &gui.lastClickY, window); + gui.resizing = true; + } + } else if (message->type == ES_MSG_MOUSE_LEFT_UP) { + if (window->restoreOnNextMove) { + window->resetPositionOnNextMove = true; + } + + gui.resizing = false; + } else { + return 0; + } + + return ES_HANDLED; +} + +// --------------------------------- Dialogs. + +void EsDialogClose(EsWindow *window) { + EsMessageMutexCheck(); + EsAssert(window->hasDialog); // The window does not have an open dialog. + window->dialogPanel->Destroy(); + window->dialogOverlay->Destroy(); // TODO This looks bad if we immediately open a new dialog. But maybe it'll look alright with exiting transitions? + window->dialogOverlay = window->dialogPanel = nullptr; + window->children[0]->children[0]->flags &= ~ES_ELEMENT_BLOCK_FOCUS; + window->children[1]->state &= ~UI_STATE_BLOCK_INTERACTION; + window->hasDialog = false; +} + +EsElement *EsDialogShowAlert(EsWindow *window, const char *title, ptrdiff_t titleBytes, + const char *content, ptrdiff_t contentBytes, uint32_t iconID, uint32_t flags) { + EsElement *dialog = EsDialogShow(window); + EsPanel *heading = EsPanelCreate(dialog, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, ES_STYLE_DIALOG_HEADING); + + if (iconID) { + EsIconDisplayCreate(heading, ES_FLAGS_DEFAULT, {}, iconID); + } + + EsTextDisplayCreate(heading, ES_CELL_H_FILL | ES_CELL_V_CENTER, ES_STYLE_TEXT_HEADING2, + title, titleBytes)->cName = "dialog heading"; + EsTextDisplayCreate(EsPanelCreate(dialog, ES_CELL_H_FILL | ES_PANEL_VERTICAL, ES_STYLE_DIALOG_CONTENT), + ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, + content, contentBytes)->cName = "dialog contents"; + + EsPanel *buttonArea = EsPanelCreate(dialog, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL | ES_PANEL_REVERSE, ES_STYLE_DIALOG_BUTTON_AREA); + + if (flags & ES_DIALOG_ALERT_OK_BUTTON) { + EsButton *button = EsButtonCreate(buttonArea, ES_BUTTON_DEFAULT, 0, "OK"); + EsButtonOnCommand(button, [] (EsInstance *instance, EsElement *, EsCommand *) { EsDialogClose(instance->window); }); + EsElementFocus(button); + } + + return buttonArea; +} + +EsElement *EsDialogShow(EsWindow *window) { + EsAssert(window->windowStyle == ES_WINDOW_NORMAL); // Can only show dialogs on normal windows. + EsAssert(!window->hasDialog); // Cannot nest dialogs. + + EsElement *mainStack = window->children[0]; + mainStack->children[0]->flags |= ES_ELEMENT_BLOCK_FOCUS; + window->children[1]->state |= UI_STATE_BLOCK_INTERACTION; + window->hasDialog = true; + window->dialogOverlay = EsPanelCreate(mainStack, ES_CELL_FILL, ES_STYLE_PANEL_MODAL_OVERLAY); + window->dialogOverlay->cName = "modal overlay"; + window->dialogPanel = EsPanelCreate(mainStack, ES_PANEL_VERTICAL | ES_CELL_CENTER | ES_CELL_SHRINK, ES_STYLE_PANEL_DIALOG_ROOT); + window->dialogPanel->cName = "dialog"; + + return window->dialogPanel; +} + +// --------------------------------- Windows. + +void UIWindowNeedsUpdate(EsWindow *window) { + if (!window->willUpdate) { + EsMessage m = { ES_MSG_UPDATE_WINDOW }; + // Don't use the userland posted message queue, since we don't want this to block WM messages. + EsSyscall(ES_SYSCALL_MESSAGE_POST, (uintptr_t) &m, (uintptr_t) window, ES_CURRENT_PROCESS, 0); + window->willUpdate = true; + } +} + +void UIWindowDestroy(EsWindow *window) { + gui.allWindows.FindAndDeleteSwap(window, true); + AccessKeyModeExit(); + EsSyscall(ES_SYSCALL_WINDOW_CLOSE, window->handle, 0, 0, 0); + EsHandleClose(window->handle); + window->checkVisible.Free(); + window->handle = ES_INVALID_HANDLE; +} + +EsElement *WindowGetMainPanel(EsWindow *window) { + if (window->windowStyle == ES_WINDOW_MENU) { + if (!window->children[0]->GetChildCount()) { + EsMenuNextColumn((EsMenu *) window, ES_FLAGS_DEFAULT); + } + + return window->children[0]->GetChild(window->children[0]->GetChildCount() - 1); + } + + return window->mainPanel; +} + +int ProcessRootMessage(EsElement *element, EsMessage *message) { + EsWindow *window = (EsWindow *) element; + EsRectangle bounds = window->GetBounds(); + int response = 0; + + if (window->windowStyle == ES_WINDOW_CONTAINER) { + if (message->type == ES_MSG_LAYOUT) { + EsElementMove(window->GetChild(0), WINDOW_INSET, WINDOW_INSET, bounds.r - WINDOW_INSET * 2, CONTAINER_TAB_BAND_HEIGHT); + } else { + response = ProcessWindowBorderMessage(window, message, bounds, WINDOW_INSET - BORDER_THICKNESS, WINDOW_INSET); + } + } else if (window->windowStyle == ES_WINDOW_MENU) { + if (message->type == ES_MSG_PAINT_BACKGROUND) { + EsDrawClear(message->painter, message->painter->clip); + } else if (message->type == ES_MSG_LAYOUT) { + if (window->GetChildCount()) { + EsElementMove(window->GetChild(0), 0, 0, bounds.r, bounds.b); + } + } + } else if (window->windowStyle == ES_WINDOW_INSPECTOR) { + if (message->type == ES_MSG_LAYOUT) { + if (window->GetChildCount()) { + EsElementMove(window->GetChild(0), BORDER_THICKNESS, BORDER_THICKNESS + 30, + bounds.r - BORDER_THICKNESS * 2, bounds.b - BORDER_THICKNESS * 2 - 30); + } + } else { + response = ProcessWindowBorderMessage(window, message, bounds, 0, BORDER_THICKNESS); + } + } else if (window->windowStyle == ES_WINDOW_NORMAL) { + if (message->type == ES_MSG_LAYOUT) { + if (window->GetChildCount()) { + EsElement *toolbar = window->toolbarSwitcher; + + if (window->toolbarFillMode) { + EsElementMove(toolbar, 0, 0, bounds.r, bounds.b); + } else { + int toolbarHeight = toolbar->GetChildCount() ? toolbar->GetHeight(bounds.r) + : toolbar->currentStyle->metrics->minimumHeight; + EsElementMove(window->GetChild(0), 0, toolbarHeight, bounds.r, bounds.b - toolbarHeight); + EsElementMove(toolbar, 0, 0, bounds.r, toolbarHeight); + EsElementMove(window->GetChild(2), 0, 0, bounds.r, bounds.b); + } + } + } + } else if (window->windowStyle == ES_WINDOW_TIP || window->windowStyle == ES_WINDOW_PLAIN) { + if (message->type == ES_MSG_LAYOUT) { + if (window->GetChildCount()) { + EsElementMove(window->GetChild(0), 0, 0, bounds.r, bounds.b); + } + } + } + + if (message->type == ES_MSG_DESTROY) { + if (window->windowStyle != ES_WINDOW_NORMAL) { + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, ES_FLAGS_DEFAULT, 0, ES_WINDOW_PROPERTY_SOLID); + } + + if (window->windowStyle == ES_WINDOW_MENU) { + window->source->state &= ~UI_STATE_MENU_SOURCE; + window->source->MaybeRefreshStyle(); + EsAssert(window->source->window->targetMenu == window); + window->source->window->targetMenu = nullptr; + } + } + + return response; +} + +EsWindow *EsWindowCreate(EsInstance *instance, EsWindowStyle style) { + EsMessageMutexCheck(); + + for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) { + UIMousePressReleased(gui.allWindows[i], nullptr, false); + } + + EsWindow *window = (EsWindow *) EsHeapAllocate(sizeof(EsWindow), true); + gui.allWindows.Add(window); + window->instance = instance; + + if (style == ES_WINDOW_NORMAL) { + window->handle = ((APIInstance *) instance->_private)->mainWindowHandle; + } else { + window->handle = EsSyscall(ES_SYSCALL_WINDOW_CREATE, style, 0, (uintptr_t) window, 0); + } + + window->Initialise(nullptr, ES_CELL_FILL, ProcessRootMessage, nullptr); + window->cName = "window"; + window->window = window; + window->width = window->windowWidth, window->height = window->windowHeight; + window->hovered = window; + window->windowStyle = style; + window->RefreshStyle(); + + if (style == ES_WINDOW_NORMAL) { + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, 0, (uintptr_t) window, ES_WINDOW_PROPERTY_OBJECT); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, 0xFF000000 | GetConstantNumber("windowFillColor"), 0, ES_WINDOW_PROPERTY_RESIZE_CLEAR_COLOR); + window->activated = true; + EsPanel *panel = EsPanelCreate(window, ES_ELEMENT_NON_CLIENT | ES_CELL_FILL | ES_PANEL_Z_STACK, ES_STYLE_PANEL_NORMAL_WINDOW_ROOT); + panel->cName = "window stack"; + window->mainPanel = EsPanelCreate(panel, ES_CELL_FILL, ES_STYLE_PANEL_NORMAL_WINDOW_ROOT); + window->mainPanel->cName = "window root"; + window->toolbarSwitcher = EsPanelCreate(window, ES_ELEMENT_NON_CLIENT | ES_PANEL_SWITCHER | ES_CELL_FILL, ES_STYLE_PANEL_TOOLBAR_ROOT); + window->toolbarSwitcher->cName = "toolbar"; + EsElement *accessKeyLayer = EsCustomElementCreate(window, ES_ELEMENT_NON_CLIENT | ES_CELL_FILL | ES_ELEMENT_NO_HOVER, nullptr); + accessKeyLayer->cName = "access key layer"; + accessKeyLayer->messageUser = AccessKeyLayerMessage; + window->state |= UI_STATE_Z_STACK; + } else if (style == ES_WINDOW_CONTAINER) { + window->windowWidth = GetConstantNumber("windowDefaultWidth"); + window->windowHeight = GetConstantNumber("windowDefaultHeight"); + static int cascadeX = -1, cascadeY = -1; + EsRectangle workArea; + EsSyscall(ES_SYSCALL_SCREEN_WORK_AREA_GET, 0, (uintptr_t) &workArea, 0, 0); + int cascadeMargin = GetConstantNumber("windowCascadeMargin"); + int cascadeOffset = GetConstantNumber("windowCascadeOffset"); + if (cascadeX == -1 || cascadeX + (int) window->windowWidth > workArea.r - cascadeMargin) cascadeX = workArea.l + cascadeMargin; + if (cascadeY == -1 || cascadeY + (int) window->windowHeight > workArea.b - cascadeMargin) cascadeY = workArea.t + cascadeMargin; + EsRectangle bounds = ES_RECT_4(cascadeX, cascadeX + window->windowWidth, cascadeY, cascadeY + window->windowHeight); + if (bounds.r > workArea.r - cascadeMargin) bounds.r = workArea.r - cascadeMargin; + if (bounds.b > workArea.b - cascadeMargin) bounds.b = workArea.b - cascadeMargin; + cascadeX += cascadeOffset, cascadeY += cascadeOffset; + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &bounds, 0, ES_FLAGS_DEFAULT); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, 0, 0, ES_WINDOW_PROPERTY_FOCUSED); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, ES_WINDOW_SOLID_TRUE, 10, ES_WINDOW_PROPERTY_SOLID); + window->mainPanel = EsPanelCreate(window, ES_ELEMENT_NON_CLIENT | ES_CELL_FILL, ES_STYLE_PANEL_CONTAINER_WINDOW_ROOT); + window->SetStyle(ES_STYLE_CONTAINER_WINDOW_ACTIVE); + } else if (style == ES_WINDOW_INSPECTOR) { + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, ES_WINDOW_SOLID_TRUE, 0, ES_WINDOW_PROPERTY_SOLID); + window->SetStyle(ES_STYLE_PANEL_INSPECTOR_WINDOW_ROOT); + window->mainPanel = EsPanelCreate(window, ES_ELEMENT_NON_CLIENT | ES_CELL_FILL, ES_STYLE_PANEL_INSPECTOR_WINDOW_CONTAINER); + EsRectangle bounds = { 10, 600, 10, 500 }; + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &bounds, 0, ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN); + } else if (style == ES_WINDOW_TIP || style == ES_WINDOW_PLAIN) { + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, style == ES_WINDOW_PLAIN ? ES_WINDOW_SOLID_TRUE : ES_FLAGS_DEFAULT, 0, ES_WINDOW_PROPERTY_SOLID); + window->mainPanel = EsPanelCreate(window, ES_ELEMENT_NON_CLIENT | ES_CELL_FILL, nullptr); + } else if (style == ES_WINDOW_MENU) { + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, ES_WINDOW_SOLID_TRUE, 9 * theming.scale, ES_WINDOW_PROPERTY_SOLID); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, BLEND_WINDOW_MATERIAL_GLASS, 0, ES_WINDOW_PROPERTY_MATERIAL); + + window->SetStyle(ES_STYLE_PANEL_MENU_ROOT); + + EsPanel *panel = EsPanelCreate(window, ES_ELEMENT_NON_CLIENT | ES_PANEL_HORIZONTAL | ES_CELL_FILL, ES_STYLE_PANEL_MENU_CONTAINER); + panel->cName = "menu"; + panel->separatorStylePart = ES_STYLE_MENU_SEPARATOR_VERTICAL; + panel->separatorFlags = ES_CELL_V_FILL; + + panel->messageUser = [] (EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_PAINT) { + EsPainter *painter = message->painter; + EsRectangle blurBounds = element->GetWindowBounds(); + blurBounds = EsRectangleAddBorder(blurBounds, ((UIStyle *) painter->style)->insets); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, element->window->handle, (uintptr_t) &blurBounds, 0, ES_WINDOW_PROPERTY_BLUR_BOUNDS); + } + + return 0; + }; + + window->mainPanel = panel; + } + + if (style == ES_WINDOW_INSPECTOR) { + InspectorSetup(window); + } + + return window; +} + +void EsWindowAddSizeAlternative(EsWindow *window, EsElement *small, EsElement *big, int widthThreshold, int heightThreshold) { + EsMessageMutexCheck(); + EsAssert(small->window == window && big->window == window); + + SizeAlternative alternative = {}; + alternative.small = small, alternative.big = big; + alternative.widthThreshold = widthThreshold, alternative.heightThreshold = heightThreshold; + window->sizeAlternatives.Add(alternative); + + bool belowThreshold = window->width < widthThreshold || window->height < heightThreshold; + EsElementSetHidden(small, !belowThreshold); + EsElementSetHidden(big, belowThreshold); +} + +// --------------------------------- Menus. + +struct EsMenu : EsWindow {}; + +void EsMenuAddSeparator(EsMenu *menu) { + EsCustomElementCreate(menu, ES_CELL_H_FILL, ES_STYLE_MENU_SEPARATOR_HORIZONTAL)->cName = "menu separator"; +} + +void EsMenuNextColumn(EsMenu *menu, uint64_t flags) { + EsPanelCreate(menu->children[0], ES_PANEL_VERTICAL | ES_CELL_V_TOP | flags, ES_STYLE_PANEL_MENU_COLUMN); +} + +EsElement *EsMenuGetSource(EsMenu *menu) { + return ((EsWindow *) menu)->source; +} + +EsMenu *EsMenuCreate(EsElement *source, uint64_t flags) { + EsWindow *menu = (EsWindow *) EsWindowCreate(source->instance, ES_WINDOW_MENU); + menu->flags |= flags; + menu->activated = true; + menu->source = source; + return (EsMenu *) menu; +} + +void EsMenuAddCommandsFromToolbar(EsMenu *menu, EsElement *element) { + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + EsElement *child = element->GetChild(i); + + if (child->flags & ES_ELEMENT_NON_CLIENT) { + continue; + } + + if (child->messageClass == ProcessButtonMessage) { + EsButton *button = (EsButton *) child; + + if (button->command) { + EsMenuAddCommand(menu, button->command->check, button->label, button->labelBytes, button->command); + } + } else { + EsMenuAddCommandsFromToolbar(menu, element); + } + } +} + +void EsMenuShow(EsMenu *menu, int fixedWidth, int fixedHeight) { + EsAssert(!menu->source->window->targetMenu); + EsAssert(~menu->source->state & UI_STATE_MENU_SOURCE); + menu->source->state |= UI_STATE_MENU_SOURCE; + menu->source->MaybeRefreshStyle(); + menu->source->window->targetMenu = menu; + + EsRectangle menuInsets = menu->GetChild(0)->currentStyle->insets; + if (fixedWidth) fixedWidth += menuInsets.l + menuInsets.r; + if (fixedHeight) fixedHeight += menuInsets.t + menuInsets.b; + int width = fixedWidth ?: menu->GetChild(0)->GetWidth(fixedHeight); + int height = menu->GetChild(0)->GetHeight(width); + + if (fixedHeight) { + if (menu->flags & ES_MENU_MAXIMUM_HEIGHT) { + if (height >= fixedHeight) { + height = fixedHeight; + } + } else { + height = fixedHeight; + } + } + + EsPoint position; + + if (~menu->flags & ES_MENU_AT_CURSOR) { + EsRectangle bounds = menu->source->GetScreenBounds(false); + + position = ES_POINT(bounds.l - (width + menuInsets.l - menuInsets.r) / 2 + menu->source->width / 2, + bounds.b - menuInsets.t); + + // Try to the keep the menu within the bounds of the source window. + + EsRectangle windowBounds = menu->source->window->GetScreenBounds(); + + if (position.x + width >= windowBounds.r) { + position.x = windowBounds.r - width - 1; + } + + if (position.x < windowBounds.l) { + position.x = windowBounds.l; + } + + if (position.y + height >= windowBounds.b) { + position.y = windowBounds.b - height - 1; + } + + if (position.y < windowBounds.t) { + position.y = windowBounds.t; + } + } else { + position = EsMouseGetPosition(); + position.x -= menuInsets.l, position.y -= menuInsets.t; + } + + menu->width = width, menu->height = height; + EsRectangle bounds = ES_RECT_4(position.x, position.x + width, position.y, position.y + height); + EsSyscall(ES_SYSCALL_WINDOW_MOVE, menu->handle, (uintptr_t) &bounds, 0, ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN | ES_WINDOW_MOVE_ALWAYS_ON_TOP); +} + +void EsMenuCloseAll() { + for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) { + if (gui.allWindows[i]->windowStyle == ES_WINDOW_MENU) { + EsElementDestroy(gui.allWindows[i]); + } + } +} + +// --------------------------------- File menu. + +const EsStyle styleFileMenuDocumentInformationPanel1 = { + .metrics = { + .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_GAP_MAJOR, + .insets = ES_RECT_4(10, 10, 5, 5), + .gapMajor = 5, + }, +}; + +const EsStyle styleFileMenuDocumentInformationPanel2 = { + .metrics = { + .mask = ES_THEME_METRICS_GAP_MAJOR, + .gapMajor = 5, + }, +}; + +void FileMenuCreate(EsInstance *_instance, EsElement *element, EsCommand *) { + // TODO Make this user-customizable? + + // const EsFileMenuSettings *settings = (const EsFileMenuSettings *) element->userData.p; + APIInstance *instance = (APIInstance *) _instance->_private; + EsAssert(instance->instanceClass == ES_INSTANCE_CLASS_EDITOR); + EsInstanceClassEditorSettings *editorSettings = &instance->editorSettings; + EsMenu *menu = EsMenuCreate(element, ES_FLAGS_DEFAULT); + EsPanel *panel1 = EsPanelCreate(menu, ES_PANEL_HORIZONTAL | ES_CELL_H_LEFT, &styleFileMenuDocumentInformationPanel1); + + bool newDocument = !instance->startupInformation || !instance->startupInformation->filePath; + + { + // TODO Get this icon from the file type database? + // We'll probably need Desktop to send this via EsApplicationStartupInformation and when the file is renamed. + + EsIconDisplayCreate(panel1, ES_FLAGS_DEFAULT, 0, editorSettings->documentIconID); + EsSpacerCreate(panel1, ES_FLAGS_DEFAULT, 0, 5, 0); + + EsPanel *panel2 = EsPanelCreate(panel1, ES_FLAGS_DEFAULT, &styleFileMenuDocumentInformationPanel2); + EsPanel *panel3 = EsPanelCreate(panel2, ES_PANEL_HORIZONTAL | ES_PANEL_H_LEFT, &styleFileMenuDocumentInformationPanel2); + + if (newDocument) { + EsTextDisplayCreate(panel3, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_LABEL, + editorSettings->newDocumentTitle, editorSettings->newDocumentTitleBytes); + } else { + EsTextDisplayCreate(panel3, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_LABEL, + instance->startupInformation->filePath, instance->startupInformation->filePathBytes); + } + + EsButton *renameButton = EsButtonCreate(panel3, ES_BUTTON_TOOLBAR); // TODO. + EsButtonSetIcon(renameButton, ES_ICON_DOCUMENT_EDIT_SYMBOLIC); + + if (!newDocument) { + EsPanel *panel4 = EsPanelCreate(panel2, ES_PANEL_TABLE | ES_PANEL_HORIZONTAL | ES_CELL_H_LEFT, &styleFileMenuDocumentInformationPanel2); + EsPanelSetBands(panel4, 2 /* columns */); + + char buffer[64]; + size_t bytes; + + bytes = EsStringFormat(buffer, sizeof(buffer), "%D", EsFileStoreGetSize(instance->fileStore)); + EsTextDisplayCreate(panel4, ES_CELL_H_RIGHT, ES_STYLE_TEXT_LABEL_SECONDARY, INTERFACE_STRING(CommonFileMenuFileSize)); + EsTextDisplayCreate(panel4, ES_CELL_H_LEFT, ES_STYLE_TEXT_LABEL, buffer, bytes); + + // TODO Modification date, author, etc. + } + } + + EsMenuAddSeparator(menu); + + if (instance->instanceClass == ES_INSTANCE_CLASS_EDITOR) { + if (instance->commandSave.disabled) { + EsMenuAddItem(menu, ES_ELEMENT_DISABLED, INTERFACE_STRING(CommonFileUnchanged)); + } else { + EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileSave), &instance->commandSave); + } + + EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileMakeCopy)); // TODO. + EsMenuAddSeparator(menu); + } + + EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileShare)); // TODO. + EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileVersionHistory)); // TODO. + EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileShowInFileManager), &instance->commandShowInFileManager); + EsMenuShow(menu); +} + +void EsToolbarAddFileMenu(EsElement *element, const EsFileMenuSettings *settings) { + EsButton *button = EsButtonCreate(element, ES_BUTTON_DROPDOWN, 0, INTERFACE_STRING(CommonFileMenu)); + button->accessKey = 'F'; + button->userData = (void *) settings; + EsButtonOnCommand(button, FileMenuCreate); +} + +// --------------------------------- Paint targets. + +bool EsPaintTargetTake(EsPaintTarget *target, size_t width, size_t height, bool hasAlphaChannel = true) { + EsMemoryZero(target, sizeof(EsPaintTarget)); + target->fullAlpha = hasAlphaChannel; + target->width = width; + target->height = height; + target->stride = width * 4; + target->bits = EsHeapAllocate(target->stride * target->height, true); + return target->bits != nullptr; +} + +EsPaintTarget *EsPaintTargetCreate(size_t width, size_t height, bool hasAlphaChannel) { + EsPaintTarget *target = (EsPaintTarget *) EsHeapAllocate(sizeof(EsPaintTarget), true); + + if (!target) { + return nullptr; + } else if (EsPaintTargetTake(target, width, height, hasAlphaChannel)) { + return target; + } else { + EsHeapFree(target); + return nullptr; + } +} + +EsPaintTarget *EsPaintTargetCreateFromBitmap(uint32_t *bits, size_t width, size_t height, bool hasAlphaChannel) { + EsPaintTarget *target = (EsPaintTarget *) EsHeapAllocate(sizeof(EsPaintTarget), true); + + if (!target) { + return nullptr; + } + + target->bits = bits; + target->width = width; + target->height = height; + target->stride = width * 4; + target->fullAlpha = hasAlphaChannel; + target->fromBitmap = true; + return target; +} + +void EsPaintTargetClear(EsPaintTarget *t) { + EsPainter painter = {}; + painter.clip.r = t->width; + painter.clip.b = t->height; + painter.target = t; + EsDrawClear(&painter, painter.clip); +} + +void EsPaintTargetReturn(EsPaintTarget *target) { + EsHeapFree(target->bits); +} + +void EsPaintTargetDestroy(EsPaintTarget *target) { + if (!target->fromBitmap) EsHeapFree(target->bits); + EsHeapFree(target); +} + +void EsPaintTargetEndDirectAccess(EsPaintTarget *target) { + // Don't need to do anything, currently. + (void) target; +} + +void EsPaintTargetGetSize(EsPaintTarget *target, size_t *width, size_t *height) { + if (width) *width = target->width; + if (height) *height = target->height; +} + +void EsPaintTargetStartDirectAccess(EsPaintTarget *target, uint32_t **bits, size_t *width, size_t *height, size_t *stride) { + if (bits) *bits = (uint32_t *) target->bits; + if (width) *width = target->width; + if (height) *height = target->height; + if (stride) *stride = target->stride; +} + +// --------------------------------- Transitions. + +EsRectangle UIGetTransitionEffectRectangle(EsRectangle bounds, EsTransitionType type, double progress, bool to) { + int width = Width(bounds), height = Height(bounds); + double ratio = (double) height / (double) width; + + if (!to) { + if (type == ES_TRANSITION_SLIDE_UP) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t - progress * height / 2, bounds.b - progress * height / 2); + } else if (type == ES_TRANSITION_SLIDE_DOWN) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + progress * height / 2, bounds.b + progress * height / 2); + } else if (type == ES_TRANSITION_COVER_UP) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t, bounds.b); + } else if (type == ES_TRANSITION_COVER_DOWN) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t, bounds.b); + } else if (type == ES_TRANSITION_SQUISH_UP || type == ES_TRANSITION_REVEAL_UP) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t, bounds.t + height * (1 - progress)); + } else if (type == ES_TRANSITION_SQUISH_DOWN || type == ES_TRANSITION_REVEAL_DOWN) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + height * progress, bounds.b); + } else if (type == ES_TRANSITION_ZOOM_OUT) { + return ES_RECT_4(bounds.l + 20 * progress, bounds.r - 20 * progress, + bounds.t + 20 * progress * ratio, bounds.b - 20 * progress * ratio); + } else if (type == ES_TRANSITION_ZOOM_IN) { + return ES_RECT_4(bounds.l - 20 * progress, bounds.r + 20 * progress, + bounds.t - 20 * progress * ratio, bounds.b + 20 * progress * ratio); + } else if (type == ES_TRANSITION_ZOOM_OUT_LIGHT) { + return ES_RECT_4(bounds.l + 5 * progress, bounds.r - 5 * progress, + bounds.t + 5 * progress * ratio, bounds.b - 5 * progress * ratio); + } else if (type == ES_TRANSITION_ZOOM_IN_LIGHT) { + return ES_RECT_4(bounds.l - 5 * progress, bounds.r + 5 * progress, + bounds.t - 5 * progress * ratio, bounds.b + 5 * progress * ratio); + } else if (type == ES_TRANSITION_FADE_IN || type == ES_TRANSITION_FADE_OUT) { + return bounds; + } else if (type == ES_TRANSITION_SLIDE_UP_OVER) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t - progress * height / 4, bounds.b - progress * height / 4); + } else if (type == ES_TRANSITION_SLIDE_DOWN_OVER) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + progress * height / 4, bounds.b + progress * height / 4); + } else if (type == ES_TRANSITION_SLIDE_UP_UNDER) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t - progress * height / 2, bounds.b - progress * height / 2); + } else if (type == ES_TRANSITION_SLIDE_DOWN_UNDER) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + progress * height / 2, bounds.b + progress * height / 2); + } + } else { + if (type == ES_TRANSITION_SLIDE_UP) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + (1 - progress) * height / 2, bounds.b + (1 - progress) * height / 2); + } else if (type == ES_TRANSITION_SLIDE_DOWN) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t - (1 - progress) * height / 2, bounds.b - (1 - progress) * height / 2); + } else if (type == ES_TRANSITION_COVER_UP) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + (1 - progress) * height, bounds.b + (1 - progress) * height); + } else if (type == ES_TRANSITION_COVER_DOWN) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t - (1 - progress) * height, bounds.b - (1 - progress) * height); + } else if (type == ES_TRANSITION_SQUISH_UP || type == ES_TRANSITION_REVEAL_UP) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + (1 - progress) * height, bounds.b); + } else if (type == ES_TRANSITION_SQUISH_DOWN || type == ES_TRANSITION_REVEAL_DOWN) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t, bounds.t + progress * height); + } else if (type == ES_TRANSITION_ZOOM_OUT) { + return ES_RECT_4(bounds.l - 20 * (1 - progress), bounds.r + 20 * (1 - progress), + bounds.t - 20 * (1 - progress) * ratio, bounds.b + 20 * (1 - progress) * ratio); + } else if (type == ES_TRANSITION_ZOOM_IN) { + return ES_RECT_4(bounds.l + 20 * (1 - progress), bounds.r - 20 * (1 - progress) + 0.5, + bounds.t + 20 * (1 - progress) * ratio, bounds.b - 20 * (1 - progress) * ratio + 0.5); + } else if (type == ES_TRANSITION_ZOOM_OUT_LIGHT) { + return ES_RECT_4(bounds.l - 5 * (1 - progress), bounds.r + 5 * (1 - progress), + bounds.t - 5 * (1 - progress) * ratio, bounds.b + 5 * (1 - progress) * ratio); + } else if (type == ES_TRANSITION_ZOOM_IN_LIGHT) { + return ES_RECT_4(bounds.l + 5 * (1 - progress), bounds.r - 5 * (1 - progress) + 0.5, + bounds.t + 5 * (1 - progress) * ratio, bounds.b - 5 * (1 - progress) * ratio + 0.5); + } else if (type == ES_TRANSITION_FADE_IN || type == ES_TRANSITION_FADE_OUT) { + return bounds; + } else if (type == ES_TRANSITION_SLIDE_UP_OVER) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + (1 - progress) * height / 2, bounds.b + (1 - progress) * height / 2); + } else if (type == ES_TRANSITION_SLIDE_DOWN_OVER) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t - (1 - progress) * height / 2, bounds.b - (1 - progress) * height / 2); + } else if (type == ES_TRANSITION_SLIDE_UP_UNDER) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t + (1 - progress) * height / 4, bounds.b + (1 - progress) * height / 4); + } else if (type == ES_TRANSITION_SLIDE_DOWN_UNDER) { + return ES_RECT_4(bounds.l, bounds.r, + bounds.t - (1 - progress) * height / 4, bounds.b - (1 - progress) * height / 4); + } + } + + EsAssert(false); // Unknown transition type. + return {}; +} + +void UIDrawTransitionEffect(EsPainter *painter, EsPaintTarget *sourceSurface, EsRectangle bounds, EsTransitionType type, double progress, bool to) { + EsRectangle destinationRegion = UIGetTransitionEffectRectangle(bounds, type, progress, to); + EsRectangle sourceRegion = ES_RECT_4(0, bounds.r - bounds.l, 0, bounds.b - bounds.t); + uint16_t alpha = (to ? progress : (1 - progress)) * 255; + EsDrawPaintTarget(painter, sourceSurface, destinationRegion, sourceRegion, alpha); +} + +void EsElementStartTransition(EsElement *element, EsTransitionType transitionType, uint32_t flags, uint32_t durationMs) { + durationMs *= ANIMATION_TIME_SCALE; + + if (!durationMs) { + return; + } + + if (element->previousTransitionFrame) { + EsPaintTargetDestroy(element->previousTransitionFrame); + element->previousTransitionFrame = nullptr; + } + + if (~flags & ES_ELEMENT_TRANSITION_ENTRANCE) { + EsRectangle paintOutsets = element->currentStyle->paintOutsets; + int width = element->width + paintOutsets.l + paintOutsets.r; + int height = element->height + paintOutsets.t + paintOutsets.b; + + element->previousTransitionFrame = EsPaintTargetCreate(width, height, true); + + if (element->previousTransitionFrame) { + EsPainter painter = {}; + painter.clip = ES_RECT_4(0, width, 0, height); + painter.offsetX = paintOutsets.l; + painter.offsetY = paintOutsets.t; + painter.target = element->previousTransitionFrame; + element->InternalPaint(&painter, PAINT_NO_TRANSITION | PAINT_NO_OFFSET); + } + } + + element->transitionTimeMs = 0; + element->transitionDurationMs = durationMs; + element->transitionType = transitionType; + element->StartAnimating(); +} + +// --------------------------------- Painting. + +EsRectangle EsPainterBoundsClient(EsPainter *painter) { + return ES_RECT_4(painter->offsetX, painter->offsetX + painter->width, painter->offsetY, painter->offsetY + painter->height); +} + +EsRectangle EsPainterBoundsInset(EsPainter *painter) { + UIStyle *style = (UIStyle *) painter->style; + return ES_RECT_4(painter->offsetX + style->insets.l, painter->offsetX + painter->width - style->insets.r, + painter->offsetY + style->insets.t, painter->offsetY + painter->height - style->insets.b); +} + +void EsElement::Repaint(bool all, EsRectangle region) { + // TODO Optimisation: don't paint if overlapped by an opaque child or sibling. + + if (all) { + region.l = -currentStyle->paintOutsets.l, region.r = width + currentStyle->paintOutsets.r; + region.t = -currentStyle->paintOutsets.t, region.b = height + currentStyle->paintOutsets.b; + } else { + region = Translate(region, -internalOffsetLeft, -internalOffsetTop); + } + + if (parent) { + EsRectangle parentBounds = parent->GetWindowBounds(false); + + region = Translate(region, offsetX + parentBounds.l, offsetY + parentBounds.t); + + if (parent->currentStyle->metrics->clipEnabled) { + Rectangle16 clipInsets = parent->currentStyle->metrics->clipInsets; + region = EsRectangleIntersection(region, EsRectangleAddBorder(parentBounds, RECT16_TO_RECT(clipInsets))); + } + + UIWindowNeedsUpdate(window); + } + + if (THEME_RECT_VALID(region)) { + window->updateRegion = EsRectangleBounding(window->updateRegion, region); + } +} + +void EsElement::InternalPaint(EsPainter *painter, int paintFlags) { + if (width <= 0 || height <= 0 || (flags & ES_ELEMENT_HIDDEN)) { + return; + } + + state |= UI_STATE_ENTERED; + + int pOffsetX = painter->offsetX; + int pOffsetY = painter->offsetY; + + if (~paintFlags & PAINT_NO_OFFSET) { + pOffsetX += offsetX; + pOffsetY += offsetY; + } + + // Is it possible for this element to paint within the clip? + + { + EsRectangle area; + area.l = pOffsetX - currentStyle->paintOutsets.l; + area.r = pOffsetX + width + currentStyle->paintOutsets.r; + area.t = pOffsetY - currentStyle->paintOutsets.t; + area.b = pOffsetY + height + currentStyle->paintOutsets.b; + + if (!THEME_RECT_VALID(EsRectangleIntersection(area, painter->clip))) { + return; + } + } + + if (state & UI_STATE_INSPECTING) EsPerformanceTimerPush(); + double timeChildPaint = 0; + + // Get the interpolated style. + + EsPainter oldPainter = *painter; + + UIStyle *style = ThemeAnimationComplete(&animation) ? currentStyle : ThemeStyleInterpolate(currentStyle, &animation); + EsDefer(if (style != currentStyle) EsHeapFree(style)); + painter->style = style; + + painter->offsetX = pOffsetX, painter->offsetY = pOffsetY; + painter->width = width, painter->height = height; + + // Get the child type of the element. + + int childType = 0; + + if (parent && parent->GetChildCount()) { + if (parent->GetChildCount() == 1 && parent->GetChild(0) == this) { + childType = THEME_CHILD_TYPE_ONLY; + } else if (parent->GetChild(0) == this) { + childType = (parent->flags & ES_ELEMENT_LAYOUT_HINT_REVERSE) ? THEME_CHILD_TYPE_LAST : THEME_CHILD_TYPE_FIRST; + } else if (parent->GetChild(parent->GetChildCount() - 1) == this) { + childType = (parent->flags & ES_ELEMENT_LAYOUT_HINT_REVERSE) ? THEME_CHILD_TYPE_FIRST : THEME_CHILD_TYPE_LAST; + } else { + childType = THEME_CHILD_TYPE_NONE; + } + + if (parent->flags & ES_ELEMENT_LAYOUT_HINT_HORIZONTAL) { + childType |= THEME_CHILD_TYPE_HORIZONTAL; + } + } + + if (paintFlags & PAINT_SHADOW) { + style->PaintLayers(painter, ES_RECT_2S(painter->width, painter->height), childType, THEME_LAYER_MODE_SHADOW); + } else if (paintFlags & PAINT_OVERLAY) { + style->PaintLayers(painter, ES_RECT_2S(painter->width, painter->height), childType, THEME_LAYER_MODE_OVERLAY); + + // Paint layout bounds, if active. + + if (window->visualizeLayoutBounds) { + EsDrawRectangle(painter, EsPainterBoundsClient(painter), 0, 0x7FFF0000, ES_RECT_1(1)); + EsDrawRectangle(painter, EsPainterBoundsInset(painter), 0, 0x7F0000FF, ES_RECT_1(1)); + } + } else if (transitionTimeMs < transitionDurationMs && (~paintFlags & PAINT_NO_TRANSITION)) { + double progress = SmoothAnimationTime((double) transitionTimeMs / (double) transitionDurationMs); + EsRectangle bounds = EsPainterBoundsClient(painter); + EsPaintTarget target; + + EsRectangle paintOutsets = currentStyle->paintOutsets; + int targetWidth = width + paintOutsets.l + paintOutsets.r; + int targetHeight = height + paintOutsets.t + paintOutsets.b; + bounds.l -= paintOutsets.l, bounds.r += paintOutsets.r; + bounds.t -= paintOutsets.t, bounds.b += paintOutsets.b; + + if (EsPaintTargetTake(&target, targetWidth, targetHeight)) { + if (previousTransitionFrame) { + UIDrawTransitionEffect(painter, previousTransitionFrame, bounds, + (EsTransitionType) transitionType, progress, false); + } + + EsPainter p = {}; + p.clip = ES_RECT_4(0, targetWidth, 0, targetHeight); + p.offsetX = paintOutsets.l; + p.offsetY = paintOutsets.t; + p.target = ⌖ + InternalPaint(&p, PAINT_NO_TRANSITION | PAINT_NO_OFFSET); + + UIDrawTransitionEffect(painter, &target, bounds, (EsTransitionType) transitionType, progress, true); + + EsPaintTargetReturn(&target); + } else { + goto paintBackground; + } + } else { + paintBackground:; + + // Paint the background. + + EsMessage m; + m.type = ES_MSG_PAINT_BACKGROUND; + m.painter = painter; + + if (!EsMessageSend(this, &m)) { + // TODO Optimisation: don't paint if overlapped by an opaque child. + style->PaintLayers(painter, ES_RECT_2S(painter->width, painter->height), childType, THEME_LAYER_MODE_BACKGROUND); + } + + // Apply the clipping insets. + + EsRectangle oldClip = painter->clip; + + if (currentStyle->metrics->clipEnabled && (~flags & ES_ELEMENT_NO_CLIP)) { + Rectangle16 insets = currentStyle->metrics->clipInsets; + EsRectangle content = ES_RECT_4(painter->offsetX + insets.l, painter->offsetX + width - insets.r, + painter->offsetY + insets.t, painter->offsetY + height - insets.b); + painter->clip = EsRectangleIntersection(content, painter->clip); + } + + if (THEME_RECT_VALID(painter->clip)) { + // Paint the content. + + painter->width -= internalOffsetLeft + internalOffsetRight; + painter->height -= internalOffsetTop + internalOffsetBottom; + painter->offsetX += internalOffsetLeft, painter->offsetY += internalOffsetTop; + + m.type = ES_MSG_PAINT; + m.painter = painter; + EsMessageSend(this, &m); + + painter->width += internalOffsetLeft + internalOffsetRight; + painter->height += internalOffsetTop + internalOffsetBottom; + painter->offsetX -= internalOffsetLeft, painter->offsetY -= internalOffsetTop; + + // Paint the children. + // TODO Optimisation: don't paint children overlapped by an opaque sibling. + + if (state & UI_STATE_INSPECTING) EsPerformanceTimerPush(); + + m.type = ES_MSG_PAINT_CHILDREN; + m.painter = painter; + + if (!EsMessageSend(this, &m)) { + bool isZStack = state & UI_STATE_Z_STACK; + + EsMessage zOrder; + zOrder.type = ES_MSG_BEFORE_Z_ORDER; + zOrder.beforeZOrder.start = 0; + zOrder.beforeZOrder.nonClient = zOrder.beforeZOrder.end = children.Length(); + zOrder.beforeZOrder.clip = Translate(painter->clip, -painter->offsetX, -painter->offsetY); + EsMessageSend(this, &zOrder); + + if (isZStack) { + // Elements cast shadows on each other. + + for (uintptr_t i = zOrder.beforeZOrder.start; i < zOrder.beforeZOrder.end; i++) { + EsElement *child = GetChildByZ(i); + if (!child) continue; + child->InternalPaint(painter, PAINT_SHADOW); + child->InternalPaint(painter, ES_FLAGS_DEFAULT); + child->InternalPaint(painter, PAINT_OVERLAY); + } + + for (uintptr_t i = zOrder.beforeZOrder.nonClient; i < children.Length(); i++) { + EsElement *child = GetChildByZ(i); + if (!child) continue; + child->InternalPaint(painter, PAINT_SHADOW); + child->InternalPaint(painter, ES_FLAGS_DEFAULT); + child->InternalPaint(painter, PAINT_OVERLAY); + } + } else { + // Elements cast shadows on the container. + + for (uintptr_t i = zOrder.beforeZOrder.start; i < zOrder.beforeZOrder.end; i++) { + EsElement *child = GetChildByZ(i); + if (child) child->InternalPaint(painter, PAINT_SHADOW); + } + + for (uintptr_t i = zOrder.beforeZOrder.nonClient; i < children.Length(); i++) { + EsElement *child = GetChildByZ(i); + if (child) child->InternalPaint(painter, PAINT_SHADOW); + } + + for (uintptr_t i = zOrder.beforeZOrder.start; i < zOrder.beforeZOrder.end; i++) { + EsElement *child = GetChildByZ(i); + if (child) child->InternalPaint(painter, ES_FLAGS_DEFAULT); + } + + for (uintptr_t i = zOrder.beforeZOrder.nonClient; i < children.Length(); i++) { + EsElement *child = GetChildByZ(i); + if (child) child->InternalPaint(painter, ES_FLAGS_DEFAULT); + } + + for (uintptr_t i = zOrder.beforeZOrder.start; i < zOrder.beforeZOrder.end; i++) { + EsElement *child = GetChildByZ(i); + if (child) child->InternalPaint(painter, PAINT_OVERLAY); + } + + for (uintptr_t i = zOrder.beforeZOrder.nonClient; i < children.Length(); i++) { + EsElement *child = GetChildByZ(i); + if (child) child->InternalPaint(painter, PAINT_OVERLAY); + } + } + + zOrder.type = ES_MSG_AFTER_Z_ORDER; + EsMessageSend(this, &zOrder); + } + + if (state & UI_STATE_INSPECTING) timeChildPaint = EsPerformanceTimerPop() * 1000; + } + + // Let the inspector draw some decorations over the element. + + painter->clip = oldClip; + InspectorNotifyElementPainted(this, painter); + } + + if (state & UI_STATE_INSPECTING) { + double timeTotalPaint = EsPerformanceTimerPop() * 1000; + InspectorNotifyElementEvent(this, "paint", "Paint in %Fms (%Fms with children).", timeTotalPaint - timeChildPaint, timeTotalPaint); + } + + *painter = oldPainter; + + if (window->visualizePaintSteps && ES_RECT_VALID(window->updateRegionInProgress) && painter->target->forWindowManager) { + EsSyscall(ES_SYSCALL_WINDOW_SET_BITS, window->handle, (uintptr_t) &window->updateRegionInProgress, + (uintptr_t) painter->target->bits, WINDOW_SET_BITS_NORMAL); + } +} + +// --------------------------------- Animations. + +bool EsElement::StartAnimating() { + if ((state & UI_STATE_ANIMATING) || (state & UI_STATE_DESTROYING)) return false; + gui.animatingElements.Add(this); + gui.animationSleep = false; + state |= UI_STATE_ANIMATING; + lastTimeStamp = 0; + return true; +} + +void ProcessAnimations() { + uint64_t timeStamp = EsTimeStamp(); // TODO Use global time instead. + int64_t waitMs = -1; + + for (uintptr_t i = 0; i < gui.animatingElements.Length(); i++) { + EsElement *element = gui.animatingElements[i]; + // EsPrint("Animating %x...\n", element); + EsAssert(element->state & UI_STATE_ANIMATING); // Element was not animating but was in the animating elements list. + + if (element->lastTimeStamp == 0) { + element->lastTimeStamp = timeStamp; + } + + EsMessage m = {}; + m.type = ES_MSG_ANIMATE; + int64_t deltaUs = (timeStamp - element->lastTimeStamp) / api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND]; + m.animate.deltaMs = deltaUs / 1000; + m.animate.complete = true; + + if (!m.animate.deltaMs) { + waitMs = 0; + continue; + } + + if (ThemeAnimationStep(&element->animation, m.animate.deltaMs)) { + element->Repaint(true, ES_RECT_1(0)); + } + + element->transitionTimeMs += m.animate.deltaMs; + bool transitionComplete = element->transitionTimeMs >= element->transitionDurationMs; + + if (!transitionComplete) { + element->Repaint(true, ES_RECT_1(0)); + } + + bool backgroundAnimationComplete = ThemeAnimationComplete(&element->animation); + + EsMessageSend(element, &m); + + if (m.animate.complete && backgroundAnimationComplete && transitionComplete) { + gui.animatingElements.DeleteSwap(i); + element->state &= ~UI_STATE_ANIMATING; + i--; + + if (element->state & UI_STATE_EXITING) { + EsElement *ancestor = element; + + while (ancestor) { + ancestor->state |= UI_STATE_DESTROYING_CHILD; + ancestor = ancestor->parent; + } + + element->state &= ~UI_STATE_EXITING; + } + } else if (m.animate.waitMs < waitMs || waitMs == -1) { + waitMs = m.animate.waitMs; + } + + element->lastTimeStamp += m.animate.deltaMs * 1000 * api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND]; + UIWindowNeedsUpdate(element->window); + } + + if (waitMs > 0) { + gui.animationSleep = true; + + EsTimerCancel(gui.animationSleepTimer); + gui.animationSleepTimer = EsTimerSet(waitMs, [] (EsGeneric) { gui.animationSleep = false; }, nullptr); + } +} + +// --------------------------------- Style state management. +// TODO Move into theme.cpp? + +bool EsElement::RefreshStyleState() { + uint16_t styleStateFlags = customStyleState; + + if (flags & ES_ELEMENT_DISABLED) { + styleStateFlags |= THEME_PRIMARY_STATE_DISABLED; + } else { + if (((state & UI_STATE_PRESSED) && ((state & UI_STATE_HOVERED) || gui.draggingStarted || (state & UI_STATE_STRONG_PRESSED))) || (state & UI_STATE_MENU_SOURCE)) { + styleStateFlags |= THEME_PRIMARY_STATE_PRESSED; + } else if (((state & UI_STATE_HOVERED) && !window->pressed) || (state & UI_STATE_PRESSED)) { + styleStateFlags |= THEME_PRIMARY_STATE_HOVERED; + } else { + styleStateFlags |= THEME_PRIMARY_STATE_IDLE; + } + + if (state & UI_STATE_FOCUSED) { + styleStateFlags |= THEME_STATE_FOCUSED; + } + } + + if (state & UI_STATE_EXITING) { + styleStateFlags |= THEME_STATE_AFTER_EXIT; + } + + bool observedBitsChanged = false; + + if (!currentStyle || currentStyle->IsStateChangeObserved(styleStateFlags, previousStyleState)) { + observedBitsChanged = true; + } + + previousStyleState = styleStateFlags; + + return observedBitsChanged; +} + +void EsElement::RefreshStyle(UIStyleKey *_oldStyleKey, bool alreadyRefreshStyleState, bool force) { + // Compute state flags. + + if (!alreadyRefreshStyleState) { + RefreshStyleState(); + } + + uint16_t styleStateFlags = previousStyleState; + + // Initialise the style. + + UIStyleKey oldStyleKey = _oldStyleKey ? *_oldStyleKey : currentStyleKey; + currentStyleKey.stateFlags = styleStateFlags; + + if (!force && 0 == EsMemoryCompare(¤tStyleKey, &oldStyleKey, sizeof(UIStyleKey)) && currentStyle) { + return; + } + + if (~state & UI_STATE_ENTERED) { + if (currentStyle) currentStyle->CloseReference(); + oldStyleKey = currentStyleKey; + oldStyleKey.stateFlags |= THEME_STATE_BEFORE_ENTER; + currentStyle = GetStyle(oldStyleKey, false); + } + + UIStyle *oldStyle = currentStyle; + currentStyle = GetStyle(currentStyleKey, false); // TODO Forcing new styles if force flag set. + + // Respond to modifications. + + bool repaint = false, animate = false; + + if (force) { + repaint = true; + } + + if (oldStyle) { + if (oldStyle->style == currentStyle->style) { + ThemeAnimationBuild(&animation, oldStyle, oldStyleKey.stateFlags, currentStyleKey.stateFlags); + animate = !ThemeAnimationComplete(&animation); + } else { + ThemeAnimationDestroy(&animation); + } + + repaint = true; + } else { + repaint = animate = true; + } + + if (repaint) { + if (animate) StartAnimating(); + Repaint(true, ES_RECT_1(0)); + } + + // Delete the old style if necessary. + + if (oldStyle) { + oldStyle->CloseReference(); + } +} + +void EsElement::SetStyle(const EsStyle *part, bool refreshIfChanged) { + UIStyleKey oldStyleKey = currentStyleKey; + currentStyleKey.part = (uintptr_t) part; + + if (currentStyleKey.part != oldStyleKey.part && refreshIfChanged) { + RefreshStyle(&oldStyleKey); + } +} + +// --------------------------------- Layouting. + +EsRectangle LayoutCell(EsElement *element, int width, int height) { + uint64_t layout = element->flags; + + int maximumWidth = element->currentStyle->metrics->maximumWidth ?: ES_PANEL_BAND_SIZE_DEFAULT; + int minimumWidth = element->currentStyle->metrics->minimumWidth ?: ES_PANEL_BAND_SIZE_DEFAULT; + int maximumHeight = element->currentStyle->metrics->maximumHeight ?: ES_PANEL_BAND_SIZE_DEFAULT; + int minimumHeight = element->currentStyle->metrics->minimumHeight ?: ES_PANEL_BAND_SIZE_DEFAULT; + + if (layout & ES_CELL_H_EXPAND) maximumWidth = INT_MAX; + if (layout & ES_CELL_H_SHRINK) minimumWidth = 0; + if (layout & ES_CELL_V_EXPAND) maximumHeight = INT_MAX; + if (layout & ES_CELL_V_SHRINK) minimumHeight = 0; + + if (maximumWidth == ES_PANEL_BAND_SIZE_DEFAULT || minimumWidth == ES_PANEL_BAND_SIZE_DEFAULT) { + int width = element->GetWidth(height); + if (maximumWidth == ES_PANEL_BAND_SIZE_DEFAULT) maximumWidth = width; + if (minimumWidth == ES_PANEL_BAND_SIZE_DEFAULT) minimumWidth = width; + } + + int preferredWidth = ClampInteger(minimumWidth, maximumWidth, width); + + if (maximumHeight == ES_PANEL_BAND_SIZE_DEFAULT || minimumHeight == ES_PANEL_BAND_SIZE_DEFAULT) { + int height = element->GetHeight(preferredWidth); + if (maximumHeight == ES_PANEL_BAND_SIZE_DEFAULT) maximumHeight = height; + if (minimumHeight == ES_PANEL_BAND_SIZE_DEFAULT) minimumHeight = height; + } + + int preferredHeight = ClampInteger(minimumHeight, maximumHeight, height); + + EsRectangle bounds = ES_RECT_4(0, width, 0, height); + + if ((layout & (ES_CELL_H_LEFT | ES_CELL_H_RIGHT)) == ES_CELL_H_LEFT) { + bounds.r = bounds.l + preferredWidth; + } else if ((layout & (ES_CELL_H_LEFT | ES_CELL_H_RIGHT)) == ES_CELL_H_RIGHT) { + bounds.l = bounds.r - preferredWidth; + } else { + bounds.l = bounds.l + width / 2 - preferredWidth / 2; + bounds.r = bounds.l + preferredWidth; + } + + if ((layout & (ES_CELL_V_TOP | ES_CELL_V_BOTTOM)) == ES_CELL_V_TOP) { + bounds.b = bounds.t + preferredHeight; + } else if ((layout & (ES_CELL_V_TOP | ES_CELL_V_BOTTOM)) == ES_CELL_V_BOTTOM) { + bounds.t = bounds.b - preferredHeight; + } else { + bounds.t = bounds.t + height / 2 - preferredHeight / 2; + bounds.b = bounds.t + preferredHeight; + } + + return bounds; +} + +void EsElementMove(EsElement *element, int x, int y, int width, int height, bool applyCellLayout) { + EsMessageMutexCheck(); + + if (applyCellLayout) { + EsRectangle bounds = LayoutCell(element, width, height); + width = Width(bounds), height = Height(bounds); + x += bounds.l, y += bounds.t; + } + + element->InternalMove(width, height, x, y); +} + +void PanelMoveChild(EsElement *element, int width, int height, int offsetX, int offsetY) { + EsPanel *panel = (EsPanel *) element->parent; + + { + EsRectangle bounds = LayoutCell(element, width, height); + width = Width(bounds), height = Height(bounds); + offsetX += bounds.l, offsetY += bounds.t; + } + + float progress = panel->transitionLengthMs ? SmoothAnimationTime((float) panel->transitionTimeMs / panel->transitionLengthMs) : 1; + + // TODO Make this faster than O(n^2). + + for (uintptr_t i = 0; i < panel->movementItems.Length(); i++) { + PanelMovementItem *item = &panel->movementItems[i]; + + if (item->element != element) { + continue; + } + + int oldWidth = Width(item->oldBounds); + int oldHeight = Height(item->oldBounds); + int oldOffsetX = item->oldBounds.l; + int oldOffsetY = item->oldBounds.t; + + element->InternalMove(LinearInterpolate(oldWidth, width, progress), + LinearInterpolate(oldHeight, height, progress), + LinearInterpolate(oldOffsetX, offsetX, progress), + LinearInterpolate(oldOffsetY, offsetY, progress)); + + return; + } + + element->InternalMove(width, height, offsetX, offsetY); +} + +void LayoutTable(EsPanel *panel, EsMessage *message) { + bool debug = false; + + bool has[2] = {}; + int in[2] = {}; + int out[2] = {}; + + if (message->type == ES_MSG_GET_WIDTH) { + in[1] = message->measure.height; + has[1] = has[1]; + } else if (message->type == ES_MSG_GET_HEIGHT) { + in[0] = message->measure.width; + has[0] = in[0]; + } else { + EsRectangle bounds = panel->GetBounds(); + in[0] = bounds.r, in[1] = bounds.b; + has[0] = has[1] = true; + } + + // if (debug) EsPrint("LayoutTable, %z, %d/%d\n", isMeasure ? "measure" : "layout", in[0], in[1]); + + size_t childCount = panel->GetChildCount(); + + uint8_t *memoryBase = (uint8_t *) EsHeapAllocate(sizeof(int) * childCount * 2 + sizeof(EsPanelBand) * (panel->bandCount[0] + panel->bandCount[1]), true), *memory = memoryBase; + + int *calculatedSize[2]; + calculatedSize[0] = (int *) memory; memory += sizeof(int) * childCount; + calculatedSize[1] = (int *) memory; memory += sizeof(int) * childCount; + EsPanelBand *calculatedProperties[2]; + calculatedProperties[0] = (EsPanelBand *) memory; memory += sizeof(EsPanelBand) * panel->bandCount[0]; + calculatedProperties[1] = (EsPanelBand *) memory; memory += sizeof(EsPanelBand) * panel->bandCount[1]; + + for (int axis = 0; axis < 2; axis++) { + if (panel->bands[axis]) { + EsMemoryCopy(calculatedProperties[axis], panel->bands[axis], sizeof(EsPanelBand) * panel->bandCount[axis]); + } else { + for (uintptr_t i = 0; i < panel->bandCount[axis]; i++) { + calculatedProperties[axis][i].preferredSize + = calculatedProperties[axis][i].maximumSize + = calculatedProperties[axis][i].minimumSize + = ES_PANEL_BAND_SIZE_DEFAULT; + } + } + } + + EsRectangle insets = panel->GetInsets(); + +#define TABLE_AXIS_HORIZONTAL (0) +#define TABLE_AXIS_VERTICAL (1) + + for (int _axis = 0; _axis < 2; _axis++) { + int axis = (~panel->flags & ES_PANEL_HORIZONTAL) ? (1 - _axis) : _axis; + int gapSize = _axis ? panel->GetGapMinor() : panel->GetGapMajor(); + int insetStart = axis ? insets.t : insets.l; + int insetEnd = axis ? insets.b : insets.r; + + if (debug) EsPrint("\tAxis %d\n", axis); + + for (uintptr_t i = 0; i < childCount; i++) { + EsElement *child = panel->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + + // Step 1: Find the preferred size of the children for this axis. + + int size; + + if ((child->flags & (axis ? ES_CELL_V_PUSH : ES_CELL_H_PUSH)) && has[axis]) { + size = 0; + } else { + int alternate = _axis ? calculatedSize[1 - axis][i] : 0; + size = axis == TABLE_AXIS_HORIZONTAL ? child->GetWidth(alternate) : child->GetHeight(alternate); + } + + if (debug) EsPrint("\tChild %d (%z) in cells %d->%d has size %d\n", i, child->cName, child->tableCell.from[axis], child->tableCell.to[axis], size); + + // Step 2: Find the preferred size of each band on this axis. + + int bandSpan = child->tableCell.to[axis] - child->tableCell.from[axis] + 1; + int totalGapSize = (bandSpan - 1) * gapSize; + + int preferredSizePerBand = (size - totalGapSize) / bandSpan; + int maximumSizeValue = axis ? child->currentStyle->metrics->maximumHeight : child->currentStyle->metrics->maximumWidth; + int minimumSizeValue = axis ? child->currentStyle->metrics->minimumHeight : child->currentStyle->metrics->minimumWidth; + int maximumSizePerBand = maximumSizeValue ? (((int) maximumSizeValue - totalGapSize) / bandSpan) : ES_PANEL_BAND_SIZE_DEFAULT; + int minimumSizePerBand = maximumSizeValue ? (((int) minimumSizeValue - totalGapSize) / bandSpan) : ES_PANEL_BAND_SIZE_DEFAULT; + + for (int j = child->tableCell.from[axis]; j <= child->tableCell.to[axis]; j++) { + EsAssert(j >= 0 && j < panel->bandCount[axis]); // Invalid element cell. + + EsPanelBand *band = calculatedProperties[axis] + j; + + if (child->flags & (axis ? ES_CELL_V_PUSH : ES_CELL_H_PUSH)) { + if (!band->push) { + band->push = 1; + } + } + + if (!panel->bands[axis] || panel->bands[axis][j].preferredSize == ES_PANEL_BAND_SIZE_DEFAULT) { + if (band->preferredSize != ES_PANEL_BAND_SIZE_DEFAULT) { + if (band->preferredSize < preferredSizePerBand) { + band->preferredSize = preferredSizePerBand; + } + } else { + band->preferredSize = preferredSizePerBand; + } + } + + if (!panel->bands[axis] || panel->bands[axis][j].maximumSize == ES_PANEL_BAND_SIZE_DEFAULT) { + if (maximumSizePerBand != ES_PANEL_BAND_SIZE_DEFAULT) { + if (band->maximumSize != ES_PANEL_BAND_SIZE_DEFAULT) { + if (band->maximumSize > maximumSizePerBand) { + band->maximumSize = maximumSizePerBand; + } + } else { + band->maximumSize = maximumSizePerBand; + } + } + } + + if (!panel->bands[axis] || panel->bands[axis][j].minimumSize == ES_PANEL_BAND_SIZE_DEFAULT) { + if (minimumSizePerBand != ES_PANEL_BAND_SIZE_DEFAULT) { + if (band->minimumSize != ES_PANEL_BAND_SIZE_DEFAULT) { + if (band->minimumSize < minimumSizePerBand) { + band->minimumSize = minimumSizePerBand; + } + } else { + band->minimumSize = minimumSizePerBand; + } + } + } + } + } + + // Step 3: Work out the size of each band. + + if (has[axis]) { + int contentSpace = in[axis] - insetStart - insetEnd - (panel->bandCount[axis] - 1) * gapSize; + + for (int i = 0; i < panel->bandCount[axis]; i++) { + EsPanelBand *band = calculatedProperties[axis] + i; + if (band->minimumSize == ES_PANEL_BAND_SIZE_DEFAULT) band->minimumSize = 0; + if (band->preferredSize == ES_PANEL_BAND_SIZE_DEFAULT) band->preferredSize = 0; + if (band->maximumSize == ES_PANEL_BAND_SIZE_DEFAULT) band->maximumSize = INT_MAX; + } + + int usedSpace = 0; + + for (int i = 0; i < panel->bandCount[axis]; i++) { + usedSpace += calculatedProperties[axis][i].preferredSize; + } + + bool shrink = usedSpace > contentSpace; + int remainingDifference = AbsoluteInteger(usedSpace - contentSpace); + + while (remainingDifference > 0) { + int availableWeight = 0; + + for (int i = 0; i < panel->bandCount[axis]; i++) { + EsPanelBand *band = calculatedProperties[axis] + i; + availableWeight += shrink ? band->pull : band->push; + } + + if (!availableWeight) { + break; // There are no more flexible bands. + } + + int perWeight = remainingDifference / availableWeight, perWeightExtra = remainingDifference % availableWeight; + bool stable = true; + + for (int i = 0; i < panel->bandCount[axis]; i++) { + EsPanelBand *band = calculatedProperties[axis] + i; + int available = shrink ? (band->preferredSize - band->minimumSize) : (band->maximumSize - band->preferredSize); + int weight = shrink ? band->pull : band->push; + int change = weight * perWeight; + int extra = MinimumInteger(perWeightExtra, weight); + change += extra, perWeightExtra -= extra; + + if (change > available) { + band->preferredSize = shrink ? band->minimumSize : band->maximumSize; + band->pull = band->push = 0; + remainingDifference -= available; + stable = false; + } + } + + if (stable) { + perWeightExtra = remainingDifference % availableWeight; + + for (int i = 0; i < panel->bandCount[axis]; i++) { + EsPanelBand *band = calculatedProperties[axis] + i; + int weight = shrink ? band->pull : band->push; + int change = weight * perWeight; + int extra = MinimumInteger(perWeightExtra, weight); + change += extra, perWeightExtra -= extra; + band->preferredSize += (shrink ? -1 : 1) * change; + if (band->preferredSize < band->minimumSize) band->preferredSize = band->minimumSize; + if (band->preferredSize > band->maximumSize) band->preferredSize = band->maximumSize; + } + + break; // We've found a working configuration. + } + } + } + + // Step 4: Work out the final size of each child. + + for (uintptr_t i = 0; i < childCount; i++) { + EsElement *child = panel->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + + int size = (child->tableCell.to[axis] - child->tableCell.from[axis]) * gapSize; + + for (int j = child->tableCell.from[axis]; j <= child->tableCell.to[axis]; j++) { + EsPanelBand *band = calculatedProperties[axis] + j; + size += band->preferredSize; + } + + calculatedSize[axis][i] = size; + } + + // Step 5: Calculate the position of the bands. + + int position = insetStart; + + for (int i = 0; i < panel->bandCount[axis]; i++) { + if (i) position += gapSize; + EsPanelBand *band = calculatedProperties[axis] + i; + int size = band->preferredSize; + band->maximumSize = position; // Aliasing maximumSize with position. + position += size; + } + + out[axis] = position + insetEnd; + } + + // Step 6: Move the children to their new location. + + if (message->type == ES_MSG_GET_WIDTH) { + message->measure.width = out[0]; + } else if (message->type == ES_MSG_GET_HEIGHT) { + message->measure.height = out[1]; + } else { + for (uintptr_t i = 0; i < childCount; i++) { + EsElement *element = panel->GetChild(i); + + if (element->flags & ES_ELEMENT_NON_CLIENT) { + continue; + } else if (element->flags & ES_ELEMENT_HIDDEN) { + element->InternalMove(0, 0, -1, -1); + continue; + } + + int position[2], size[2]; + + for (int axis = 0; axis < 2; axis++) { + position[axis] = calculatedProperties[axis][element->tableCell.from[axis]].maximumSize; + size[axis] = calculatedSize[axis][i]; + } + + PanelMoveChild(element, size[0], size[1], position[0] - panel->scroll.position[0], position[1] - panel->scroll.position[1]); + } + } + + if (debug) { + EsPrint("\t%d/%d\n", out[0], out[1]); + } + + EsHeapFree(memoryBase); +} + +int LayoutStackDeterminePerPush(EsPanel *panel, int available, int secondary) { + size_t childCount = panel->GetChildCount(); + int fill = 0, count = 0, perPush = 0; + + for (uintptr_t i = 0; i < childCount; i++) { + EsElement *child = panel->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + + count++; + + if (panel->flags & ES_PANEL_HORIZONTAL) { + if (child->flags & ES_CELL_H_PUSH) { + fill++; + } else if (available > 0) { + available -= child->GetWidth(secondary); + } + } else { + if (child->flags & ES_CELL_V_PUSH) { + fill++; + } else if (available > 0) { + available -= child->GetHeight(secondary); + } + } + } + + if (count) { + available -= (count - 1) * panel->GetGapMajor(); + } + + if (available > 0 && fill) { + perPush = available / fill; + } + + return perPush; +} + +void LayoutStackSecondary(EsPanel *panel, EsMessage *message) { + bool horizontal = panel->flags & ES_PANEL_HORIZONTAL; + size_t childCount = panel->GetChildCount(); + EsRectangle insets = panel->GetInsets(); + int size = 0; + + int primary = horizontal ? message->measure.width : message->measure.height; + int perPush = 0; + + if (panel->state & UI_STATE_INSPECTING) { + InspectorNotifyElementEvent(panel, "layout", "Measuring stack on secondary axis with %d children, insets %R; provided primary size is %d.\n", + panel, childCount, insets, primary); + } + + if (primary) { + if (horizontal) primary -= insets.l + insets.r; + else primary -= insets.t + insets.b; + perPush = LayoutStackDeterminePerPush(panel, primary, 0); + } + + for (uintptr_t i = 0; i < childCount; i++) { + EsElement *child = panel->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + + if (horizontal) { + int height = child->GetHeight((child->flags & ES_CELL_H_PUSH) ? perPush : 0); + if (height > size) size = height; + } else { + int width = child->GetWidth((child->flags & ES_CELL_V_PUSH) ? perPush : 0); + if (width > size) size = width; + } + } + + if (horizontal) message->measure.height = size + insets.t + insets.b; + else message->measure.width = size + insets.l + insets.r; +} + +void LayoutStackPrimary(EsPanel *panel, EsMessage *message) { + bool horizontal = panel->flags & ES_PANEL_HORIZONTAL; + bool reverse = panel->flags & ES_PANEL_REVERSE; + EsRectangle bounds = panel->GetBounds(); + size_t childCount = panel->GetChildCount(); + + EsRectangle insets = panel->GetInsets(); + int gap = panel->GetGapMajor(); + + if (message->type != ES_MSG_LAYOUT && (panel->state & UI_STATE_INSPECTING)) { + InspectorNotifyElementEvent(panel, "layout", "Measuring stack on primary axis with %d children, gap %d, insets %R.\n", childCount, gap, insets); + } + + if (message->type == ES_MSG_LAYOUT && (panel->state & UI_STATE_INSPECTING)) { + InspectorNotifyElementEvent(panel, "layout", "LayoutStack into %R with %d children, gap %d, insets %R.\n", bounds, childCount, gap, insets); + } + + int hBase = message->type == ES_MSG_GET_HEIGHT ? message->measure.width : Width(bounds); + int vBase = message->type == ES_MSG_GET_WIDTH ? message->measure.height : Height(bounds); + + int hSpace = hBase ? (hBase - insets.l - insets.r) : 0; + int vSpace = vBase ? (vBase - insets.t - insets.b) : 0; + int available = horizontal ? hSpace : vSpace; + int perPush = LayoutStackDeterminePerPush(panel, available, horizontal ? vSpace : hSpace); + + int position = horizontal ? (reverse ? insets.r : insets.l) : (reverse ? insets.b : insets.t); + bool anyNonHiddenChildren = false; + + for (uintptr_t i = 0; i < childCount; i++) { + EsElement *child = panel->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + EsRectangle relative; + anyNonHiddenChildren = true; + + if (horizontal) { + int width = (child->flags & ES_CELL_H_PUSH) ? perPush : child->GetWidth(vSpace); + + if (reverse) { + relative = ES_RECT_4(bounds.r - position - width, bounds.r - position, insets.t, bounds.b - insets.b); + } else { + relative = ES_RECT_4(position, position + width, insets.t, bounds.b - insets.b); + } + + position += width + gap; + } else { + int height = (child->flags & ES_CELL_V_PUSH) ? perPush : child->GetHeight(hSpace); + + if (reverse) { + relative = ES_RECT_4(insets.l, bounds.r - insets.r, bounds.b - position - height, bounds.b - position); + } else { + relative = ES_RECT_4(insets.l, bounds.r - insets.r, position, position + height); + } + + position += height + gap; + } + + if (message->type == ES_MSG_LAYOUT) { + if (panel->state & UI_STATE_INSPECTING) { + InspectorNotifyElementEvent(panel, "layout", "\tMove child %d into %R.\n", i, relative); + } + + EsRectangle childBounds = Translate(relative, -panel->scroll.position[0], -panel->scroll.position[1]); + PanelMoveChild(child, Width(childBounds), Height(childBounds), childBounds.l, childBounds.t); + } + } + + if (anyNonHiddenChildren) position -= gap; + + if (message->type == ES_MSG_GET_WIDTH) { + message->measure.width = position + (reverse ? insets.l : insets.r); + } else if (message->type == ES_MSG_GET_HEIGHT) { + message->measure.height = position + (reverse ? insets.t : insets.b); + } +} + +void LayoutStack(EsPanel *panel, EsMessage *message) { + bool horizontal = panel->flags & ES_PANEL_HORIZONTAL; + + if (message->type == ES_MSG_LAYOUT + || (message->type == ES_MSG_GET_WIDTH && horizontal) + || (message->type == ES_MSG_GET_HEIGHT && !horizontal)) { + LayoutStackPrimary(panel, message); + } else { + LayoutStackSecondary(panel, message); + } +} + +int EsElement::GetWidth(int height) { + if (currentStyle->preferredWidth) return currentStyle->preferredWidth; + if (!height) height = currentStyle->preferredHeight; + else if (currentStyle->preferredHeight && currentStyle->preferredHeight > height && (~flags & (ES_CELL_V_SHRINK))) height = currentStyle->preferredHeight; + else if (currentStyle->preferredHeight && currentStyle->preferredHeight < height && (~flags & (ES_CELL_V_EXPAND))) height = currentStyle->preferredHeight; + else if (currentStyle->metrics->minimumHeight && currentStyle->metrics->minimumHeight > height) height = currentStyle->metrics->minimumHeight; + else if (currentStyle->metrics->maximumHeight && currentStyle->metrics->maximumHeight < height) height = currentStyle->metrics->maximumHeight; + if (height) height -= internalOffsetTop + internalOffsetBottom; + EsMessage m = { ES_MSG_GET_WIDTH }; + m.measure.height = height; + EsMessageSend(this, &m); + int width = m.measure.width + internalOffsetLeft + internalOffsetRight; + if (currentStyle->metrics->minimumWidth && currentStyle->metrics->minimumWidth > width) width = currentStyle->metrics->minimumWidth; + if (currentStyle->metrics->maximumWidth && currentStyle->metrics->maximumWidth < width) width = currentStyle->metrics->maximumWidth; + return width; +} + +int EsElement::GetHeight(int width) { + if (currentStyle->preferredHeight) return currentStyle->preferredHeight; + if (!width) width = currentStyle->preferredWidth; + else if (currentStyle->preferredWidth && currentStyle->preferredWidth > width && (~flags & (ES_CELL_H_SHRINK))) width = currentStyle->preferredWidth; + else if (currentStyle->preferredWidth && currentStyle->preferredWidth < width && (~flags & (ES_CELL_H_EXPAND))) width = currentStyle->preferredWidth; + else if (currentStyle->metrics->minimumWidth && currentStyle->metrics->minimumWidth > width) width = currentStyle->metrics->minimumWidth; + else if (currentStyle->metrics->maximumWidth && currentStyle->metrics->maximumWidth < width) width = currentStyle->metrics->maximumWidth; + if (width) width -= internalOffsetLeft + internalOffsetRight; + EsMessage m = { ES_MSG_GET_HEIGHT }; + m.measure.width = width; + EsMessageSend(this, &m); + int height = m.measure.height + internalOffsetTop + internalOffsetBottom; + if (currentStyle->metrics->minimumHeight && currentStyle->metrics->minimumHeight > height) height = currentStyle->metrics->minimumHeight; + if (currentStyle->metrics->maximumHeight && currentStyle->metrics->maximumHeight < height) height = currentStyle->metrics->maximumHeight; + return height; +} + +void EsElement::InternalMove(int _width, int _height, int _offsetX, int _offsetY) { + if (state & UI_STATE_EXITING) { + return; + } + +#ifdef TRACE_LAYOUT + if (parent) { + EsElement *parent = this->parent->parent; + while (parent) parent = parent->parent, EsPrint("\t"); + EsPrint("(move) %z\n", debugName); + } +#endif + +#ifdef TRACE_LAYOUT + if (parent) { + EsElement *parent = this->parent->parent; + while (parent) parent = parent->parent, EsPrint("\t"); + EsPrint("(move) %z :: in %d, %d; %d, %d :: ", debugName, _offsetX, _offsetY, _width, _height); + } +#endif + + // Add the internal offset. + + if (parent) { + _offsetX += parent->internalOffsetLeft; + _offsetY += parent->internalOffsetTop; + } + + // What has changed? + + bool hasPositionChanged = _offsetX != offsetX || _offsetY != offsetY; + bool hasSizeChanged = _width != width || _height != height; + bool relayoutRequested = state & UI_STATE_RELAYOUT; + bool relayoutChild = state & UI_STATE_RELAYOUT_CHILD; + int oldOffsetX = offsetX, oldOffsetY = offsetY; + +#ifdef TRACE_LAYOUT + if (parent) { + EsPrint("align %d, %d; %d, %d ::%z%z%z%z\n", _offsetX, _offsetY, _width, _height, + hasPositionChanged ? " pos" : "", hasSizeChanged ? " size" : "", + relayoutRequested ? " rel" : "", relayoutChild ? " child" : ""); + } +#endif + + // Update the variables. + + offsetX = _offsetX; + offsetY = _offsetY; + width = _width; + height = _height; + state &= ~(UI_STATE_RELAYOUT | UI_STATE_RELAYOUT_CHILD); + + if (!relayoutRequested && !hasSizeChanged) { + // If our size hasn't changed and a relayout wasn't requested, then we don't need to do any layouting. + + if (hasPositionChanged) { + // Clear the old position. + + if (parent) { + EsRectangle paintOutsets = currentStyle->paintOutsets; + EsRectangle rectangle = ES_RECT_4(oldOffsetX - paintOutsets.l, oldOffsetX + width + paintOutsets.r, + oldOffsetY - paintOutsets.t, oldOffsetY + height + paintOutsets.b); + parent->Repaint(false, rectangle); + } + + // Repaint if we've moved. + + Repaint(true); + } + + if (relayoutChild) { + for (uintptr_t i = 0; i < children.Length(); i++) { + if (children[i]->state & (UI_STATE_RELAYOUT | UI_STATE_RELAYOUT_CHILD)) { + children[i]->InternalMove(children[i]->width, children[i]->height, children[i]->offsetX, children[i]->offsetY); + } + } + } + } else { + // Tell the element to layout its contents. + + if (state & UI_STATE_INSPECTING) EsPerformanceTimerPush(); + EsMessage m = { ES_MSG_LAYOUT }; + m.layout.sizeChanged = hasSizeChanged; + EsMessageSend(this, &m); + if (state & UI_STATE_INSPECTING) InspectorNotifyElementEvent(this, "layout", "Layout in %Fms.\n", EsPerformanceTimerPop() * 1000); + + // Repaint. + + Repaint(true); + } + + if (window != this) { + window->processCheckVisible = true; + } + + if (hasPositionChanged || hasSizeChanged) { + InspectorNotifyElementMoved(this, ES_RECT_4(offsetX, offsetX + width, offsetY, offsetY + height)); + } +} + +EsRectangle EsElementGetPreferredSize(EsElement *element) { + EsMessageMutexCheck(); + + return ES_RECT_4(0, element->currentStyle->preferredWidth, 0, element->currentStyle->preferredHeight); +} + +void EsElementRelayout(EsElement *element) { + if (element->state & UI_STATE_DESTROYING) return; + element->state |= UI_STATE_RELAYOUT; + UIWindowNeedsUpdate(element->window); + + while (element) { + element->state |= UI_STATE_RELAYOUT_CHILD; + element = element->parent; + } +} + +void EsElementUpdateContentSize(EsElement *element, uint32_t flags) { + if (element->state & UI_STATE_DESTROYING) return; + if (!flags) flags = ES_ELEMENT_UPDATE_CONTENT_WIDTH | ES_ELEMENT_UPDATE_CONTENT_HEIGHT; + + while (element && flags) { + element->state &= ~UI_STATE_USE_MEASUREMENT_CACHE; + EsElementRelayout(element); + + if (element->currentStyle->preferredWidth || ((element->flags & ES_CELL_H_FILL) == ES_CELL_H_FILL)) { + flags &= ~ES_ELEMENT_UPDATE_CONTENT_WIDTH; + } + + if (element->currentStyle->preferredHeight || ((element->flags & ES_CELL_V_FILL) == ES_CELL_V_FILL)) { + flags &= ~ES_ELEMENT_UPDATE_CONTENT_HEIGHT; + } + + element = element->parent; + } +} + +// --------------------------------- Scrollbars. + +// #define ENABLE_SMOOTH_SCROLLING + +struct EsScrollbar : EsElement { + EsButton *up, *down; + EsElement *thumb; + double position, autoScrollSpeed, smoothScrollTarget; + int viewportSize, contentSize, thumbSize, oldThumbPosition, thumbPosition, originalThumbPosition, oldPosition; + bool horizontal; +}; + +void ScrollbarLayout(EsScrollbar *scrollbar) { + if (scrollbar->viewportSize >= scrollbar->contentSize || scrollbar->viewportSize <= 0 || scrollbar->contentSize <= 0) { + EsElementSetDisabled(scrollbar, true); + } else { + EsElementSetDisabled(scrollbar, false); + EsRectangle bounds = scrollbar->GetBounds(); + + if (scrollbar->horizontal) { + scrollbar->thumbSize = scrollbar->viewportSize * (bounds.r - scrollbar->height * 2) / scrollbar->contentSize; + + if (scrollbar->thumbSize < scrollbar->thumb->currentStyle->preferredWidth) { + scrollbar->thumbSize = scrollbar->thumb->currentStyle->preferredWidth; + } + + if (scrollbar->thumbSize > Width(bounds) - scrollbar->height * 2) { + scrollbar->thumbSize = Width(bounds) - scrollbar->height * 2; + } + + scrollbar->thumbPosition = LinearMap(0, scrollbar->contentSize - scrollbar->viewportSize, + scrollbar->height, bounds.r - scrollbar->thumbSize - scrollbar->height, scrollbar->smoothScrollTarget); + + EsElementMove(scrollbar->up, 0, 0, (int) scrollbar->thumbPosition + scrollbar->thumbSize / 2, scrollbar->thumb->currentStyle->preferredHeight); + EsElementMove(scrollbar->thumb, (int) scrollbar->thumbPosition, 0, scrollbar->thumbSize, scrollbar->thumb->currentStyle->preferredHeight); + EsElementMove(scrollbar->down, (int) scrollbar->thumbPosition + scrollbar->thumbSize / 2, 0, + bounds.r - scrollbar->thumbSize / 2 - (int) scrollbar->thumbPosition, + scrollbar->thumb->currentStyle->preferredHeight); + } else { + scrollbar->thumbSize = scrollbar->viewportSize * (bounds.b - scrollbar->width * 2) / scrollbar->contentSize; + + if (scrollbar->thumbSize < scrollbar->thumb->currentStyle->preferredHeight) { + scrollbar->thumbSize = scrollbar->thumb->currentStyle->preferredHeight; + } + + if (scrollbar->thumbSize > Height(bounds) - scrollbar->width * 2) { + scrollbar->thumbSize = Height(bounds) - scrollbar->width * 2; + } + + scrollbar->thumbPosition = LinearMap(0, scrollbar->contentSize - scrollbar->viewportSize, + scrollbar->width, bounds.b - scrollbar->thumbSize - scrollbar->width, scrollbar->smoothScrollTarget); + + EsElementMove(scrollbar->up, 0, 0, scrollbar->thumb->currentStyle->preferredWidth, (int) scrollbar->thumbPosition + scrollbar->thumbSize / 2); + EsElementMove(scrollbar->thumb, 0, (int) scrollbar->thumbPosition, scrollbar->thumb->currentStyle->preferredWidth, scrollbar->thumbSize); + EsElementMove(scrollbar->down, 0, (int) scrollbar->thumbPosition + scrollbar->thumbSize / 2, + scrollbar->thumb->currentStyle->preferredWidth, + bounds.b - scrollbar->thumbSize / 2 - (int) scrollbar->thumbPosition); + } + } +} + +void ScrollbarSetMeasurements(EsScrollbar *scrollbar, int viewportSize, int contentSize) { + EsMessageMutexCheck(); + + if (scrollbar->viewportSize == viewportSize && scrollbar->contentSize == contentSize) { + return; + } + + scrollbar->viewportSize = viewportSize; + scrollbar->contentSize = contentSize; + + ScrollbarLayout(scrollbar); +} + +void ScrollbarSetPosition(EsScrollbar *scrollbar, double position, bool sendMovedMessage, bool smoothScroll) { + EsMessageMutexCheck(); + + if (position > scrollbar->contentSize - scrollbar->viewportSize) position = scrollbar->contentSize - scrollbar->viewportSize; + if (position < 0) position = 0; + + scrollbar->smoothScrollTarget = position; + + int previous = scrollbar->position; + +#ifdef ENABLE_SMOOTH_SCROLLING + if (smoothScroll && OSCRTabsf(position - scrollbar->position) > 10) { + scrollbar->StartAnimating(); + } else { + scrollbar->position = position; + } +#else + (void) smoothScroll; + scrollbar->position = position; +#endif + + EsRectangle bounds = scrollbar->GetBounds(); + + scrollbar->thumbPosition = LinearMap(0, scrollbar->contentSize - scrollbar->viewportSize, + 0, (scrollbar->horizontal ? bounds.r : bounds.b) - scrollbar->thumbSize, position); + + if (sendMovedMessage && scrollbar->oldPosition != (int) scrollbar->position) { + EsMessage m = { ES_MSG_SCROLLBAR_MOVED }; + m.scrollbarMoved.scroll = (int) position; + m.scrollbarMoved.previous = previous; + EsMessageSend(scrollbar, &m); + } + + if (scrollbar->thumbPosition != scrollbar->oldThumbPosition) { + ScrollbarLayout(scrollbar); + } + + scrollbar->oldThumbPosition = scrollbar->thumbPosition; + scrollbar->oldPosition = scrollbar->position; +} + +int ProcessScrollbarButtonMessage(EsElement *element, EsMessage *message) { + EsScrollbar *scrollbar = (EsScrollbar *) element->parent; + + if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + element->state |= UI_STATE_STRONG_PRESSED; + +#define UI_SCROLLBAR_AUTO_SPEED (10.0) + scrollbar->autoScrollSpeed = scrollbar->viewportSize / UI_SCROLLBAR_AUTO_SPEED / (100); + + if (scrollbar->up == element) { + scrollbar->autoScrollSpeed *= -1; + } + + element->StartAnimating(); + } else if (message->type == ES_MSG_MOUSE_LEFT_UP) { + element->state &= ~UI_STATE_STRONG_PRESSED; + scrollbar->autoScrollSpeed = 0; + } else if (message->type == ES_MSG_ANIMATE) { + if (scrollbar->autoScrollSpeed) { + ScrollbarSetPosition(scrollbar, scrollbar->autoScrollSpeed * message->animate.deltaMs + scrollbar->position, true, false); + message->animate.waitMs = 0; + message->animate.complete = false; + } else { + message->animate.complete = true; + } + } else { + return 0; + } + + return ES_HANDLED; +} + +EsScrollbar *ScrollbarCreate(EsElement *parent, uint64_t flags) { + EsScrollbar *scrollbar = (EsScrollbar *) EsHeapAllocate(sizeof(EsScrollbar), true); + scrollbar->thumb = (EsElement *) EsHeapAllocate(sizeof(EsElement), true); + + if (flags & ES_SCROLLBAR_HORIZONTAL) { + scrollbar->horizontal = true; + } + + scrollbar->Initialise(parent, flags, [] (EsElement *element, EsMessage *message) { + EsScrollbar *scrollbar = (EsScrollbar *) element; + + if (message->type == ES_MSG_LAYOUT) { + ScrollbarLayout(scrollbar); + } else if (message->type == ES_MSG_ANIMATE) { + if (scrollbar->position != scrollbar->smoothScrollTarget) { + double factor = EsCRTexp2f(-5.0f / message->animate.deltaMs); + // EsPrint("%dmcs -> %F\n", message->animate.deltaUs, factor); + scrollbar->position += (scrollbar->smoothScrollTarget - scrollbar->position) * factor; + ScrollbarSetPosition(scrollbar, scrollbar->smoothScrollTarget, true, true); + bool done = scrollbar->position == scrollbar->smoothScrollTarget; + message->animate.waitMs = 0, message->animate.complete = done; + } else message->animate.complete = true; + } else { + return 0; + } + + return ES_HANDLED; + }, nullptr); + + scrollbar->cName = "scrollbar"; + + scrollbar->up = EsButtonCreate(scrollbar, ES_CELL_FILL); + scrollbar->up->messageUser = ProcessScrollbarButtonMessage; + scrollbar->down = EsButtonCreate(scrollbar, ES_CELL_FILL); + scrollbar->down->messageUser = ProcessScrollbarButtonMessage; + + scrollbar->thumb->Initialise(scrollbar, ES_CELL_FILL, [] (EsElement *element, EsMessage *message) { + EsScrollbar *scrollbar = (EsScrollbar *) element->parent; + EsRectangle bounds = scrollbar->GetBounds(); + + if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + if (scrollbar->horizontal) { + float p = LinearMap(scrollbar->height, bounds.r - scrollbar->thumbSize - scrollbar->height, 0, scrollbar->contentSize - scrollbar->viewportSize, + message->mouseDragged.newPositionX - message->mouseDragged.originalPositionX + scrollbar->originalThumbPosition); + ScrollbarSetPosition(scrollbar, p, true, true); + } else { + float p = LinearMap(scrollbar->width, bounds.b - scrollbar->thumbSize - scrollbar->width, 0, scrollbar->contentSize - scrollbar->viewportSize, + message->mouseDragged.newPositionY - message->mouseDragged.originalPositionY + scrollbar->originalThumbPosition); + ScrollbarSetPosition(scrollbar, p, true, true); + } + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + scrollbar->originalThumbPosition = scrollbar->thumbPosition; + } else { + return 0; + } + + return ES_HANDLED; + }, nullptr); + + scrollbar->thumb->cName = "scrollbar thumb"; + + if (scrollbar->horizontal) { + scrollbar->up->SetStyle(ES_STYLE_PUSH_BUTTON_SCROLLBAR_LEFT); + scrollbar->down->SetStyle(ES_STYLE_PUSH_BUTTON_SCROLLBAR_RIGHT); + scrollbar->thumb->SetStyle(ES_STYLE_SCROLLBAR_THUMB_HORIZONTAL); + scrollbar->SetStyle(ES_STYLE_SCROLLBAR_BAR_HORIZONTAL); + } else { + scrollbar->up->SetStyle(ES_STYLE_PUSH_BUTTON_SCROLLBAR_UP); + scrollbar->down->SetStyle(ES_STYLE_PUSH_BUTTON_SCROLLBAR_DOWN); + scrollbar->thumb->SetStyle(ES_STYLE_SCROLLBAR_THUMB_VERTICAL); + scrollbar->SetStyle(ES_STYLE_SCROLLBAR_BAR_VERTICAL); + } + + scrollbar->up->flags &= ~ES_ELEMENT_FOCUSABLE; + scrollbar->down->flags &= ~ES_ELEMENT_FOCUSABLE; + + return scrollbar; +} + +void ScrollPane::Setup(EsElement *_parent, uint8_t _xMode, uint8_t _yMode, uint16_t _flags) { + parent = _parent; + mode[0] = _xMode; + mode[1] = _yMode; + flags = _flags; + + if (mode[0] == SCROLL_MODE_NONE) flags &= ~SCROLL_X_DRAG; + if (mode[1] == SCROLL_MODE_NONE) flags &= ~SCROLL_Y_DRAG; + + for (int axis = 0; axis < 2; axis++) { + if (mode[axis] == SCROLL_MODE_FIXED || mode[axis] == SCROLL_MODE_AUTO) { + uint64_t flags = ES_CELL_FILL | ES_ELEMENT_NON_CLIENT | (axis ? ES_SCROLLBAR_VERTICAL : ES_SCROLLBAR_HORIZONTAL); + if (!bar[axis]) bar[axis] = ScrollbarCreate(parent, flags); + bar[axis]->userData = this; + + bar[axis]->messageUser = [] (EsElement *element, EsMessage *message) { + ScrollPane *pane = (ScrollPane *) element->userData.p; + + if (message->type == ES_MSG_SCROLLBAR_MOVED) { + int axis = (element->flags & ES_SCROLLBAR_HORIZONTAL) ? 0 : 1; + EsMessage m = *message; + m.type = axis ? ES_MSG_SCROLL_Y : ES_MSG_SCROLL_X; + pane->position[axis] = m.scrollbarMoved.scroll; + EsMessageSend(pane->parent, &m); + } + + return 0; + }; + } else if (bar[axis]) { + EsElementDestroy(bar[axis]); + bar[axis] = nullptr; + } + } + + if (bar[0] && bar[1]) { + if (!pad) pad = EsCustomElementCreate(parent, ES_CELL_FILL | ES_ELEMENT_NON_CLIENT, ES_STYLE_SCROLLBAR_PAD); + pad->cName = "scrollbar pad"; + } else if (pad) { + EsElementDestroy(pad); + pad = nullptr; + } +} + +void ScrollPane::ReceivedMessage(EsMessage *message) { + if (message->type == ES_MSG_LAYOUT) { + Refresh(); + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG || message->type == ES_MSG_MOUSE_RIGHT_DRAG || message->type == ES_MSG_MOUSE_MIDDLE_DRAG) { + if (flags & (SCROLL_X_DRAG | SCROLL_Y_DRAG)) { + parent->StartAnimating(); + dragScrolling = true; + } + } else if (message->type == ES_MSG_MOUSE_LEFT_UP || message->type == ES_MSG_MOUSE_RIGHT_UP || message->type == ES_MSG_MOUSE_MIDDLE_UP) { + dragScrolling = false; + } else if (message->type == ES_MSG_ANIMATE) { + if (dragScrolling) { + EsPoint point = EsMouseGetPosition(parent); + EsRectangle bounds = parent->GetBounds(); + double distanceX = point.x < bounds.l ? point.x - bounds.l : point.x >= bounds.r ? point.x - bounds.r + 1 : 0; + double distanceY = point.y < bounds.t ? point.y - bounds.t : point.y >= bounds.b ? point.y - bounds.b + 1 : 0; + double deltaX = message->animate.deltaMs * distanceX / 300.0; + double deltaY = message->animate.deltaMs * distanceY / 300.0; + if (deltaX && (flags & SCROLL_X_DRAG)) SetX(position[0] + deltaX, true); + if (deltaY && (flags & SCROLL_Y_DRAG)) SetY(position[1] + deltaY, true); + message->animate.complete = false; + } + } else if (message->type == ES_MSG_GET_HEIGHT) { + if (message->measure.width && (mode[0] == SCROLL_MODE_AUTO) && (mode[1] != SCROLL_MODE_AUTO)) { + // To accurately measure the height of the element for this width, + // we need to determine whether the horizontal scrollbar will be present. + // TODO This assumes that the element will be send a LAYOUT message after measurements are complete, + // in order for the scrollbars to be updated. But I think this will always happen..? + EsMessage m = {}; + m.type = ES_MSG_GET_WIDTH; + EsMessageSend(parent, &m); + parent->internalOffsetBottom = (m.measure.width + fixedViewport[0] > message->measure.width) ? bar[0]->currentStyle->preferredHeight : 0; + } + } else if (message->type == ES_MSG_GET_WIDTH) { + if (message->measure.width && (mode[1] == SCROLL_MODE_AUTO) && (mode[0] != SCROLL_MODE_AUTO)) { + // As above. + EsMessage m = {}; + m.type = ES_MSG_GET_HEIGHT; + EsMessageSend(parent, &m); + parent->internalOffsetRight = (m.measure.height + fixedViewport[1] > message->measure.height) ? bar[1]->currentStyle->preferredWidth : 0; + } + } +} + +void ScrollPane::SetPosition(int axis, double newScroll, bool sendMovedMessage) { + if (mode[axis] == SCROLL_MODE_NONE) return; + if (newScroll < 0) newScroll = 0; + else if (newScroll > limit[axis]) newScroll = limit[axis]; + if (newScroll == position[axis]) return; + double previous = position[axis]; + position[axis] = newScroll; + if (bar[axis]) ScrollbarSetPosition(bar[axis], position[axis], false, false); + + if (sendMovedMessage) { + EsMessage m = {}; + m.type = axis ? ES_MSG_SCROLL_Y : ES_MSG_SCROLL_X; + m.scrollbarMoved.scroll = position[axis]; + m.scrollbarMoved.previous = previous; + EsMessageSend(parent, &m); + } +} + +bool ScrollPane::RefreshLimit(int axis, int64_t *contentSize) { + if (mode[axis] != SCROLL_MODE_NONE) { + uint8_t *internalOffset = axis ? &parent->internalOffsetRight : &parent->internalOffsetBottom; + EsRectangle bounds = parent->GetBounds(); + + EsMessage m = {}; + m.type = axis ? ES_MSG_GET_HEIGHT : ES_MSG_GET_WIDTH; + if (axis) m.measure.width = bounds.r; + else m.measure.height = bounds.b; + EsMessageSend(parent, &m); + + *contentSize = axis ? m.measure.height : m.measure.width; + limit[axis] = *contentSize - (axis ? bounds.b : bounds.r) + fixedViewport[axis]; + if (limit[axis] < 0) limit[axis] = 0; + + if (parent->state & UI_STATE_INSPECTING) { + InspectorNotifyElementEvent(parent, "scroll", "New %c limit: %d. (Measured content %d with other axis %d.)\n", + axis + 'X', limit[axis], *contentSize, axis ? bounds.r : bounds.b); + } + + if (mode[axis] == SCROLL_MODE_AUTO && limit[axis] > 0 && !(*internalOffset)) { + *internalOffset = axis ? bar[axis]->currentStyle->preferredWidth : bar[axis]->currentStyle->preferredHeight; + return true; + } + } + + return false; +} + +void ScrollPane::Refresh() { + if (parent->state & UI_STATE_INSPECTING) { + InspectorNotifyElementEvent(parent, "scroll", "Refreshing scroll pane...\n"); + } + + parent->internalOffsetRight = mode[1] == SCROLL_MODE_FIXED ? bar[1]->currentStyle->preferredWidth : 0; + parent->internalOffsetBottom = mode[0] == SCROLL_MODE_FIXED ? bar[0]->currentStyle->preferredHeight : 0; + + int64_t contentWidth = 0, contentHeight = 0; + + bool recalculateLimits1 = RefreshLimit(0, &contentWidth); + bool recalculateLimits2 = RefreshLimit(1, &contentHeight); + + if (recalculateLimits1 || recalculateLimits2) { + RefreshLimit(0, &contentWidth); + RefreshLimit(1, &contentHeight); + } + + EsRectangle bounds = parent->GetBounds(); + + if (bar[0]) ScrollbarSetMeasurements(bar[0], bounds.r - fixedViewport[0], contentWidth); + if (bar[1]) ScrollbarSetMeasurements(bar[1], bounds.b - fixedViewport[1], contentHeight); + + SetPosition(0, position[0], true); + SetPosition(1, position[1], true); + + if (bar[0]) { + bar[0]->InternalMove(parent->width - parent->internalOffsetRight, bar[0]->currentStyle->preferredHeight, + 0, parent->height - parent->internalOffsetBottom); + } + + if (bar[1]) { + bar[1]->InternalMove(bar[1]->currentStyle->preferredWidth, parent->height - parent->internalOffsetBottom, + parent->width - parent->internalOffsetRight, 0); + } + + if (pad) { + pad->InternalMove(parent->internalOffsetRight, parent->internalOffsetBottom, + parent->width - parent->internalOffsetRight, parent->height - parent->internalOffsetBottom); + } +} + +// --------------------------------- Panels. + +void PanelSwitcherTransitionComplete(EsPanel *panel) { + if (panel->switchedFrom) { + if (panel->destroyPreviousAfterTransitionCompletes) { + panel->switchedFrom->Destroy(); + } else { + EsElementSetHidden(panel->switchedFrom, true); + } + + panel->switchedFrom = nullptr; + } + + panel->transitionType = ES_TRANSITION_NONE; +} + +void PanelTableSetChildCell(EsPanel *panel, EsElement *child) { + uintptr_t index = panel->tableIndex++; + TableCell cell = {}; + + if (panel->flags & ES_PANEL_HORIZONTAL) { + cell.from[0] = cell.to[0] = index % panel->bandCount[0]; + cell.from[1] = cell.to[1] = index / panel->bandCount[0]; + + if (panel->bandCount[1] <= cell.from[1] && !panel->bands[1]) { + panel->bandCount[1] = cell.from[1] + 1; + } + } else { + cell.from[0] = cell.to[0] = index / panel->bandCount[1]; + cell.from[1] = cell.to[1] = index % panel->bandCount[1]; + + if (panel->bandCount[0] <= cell.from[0] && !panel->bands[0]) { + panel->bandCount[0] = cell.from[0] + 1; + } + } + + child->tableCell = cell; +} + +int ProcessPanelMessage(EsElement *element, EsMessage *message) { + EsPanel *panel = (EsPanel *) element; + EsRectangle bounds = panel->GetBounds(); + + panel->scroll.ReceivedMessage(message); + + if (message->type == ES_MSG_LAYOUT) { + if (panel->flags & ES_PANEL_TABLE) { + LayoutTable(panel, message); + } else if (panel->flags & ES_PANEL_SWITCHER) { + EsRectangle insets = panel->GetInsets(); + + if (panel->switchedFrom) { + EsElementMove(panel->switchedFrom, bounds.l + insets.l, bounds.t + insets.t, + bounds.r - bounds.l - insets.r - insets.l, bounds.b - bounds.t - insets.b - insets.t); + } + + if (panel->switchedTo) { + EsElementMove(panel->switchedTo, bounds.l + insets.l, bounds.t + insets.t, + bounds.r - bounds.l - insets.r - insets.l, bounds.b - bounds.t - insets.b - insets.t); + } + } else if (panel->flags & ES_PANEL_Z_STACK) { + EsRectangle insets = panel->GetInsets(); + + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + EsElement *child = element->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + PanelMoveChild(child, bounds.r - bounds.l - insets.r - insets.l, + bounds.b - bounds.t - insets.b - insets.t, + bounds.l + insets.l, bounds.t + insets.t); + } + } else { + LayoutStack(panel, message); + } + } else if (message->type == ES_MSG_PAINT_CHILDREN) { + if ((panel->flags & ES_PANEL_SWITCHER) && panel->transitionType != ES_TRANSITION_NONE) { + double progress = SmoothAnimationTimeSharp((double) panel->transitionTimeMs / (double) panel->transitionLengthMs); + EsRectangle bounds = EsPainterBoundsClient(message->painter); + int width = Width(bounds), height = Height(bounds); + EsPaintTarget target; + + if (EsPaintTargetTake(&target, width, height)) { + EsPainter painter = { .clip = ES_RECT_4(0, width, 0, height), .width = width, .height = height, .target = &target }; + + // TODO 'Clip'-style transitions. ES_TRANSITION_REVEAL_UP/ES_TRANSITION_REVEAL_DOWN. + + if (panel->switchedFrom) { + panel->switchedFrom->InternalPaint(&painter, PAINT_SHADOW); + panel->switchedFrom->InternalPaint(&painter, ES_FLAGS_DEFAULT); + panel->switchedFrom->InternalPaint(&painter, PAINT_OVERLAY); + UIDrawTransitionEffect(message->painter, &target, bounds, (EsTransitionType) panel->transitionType, progress, false); + EsPaintTargetClear(&target); + } + + if (panel->switchedTo) { + panel->switchedTo->InternalPaint(&painter, PAINT_SHADOW); + panel->switchedTo->InternalPaint(&painter, ES_FLAGS_DEFAULT); + panel->switchedTo->InternalPaint(&painter, PAINT_OVERLAY); + UIDrawTransitionEffect(message->painter, &target, bounds, (EsTransitionType) panel->transitionType, progress, true); + } + + EsPaintTargetReturn(&target); + } else { + // Not enough memory to get a paint target. + return 0; + } + } else { + return 0; + } + } else if (message->type == ES_MSG_GET_WIDTH) { + if (!panel->measurementCache.Get(message, &panel->state)) { + if (panel->flags & ES_PANEL_TABLE) { + LayoutTable(panel, message); + } else if (panel->flags & (ES_PANEL_Z_STACK | ES_PANEL_SWITCHER)) { + int maximum = 0; + + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + EsElement *child = element->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + int size = child->GetWidth(message->measure.height); + if (size > maximum) maximum = size; + } + + message->measure.width = maximum + panel->GetInsetWidth(); + } else { + LayoutStack(panel, message); + } + + panel->measurementCache.Store(message); + } + } else if (message->type == ES_MSG_GET_HEIGHT) { + if (!panel->measurementCache.Get(message, &panel->state)) { + if (panel->flags & ES_PANEL_TABLE) { + LayoutTable(panel, message); + } else if (panel->flags & (ES_PANEL_Z_STACK | ES_PANEL_SWITCHER)) { + int maximum = 0; + + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + EsElement *child = element->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + int size = child->GetHeight(message->measure.width); + if (size > maximum) maximum = size; + } + + message->measure.height = maximum + panel->GetInsetHeight(); + } else { + LayoutStack(panel, message); + } + panel->measurementCache.Store(message); + } + } else if (message->type == ES_MSG_ENSURE_VISIBLE) { + EsElement *child = message->child, *e = child; + int offsetX = panel->scroll.position[0], offsetY = panel->scroll.position[1]; + while (e != element) offsetX += e->offsetX, offsetY += e->offsetY, e = e->parent; + EsRectangle bounds = panel->GetBounds(); + panel->scroll.SetX(offsetX + child->width / 2 - bounds.r / 2); + panel->scroll.SetY(offsetY + child->height / 2 - bounds.b / 2); + } else if (message->type == ES_MSG_PRE_ADD_CHILD) { + if (!panel->addingSeparator && panel->separatorStylePart && panel->GetChildCount()) { + panel->addingSeparator = true; + EsCustomElementCreate(panel, panel->separatorFlags, panel->separatorStylePart)->cName = "panel separator"; + panel->addingSeparator = false; + } + } else if (message->type == ES_MSG_ADD_CHILD) { + if (panel->flags & ES_PANEL_TABLE) { + if (!panel->bandCount[0] && !panel->bandCount[1]) { + // The application has not yet set the number of columns/rows, + // so we can't perform automatical element placement. + // The application will need to call EsPanelTableSetChildCells. + } else { + PanelTableSetChildCell(panel, (EsElement *) message->child); + } + } else if (panel->flags & ES_PANEL_SWITCHER) { + EsElement *child = (EsElement *) message->child; + child->state |= UI_STATE_BLOCK_INTERACTION; + } + } else if (message->type == ES_MSG_SCROLL_X || message->type == ES_MSG_SCROLL_Y) { + int delta = message->scrollbarMoved.scroll - message->scrollbarMoved.previous; + int deltaX = message->type == ES_MSG_SCROLL_X ? delta : 0; + int deltaY = message->type == ES_MSG_SCROLL_Y ? delta : 0; + + for (uintptr_t i = 0; i < panel->GetChildCount(); i++) { + EsElement *child = panel->GetChild(i); + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue; + child->InternalMove(child->width, child->height, child->offsetX - deltaX, child->offsetY - deltaY); + } + } else if (message->type == ES_MSG_ANIMATE) { + panel->transitionTimeMs += message->animate.deltaMs; + message->animate.complete = panel->transitionTimeMs >= panel->transitionLengthMs; + + if (panel->flags & ES_PANEL_SWITCHER) { + panel->Repaint(true); + + if (message->animate.complete) { + PanelSwitcherTransitionComplete(panel); + } + } else if (panel->movementItems.Length()) { + EsElementRelayout(panel); + + if (message->animate.complete) { + panel->movementItems.Free(); + } + } + } else if (message->type == ES_MSG_DESTROY_CONTENTS) { + if ((panel->flags & ES_PANEL_TABLE)) { + panel->tableIndex = 0; + panel->bandCount[(panel->flags & ES_PANEL_HORIZONTAL) ? 1 : 0] = 0; + } + } else if (message->type == ES_MSG_DESTROY) { + if ((panel->flags & ES_PANEL_TABLE)) { + EsHeapFree(panel->bands[0]); + EsHeapFree(panel->bands[1]); + } + } else if (message->type == ES_MSG_KEY_DOWN) { + if (!(panel->flags & (ES_PANEL_TABLE | ES_PANEL_SWITCHER)) + && panel->window->focused && panel->window->focused->parent == panel + && (panel->flags & ES_PANEL_HORIZONTAL)) { + bool reverse = panel->flags & ES_PANEL_REVERSE, + left = message->keyboard.scancode == ES_SCANCODE_LEFT_ARROW, + right = message->keyboard.scancode == ES_SCANCODE_RIGHT_ARROW; + + if ((left && !reverse) || (right && reverse)) { + EsElement *focus = nullptr; + + for (uintptr_t i = 0; i < panel->GetChildCount(); i++) { + EsElement *child = panel->GetChild(i); + + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) { + continue; + } + + if (child == panel->window->focused) { + break; + } else if (child->IsFocusable()) { + focus = child; + } + } + + if (focus) { + EsElementFocus(focus); + } + } else if ((left && reverse) || (right && !reverse)) { + EsElement *focus = nullptr; + + for (uintptr_t i = panel->GetChildCount(); i > 0; i--) { + EsElement *child = panel->GetChild(i - 1); + + if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) { + continue; + } + + if (child == panel->window->focused) { + break; + } else if (child->IsFocusable()) { + focus = child; + } + } + + if (focus) { + EsElementFocus(focus); + } + } else { + return 0; + } + } else { + return 0; + } + } else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) { + EsBuffer *buffer = message->getContent.buffer; + + if (panel->flags & ES_PANEL_Z_STACK) { + EsBufferFormat(buffer, "z-stack"); + } else if (panel->flags & ES_PANEL_SWITCHER) { + EsBufferFormat(buffer, "switcher"); + } else if (panel->flags & ES_PANEL_TABLE) { + EsBufferFormat(buffer, "table"); + } else { + EsBufferFormat(buffer, "%z%z stack", + (panel->flags & ES_PANEL_REVERSE) ? "reverse " : "", + (panel->flags & ES_PANEL_HORIZONTAL) ? "horizontal" : "vertical"); + } + } else if (message->type == ES_MSG_BEFORE_Z_ORDER) { + bool isStack = !(panel->flags & (ES_PANEL_TABLE | ES_PANEL_SWITCHER | ES_PANEL_Z_STACK)); + + if (isStack && panel->children.Length() > 100) { + // Count the number of client children. + + size_t childCount = panel->children.Length(); + + while (childCount) { + if (panel->children[childCount - 1]->flags & ES_ELEMENT_NON_CLIENT) { + childCount--; + } else { + break; + } + } + + if (childCount < 100) { + return 0; + } + + message->beforeZOrder.nonClient = childCount; + + // Binary search for an early visible child. + + bool found = false; + uintptr_t position = 0; + + if (panel->flags & ES_PANEL_HORIZONTAL) { + ES_MACRO_SEARCH(childCount, result = message->beforeZOrder.clip.l - panel->children[index]->offsetX;, position, found); + } else { + ES_MACRO_SEARCH(childCount, result = message->beforeZOrder.clip.t - panel->children[index]->offsetY;, position, found); + } + + if (!found) { + position = 0; + } + + // Search back until we find the first. + // Assumption: children with paint outsets do not extend beyond the next child. + + while (position) { + if (position < childCount) { + EsElement *child = panel->children[position]; + + if (panel->flags & ES_PANEL_HORIZONTAL) { + if (child->offsetX + child->width + child->currentStyle->paintOutsets.r < message->beforeZOrder.clip.l) { + break; + } + } else { + if (child->offsetY + child->height + child->currentStyle->paintOutsets.b < message->beforeZOrder.clip.t) { + break; + } + } + } + + position--; + } + + message->beforeZOrder.start = position; + + // Search forward until we find the last visible child. + + while (position < childCount) { + EsElement *child = panel->children[position]; + + if (panel->flags & ES_PANEL_HORIZONTAL) { + if (child->offsetX - child->currentStyle->paintOutsets.l > message->beforeZOrder.clip.r) { + break; + } + } else { + if (child->offsetY - child->currentStyle->paintOutsets.t > message->beforeZOrder.clip.b) { + break; + } + } + + position++; + } + + message->beforeZOrder.end = position; + } + } else { + return 0; + } + + return ES_HANDLED; +} + +EsPanel *EsPanelCreate(EsElement *parent, uint64_t flags, const EsStyle *style) { + EsPanel *panel = (EsPanel *) EsHeapAllocate(sizeof(EsPanel), true); + + panel->Initialise(parent, flags, ProcessPanelMessage, style); + panel->cName = "panel"; + + if (flags & ES_PANEL_Z_STACK) panel->state |= UI_STATE_Z_STACK; + if (flags & ES_PANEL_HORIZONTAL) panel->flags |= ES_ELEMENT_LAYOUT_HINT_HORIZONTAL; + if (flags & ES_PANEL_REVERSE) panel->flags |= ES_ELEMENT_LAYOUT_HINT_REVERSE; + + panel->scroll.Setup(panel, + ((flags & ES_PANEL_H_SCROLL_FIXED) ? SCROLL_MODE_FIXED : (flags & ES_PANEL_H_SCROLL_AUTO) ? SCROLL_MODE_AUTO : SCROLL_MODE_NONE), + ((flags & ES_PANEL_V_SCROLL_FIXED) ? SCROLL_MODE_FIXED : (flags & ES_PANEL_V_SCROLL_AUTO) ? SCROLL_MODE_AUTO : SCROLL_MODE_NONE), + ES_FLAGS_DEFAULT); + + return panel; +} + +struct EsSpacer : EsElement { + int width, height; +}; + +int ProcessSpacerMessage(EsElement *element, EsMessage *message) { + EsSpacer *spacer = (EsSpacer *) element; + + if (message->type == ES_MSG_GET_WIDTH) { + message->measure.width = spacer->width * spacer->currentStyle->scale; + } else if (message->type == ES_MSG_GET_HEIGHT) { + message->measure.height = spacer->height * spacer->currentStyle->scale; + } + + return 0; +} + +EsElement *EsSpacerCreate(EsElement *panel, uint64_t flags, const EsStyle *style, int width, int height) { + EsSpacer *spacer = (EsSpacer *) EsHeapAllocate(sizeof(EsSpacer), true); + spacer->Initialise(panel, flags, ProcessSpacerMessage, style); + spacer->cName = "spacer"; + spacer->width = width == -1 ? 4 : width; + spacer->height = height == -1 ? 4 : height; + return spacer; +} + +EsElement *EsCustomElementCreate(EsElement *parent, uint64_t flags, const EsStyle *style) { + EsElement *element = (EsElement *) EsHeapAllocate(sizeof(EsElement), true); + element->Initialise(parent, flags, nullptr, style); + element->cName = "custom element"; + return element; +} + +void EsElementSetCellRange(EsElement *element, int xFrom, int yFrom, int xTo, int yTo) { + EsMessageMutexCheck(); + + if (xFrom == -1) xFrom = element->tableCell.from[0]; + if (yFrom == -1) yFrom = element->tableCell.from[1]; + if (xTo == -1) xTo = xFrom; + if (yTo == -1) yTo = yFrom; + + EsPanel *panel = (EsPanel *) element->parent; + EsAssert(panel->messageClass == ProcessPanelMessage && panel->flags & ES_PANEL_TABLE); // Invalid parent for SetCellRange. + + TableCell cell = {}; + cell.from[0] = xFrom, cell.from[1] = yFrom; + cell.to[0] = xTo, cell.to[1] = yTo; + element->tableCell = cell; +} + +void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount, EsPanelBand *columns, EsPanelBand *rows) { + EsMessageMutexCheck(); + EsAssert(panel->flags & ES_PANEL_TABLE); // Cannot set the bands layout for a non-table panel. + EsHeapFree(panel->bands[0]); + EsHeapFree(panel->bands[1]); + panel->bands[0] = nullptr; + panel->bands[1] = nullptr; + panel->bandCount[0] = columnCount; + panel->bandCount[1] = rowCount; + panel->bands[0] = columns ? (EsPanelBand *) EsHeapAllocate(columnCount * sizeof(EsPanelBand), false) : nullptr; + panel->bands[1] = rows ? (EsPanelBand *) EsHeapAllocate(rowCount * sizeof(EsPanelBand), false) : nullptr; + if (columns) EsMemoryCopy(panel->bands[0], columns, columnCount * sizeof(EsPanelBand)); + if (rows) EsMemoryCopy(panel->bands[1], rows, rowCount * sizeof(EsPanelBand)); +} + +void EsPanelSetBandsAll(EsPanel *panel, EsPanelBand *column, EsPanelBand *row) { + EsMessageMutexCheck(); + EsAssert(panel->flags & ES_PANEL_TABLE); // Cannot set the bands layout for a non-table panel. + + EsPanelBand *templates[2] = { column, row }; + + for (uintptr_t axis = 0; axis < 2; axis++) { + if (!templates[axis]) continue; + + if (!panel->bands[axis]) { + panel->bands[axis] = (EsPanelBand *) EsHeapAllocate(panel->bandCount[axis] * sizeof(EsPanelBand), false); + } + + for (uintptr_t i = 0; i < panel->bandCount[axis]; i++) { + panel->bands[axis][i] = *templates[axis]; + } + } +} + +void EsPanelTableSetChildCells(EsPanel *panel) { + // The number of columns/rows should have been set by the time this function is called. + EsAssert(panel->bandCount[0] || panel->bandCount[1]); + + panel->tableIndex = 0; + panel->bandCount[(panel->flags & ES_PANEL_HORIZONTAL) ? 1 : 0] = 0; + + for (uintptr_t i = 0; i < panel->GetChildCount(); i++) { + EsElement *child = panel->GetChild(i); + if (child->flags & ES_ELEMENT_NON_CLIENT) continue; + PanelTableSetChildCell(panel, child); + } +} + +void EsPanelSwitchTo(EsPanel *panel, EsElement *targetChild, EsTransitionType transitionType, uint32_t flags, uint32_t timeMs) { + EsMessageMutexCheck(); + EsAssert(panel->flags & ES_PANEL_SWITCHER); // Cannot switch element for a non-switcher panel. + timeMs *= ANIMATION_TIME_SCALE; + + if (targetChild == panel->switchedTo) { + return; + } + + if (panel->switchedFrom) { + // We're interrupting the previous transition. + PanelSwitcherTransitionComplete(panel); + } + + panel->transitionType = transitionType; + panel->transitionTimeMs = 0; + panel->transitionLengthMs = timeMs; + panel->switchedFrom = panel->switchedTo; + panel->switchedTo = targetChild; + panel->destroyPreviousAfterTransitionCompletes = flags & ES_PANEL_SWITCHER_DESTROY_PREVIOUS_AFTER_TRANSITION; + + if (panel->switchedTo) { + EsElementSetHidden(panel->switchedTo, false); + panel->switchedTo->state &= ~UI_STATE_BLOCK_INTERACTION; + panel->switchedTo->BringToFront(); + } + + if (panel->switchedFrom) { + panel->switchedFrom->state |= UI_STATE_BLOCK_INTERACTION; + UIMaybeRemoveFocusedElement(panel->window); + } + + if (transitionType == ES_TRANSITION_NONE || panel->switchedFrom == panel->switchedTo || !panel->transitionLengthMs) { + PanelSwitcherTransitionComplete(panel); + } else { + panel->StartAnimating(); + } + + EsElementRelayout(panel); +} + +void EsPanelStartMovementAnimation(EsPanel *panel, uint32_t timeMs) { + // TODO Custom smoothing functions. + + timeMs *= ANIMATION_TIME_SCALE; + if (!timeMs) return; + EsMessageMutexCheck(); + EsAssert(~panel->flags & ES_PANEL_SWITCHER); // Use EsPanelSwitchTo! + panel->transitionTimeMs = 0; + panel->transitionLengthMs = timeMs; + panel->StartAnimating(); + panel->movementItems.Free(); + + for (uintptr_t i = 0; i < panel->GetChildCount(); i++) { + EsElement *element = panel->GetChild(i); + + if (element->flags & ES_ELEMENT_NON_CLIENT) { + continue; + } + + PanelMovementItem item = {}; + item.element = element; + item.oldBounds = ES_RECT_4(element->offsetX, element->offsetX + element->width, + element->offsetY, element->offsetY + element->height); + panel->movementItems.Add(item); + } + + EsElementRelayout(panel); +} + +// --------------------------------- Canvas panes. + +struct EsCanvasPane : EsElement { + double panX, panY, zoom; + bool zoomFit, contentsChanged, center; + int previousWidth, previousHeight; +}; + +EsElement *CanvasPaneGetCanvas(EsElement *element) { + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + if (~element->GetChild(i)->flags & ES_ELEMENT_NON_CLIENT) { + return element->GetChild(i); + } + } + + return nullptr; +} + +int ProcessCanvasPaneMessage(EsElement *element, EsMessage *message) { + EsCanvasPane *pane = (EsCanvasPane *) element; + + if (message->type == ES_MSG_LAYOUT) { + EsElement *canvas = CanvasPaneGetCanvas(element); + if (!canvas) return 0; + + EsRectangle bounds = element->GetBounds(); + EsRectangle insets = element->currentStyle->insets; + bounds.l += insets.l, bounds.r -= insets.r; + bounds.t += insets.t, bounds.b -= insets.b; + + pane->panX -= (Width(bounds) - pane->previousWidth) / 2 / pane->zoom; + pane->panY -= (Height(bounds) - pane->previousHeight) / 2 / pane->zoom; + pane->previousWidth = Width(bounds), pane->previousHeight = Height(bounds); + + int width = canvas->GetWidth(0), height = canvas->GetHeight(0); + + double minimumZoomX = 1, minimumZoomY = 1; + if (width > Width(bounds)) minimumZoomX = (double) Width(bounds) / width; + if (height > Height(bounds)) minimumZoomY = (double) Height(bounds) / height; + double minimumZoom = minimumZoomX < minimumZoomY ? minimumZoomX : minimumZoomY; + + if (pane->zoom < minimumZoom || pane->contentsChanged || pane->zoomFit) { + pane->zoom = minimumZoom; + pane->zoomFit = true; + } + + pane->contentsChanged = false; + + if (pane->panX < 0) pane->panX = 0; + if (pane->panX > width - Width(bounds) / pane->zoom) pane->panX = width - Width(bounds) / pane->zoom; + if (pane->panY < 0) pane->panY = 0; + if (pane->panY > height - Height(bounds) / pane->zoom) pane->panY = height - Height(bounds) / pane->zoom; + + if (width * pane->zoom <= Width(bounds) || pane->center) { + pane->panX = width / 2 - Width(bounds) / pane->zoom / 2; + } + + if (height * pane->zoom <= Height(bounds) || pane->center) { + pane->panY = height / 2 - Height(bounds) / pane->zoom / 2; + } + + pane->center = false; + + int x = (int) (0.5f + LinearMap(pane->panX, pane->panX + Width(bounds) / pane->zoom, 0, Width(bounds), 0)); + int y = (int) (0.5f + LinearMap(pane->panY, pane->panY + Height(bounds) / pane->zoom, 0, Height(bounds), 0)); + canvas->InternalMove(width, height, x + bounds.l, y + bounds.t); + } else if (message->type == ES_MSG_PAINT) { + EsElement *canvas = CanvasPaneGetCanvas(element); + if (!canvas) return 0; + + UIStyle *style = GetStyle(MakeStyleKey(ES_STYLE_CANVAS_SHADOW, 0), true); + EsRectangle shadow1 = ES_RECT_4PD(canvas->offsetX + style->preferredWidth, canvas->offsetY + canvas->height, + canvas->width, style->preferredHeight); + EsRectangle shadow2 = ES_RECT_4PD(canvas->offsetX + canvas->width, canvas->offsetY + style->preferredHeight, + style->preferredWidth, canvas->height - style->preferredHeight); + style->PaintLayers(message->painter, shadow1, THEME_CHILD_TYPE_ONLY, ES_FLAGS_DEFAULT); + style->PaintLayers(message->painter, shadow2, THEME_CHILD_TYPE_ONLY, ES_FLAGS_DEFAULT); + } + + return 0; +} + +EsCanvasPane *EsCanvasPaneCreate(EsElement *parent, uint64_t flags, const EsStyle *style) { + EsCanvasPane *pane = (EsCanvasPane *) EsHeapAllocate(sizeof(EsCanvasPane), true); + pane->Initialise(parent, flags, ProcessCanvasPaneMessage, style); + pane->cName = "canvas pane"; + pane->zoom = 1.0; + return pane; +} + +// --------------------------------- Text displays and textboxes. + +#define TEXT_ELEMENTS +#include "text.cpp" +#undef TEXT_ELEMENTS + +// --------------------------------- Announcements. + +// TODO Different colored messages for info/warning/error. +// TODO Different hold times. + +int AnnouncementMessage(EsElement *element, EsMessage *message) { + EsWindow *window = (EsWindow *) element; + + if (message->type == ES_MSG_ANIMATE) { + window->announcementTimeMs += message->animate.deltaMs; + + double progress = window->announcementTimeMs / GetConstantNumber("announcementDuration"); + + if (progress > 1) { + progress = 1; + EsElementDestroy(window); + return 0; + } + + progress = 2 * progress - 1; + progress = (1 + progress * progress * progress * progress * progress) * 0.5; + + double inOnly = 2 * (progress < 0.5 ? progress : 0.5); + double inOut = progress < 0.5 ? progress * 2 : (2 - progress * 2); + + EsRectangle bounds = EsWindowGetBounds(window); + int32_t height = Height(bounds); + bounds.t = window->announcementBaseY - inOnly * GetConstantNumber("announcementMovement"); + bounds.b = bounds.t + height; + + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, 0xFF * inOut, 0, ES_WINDOW_PROPERTY_ALPHA); + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &bounds, 0, + ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN | ES_WINDOW_MOVE_ALWAYS_ON_TOP | ES_WINDOW_MOVE_UPDATE_SCREEN); + + message->animate.complete = false; + } + + return 0; +} + +void EsAnnouncementShow(EsWindow *parent, uint64_t flags, int32_t x, int32_t y, const char *text, ptrdiff_t textBytes) { + (void) flags; + + EsWindow *window = EsWindowCreate(nullptr, ES_WINDOW_TIP); + window->messageUser = AnnouncementMessage; + + EsTextDisplay *display = EsTextDisplayCreate(window, ES_CELL_FILL, ES_STYLE_ANNOUNCEMENT, text, textBytes); + + int32_t width = display->GetWidth(0); + int32_t height = display->GetHeight(width); + + EsRectangle parentBounds = EsWindowGetBounds(parent); + EsRectangle bounds = ES_RECT_4PD(x - width / 2 + parentBounds.l, y - height + parentBounds.t, width, height); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, 0x00, 0, ES_WINDOW_PROPERTY_ALPHA); + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &bounds, 0, ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN | ES_WINDOW_MOVE_ALWAYS_ON_TOP); + window->announcementBaseY = EsWindowGetBounds(window).t; + window->StartAnimating(); +} + +// --------------------------------- Buttons. + +int ProcessButtonMessage(EsElement *element, EsMessage *message) { + EsButton *button = (EsButton *) element; + + if (message->type == ES_MSG_PAINT) { + EsDrawContent(message->painter, element, + ES_RECT_2S(message->painter->width, message->painter->height), + button->label, button->labelBytes, button->iconID, + (button->flags & ES_BUTTON_DROPDOWN) ? ES_DRAW_CONTENT_MARKER_DOWN_ARROW : ES_FLAGS_DEFAULT); + } else if (message->type == ES_MSG_GET_WIDTH) { + if (!button->measurementCache.Get(message, &button->state)) { + int stringWidth = button->currentStyle->MeasureTextWidth(button->label, button->labelBytes); + int iconWidth = button->iconID ? button->currentStyle->metrics->iconSize : 0; + int contentWidth = stringWidth + iconWidth + ((stringWidth && iconWidth) ? button->currentStyle->gapMinor : 0) + + button->currentStyle->insets.l + button->currentStyle->insets.r; + + if (button->flags & ES_BUTTON_DROPDOWN) { + int64_t width = 0; + GetPreferredSizeFromStylePart(ES_STYLE_MARKER_DOWN_ARROW, &width, nullptr); + contentWidth += width + button->currentStyle->gapMinor; + } + + int minimumReportedWidth = GetConstantNumber("pushButtonMinimumReportedWidth"); + if (button->flags & ES_BUTTON_MENU_ITEM) minimumReportedWidth = GetConstantNumber("menuItemMinimumReportedWidth"); + if (!stringWidth || (button->flags & ES_BUTTON_COMPACT)) minimumReportedWidth = 0; + + message->measure.width = minimumReportedWidth > contentWidth ? minimumReportedWidth : contentWidth; + + button->measurementCache.Store(message); + } + } else if (message->type == ES_MSG_DESTROY) { + EsHeapFree(button->label); + + if (button->command) { + Array elements = { button->command->elements }; + elements.FindAndDeleteSwap(button, true); + button->command->elements = elements.array; + } + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + } else if (message->type == ES_MSG_MOUSE_LEFT_CLICK) { + if (button->flags & ES_BUTTON_CHECKBOX) { + button->customStyleState &= ~THEME_STATE_INDETERMINATE; + button->customStyleState ^= THEME_STATE_CHECKED; + } else if (button->flags & ES_BUTTON_RADIOBOX) { + button->customStyleState |= THEME_STATE_CHECKED; + + EsMessage m = { ES_MSG_RADIO_GROUP_UPDATED }; + + for (uintptr_t i = 0; i < button->parent->GetChildCount(); i++) { + if (button->parent->GetChild(i) != button) { + EsMessageSend(button->parent->GetChild(i), &m); + } + } + } + + if (button->checkBuddy) { + EsElementSetDisabled(button->checkBuddy, !(button->customStyleState & (THEME_STATE_CHECKED | THEME_STATE_INDETERMINATE))); + } + + if (button->onCommand) { + button->onCommand(button->instance, button, button->command); + } + + if (button->flags & ES_BUTTON_MENU_ITEM) { + button->window->Destroy(); + } + } else if (message->type == ES_MSG_RADIO_GROUP_UPDATED && (button->flags & ES_BUTTON_RADIOBOX)) { + EsButtonSetCheck(button, ES_CHECK_UNCHECKED); + } else if (message->type == ES_MSG_FOCUSED_START) { + if (button->window->defaultEnterButton && (button->flags & ES_BUTTON_PUSH)) { + button->window->enterButton->customStyleState &= ~THEME_STATE_DEFAULT_BUTTON; + button->window->enterButton->MaybeRefreshStyle(); + button->customStyleState |= THEME_STATE_DEFAULT_BUTTON; + button->window->enterButton = button; + } + } else if (message->type == ES_MSG_FOCUSED_END) { + if (button->window->enterButton == button) { + button->customStyleState &= ~THEME_STATE_DEFAULT_BUTTON; + button->window->enterButton = button->window->defaultEnterButton; + button->window->enterButton->customStyleState |= THEME_STATE_DEFAULT_BUTTON; + button->window->enterButton->MaybeRefreshStyle(); + } + } else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) { + EsBufferFormat(message->getContent.buffer, "'%s'", button->labelBytes, button->label); + } else { + return 0; + } + + return ES_HANDLED; +} + +EsButton *EsButtonCreate(EsElement *parent, uint64_t flags, const EsStyle *style, const char *label, ptrdiff_t labelBytes) { + EsButton *button = (EsButton *) EsHeapAllocate(sizeof(EsButton), true); + + if (!style) { + if (flags & ES_BUTTON_MENU_ITEM) { + if (flags & ES_MENU_ITEM_HEADER) { + style = ES_STYLE_MENU_ITEM_HEADER; + } else { + style = ES_STYLE_MENU_ITEM_NORMAL; + } + } else if (flags & ES_BUTTON_TOOLBAR) { + style = ES_STYLE_PUSH_BUTTON_TOOLBAR; + } else if (flags & ES_BUTTON_CHECKBOX) { + style = ES_STYLE_CHECKBOX_NORMAL; + } else if (flags & ES_BUTTON_RADIOBOX) { + style = ES_STYLE_CHECKBOX_RADIOBOX; + } else if (flags & ES_BUTTON_DEFAULT) { + style = ES_STYLE_PUSH_BUTTON_NORMAL; + } else { + style = ES_STYLE_PUSH_BUTTON_NORMAL; + } + + style = UIGetDefaultStyleVariant(style, parent); + } + + if (style == ES_STYLE_PUSH_BUTTON_NORMAL) { + flags |= ES_BUTTON_PUSH; + } else if (style == ES_STYLE_PUSH_BUTTON_TOOLBAR || style == ES_STYLE_PUSH_BUTTON_TOOLBAR_MEDIUM + || style == ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG || style == ES_STYLE_PUSH_BUTTON_STATUS_BAR) { + flags |= ES_BUTTON_COMPACT | ES_BUTTON_NOT_FOCUSABLE; + } else if (style == ES_STYLE_CHECKBOX_NORMAL || style == ES_STYLE_CHECKBOX_RADIOBOX) { + flags |= ES_BUTTON_COMPACT; + } + + if (~flags & ES_BUTTON_NOT_FOCUSABLE) { + flags |= ES_ELEMENT_FOCUSABLE; + } + + button->Initialise(parent, flags, ProcessButtonMessage, style); + button->cName = "button"; + + if (flags & ES_BUTTON_DEFAULT) { + button->window->defaultEnterButton = button; + button->window->enterButton = button; + button->customStyleState |= THEME_STATE_DEFAULT_BUTTON; + } else if (flags & ES_BUTTON_CANCEL) { + button->window->escapeButton = button; + } + + if (labelBytes == -1) labelBytes = EsCStringLength(label); + HeapDuplicate((void **) &button->label, label, labelBytes); + button->labelBytes = labelBytes; + + if ((flags & ES_BUTTON_MENU_ITEM) && (flags & ES_MENU_ITEM_HEADER)) { + EsElementSetDisabled(button, true); + } + + EsButtonSetCheck(button, (EsCheckState) (flags & 3), false); + + return button; +} + +void EsButtonSetIcon(EsButton *button, uint32_t iconID) { + EsMessageMutexCheck(); + + button->iconID = iconID; + button->Repaint(true); +} + +void EsButtonOnCommand(EsButton *button, EsCommandCallbackFunction onCommand, EsCommand *command) { + EsMessageMutexCheck(); + + button->onCommand = onCommand; + button->command = command; +} + +void EsButtonSetCheckBuddy(EsButton *button, EsElement *checkBuddy) { + EsMessageMutexCheck(); + + button->checkBuddy = checkBuddy; + EsElementSetDisabled(button->checkBuddy, !(button->customStyleState & (THEME_STATE_CHECKED | THEME_STATE_INDETERMINATE))); +} + +EsElement *EsButtonGetCheckBuddy(EsButton *button) { + EsMessageMutexCheck(); + + return button->checkBuddy; +} + +EsCheckState EsButtonGetCheck(EsButton *button) { + EsMessageMutexCheck(); + + if (button->customStyleState & THEME_STATE_CHECKED) return ES_CHECK_CHECKED; + if (button->customStyleState & THEME_STATE_INDETERMINATE) return ES_CHECK_INDETERMINATE; + return ES_CHECK_UNCHECKED; +} + +void EsButtonSetCheck(EsButton *button, EsCheckState checkState, bool sendUpdatedMessage) { + if (checkState == EsButtonGetCheck(button)) { + return; + } + + button->customStyleState &= ~(THEME_STATE_CHECKED | THEME_STATE_INDETERMINATE); + + if (checkState == ES_CHECK_CHECKED) button->customStyleState |= THEME_STATE_CHECKED; + if (checkState == ES_CHECK_INDETERMINATE) button->customStyleState |= THEME_STATE_INDETERMINATE; + + if (sendUpdatedMessage) { + EsMessage m = { ES_MSG_CHECK_UPDATED }; + m.checkState = checkState; + EsMessageSend(button, &m); + + if (button->onCommand) { + button->onCommand(button->instance, button, button->command); + } + } + + if (button->checkBuddy) { + EsElementSetDisabled(button->checkBuddy, !(button->customStyleState & (THEME_STATE_CHECKED | THEME_STATE_INDETERMINATE))); + } + + button->MaybeRefreshStyle(); +} + +void EsMenuAddItem(EsMenu *menu, uint64_t flags, const char *label, ptrdiff_t labelBytes, EsMenuCallbackFunction callback, EsGeneric context) { + EsButton *button = (EsButton *) EsButtonCreate(menu, + ES_BUTTON_NOT_FOCUSABLE | ES_BUTTON_MENU_ITEM | ES_CELL_H_FILL | flags, 0, + label, labelBytes != -1 ? labelBytes : EsCStringLength(label)); + button->userData = (void *) callback; + + button->messageUser = [] (EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_MOUSE_LEFT_CLICK) { + EsMenuCallbackFunction callback = (EsMenuCallbackFunction) element->userData.p; + if (callback) callback((EsMenu *) element->window, ((EsButton *) element)->menuItemContext); + } + + return 0; + }; + + button->menuItemContext = context; + + if (flags & ES_MENU_ITEM_CHECKED) { + EsButtonSetCheck(button, ES_CHECK_CHECKED); + } +} + +void EsMenuAddCommand(EsMenu *menu, uint64_t flags, const char *label, ptrdiff_t labelBytes, EsCommand *command) { + EsButton *button = (EsButton *) EsButtonCreate(menu, + ES_BUTTON_NOT_FOCUSABLE | ES_BUTTON_MENU_ITEM | ES_CELL_H_FILL | flags, + 0, label, labelBytes); + EsCommandAddButton(command, button); +} + +// --------------------------------- Color wells and pickers. + +struct EsColorWell : EsElement { + uint32_t color; + struct ColorPicker *picker; + bool indeterminate; +}; + +int ProcessColorWellMessage(EsElement *element, EsMessage *message); + +struct ColorPicker { + uint32_t color; + float hue, saturation, value, opacity; + float dragStartHue, dragStartSaturation; + int dragComponent; + bool indeterminateBeforeEyedrop; + bool modified; + + ColorPickerHost host; + EsPanel *panel; + EsElement *circle, *slider, *circlePoint, *sliderPoint, *opacitySlider, *opacitySliderPoint; + EsTextbox *textbox; + + uint32_t GetColorForHost() { + return color | (host.hasOpacity ? ((uint32_t) (255.0f * opacity) << 24) : 0); + } + + void Sync(EsElement *excluding) { + if (excluding != textbox && textbox) { + char string[16]; + size_t length; + + if (host.indeterminate && *host.indeterminate) { + string[0] = '#'; + length = 1; + } else { + const char *hexChars = "0123456789ABCDEF"; + + if (host.hasOpacity) { + uint8_t alpha = (uint8_t) (opacity * 0xFF); + length = EsStringFormat(string, sizeof(string), "#%c%c%c%c%c%c%c%c", + hexChars[(alpha >> 4) & 0xF], hexChars[(alpha >> 0) & 0xF], hexChars[(color >> 20) & 0xF], hexChars[(color >> 16) & 0xF], + hexChars[(color >> 12) & 0xF], hexChars[(color >> 8) & 0xF], hexChars[(color >> 4) & 0xF], hexChars[(color >> 0) & 0xF]); + } else { + length = EsStringFormat(string, sizeof(string), "#%c%c%c%c%c%c", + hexChars[(color >> 20) & 0xF], hexChars[(color >> 16) & 0xF], hexChars[(color >> 12) & 0xF], + hexChars[(color >> 8) & 0xF], hexChars[(color >> 4) & 0xF], hexChars[(color >> 0) & 0xF]); + } + } + + EsTextboxSelectAll(textbox); + EsTextboxInsert(textbox, string, length, false); + } + + if (excluding != circle) circle->Repaint(true); + if (excluding != slider) slider->Repaint(true); + if (excluding != opacitySlider && opacitySlider) opacitySlider->Repaint(true); + + if (excluding != circlePoint) { + if (host.indeterminate && *host.indeterminate) { + EsElementSetHidden(circlePoint, true); + } else { + EsElementSetHidden(circlePoint, false); + float x = saturation * EsCRTcosf((hue - 3) * 1.047197551) * 0.5f + 0.5f; + float y = saturation * EsCRTsinf((hue - 3) * 1.047197551) * 0.5f + 0.5f; + EsRectangle pointSize = EsElementGetPreferredSize(circlePoint), circleSize = EsElementGetPreferredSize(circle); + int x2 = x * circleSize.r - pointSize.r / 2, y2 = y * circleSize.b - pointSize.b / 2; + EsElementMove(circlePoint, x2, y2, pointSize.r, pointSize.b, true); + circlePoint->Repaint(true); + } + } + + if (excluding != sliderPoint) { + if (host.indeterminate && *host.indeterminate) { + EsElementSetHidden(sliderPoint, true); + } else { + EsElementSetHidden(sliderPoint, false); + float x = 0.5f, y = 1.0f - EsCRTpowf(value, 1.333f); + EsRectangle pointSize = EsElementGetPreferredSize(sliderPoint), sliderSize = EsElementGetPreferredSize(slider); + int x2 = x * sliderSize.r - pointSize.r / 2, y2 = y * sliderSize.b - pointSize.b / 2; + EsElementMove(sliderPoint, x2, y2, pointSize.r, pointSize.b, true); + sliderPoint->Repaint(true); + } + } + + if (excluding != opacitySliderPoint && opacitySliderPoint) { + if (host.indeterminate && *host.indeterminate) { + EsElementSetHidden(opacitySliderPoint, true); + } else { + EsElementSetHidden(opacitySliderPoint, false); + float x = 0.5f, y = 1.0f - opacity; + EsRectangle pointSize = EsElementGetPreferredSize(opacitySliderPoint), sliderSize = EsElementGetPreferredSize(opacitySlider); + int x2 = x * sliderSize.r - pointSize.r / 2, y2 = y * sliderSize.b - pointSize.b / 2; + EsElementMove(opacitySliderPoint, x2, y2, pointSize.r, pointSize.b, true); + opacitySliderPoint->Repaint(true); + } + } + + if (excluding != host.well && host.well) { + if (host.well->messageClass == ProcessColorWellMessage) { + ((EsColorWell *) host.well)->color = GetColorForHost(); + host.well->Repaint(true); + } + + EsMessage m = { ES_MSG_COLOR_CHANGED }; + m.colorChanged.newColor = GetColorForHost(); + m.colorChanged.pickerClosed = false; + EsMessageSend(host.well, &m); + + modified = true; + } + } + + void PositionOnCircleToColor(int _x, int _y) { + EsRectangle size = EsElementGetInsetSize(circle); + float x = (float) _x / (float) (size.r - 1) * 2.0f - 1.0f; + float y = (float) _y / (float) (size.b - 1) * 2.0f - 1.0f; + float newSaturation = EsCRTsqrtf(x * x + y * y), newHue = EsCRTatan2f(y, x) * 0.954929659f + 3; + if (!EsKeyboardIsAltHeld() && newSaturation < 0.1f) newSaturation = 0; + if (newSaturation > 1) newSaturation = 1; + if (newHue >= 6) newHue -= 6; + if (newHue < 0 || newHue >= 6) newHue = 0; + + if (EsKeyboardIsShiftHeld()) { + float deltaHue = dragStartHue - newHue; + float deltaSaturation = EsCRTfabs(dragStartSaturation - newSaturation); + + if (-3 < deltaHue && deltaHue < 3) deltaHue = EsCRTfabs(deltaHue); + if (deltaHue < -3) deltaHue += 6; + if (deltaHue > 3) deltaHue = -deltaHue + 6; + deltaHue /= 2; + + if (deltaHue < deltaSaturation) { + newHue = dragStartHue; + } else { + newSaturation = dragStartSaturation; + } + } + + uint32_t newColor = EsColorConvertToRGB(newHue, newSaturation, value); + hue = newHue, color = newColor, saturation = newSaturation; + if (host.indeterminate) *host.indeterminate = false; + Sync(circle); + } + + void PositionOnSliderToColor(int _x, int _y) { + (void) _x; + EsRectangle size = EsElementGetInsetSize(slider); + float y = 1 - (float) _y / (float) (size.b - 1); + if (y < 0) y = 0; + y = EsCRTsqrtf(y) * EsCRTsqrtf(EsCRTsqrtf(y)); + if (y > 1) y = 1; + if (y < 0) y = 0; + uint32_t newColor = EsColorConvertToRGB(hue, saturation, y); + color = newColor; + value = y; + if (host.indeterminate) *host.indeterminate = false; + Sync(slider); + } + + void PositionOnOpacitySliderToColor(int _x, int _y) { + (void) _x; + EsRectangle size = EsElementGetInsetSize(opacitySlider); + float y = 1 - (float) _y / (float) (size.b - 1); + if (y > 1) y = 1; + if (y < 0) y = 0; + opacity = y; + if (host.indeterminate) *host.indeterminate = false; + Sync(opacitySlider); + } +}; + +int ProcessColorChosenPointMessage(EsElement *element, EsMessage *message) { + ColorPicker *picker = (ColorPicker *) element->userData.p; + + if (message->type == ES_MSG_PAINT) { + EsRectangle bounds = EsPainterBoundsInset(message->painter); + EsStyledBox box = {}; + box.bounds = bounds; + box.clip = message->painter->clip; + box.borderColor = 0xFFFFFFFF; + box.backgroundColor = picker->color | 0xFF000000; + box.backgroundColor2 = picker->color | ((uint32_t) (255.0f * picker->opacity) << 24); + box.borders = ES_RECT_1(2); + box.cornerRadiusTopLeft = box.cornerRadiusTopRight = box.cornerRadiusBottomLeft = box.cornerRadiusBottomRight = Width(box.bounds) / 2; + + if (picker->opacity < 1 && picker->host.hasOpacity) { + box.fragmentShader = [] (int x, int y, EsStyledBox *box) -> uint32_t { + // TODO Move the alpha background as the chosen point moves. + return EsColorBlend(((((x - 2) >> 3) ^ ((y + 5) >> 3)) & 1) ? 0xFFFFFFFF : 0xFFC0C0C0, + box->backgroundColor2, false); + }; + } + + DrawStyledBox(message->painter, box); + } + + return 0; +} + +void ColorPickerCreate(EsElement *parent, ColorPickerHost host, uint32_t initialColor, bool showTextbox) { + ColorPicker *picker = (ColorPicker *) EsHeapAllocate(sizeof(ColorPicker), true); + picker->host = host; + picker->color = initialColor & 0xFFFFFF; + picker->opacity = (float) (initialColor >> 24) / 255.0f; + if (host.well && host.well->messageClass == ProcessColorWellMessage) ((EsColorWell *) host.well)->picker = picker; + EsColorConvertToHSV(picker->color, &picker->hue, &picker->saturation, &picker->value); + + picker->panel = EsPanelCreate(parent, ES_PANEL_HORIZONTAL | ES_PANEL_TABLE, ES_STYLE_COLOR_PICKER_MAIN_PANEL); + + picker->panel->userData = picker; + + picker->panel->messageUser = [] (EsElement *element, EsMessage *message) { + ColorPicker *picker = (ColorPicker *) element->userData.p; + + if (message->type == ES_MSG_DESTROY) { + if (picker->host.well && picker->modified) { + EsMessage m = { ES_MSG_COLOR_CHANGED }; + m.colorChanged.newColor = picker->GetColorForHost(); + m.colorChanged.pickerClosed = true; + EsMessageSend(picker->host.well, &m); + + if (picker->host.well->messageClass == ProcessColorWellMessage) { + ((EsColorWell *) picker->host.well)->picker = nullptr; + } + } + + EsHeapFree(picker); + } + + return 0; + }; + + bool hasOpacity = picker->host.hasOpacity; + + EsPanelSetBands(picker->panel, hasOpacity ? 3 : 2, showTextbox ? 2 : 1); + + picker->circle = EsCustomElementCreate(picker->panel, ES_ELEMENT_FOCUSABLE | ES_ELEMENT_NOT_TAB_TRAVERSABLE, ES_STYLE_COLOR_CIRCLE); + + picker->circle->cName = "hue-saturation wheel"; + picker->circle->userData = picker; + + picker->circle->messageUser = [] (EsElement *element, EsMessage *message) { + ColorPicker *picker = (ColorPicker *) element->userData.p; + + if (message->type == ES_MSG_PAINT) { + // EsPerformanceTimerPush(); + + EsPainter *painter = message->painter; + EsRectangle bounds = EsPainterBoundsInset(painter); + EsRectangle clip = painter->clip; + EsRectangleClip(clip, bounds, &clip); + uint32_t stride = painter->target->stride; + uint32_t *bitmap = (uint32_t *) painter->target->bits; + float epsilon = 1.0f / (bounds.b - bounds.t - 1); + + for (int j = clip.t; j < clip.b; j++) { + for (int i = clip.l; i < clip.r; i++) { + float x = (float) (i - bounds.l) / (float) (bounds.r - bounds.l - 1) * 2.0f - 1.0f; + float y = (float) (j - bounds.t) / (float) (bounds.b - bounds.t - 1) * 2.0f - 1.0f; + float radius = EsCRTsqrtf(x * x + y * y), hue = EsCRTatan2f(y, x) * 0.954929659f + 3; + if (hue >= 6) hue -= 6; + + if (radius > 1.0f + epsilon) { + // Outside the circle. + } else if (radius > 1.0f - epsilon) { + // On the edge. + uint32_t over = EsColorConvertToRGB(hue, 1, picker->value); + // float opacity = (1.0f - ((radius - (1.0f - epsilon)) / epsilon * 0.5f)); + float opacity = 0.5f - (radius - 1.0f) / epsilon * 0.5f; + uint32_t alpha = (((uint32_t) (255.0f * opacity)) & 0xFF) << 24; + uint32_t *under = &bitmap[i + j * (stride >> 2)]; + *under = EsColorBlend(*under, over | alpha, true); + } else { + // Inside the circle. + uint32_t over = EsColorConvertToRGB(hue, radius, picker->value); + bitmap[i + j * (stride >> 2)] = over | 0xFF000000; + } + } + } + + // EsPrint("Rendered color circle in %*Fms.\n", 3, 1000 * EsPerformanceTimerPop()); + } else if (message->type == ES_MSG_HIT_TEST) { + EsRectangle size = EsElementGetInsetSize(element); + float x = (float) message->hitTest.x / (float) (size.r - 1) * 2.0f - 1.0f; + float y = (float) message->hitTest.y / (float) (size.b - 1) * 2.0f - 1.0f; + message->hitTest.inside = x * x + y * y <= 1; + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + picker->PositionOnCircleToColor(message->mouseDragged.newPositionX, message->mouseDragged.newPositionY); + } else if (message->type == ES_MSG_KEY_DOWN) { + if ((message->keyboard.scancode == ES_SCANCODE_LEFT_SHIFT || message->keyboard.scancode == ES_SCANCODE_RIGHT_SHIFT) && !message->keyboard.repeat) { + picker->dragStartHue = picker->hue; + picker->dragStartSaturation = picker->saturation; + } else { + return 0; + } + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + picker->PositionOnCircleToColor(message->mouseDown.positionX, message->mouseDown.positionY); + picker->dragStartHue = picker->hue; + picker->dragStartSaturation = picker->saturation; + } else { + return 0; + } + + return ES_HANDLED; + }; + + picker->circlePoint = EsCustomElementCreate(picker->circle, ES_ELEMENT_NO_HOVER, ES_STYLE_COLOR_CHOSEN_POINT); + picker->circlePoint->messageUser = ProcessColorChosenPointMessage; + picker->circlePoint->cName = "selected hue-saturation"; + picker->circlePoint->userData = picker; + + picker->slider = EsCustomElementCreate(picker->panel, ES_ELEMENT_FOCUSABLE | ES_ELEMENT_NOT_TAB_TRAVERSABLE, ES_STYLE_COLOR_SLIDER); + picker->slider->cName = "value slider"; + picker->slider->userData = picker; + + picker->slider->messageUser = [] (EsElement *element, EsMessage *message) { + ColorPicker *picker = (ColorPicker *) element->userData.p; + + if (message->type == ES_MSG_PAINT) { + // EsPerformanceTimerPush(); + + EsPainter *painter = message->painter; + EsRectangle bounds = EsPainterBoundsInset(painter); + EsRectangle clip = painter->clip; + EsRectangleClip(clip, bounds, &clip); + uint32_t stride = painter->target->stride; + uint32_t *bitmap = (uint32_t *) painter->target->bits; + + float valueIncrement = -1.0f / (bounds.b - bounds.t - 1), value = 1.0f; + + for (int j = clip.t; j < clip.b; j++, value += valueIncrement) { + // float valueSqrt = EsCRTsqrtf(value); + // uint32_t color = EsColorConvertToRGB(picker->hue, picker->saturation, valueSqrt * EsCRTsqrtf(valueSqrt)); + + for (int i = clip.l; i < clip.r; i++) { + float i2 = (float) (i - ((bounds.l + bounds.r) >> 1)) / (float) (bounds.r - bounds.l); + uint32_t color = EsColorConvertToRGB(picker->hue, picker->saturation, EsCRTpowf(value, 0.75f + i2 * i2 * 0.3f)); + bitmap[i + j * (stride >> 2)] = 0xFF000000 | color; + } + } + + // EsPrint("Rendered color slider in %*Fms.\n", 3, 1000 * EsPerformanceTimerPop()); + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + picker->PositionOnSliderToColor(message->mouseDragged.newPositionX, message->mouseDragged.newPositionY); + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + picker->PositionOnSliderToColor(message->mouseDown.positionX, message->mouseDown.positionY); + } else { + return 0; + } + + return ES_HANDLED; + }; + + picker->sliderPoint = EsCustomElementCreate(picker->slider, ES_ELEMENT_NO_HOVER, ES_STYLE_COLOR_CHOSEN_POINT); + picker->sliderPoint->messageUser = ProcessColorChosenPointMessage; + picker->sliderPoint->cName = "selected value"; + picker->sliderPoint->userData = picker; + + if (hasOpacity) { + picker->opacitySlider = EsCustomElementCreate(picker->panel, ES_ELEMENT_FOCUSABLE | ES_ELEMENT_NOT_TAB_TRAVERSABLE, ES_STYLE_COLOR_SLIDER); + picker->opacitySlider->cName = "opacity slider"; + picker->opacitySlider->userData = picker; + + picker->opacitySlider->messageUser = [] (EsElement *element, EsMessage *message) { + ColorPicker *picker = (ColorPicker *) element->userData.p; + + if (message->type == ES_MSG_PAINT) { + // EsPerformanceTimerPush(); + + EsPainter *painter = message->painter; + EsRectangle bounds = EsPainterBoundsInset(painter); + EsRectangle clip = painter->clip; + EsRectangleClip(clip, bounds, &clip); + uint32_t stride = painter->target->stride; + uint32_t *bitmap = (uint32_t *) painter->target->bits; + + float opacityIncrement = -1.0f / (bounds.b - bounds.t - 1), opacity = 1.0f; + + for (int j = clip.t; j < clip.b; j++, opacity += opacityIncrement) { + uint32_t alpha = (uint32_t) (opacity * 255.0f) << 24; + + for (int i = clip.l; i < clip.r; i++) { + bitmap[i + j * (stride >> 2)] + = EsColorBlend(((((i - bounds.l + 1) >> 3) ^ ((j - bounds.t + 2) >> 3)) & 1) ? 0xFFFFFFFF : 0xFFC0C0C0, + alpha | (picker->color & 0xFFFFFF), false); + } + } + + // EsPrint("Rendered opacity slider in %*Fms.\n", 3, 1000 * EsPerformanceTimerPop()); + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + picker->PositionOnOpacitySliderToColor(message->mouseDragged.newPositionX, message->mouseDragged.newPositionY); + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + picker->PositionOnOpacitySliderToColor(message->mouseDown.positionX, message->mouseDown.positionY); + } else { + return 0; + } + + return ES_HANDLED; + }; + + picker->opacitySliderPoint = EsCustomElementCreate(picker->opacitySlider, ES_ELEMENT_NO_HOVER, ES_STYLE_COLOR_CHOSEN_POINT); + picker->opacitySliderPoint->messageUser = ProcessColorChosenPointMessage; + picker->opacitySliderPoint->cName = "selected opacity"; + picker->opacitySliderPoint->userData = picker; + } + + if (showTextbox) { + picker->textbox = EsTextboxCreate(picker->panel, ES_TEXTBOX_EDIT_BASED | ES_CELL_EXPAND | ES_TEXTBOX_NO_SMART_CONTEXT_MENUS, ES_STYLE_COLOR_HEX_TEXTBOX); + picker->textbox->userData = picker; + + picker->textbox->messageUser = [] (EsElement *element, EsMessage *message) { + ColorPicker *picker = (ColorPicker *) element->userData.p; + + if (message->type == ES_MSG_TEXTBOX_UPDATED) { + size_t bytes; + char *string = EsTextboxGetContents(picker->textbox, &bytes); + uint32_t color = EsColorParse(string, bytes); + picker->opacity = (float) (color >> 24) / 255.0f; + color &= 0xFFFFFF; + EsColorConvertToHSV(color, &picker->hue, &picker->saturation, &picker->value); + picker->color = color; + if (picker->host.indeterminate) *picker->host.indeterminate = false; + picker->Sync(picker->textbox); + EsHeapFree(string); + } else if (message->type == ES_MSG_TEXTBOX_EDIT_START) { + EsTextboxSetSelection((EsTextbox *) element, 0, 1, 0, -1); + } else if (message->type == ES_MSG_TEXTBOX_EDIT_END) { + picker->Sync(nullptr); + } else if (message->type == ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA) { + int componentCount = picker->host.hasOpacity ? 4 : 3; + int componentIndex = (message->numberDragDelta.hoverCharacter - 1) / 2; + if (componentIndex < 0) componentIndex = 0; + if (componentIndex >= componentCount) componentIndex = componentCount - 1; + componentIndex = componentCount - componentIndex - 1; + picker->dragComponent = componentIndex; + + if (componentIndex == 3) { + picker->opacity += message->numberDragDelta.delta / 255.0f; + if (picker->opacity < 0) picker->opacity = 0; + if (picker->opacity > 1) picker->opacity = 1; + } else { + int32_t componentValue = (picker->color >> (componentIndex << 3)) & 0xFF; + componentValue += message->numberDragDelta.delta; + if (componentValue < 0) componentValue = 0; + if (componentValue > 255) componentValue = 255; + picker->color &= ~(0xFF << (componentIndex << 3)); + picker->color |= (uint32_t) componentValue << (componentIndex << 3); + EsColorConvertToHSV(picker->color, &picker->hue, &picker->saturation, &picker->value); + } + + picker->Sync(nullptr); + } else { + return 0; + } + + return ES_HANDLED; + }; + + EsTextboxUseNumberOverlay(picker->textbox, false); + + EsButton *eyedropperButton = EsButtonCreate(picker->panel, ES_CELL_EXPAND, 0); + eyedropperButton->userData = picker; + + eyedropperButton->messageUser = [] (EsElement *element, EsMessage *message) { + ColorPicker *picker = (ColorPicker *) element->userData.p; + + if (message->type == ES_MSG_MOUSE_LEFT_CLICK) { + picker->indeterminateBeforeEyedrop = picker->host.indeterminate && *picker->host.indeterminate; + EsSyscall(ES_SYSCALL_EYEDROP_START, (uintptr_t) element, picker->circle->window->handle, picker->color, 0); + } else if (message->type == ES_MSG_EYEDROP_REPORT) { + if (message->eyedrop.cancelled && picker->indeterminateBeforeEyedrop) { + if (picker->host.well && picker->host.well->messageClass == ProcessColorWellMessage) { + EsColorWellSetIndeterminate((EsColorWell *) picker->host.well); + } + } else { + picker->color = message->eyedrop.color; + EsColorConvertToHSV(picker->color, &picker->hue, &picker->saturation, &picker->value); + if (picker->host.indeterminate) *picker->host.indeterminate = false; + picker->Sync(nullptr); + } + } else { + return 0; + } + + return ES_HANDLED; + }; + + EsButtonSetIcon(eyedropperButton, ES_ICON_COLOR_SELECT_SYMBOLIC); + + if (hasOpacity) { + EsElementSetCellRange(eyedropperButton, 1, 1, 2, 1); + } + } + + picker->Sync(picker->host.well); + if (picker->textbox) EsElementFocus(picker->textbox); +} + +uint32_t EsColorWellGetRGB(EsColorWell *well) { + EsMessageMutexCheck(); + + return well->color & ((well->flags & ES_COLOR_WELL_HAS_OPACITY) ? 0xFFFFFFFF : 0x00FFFFFF); +} + +void EsColorWellSetRGB(EsColorWell *well, uint32_t color, bool sendChangedMessage) { + EsMessageMutexCheck(); + + well->color = color; + well->indeterminate = false; + well->Repaint(true); + + if (sendChangedMessage) { + EsMessage m = { ES_MSG_COLOR_CHANGED }; + m.colorChanged.newColor = color; + m.colorChanged.pickerClosed = true; + EsMessageSend(well, &m); + } + + if (well->picker) { + well->picker->color = color & 0xFFFFFF; + well->picker->opacity = (color >> 24) / 255.0f; + EsColorConvertToHSV(well->picker->color, &well->picker->hue, &well->picker->saturation, &well->picker->value); + well->picker->Sync(well); + } +} + +void EsColorWellSetIndeterminate(EsColorWell *well) { + EsMessageMutexCheck(); + + well->color = 0xFFFFFFFF; + well->indeterminate = true; + well->Repaint(true); + + if (well->picker) { + well->picker->color = 0xFFFFFF; + well->picker->opacity = 1.0f; + EsColorConvertToHSV(well->picker->color, &well->picker->hue, &well->picker->saturation, &well->picker->value); + well->picker->Sync(well); + } +} + +int ProcessColorWellMessage(EsElement *element, EsMessage *message) { + EsColorWell *well = (EsColorWell *) element; + + if (message->type == ES_MSG_PAINT) { + EsRectangle bounds = EsPainterBoundsInset(message->painter); + EsStyledBox box = {}; + box.bounds = bounds; + box.clip = message->painter->clip; + box.borders = ES_RECT_1(1); + + if (well->indeterminate) { + box.backgroundColor = 0; + box.borderColor = 0x40000000; + } else { + box.backgroundColor = well->color; + if (~well->flags & ES_COLOR_WELL_HAS_OPACITY) box.backgroundColor |= 0xFF000000; + box.borderColor = EsColorBlend(well->color | 0xFF000000, 0x40000000, false); + + if ((well->flags & ES_COLOR_WELL_HAS_OPACITY) && ((well->color & 0xFF000000) != 0xFF000000)) { + box.fragmentShader = [] (int x, int y, EsStyledBox *box) -> uint32_t { + return EsColorBlend(((((x - box->bounds.l - 4) >> 3) ^ ((y - box->bounds.t + 2) >> 3)) & 1) + ? 0xFFFFFFFF : 0xFFC0C0C0, box->backgroundColor, false); + }; + } + } + + DrawStyledBox(message->painter, box); + } else if (message->type == ES_MSG_MOUSE_LEFT_CLICK) { + EsMenu *menu = EsMenuCreate(well, ES_FLAGS_DEFAULT); + ColorPickerHost host = { well, &well->indeterminate, (well->flags & ES_COLOR_WELL_HAS_OPACITY) ? true : false }; + ColorPickerCreate((EsElement *) menu, host, well->color, true); + EsMenuShow(menu); + } else { + return 0; + } + + return ES_HANDLED; +} + +EsColorWell *EsColorWellCreate(EsElement *parent, uint64_t flags, uint32_t initialColor) { + EsColorWell *well = (EsColorWell *) EsHeapAllocate(sizeof(EsColorWell), true); + well->color = initialColor; + well->Initialise(parent, flags | ES_ELEMENT_FOCUSABLE, ProcessColorWellMessage, ES_STYLE_PUSH_BUTTON_NORMAL_COLOR_WELL); + well->cName = "color well"; + return well; +} + +// --------------------------------- Splitters. + +// TODO With dockable UI, show split bars at the start and end of the splitter as drop targets. +// The root splitter will also need two split bars at the start and end of the other axis. +// Split bars should also be enlarged when actings as drop targets. +// When dropping on an existing non-splitter panel, you can either form a tab group, +// or create a new split on the other axis, on one of the two sides. + +struct EsSplitter : EsElement { + bool horizontal; + bool addingSplitBar; + int previousSize; + Array resizeStartSizes; + bool calculatedInitialSize; +}; + +struct SplitBar : EsElement { + int position, dragStartPosition; + + void Move(int newPosition, bool fromKeyboard) { + EsSplitter *splitter = (EsSplitter *) parent; + EsElement *panelBefore = nullptr, *panelAfter = nullptr; + int barBefore = 0, barAfter; + if (splitter->horizontal) barAfter = EsRectangleAddBorder(splitter->GetBounds(), splitter->currentStyle->borders).r - currentStyle->preferredWidth; + else barAfter = EsRectangleAddBorder(splitter->GetBounds(), splitter->currentStyle->borders).b - currentStyle->preferredHeight; + int preferredSize = splitter->horizontal ? currentStyle->preferredWidth : currentStyle->preferredHeight; + splitter->resizeStartSizes.Free(); + + for (uintptr_t i = 0; i < splitter->GetChildCount(); i++) { + if (splitter->GetChild(i) == this) { + EsAssert(i & 1); // Expected split bars between each EsSplitter child. + panelBefore = splitter->GetChild(i - 1); + panelAfter = splitter->GetChild(i + 1); + + if (i != 1) { + barBefore = ((SplitBar *) splitter->GetChild(i - 2))->position + preferredSize; + } + + if (i != splitter->GetChildCount() - 2) { + barAfter = ((SplitBar *) splitter->GetChild(i + 2))->position - preferredSize; + } + + break; + } + } + + EsAssert(panelBefore && panelAfter); // Could not find split bar in parent. + + barBefore -= splitter->horizontal ? currentStyle->borders.l : currentStyle->borders.t; + barAfter += splitter->horizontal ? currentStyle->borders.r : currentStyle->borders.b; + + int minimumPosition, maximumPosition, minimumPosition1, maximumPosition1, minimumPosition2, maximumPosition2; + + if (splitter->horizontal) { + minimumPosition1 = barBefore + panelBefore->currentStyle->metrics->minimumWidth; + maximumPosition1 = barAfter - panelAfter ->currentStyle->metrics->minimumWidth; + minimumPosition2 = barAfter - panelAfter ->currentStyle->metrics->maximumWidth; + maximumPosition2 = barBefore + panelBefore->currentStyle->metrics->maximumWidth; + if (!panelAfter ->currentStyle->metrics->maximumWidth) minimumPosition2 = INT_MIN; + if (!panelBefore->currentStyle->metrics->maximumWidth) maximumPosition2 = INT_MAX; + } else { + minimumPosition1 = barBefore + panelBefore->currentStyle->metrics->minimumHeight; + maximumPosition1 = barAfter - panelAfter ->currentStyle->metrics->minimumHeight; + minimumPosition2 = barAfter - panelAfter ->currentStyle->metrics->maximumHeight; + maximumPosition2 = barBefore + panelBefore->currentStyle->metrics->maximumHeight; + if (!panelAfter ->currentStyle->metrics->maximumHeight) minimumPosition2 = INT_MIN; + if (!panelBefore->currentStyle->metrics->maximumHeight) maximumPosition2 = INT_MAX; + } + + minimumPosition = minimumPosition1 > minimumPosition2 ? minimumPosition1 : minimumPosition2; + maximumPosition = maximumPosition1 < maximumPosition2 ? maximumPosition1 : maximumPosition2; + + if (minimumPosition < maximumPosition) { + int oldPosition = position; + + if (newPosition < minimumPosition) { + if (newPosition > minimumPosition2 + && (fromKeyboard || newPosition < (barBefore + minimumPosition1) / 2) + && (!fromKeyboard || newPosition < position) + && panelBefore->flags & ES_CELL_COLLAPSABLE) { + position = barBefore > minimumPosition2 ? barBefore : minimumPosition2; + } else { + position = minimumPosition; + } + } else if (newPosition > maximumPosition) { + if (newPosition < maximumPosition2 + && (fromKeyboard || newPosition > (barAfter + maximumPosition1) / 2) + && (!fromKeyboard || newPosition > position) + && panelAfter->flags & ES_CELL_COLLAPSABLE) { + position = barAfter < maximumPosition2 ? barAfter : maximumPosition2; + } else { + position = maximumPosition; + } + } else { + position = newPosition; + } + + if (oldPosition != position) { + EsElementRelayout(splitter); + } + } + } +}; + +int ProcessSplitBarMessage(EsElement *element, EsMessage *message) { + SplitBar *bar = (SplitBar *) element; + EsSplitter *splitter = (EsSplitter *) bar->parent; + + if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + bar->dragStartPosition = bar->position; + + if (!bar->window->focused || bar->window->focused->messageClass != ProcessSplitBarMessage) { + // Don't take focus. + return ES_REJECTED; + } + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + if (splitter->horizontal) { + bar->Move(message->mouseDragged.newPositionX - message->mouseDragged.originalPositionX + bar->dragStartPosition, false); + } else { + bar->Move(message->mouseDragged.newPositionY - message->mouseDragged.originalPositionY + bar->dragStartPosition, false); + } + } else if (message->type == ES_MSG_KEY_TYPED) { + if (message->keyboard.scancode == (splitter->horizontal ? ES_SCANCODE_LEFT_ARROW : ES_SCANCODE_UP_ARROW)) { + bar->Move(bar->position - GetConstantNumber("splitBarKeyboardMovementAmount"), true); + } else if (message->keyboard.scancode == (splitter->horizontal ? ES_SCANCODE_RIGHT_ARROW : ES_SCANCODE_DOWN_ARROW)) { + bar->Move(bar->position + GetConstantNumber("splitBarKeyboardMovementAmount"), true); + } else { + return 0; + } + } else { + return 0; + } + + return ES_HANDLED; +} + +int ProcessSplitterMessage(EsElement *element, EsMessage *message) { + EsSplitter *splitter = (EsSplitter *) element; + + if (message->type == ES_MSG_LAYOUT && splitter->GetChildCount()) { + EsRectangle client = splitter->GetBounds(); + EsRectangle bounds = EsRectangleAddBorder(client, splitter->currentStyle->insets); + + size_t childCount = splitter->GetChildCount(); + EsAssert(childCount & 1); // Expected split bars between each EsSplitter child. + uint64_t pushFlag = splitter->horizontal ? ES_CELL_H_PUSH : ES_CELL_V_PUSH; + + if (!splitter->calculatedInitialSize) { + for (uintptr_t i = 0; i < childCount; i += 2) { + EsElement *child = splitter->GetChild(i); + + if (~child->flags & pushFlag) { + int width = child->GetWidth(bounds.b - bounds.t); + int height = child->GetHeight(width); + splitter->resizeStartSizes.Add(splitter->horizontal ? width : height); + } else { + splitter->resizeStartSizes.Add(0); + } + } + } + + int64_t newSize = splitter->horizontal ? (bounds.r - bounds.l) : (bounds.b - bounds.t); + + if (newSize != splitter->previousSize && childCount > 1) { + // Step 1: Make a list of current sizes. + + int64_t barSize = splitter->horizontal ? splitter->GetChild(1)->currentStyle->preferredWidth : splitter->GetChild(1)->currentStyle->preferredHeight; + int64_t previousPosition = 0; + + if (!splitter->resizeStartSizes.Length()) { + for (uintptr_t i = 1; i < childCount; i += 2) { + int64_t position = ((SplitBar *) splitter->GetChild(i))->position; + splitter->resizeStartSizes.Add(position - previousPosition); + previousPosition = position + barSize; + } + + splitter->resizeStartSizes.Add(splitter->previousSize - previousPosition); + } + + Array currentSizes = {}; + + for (uintptr_t i = 0; i < splitter->resizeStartSizes.Length(); i++) { + currentSizes.Add(splitter->resizeStartSizes[i]); + } + + // Step 2: Calculate the fixed size, and total weight. + + int64_t fixedSize = 0, totalWeight = 0; + + for (uintptr_t i = 0; i < childCount; i += 2) { + EsElement *child = splitter->GetChild(i); + + if (~child->flags & pushFlag) { + fixedSize += currentSizes[i >> 1]; + } else { + if (currentSizes[i >> 1] < 1) currentSizes[i >> 1] = 1; + totalWeight += currentSizes[i >> 1]; + } + } + + EsAssert(totalWeight); // Splitter must have at least one child with a PUSH flag for its orientation. + + // Step 3: Calculate the new weighted sizes. + + int64_t availableSpace = newSize - fixedSize - barSize * (childCount >> 1); + + if (availableSpace >= 0) { + for (uintptr_t i = 0; i < childCount; i += 2) { + EsElement *child = splitter->GetChild(i); + + if (child->flags & pushFlag) { + currentSizes[i >> 1] = availableSpace * currentSizes[i >> 1] / totalWeight; + } + } + } else { + availableSpace += fixedSize; + if (availableSpace < 0) availableSpace = 0; + + for (uintptr_t i = 0; i < childCount; i += 2) { + EsElement *child = splitter->GetChild(i); + + if (child->flags & pushFlag) { + currentSizes[i >> 1] = 0; + } else { + currentSizes[i >> 1] = availableSpace * currentSizes[i >> 1] / fixedSize; + } + } + } + + // Step 4: Update the positions. + + previousPosition = 0; + + for (uintptr_t i = 1; i < childCount; i += 2) { + SplitBar *bar = (SplitBar *) splitter->GetChild(i); + bar->position = previousPosition + currentSizes[i >> 1]; + previousPosition = bar->position + barSize - (splitter->horizontal ? bar->currentStyle->borders.l : bar->currentStyle->borders.t); + + if (bar->position == 0) { + bar->position -= splitter->horizontal ? bar->currentStyle->borders.l : bar->currentStyle->borders.t; + } else if (bar->position == newSize - barSize) { + bar->position += splitter->horizontal ? bar->currentStyle->borders.r : bar->currentStyle->borders.b; + } + } + + currentSizes.Free(); + } + + splitter->calculatedInitialSize = true; + splitter->previousSize = newSize; + + int position = splitter->horizontal ? bounds.l : bounds.t; + + for (uintptr_t i = 0; i < childCount; i++) { + EsElement *child = splitter->GetChild(i); + + if (i & 1) { + if (splitter->horizontal) { + int size = child->currentStyle->preferredWidth; + EsElementMove(child, position, client.t, size, client.b - client.t); + position += size; + } else { + int size = child->currentStyle->preferredHeight; + EsElementMove(child, client.l, position, client.r - client.l, size); + position += size; + } + } else if (i == childCount - 1) { + if (splitter->horizontal) { + EsElementMove(child, position, bounds.t, bounds.r - position, bounds.b - bounds.t); + } else { + EsElementMove(child, bounds.l, position, bounds.r - bounds.l, bounds.b - position); + } + } else { + SplitBar *bar = (SplitBar *) splitter->GetChild(i + 1); + int size = bar->position - position; + + if (splitter->horizontal) { + EsElementMove(child, position, bounds.t, size, bounds.b - bounds.t); + } else { + EsElementMove(child, bounds.l, position, bounds.r - bounds.l, size); + } + + position += size; + } + } + } else if ((message->type == ES_MSG_GET_WIDTH && splitter->horizontal) + || (message->type == ES_MSG_GET_HEIGHT && !splitter->horizontal)) { + int size = 0; + + for (uintptr_t i = 0; i < splitter->GetChildCount(); i++) { + EsElement *child = splitter->GetChild(i); + size += splitter->horizontal ? child->GetWidth(message->measure.height) : child->GetHeight(message->measure.width); + } + + if (splitter->horizontal) { + message->measure.width = size; + } else { + message->measure.height = size; + } + } else if (message->type == ES_MSG_PRE_ADD_CHILD && !splitter->addingSplitBar && splitter->GetChildCount()) { + splitter->addingSplitBar = true; + SplitBar *bar = (SplitBar *) EsHeapAllocate(sizeof(SplitBar), true); + + bar->Initialise(splitter, ES_ELEMENT_FOCUSABLE | ES_ELEMENT_NOT_TAB_TRAVERSABLE | ES_ELEMENT_CENTER_ACCESS_KEY_HINT | ES_CELL_EXPAND, + ProcessSplitBarMessage, splitter->horizontal ? ES_STYLE_SPLIT_BAR_VERTICAL : ES_STYLE_SPLIT_BAR_HORIZONTAL); + + bar->cName = "split bar"; + bar->accessKey = 'Q'; + + splitter->addingSplitBar = false; + } else if (message->type == ES_MSG_REMOVE_CHILD && ((EsElement *) message->child)->messageClass != ProcessSplitBarMessage) { + for (uintptr_t i = 0; i < splitter->GetChildCount(); i++) { + if (splitter->GetChild(i) == message->child) { + // Remove the corresponding split bar. + + if (i) { + splitter->GetChild(i - 1)->Destroy(); + } else { + splitter->GetChild(i + 1)->Destroy(); + } + + break; + } + } + } else if (message->type == ES_MSG_DESTROY) { + splitter->resizeStartSizes.Free(); + } + + return 0; +} + +EsSplitter *EsSplitterCreate(EsElement *parent, uint64_t flags, const EsStyle *style) { + EsSplitter *splitter = (EsSplitter *) EsHeapAllocate(sizeof(EsSplitter), true); + splitter->horizontal = flags & ES_SPLITTER_HORIZONTAL; + splitter->Initialise(parent, flags | ES_ELEMENT_NO_CLIP, ProcessSplitterMessage, + style ?: ES_STYLE_PANEL_WINDOW_BACKGROUND); + splitter->cName = "splitter"; + return splitter; +} + +// --------------------------------- Image displays. + +// TODO +// asynchronous/synchronous load/decode from file/memory +// unloading image when not visible +// aspect ratio; sizing +// upscale/downscale quality +// subregion, transformations +// transparency, IsRegionCompletelyOpaque, proper blending mode with fragmentShader in DrawStyledBox +// image sets, DPI; SVG scaling +// embedding in TextDisplay +// merge with IconDisplay +// decode in separate process for security? +// clipboard +// zoom/pan + +struct EsImageDisplay : EsElement { + void *source; + size_t sourceBytes; + + uint32_t *bits; + size_t width, height, stride; +}; + +int ProcessImageDisplayMessage(EsElement *element, EsMessage *message) { + EsImageDisplay *display = (EsImageDisplay *) element; + + if (message->type == ES_MSG_PAINT && (display->bits || display->source)) { + if (!display->bits && display->source) { + uint32_t width, height; + uint8_t *bits = EsImageLoad((uint8_t *) display->source, display->sourceBytes, &width, &height, 4); + + if (bits) { + display->bits = (uint32_t *) bits; + display->width = width; + display->height = height; + display->stride = width * 4; + } + + if (~display->flags & UI_STATE_CHECK_VISIBLE) { + display->state |= UI_STATE_CHECK_VISIBLE; + display->window->checkVisible.Add(display); + } + } + + EsPaintTarget source = {}; + source.bits = display->bits; + source.width = display->width; + source.height = display->height; + source.stride = display->stride; + EsDrawPaintTarget(message->painter, &source, + EsPainterBoundsInset(message->painter), + ES_RECT_4(0, display->width, 0, display->height), 0xFF); + } else if (message->type == ES_MSG_GET_WIDTH) { + message->measure.width = display->width; + } else if (message->type == ES_MSG_GET_HEIGHT) { + message->measure.height = display->height; + } else if (message->type == ES_MSG_DESTROY) { + EsHeapFree(display->bits); + EsHeapFree(display->source); + } else if (message->type == ES_MSG_NOT_VISIBLE) { + EsHeapFree(display->bits); + display->bits = nullptr; + } + + return 0; +} + +EsImageDisplay *EsImageDisplayCreate(EsElement *parent, uint64_t flags, const EsStyle *style) { + EsImageDisplay *display = (EsImageDisplay *) EsHeapAllocate(sizeof(EsImageDisplay), true); + display->Initialise(parent, flags, ProcessImageDisplayMessage, style); + display->cName = "image"; + return display; +} + +void EsImageDisplayLoadBits(EsImageDisplay *display, const uint32_t *bits, size_t width, size_t height, size_t stride) { + EsHeapFree(display->bits); + display->bits = (uint32_t *) EsHeapAllocate(stride * height, false); + display->width = width; + display->height = height; + display->stride = stride; + EsMemoryCopy(display->bits, bits, stride * height); +} + +void EsImageDisplayLoadFromMemory(EsImageDisplay *display, const void *buffer, size_t bufferBytes) { + if (display->flags & ES_IMAGE_DISPLAY_DECODE_WHEN_NEEDED) { + EsHeapFree(display->source); + EsHeapFree(display->bits); + display->bits = nullptr; + display->source = EsHeapAllocate(bufferBytes, false); + if (!display->source) return; + EsMemoryCopy(display->source, buffer, bufferBytes); + display->sourceBytes = bufferBytes; + + if (~display->flags & ES_IMAGE_DISPLAY_MANUAL_SIZE) { + // TODO Make a version of EsImageLoad that doesn't load the full image, but only gets the size. + uint32_t width, height; + uint8_t *bits = EsImageLoad((uint8_t *) buffer, bufferBytes, &width, &height, 4); + EsHeapFree(bits); + display->width = width; + display->height = height; + } + } else { + uint32_t width, height; + uint8_t *bits = EsImageLoad((uint8_t *) buffer, bufferBytes, &width, &height, 4); + if (!bits) return; + EsHeapFree(display->bits); + display->bits = (uint32_t *) bits; + display->width = width; + display->height = height; + display->stride = width * 4; + } +} + +struct EsIconDisplay : EsElement { + uint32_t iconID; +}; + +int ProcessIconDisplayMessage(EsElement *element, EsMessage *message) { + EsIconDisplay *display = (EsIconDisplay *) element; + + if (message->type == ES_MSG_PAINT) { + EsDrawContent(message->painter, element, ES_RECT_2S(message->painter->width, message->painter->height), "", 0, display->iconID); + } + + return 0; +} + +EsIconDisplay *EsIconDisplayCreate(EsElement *parent, uint64_t flags, const EsStyle *style, uint32_t iconID) { + EsIconDisplay *display = (EsIconDisplay *) EsHeapAllocate(sizeof(EsIconDisplay), true); + display->Initialise(parent, flags, ProcessIconDisplayMessage, style ?: ES_STYLE_ICON_DISPLAY); + display->cName = "icon"; + display->iconID = iconID; + return display; +} + +// --------------------------------- Message loop and core UI infrastructure. + +void EsElement::PrintTree(int depth) { + const char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + EsPrint("%s%z c:%d, %z\n", depth, tabs, cName, children.Length(), state & UI_STATE_DESTROYING ? "DESTROYING" : ""); + + for (uintptr_t i = 0; i < children.Length(); i++) { + children[i]->PrintTree(depth + 1); + } +} + +void EsElement::Destroy(bool manual) { + if (state & UI_STATE_DESTROYING) { + return; + } + + if (manual) { +#ifndef DISABLE_ALL_ANIMATIONS + if (currentStyle->metrics->exitDuration) { + if (previousTransitionFrame) { + EsPaintTargetDestroy(previousTransitionFrame); + } + + previousTransitionFrame = EsPaintTargetCreate(width, height, true); + + if (previousTransitionFrame) { + // TODO Doesn't support shadows. + EsPainter painter = {}; + painter.clip = ES_RECT_4(0, width, 0, height); + painter.target = previousTransitionFrame; + InternalPaint(&painter, PAINT_NO_TRANSITION | PAINT_NO_OFFSET); + state |= UI_STATE_EXITING; + RefreshStyle(); + } + } +#endif + + EsElement *ancestor = parent; + + while (ancestor && (~ancestor->state & UI_STATE_DESTROYING_CHILD)) { + ancestor->state |= UI_STATE_DESTROYING_CHILD; + ancestor = ancestor->parent; + } + } + + state |= UI_STATE_DESTROYING | UI_STATE_DESTROYING_CHILD | UI_STATE_BLOCK_INTERACTION; + + if (parent) { + EsMessage m = { ES_MSG_REMOVE_CHILD }; + m.child = this; + EsMessageSend(parent, &m); + } + + if (window->hovered == this) { + window->hovered = window; + window->state |= UI_STATE_HOVERED; + EsMessage m = {}; + m.type = ES_MSG_HOVERED_START; + EsMessageSend(window, &m); + } + + EsMessage m = { ES_MSG_DESTROY }; + if (messageUser) messageUser(this, &m); + messageUser = nullptr; + if (messageClass) messageClass(this, &m); + messageClass = nullptr; + + if (window->inactiveFocus == this) window->inactiveFocus = nullptr; + if (window->pressed == this) window->pressed = nullptr; + if (window->focused == this) window->focused = nullptr; + if (window->defaultEnterButton == this) window->defaultEnterButton = nullptr; + if (window->enterButton == this) window->enterButton = window->defaultEnterButton; + if (window->escapeButton == this) window->escapeButton = nullptr; + if (window->ensureVisible == this) window->ensureVisible = nullptr; + if (window->dragged == this) window->dragged = nullptr; + if (gui.clickChainElement == this) gui.clickChainElement = nullptr; + + if (parent) EsElementUpdateContentSize(parent); + + UIWindowNeedsUpdate(window); +} + +bool EsElement::InternalDestroy() { + if (~state & UI_STATE_DESTROYING_CHILD) { + return false; + } + + for (uintptr_t i = 0; i < children.Length(); i++) { + if (state & UI_STATE_DESTROYING) { + children[i]->Destroy(false); + } + + if (children[i]->InternalDestroy() && (~state & UI_STATE_DESTROYING)) { + children.Delete(i); + i--; + } + } + + state &= ~UI_STATE_DESTROYING_CHILD; + + if (~state & UI_STATE_DESTROYING) { + return false; + } + + children.Free(); + + if (state & UI_STATE_EXITING) { + return false; + } + + InspectorNotifyElementDestroyed(this); + + if (state & UI_STATE_ANIMATING) { + for (uintptr_t i = 0; i < gui.animatingElements.Length(); i++) { + if (gui.animatingElements[i] == this) { + gui.animatingElements.DeleteSwap(i); + break; + } + } + + state &= ~UI_STATE_ANIMATING; + } + + if (state & UI_STATE_CHECK_VISIBLE) { + window->checkVisible.FindAndDeleteSwap(this, true); + } + + if (currentStyle) currentStyle->CloseReference(); + if (previousTransitionFrame) EsPaintTargetDestroy(previousTransitionFrame); + ThemeAnimationDestroy(&animation); + if (window == this) UIWindowDestroy(window); // Windows are deallocated after receiving ES_MSG_WINDOW_DESTROYED. + else EsHeapFree(this); + + return true; +} + +EsElement *EsWindowGetToolbar(EsWindow *window, bool createNew) { + if (createNew || !window->toolbar) { + bool first = !window->toolbar; + window->toolbar = EsPanelCreate(window->toolbarSwitcher, ES_PANEL_HORIZONTAL | ES_CELL_FILL, ES_STYLE_PANEL_TOOLBAR); + window->toolbar->cName = "toolbar"; + EsAssert(window->toolbar->messageClass == ProcessPanelMessage); + + window->toolbar->messageClass = [] (EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_GET_CHILD_STYLE_VARIANT) { + if (message->childStyleVariant == ES_STYLE_TEXT_LABEL) { + message->childStyleVariant = ES_STYLE_TEXT_TOOLBAR; + return ES_HANDLED; + } else if (message->childStyleVariant == ES_STYLE_PUSH_BUTTON_NORMAL + || message->childStyleVariant == ES_STYLE_CHECKBOX_NORMAL + || message->childStyleVariant == ES_STYLE_CHECKBOX_RADIOBOX) { + message->childStyleVariant = ES_STYLE_PUSH_BUTTON_TOOLBAR; + return ES_HANDLED; + } + } + + return ProcessPanelMessage(element, message); + }; + + if (first) EsPanelSwitchTo(window->toolbarSwitcher, window->toolbar, ES_TRANSITION_NONE); + } + + return window->toolbar; +} + +void EsWindowSwitchToolbar(EsWindow *window, EsElement *toolbar, EsTransitionType transitionType) { + EsPanelSwitchTo(window->toolbarSwitcher, toolbar, transitionType); +} + +EsRectangle EsWindowGetBounds(EsWindow *window) { + EsRectangle bounds; + EsSyscall(ES_SYSCALL_WINDOW_GET_BOUNDS, window->handle, (uintptr_t) &bounds, 0, 0); + return bounds; +} + +EsRectangle EsElementGetInsetSize(EsElement *element) { + EsMessageMutexCheck(); + + EsRectangle insets = element->currentStyle->insets; + return ES_RECT_4(0, element->width - insets.l - insets.r, + 0, element->height - insets.t - insets.b); +} + +void EsWindowSetIcon(EsWindow *window, uint32_t iconID) { + EsMessageMutexCheck(); + + char buffer[5]; + buffer[0] = DESKTOP_MSG_SET_ICON; + EsMemoryCopy(buffer + 1, &iconID, sizeof(uint32_t)); + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) buffer, sizeof(buffer), window->handle, 0); +} + +void EsWindowSetTitle(EsWindow *window, const char *title, ptrdiff_t titleBytes) { + EsMessageMutexCheck(); + + APIInstance *instance = window->instance ? ((APIInstance *) window->instance->_private) : nullptr; + const char *applicationName = instance ? instance->applicationName : nullptr; + size_t applicationNameBytes = instance ? instance->applicationNameBytes : 0; + + if (!applicationNameBytes && !titleBytes) { + return; + } + + if (titleBytes == -1) { + titleBytes = EsCStringLength(title); + } + + if (titleBytes) { + applicationNameBytes = 0; + } + + char buffer[4096]; + size_t bytes = EsStringFormat(buffer, 4096, "%c%s%s", DESKTOP_MSG_SET_TITLE, titleBytes, title, applicationNameBytes, applicationName); + EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) buffer, bytes, window->handle, 0); +} + +void EsMouseSetPosition(EsWindow *relativeWindow, int x, int y) { + if (relativeWindow) { + EsRectangle bounds = EsWindowGetBounds(relativeWindow); + x += bounds.l; + y += bounds.t; + } + + EsSyscall(ES_SYSCALL_CURSOR_POSITION_SET, x, y, 0, 0); +} + +EsPoint EsMouseGetPosition(EsElement *relativeElement) { + if (relativeElement) { + EsPoint position = relativeElement->window->mousePosition; + EsRectangle bounds = relativeElement->GetWindowBounds(); + position.x -= bounds.l; + position.y -= bounds.t; + return position; + } else { + EsPoint position; + EsSyscall(ES_SYSCALL_CURSOR_POSITION_GET, (uintptr_t) &position, 0, 0, 0); + return position; + } +} + +const EsStyle *UIGetDefaultStyleVariant(const EsStyle *style, EsElement *parent) { + EsMessage m = { .type = ES_MSG_GET_CHILD_STYLE_VARIANT, .childStyleVariant = style }; + EsElement *ancestor = parent; + + while (ancestor) { + if (ES_HANDLED == EsMessageSend(ancestor, &m)) { + break; + } + + ancestor = ancestor->parent; + } + + return m.childStyleVariant; +} + +EsElement *UIFindHoverElementRecursively2(EsElement *element, int offsetX, int offsetY, EsPoint position, uintptr_t i) { + EsElement *child = element->GetChildByZ(i - 1); + + if (!child) return nullptr; + if (child->flags & ES_ELEMENT_HIDDEN) return nullptr; + if (child->state & UI_STATE_DESTROYING) return nullptr; + if (child->state & UI_STATE_BLOCK_INTERACTION) return nullptr; + + if (!EsRectangleContains(ES_RECT_4(offsetX + child->offsetX, offsetX + child->offsetX + child->width, + offsetY + child->offsetY, offsetY + child->offsetY + child->height), + position.x, position.y)) { + return nullptr; + } + + EsMessage m = { ES_MSG_HIT_TEST }; + m.hitTest.x = position.x - offsetX - child->offsetX - child->internalOffsetLeft; + m.hitTest.y = position.y - offsetY - child->offsetY - child->internalOffsetTop; + m.hitTest.inside = true; + int response = EsMessageSend(child, &m); + + if ((response != ES_HANDLED || m.hitTest.inside) && response != ES_REJECTED) { + return UIFindHoverElementRecursively(child, offsetX, offsetY, position); + } + + return nullptr; +} + +EsElement *UIFindHoverElementRecursively(EsElement *element, int offsetX, int offsetY, EsPoint position) { + offsetX += element->offsetX; + offsetY += element->offsetY; + + EsMessage zOrder = { ES_MSG_BEFORE_Z_ORDER }; + zOrder.beforeZOrder.nonClient = zOrder.beforeZOrder.end = element->children.Length(); + zOrder.beforeZOrder.clip = Translate(ES_RECT_4(0, element->width, 0, element->height), offsetX, offsetY); + EsMessageSend(element, &zOrder); + + EsElement *result = nullptr; + + if (~element->flags & ES_ELEMENT_NO_HOVER_DESCENDENTS) { + for (uintptr_t i = element->children.Length(); !result && i > zOrder.beforeZOrder.nonClient; i--) { + result = UIFindHoverElementRecursively2(element, offsetX, offsetY, position, i); + } + + for (uintptr_t i = zOrder.beforeZOrder.end; !result && i > zOrder.beforeZOrder.start; i--) { + result = UIFindHoverElementRecursively2(element, offsetX, offsetY, position, i); + } + } + + zOrder.type = ES_MSG_AFTER_Z_ORDER; + EsMessageSend(element, &zOrder); + + return result ? result : (element->flags & ES_ELEMENT_NO_HOVER) ? nullptr : element; +} + +void UIFindHoverElement(EsWindow *window) { + // TS("Finding element under cursor\n"); + + EsPoint position = EsMouseGetPosition(window); + + EsElement *element; + + if (position.x < 0 || position.y < 0 || position.x >= window->width || position.y >= window->height || !window->hovering) { + element = window; + } else { + element = UIFindHoverElementRecursively(window, 0, 0, position); + } + + if (element->state & UI_STATE_HOVERED) { + EsAssert(window->hovered == element); // Window's hovered element mismatched element state flags. + } else { + EsMessage m = {}; + m.type = ES_MSG_HOVERED_END; + window->hovered->state &= ~UI_STATE_HOVERED; + EsMessageSend(window->hovered, &m); + element->state |= UI_STATE_HOVERED; + m.type = ES_MSG_HOVERED_START; + EsMessageSend((window->hovered = element), &m); + } +} + +void UIRemoveFocusFromElement(EsElement *oldFocus) { + if (!oldFocus) return; + EsMessage m = {}; + + if (~oldFocus->state & UI_STATE_LOST_STRONG_FOCUS) { + m.type = ES_MSG_STRONG_FOCUS_END; + oldFocus->state |= UI_STATE_LOST_STRONG_FOCUS; + EsMessageSend(oldFocus, &m); + } + + m.type = ES_MSG_FOCUSED_END; + oldFocus->state &= ~(UI_STATE_FOCUSED | UI_STATE_LOST_STRONG_FOCUS); + EsMessageSend(oldFocus, &m); +} + +void UIMaybeRemoveFocusedElement(EsWindow *window) { + if (window->focused && !window->focused->IsFocusable()) { + EsElement *oldFocus = window->focused; + window->focused = nullptr; + UIRemoveFocusFromElement(oldFocus); + } +} + +void EsElementFocus(EsElement *element, uint32_t flags) { + EsMessageMutexCheck(); + + EsWindow *window = element->window; + EsMessage m; + + // If this element is not focusable or if the window doesn't allow focused elements, ignore the request. + + if (!element->IsFocusable() || (window->windowStyle == ES_WINDOW_CONTAINER)) return; + + // If the element is already focused, then don't resend it any messages. + + if (window->focused == element) return; + + // Tell the previously focused element it's no longer focused. + + EsElement *oldFocus = window->focused; + window->focused = element; + UIRemoveFocusFromElement(oldFocus); + + // Tell any parents of the previously focused element that aren't parents of the newly focused element that they no longer has focus-within, + // and the parents of the newly focused element that they have focus-within. + + EsElement *parent = element->parent; + + while (parent) { + parent->state |= UI_STATE_TEMP; + parent = parent->parent; + } + + if (oldFocus) { + parent = oldFocus->parent; + + while (parent) { + if (~parent->state & UI_STATE_TEMP) { + parent->state &= ~UI_STATE_FOCUS_WITHIN; + m.type = ES_MSG_FOCUS_WITHIN_END; + EsMessageSend(parent, &m); + } + + parent = parent->parent; + } + } + + parent = element->parent; + window->focused = element; + + while (parent) { + if (~parent->state & UI_STATE_FOCUS_WITHIN) { + parent->state |= UI_STATE_FOCUS_WITHIN; + m.type = ES_MSG_FOCUS_WITHIN_START; + EsMessageSend(parent, &m); + + EsAssert(window->focused == element); // Cannot change window focus from FOCUS_WITHIN_START message. + } + + parent->state &= ~UI_STATE_TEMP; + parent = parent->parent; + } + + // Tell the newly focused element it's focused. + + m.type = ES_MSG_FOCUSED_START; + m.focus.flags = flags; + window->focused->state |= UI_STATE_FOCUSED; + EsMessageSend(element, &m); + EsAssert(window->focused == element); // Cannot change window focus from FOCUSED_START message. + + // Ensure the element is visible. + + if ((flags & ES_ELEMENT_FOCUS_ENSURE_VISIBLE) && element) { + window->ensureVisible = element; + } +} + +EsRectangle EsElementGetWindowBounds(EsElement *element, bool client) { + EsElement *e = element; + int x = 0, y = 0; + + while (element) { + x += element->offsetX, y += element->offsetY; + element = element->parent; + } + + int cw = e->width - (client ? (e->internalOffsetLeft + e->internalOffsetRight) : 0); + int ch = e->height - (client ? (e->internalOffsetTop + e->internalOffsetBottom) : 0); + + return ES_RECT_4(x, x + cw, y, y + ch); +} + +EsRectangle EsElementGetScreenBounds(EsElement *element, bool client) { + EsRectangle elementBoundsInWindow = EsElementGetWindowBounds(element, client); + EsRectangle windowBoundsInScreen = EsWindowGetBounds(element->window); + return Translate(elementBoundsInWindow, windowBoundsInScreen.l, windowBoundsInScreen.t); +} + +void EsElementInsertAfter(EsElement *element) { + EsAssert(!gui.insertAfter); + gui.insertAfter = element; +} + +void EsElement::Initialise(EsElement *_parent, uint64_t _flags, EsUICallbackFunction _classCallback, const EsStyle *style) { + EsMessageMutexCheck(); + + // EsPrint("New element '%z' %x with parent %x.\n", _debugName, this, _parent); + + messageClass = _classCallback; + flags = _flags; + + if (gui.insertAfter) { + if (_parent) { + EsAssert(_parent == gui.insertAfter || _parent == gui.insertAfter->parent); + } else { + _parent = gui.insertAfter->parent; + } + } + + if (_parent) { + if (!_parent->parent && (~_flags & ES_ELEMENT_NON_CLIENT)) { + _parent = WindowGetMainPanel((EsWindow *) _parent); + } + + parent = _parent; + window = parent->window; + instance = window->instance; + + if (parent->flags & ES_ELEMENT_DISABLED) flags |= ES_ELEMENT_DISABLED; + + if (~flags & ES_ELEMENT_NON_CLIENT) { + EsMessage m = {}; + m.type = ES_MSG_PRE_ADD_CHILD; + m.child = this; + EsMessageSend(parent, &m); + } + + if (gui.insertAfter == _parent) { + parent->children.Insert(this, 0); + gui.insertAfter = nullptr; + } else if (gui.insertAfter) { + uintptr_t i = parent->children.Find(gui.insertAfter, true); + parent->children.Insert(this, i + 1); + gui.insertAfter = nullptr; + } else if (flags & ES_ELEMENT_NON_CLIENT) { + parent->children.Add(this); + } else { + for (uintptr_t i = parent->children.Length();; i--) { + if (i == 0 || (~parent->children[i - 1]->flags & ES_ELEMENT_NON_CLIENT)) { + parent->children.Insert(this, i); + break; + } + } + } + + if (~flags & ES_ELEMENT_NON_CLIENT) { + EsMessage m = {}; + m.type = ES_MSG_ADD_CHILD; + m.child = this; + EsMessageSend(parent, &m); + } + + EsElementUpdateContentSize(parent); + } + + SetStyle(style, false); + RefreshStyle(); + InspectorNotifyElementCreated(this); +} + +EsRectangle EsElementGetInsets(EsElement *element) { + EsMessageMutexCheck(); + return element->currentStyle->insets; +} + +EsThemeMetrics EsElementGetMetrics(EsElement *element) { + EsMessageMutexCheck(); + EsThemeMetrics m = {}; + ThemeMetrics *metrics = element->currentStyle->metrics; +#define RECTANGLE_8_TO_ES_RECTANGLE(x) { (int32_t) (x).l, (int32_t) (x).r, (int32_t) (x).t, (int32_t) (x).b } + m.insets = RECTANGLE_8_TO_ES_RECTANGLE(metrics->insets); + m.clipInsets = RECTANGLE_8_TO_ES_RECTANGLE(metrics->clipInsets); + m.globalOffset = RECTANGLE_8_TO_ES_RECTANGLE(metrics->globalOffset); + m.clipEnabled = metrics->clipEnabled; + m.cursor = metrics->cursor; + m.entranceTransition = metrics->entranceTransition; + m.exitTransition = metrics->exitTransition; + m.entranceDuration = metrics->entranceDuration; + m.exitDuration = metrics->exitDuration; + m.preferredWidth = metrics->preferredWidth; + m.preferredHeight = metrics->preferredHeight; + m.minimumWidth = metrics->minimumWidth; + m.minimumHeight = metrics->minimumHeight; + m.maximumWidth = metrics->maximumWidth; + m.maximumHeight = metrics->maximumHeight; + m.gapMajor = metrics->gapMajor; + m.gapMinor = metrics->gapMinor; + m.gapWrap = metrics->gapWrap; + m.textColor = metrics->textColor; + m.selectedBackground = metrics->selectedBackground; + m.selectedText = metrics->selectedText; + m.iconColor = metrics->iconColor; + m.textAlign = metrics->textAlign; + m.textSize = metrics->textSize; + m.fontFamily = metrics->fontFamily; + m.fontWeight = metrics->fontWeight; + m.iconSize = metrics->iconSize; + m.isItalic = metrics->isItalic; + m.ellipsis = metrics->ellipsis; + return m; +} + +void EsElementSetCallback(EsElement *element, EsUICallbackFunction callback) { + EsMessageMutexCheck(); + element->messageUser = callback; +} + +void EsElementSetHidden(EsElement *element, bool hidden) { + EsMessageMutexCheck(); + + bool old = element->flags & ES_ELEMENT_HIDDEN; + if (old == hidden) return; + + if (hidden) { + element->flags |= ES_ELEMENT_HIDDEN; + } else { + element->flags &= ~ES_ELEMENT_HIDDEN; + } + + EsElementUpdateContentSize(element->parent); + UIMaybeRemoveFocusedElement(element->window); +} + +void EsElementSetDisabled(EsElement *element, bool disabled) { + EsMessageMutexCheck(); + + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + if (element->GetChild(i)->flags & ES_ELEMENT_NON_CLIENT) continue; + EsElementSetDisabled(element->GetChild(i), disabled); + } + + if ((element->flags & ES_ELEMENT_DISABLED) && disabled) return; + if ((~element->flags & ES_ELEMENT_DISABLED) && !disabled) return; + + if (disabled) element->flags |= ES_ELEMENT_DISABLED; + else element->flags &= ~ES_ELEMENT_DISABLED; + + element->MaybeRefreshStyle(); + + if (element->window->focused == element) { + element->window->focused = nullptr; + } +} + +void EsElementDestroy(EsElement *element) { + EsMessageMutexCheck(); + element->Destroy(); +} + +void EsElementDestroyContents(EsElement *element) { + EsMessageMutexCheck(); + + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + if (element->GetChild(i)->flags & ES_ELEMENT_NON_CLIENT) continue; + element->GetChild(i)->Destroy(); + } + + EsMessage m = {}; + m.type = ES_MSG_DESTROY_CONTENTS; + EsMessageSend(element, &m); +} + +EsElement *UITabTraversalGetChild(EsElement *element, uintptr_t index) { + if (element->flags & ES_ELEMENT_LAYOUT_HINT_REVERSE) { + return element->children[element->children.Length() - index - 1]; + } else { + return element->children[index]; + } +} + +EsElement *UITabTraversalDo(EsElement *element, bool shift) { + if (shift) { + if (element->parent && UITabTraversalGetChild(element->parent, 0) != element) { + for (uintptr_t i = 1; i < element->parent->children.Length(); i++) { + if (UITabTraversalGetChild(element->parent, i) == element) { + element = UITabTraversalGetChild(element->parent, i - 1); + + while (element->children.Length()) { + element = UITabTraversalGetChild(element, element->children.Length() - 1); + } + + return element; + } + } + } else if (element->parent) { + return element->parent; + } else { + while (element->children.Length()) { + element = UITabTraversalGetChild(element, element->children.Length() - 1); + } + + return element; + } + } else { + if (element->children.Length()) { + return UITabTraversalGetChild(element, 0); + } else while (element->parent) { + EsElement *child = element; + element = element->parent; + + for (uintptr_t i = 0; i < element->children.Length() - 1u; i++) { + if (UITabTraversalGetChild(element, i) == child) { + element = UITabTraversalGetChild(element, i + 1); + return element; + } + } + } + } + + return element; +} + +uint8_t EsKeyboardGetModifiers() { + return gui.leftModifiers | gui.rightModifiers; +} + +bool EsMouseIsLeftHeld() { return gui.mouseButtonDown && gui.lastClickButton == ES_MSG_MOUSE_LEFT_DOWN; } +bool EsMouseIsRightHeld() { return gui.mouseButtonDown && gui.lastClickButton == ES_MSG_MOUSE_RIGHT_DOWN; } +bool EsMouseIsMiddleHeld() { return gui.mouseButtonDown && gui.lastClickButton == ES_MSG_MOUSE_MIDDLE_DOWN; } + +void EsStyleRefreshAll(EsElement *element) { + EsMessageMutexCheck(); + + element->RefreshStyle(nullptr, false, true); + + for (uintptr_t i = 0; i < element->children.Length(); i++) { + if (element->children[i]) { + EsStyleRefreshAll(element->children[i]); + } + } +} + +void EsUISetDPI(int dpiScale) { + EsMessageMutexCheck(); + + if (dpiScale < 50) { + dpiScale = 50; + } + + theming.scale = dpiScale / 100.0f; + + for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) { + EsStyleRefreshAll(gui.allWindows[i]); + } +} + +void EsElementGetSize(EsElement *element, int *width, int *height) { + EsMessageMutexCheck(); + + EsRectangle bounds = element->GetBounds(); + *width = bounds.r; + *height = bounds.b; +} + +void EsElementGetTextStyle(EsElement *element, EsTextStyle *style) { + element->currentStyle->GetTextStyle(style); +} + +void EsElementRepaint(EsElement *element, const EsRectangle *region) { + EsMessageMutexCheck(); + if (region) element->Repaint(false, *region); + else element->Repaint(true /* repaint all */); +} + +void EsElementRepaintForScroll(EsElement *element, EsMessage *message) { + // TODO Support custom borders sizes. + + EsRectangle borders = ES_RECT_4(element->internalOffsetLeft, element->internalOffsetRight, + element->internalOffsetTop, element->internalOffsetBottom); + EsRectangle content = ES_RECT_4(borders.l, element->width - borders.r, borders.t, element->height - borders.b); + EsRectangle repaint = content; + int64_t delta = message->scrollbarMoved.scroll - message->scrollbarMoved.previous; + + if (message->type == ES_MSG_SCROLL_Y) { + if (delta > 0) repaint.t = element->height - delta - borders.b; + else repaint.b = borders.t - delta; + } else if (message->type == ES_MSG_SCROLL_X) { + if (delta > 0) repaint.l = element->width - delta - borders.r; + else repaint.r = borders.l - delta; + } else { + EsAssert(false); + } + + EsRectangle rectangle = element->GetWindowBounds(false); + EsRectangle scrollBits = Translate(content, rectangle.l, rectangle.t); + EsSyscall(ES_SYSCALL_WINDOW_SET_BITS, element->window->handle, (uintptr_t) &scrollBits, delta, + message->type == ES_MSG_SCROLL_Y ? WINDOW_SET_BITS_SCROLL_VERTICAL : WINDOW_SET_BITS_SCROLL_HORIZONTAL); + + repaint = EsRectangleIntersection(repaint, content); + EsElementRepaint(element, &repaint); + UIWindowPaintNow(element->window, nullptr, false); +} + +bool EsElementStartAnimating(EsElement *element) { + EsMessageMutexCheck(); + + return element->StartAnimating(); +} + +EsElement *EsElementGetLayoutParent(EsElement *element) { + EsMessageMutexCheck(); + + return element->parent; +} + +void EsElementDraw(EsElement *element, EsPainter *painter) { + element->InternalPaint(painter, PAINT_SHADOW); + element->InternalPaint(painter, ES_FLAGS_DEFAULT); + element->InternalPaint(painter, PAINT_OVERLAY); +} + +int UIMessageSendPropagateToAncestors(EsElement *element, EsMessage *message, EsElement **handler = nullptr) { + while (element) { + int response = EsMessageSend(element, message); + + if (response) { + if (handler) *handler = element; + return response; + } + + element = element->parent; + } + + if (handler) *handler = nullptr; + return 0; +} + +void UIMousePressReleased(EsWindow *window, EsMessage *message, bool sendClick) { + if (window->pressed) { + EsElement *pressed = window->pressed; + window->pressed = nullptr; + + if (message) { + EsRectangle bounds = pressed->GetWindowBounds(); + message->mouseDown.positionX -= bounds.l; + message->mouseDown.positionY -= bounds.t; + UIMessageSendPropagateToAncestors(pressed, message); + } else { + EsMessage m = {}; + m.type = (EsMessageType) (gui.lastClickButton + 1); + UIMessageSendPropagateToAncestors(pressed, &m); + } + + pressed->state &= ~UI_STATE_PRESSED; + EsMessage m = { ES_MSG_PRESSED_END }; + EsMessageSend(pressed, &m); + + if (message && (pressed->state & UI_STATE_HOVERED) && !gui.draggingStarted && sendClick) { + if (message->type == ES_MSG_MOUSE_LEFT_UP) { + m.type = ES_MSG_MOUSE_LEFT_CLICK; + EsMessageSend(pressed, &m); + } else if (message->type == ES_MSG_MOUSE_RIGHT_UP) { + m.type = ES_MSG_MOUSE_RIGHT_CLICK; + EsMessageSend(pressed, &m); + } else if (message->type == ES_MSG_MOUSE_MIDDLE_UP) { + m.type = ES_MSG_MOUSE_MIDDLE_CLICK; + EsMessageSend(pressed, &m); + } + } + + if (window->hovered) window->hovered->MaybeRefreshStyle(); + } + + gui.draggingStarted = false; +} + +void UIInitialiseKeyboardShortcutNamesTable() { +#define ADD_KEYBOARD_SHORTCUT_NAME(a, b) HashTablePutShort(&gui.keyboardShortcutNames, a, (void *) b) + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_A, "A"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_B, "B"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_C, "C"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_D, "D"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_E, "E"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F, "F"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_G, "G"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_H, "H"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_I, "I"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_J, "J"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_K, "K"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_L, "L"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_M, "M"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_N, "N"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_O, "O"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_P, "P"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_Q, "Q"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_R, "R"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_S, "S"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_T, "T"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_U, "U"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_V, "V"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_W, "W"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_X, "X"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_Y, "Y"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_Z, "Z"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_0, "0"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_1, "1"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_2, "2"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_3, "3"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_4, "4"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_5, "5"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_6, "6"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_7, "7"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_8, "8"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_9, "9"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_BACKSPACE, "Backspace"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_ESCAPE, "Esc"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_INSERT, "Ins"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_HOME, "Home"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_PAGE_UP, "PgUp"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_DELETE, "Del"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_END, "End"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_PAGE_DOWN, "PgDn"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_UP_ARROW, "Up"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_LEFT_ARROW, "Left"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_DOWN_ARROW, "Down"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_RIGHT_ARROW, "Right"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_SPACE, "Space"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_TAB, "Tab"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_ENTER, "Enter"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F1, "F1"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F2, "F2"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F3, "F3"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F4, "F4"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F5, "F5"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F6, "F6"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F7, "F7"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F8, "F8"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F9, "F9"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F10, "F10"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F11, "F11"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_F12, "F12"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_MM_NEXT, "Next Track"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_MM_PREVIOUS, "Previous Track"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_MM_STOP, "Stop Media"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_MM_PAUSE, "Play/Pause"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_MM_MUTE, "Mute"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_MM_QUIETER, "Quieter"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_MM_LOUDER, "Louder"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_MM_SELECT, "Open Media"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_WWW_SEARCH, "Search"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_WWW_HOME, "Homepage"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_WWW_BACK, "Back"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_WWW_FORWARD, "Forward"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_WWW_STOP, "Stop"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_WWW_REFRESH, "Refresh"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_WWW_STARRED, "Bookmark"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_SLASH, "/"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_PUNCTUATION_1, "\\"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_LEFT_BRACE, "("); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_RIGHT_BRACE, ")"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_EQUALS, "="); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_PUNCTUATION_5, "`"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_HYPHEN, "-"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_PUNCTUATION_3, ";"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_PUNCTUATION_4, "'"); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_COMMA, ","); + ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_PERIOD, "."); +} + +void AccessKeysGather(EsElement *element) { + if (element->flags & ES_ELEMENT_BLOCK_FOCUS) return; + if (element->state & UI_STATE_BLOCK_INTERACTION) return; + if (element->flags & ES_ELEMENT_HIDDEN) return; + + for (uintptr_t i = 0; i < element->children.Length(); i++) { + AccessKeysGather(element->children[i]); + } + + if (!element->accessKey) return; + if (element->state & UI_STATE_DESTROYING) return; + if (element->flags & ES_ELEMENT_DISABLED) return; + + EsRectangle bounds = element->GetWindowBounds(); + + AccessKeyEntry entry = {}; + entry.character = element->accessKey; + entry.number = gui.accessKeys.numbers[entry.character - 'A']; + entry.element = element; + + if (element->flags & ES_ELEMENT_CENTER_ACCESS_KEY_HINT) { + entry.x = (bounds.l + bounds.r) / 2; + entry.y = (bounds.t + bounds.b) / 2; + } else { + entry.x = (bounds.l + bounds.r) / 2; + entry.y = bounds.b; + } + + if (entry.number >= 10) return; + + gui.accessKeys.entries.Add(entry); + gui.accessKeys.numbers[entry.character - 'A']++; +} + +void AccessKeyHintsShow(EsPainter *painter) { + for (uintptr_t i = 0; i < gui.accessKeys.entries.Length(); i++) { + AccessKeyEntry *entry = &gui.accessKeys.entries[i]; + UIStyle *style = gui.accessKeys.hintStyle; + + if (gui.accessKeys.typedCharacter && entry->character != gui.accessKeys.typedCharacter) { + continue; + } + + EsRectangle bounds = ES_RECT_4( + entry->x - style->preferredWidth / 2, + entry->x + style->preferredWidth / 2, + entry->y - style->preferredHeight / 4, + entry->y + 3 * style->preferredHeight / 4); + + if (entry->element->flags & ES_ELEMENT_CENTER_ACCESS_KEY_HINT) { + bounds.t -= style->preferredHeight / 4; + bounds.b -= style->preferredHeight / 4; + } + + if (bounds.r > (int32_t) gui.accessKeys.window->windowWidth) { + bounds.l = gui.accessKeys.window->windowWidth - style->preferredWidth; + bounds.r = bounds.l + style->preferredWidth; + } + + if (bounds.l < 0) { + bounds.l = 0; + bounds.r = bounds.l + style->preferredWidth; + } + + if (bounds.b > (int32_t) gui.accessKeys.window->windowHeight) { + bounds.t = gui.accessKeys.window->windowHeight - style->preferredHeight; + bounds.b = bounds.t + style->preferredHeight; + } + + if (bounds.t < 0) { + bounds.t = 0; + bounds.b = bounds.t + style->preferredHeight; + } + + style->PaintLayers(painter, bounds, 0, THEME_LAYER_MODE_BACKGROUND); + + char c = gui.accessKeys.typedCharacter ? entry->number + '0' : entry->character; + style->PaintText(painter, nullptr, bounds, &c, 1, 0, ES_FLAGS_DEFAULT); + } +} + +int AccessKeyLayerMessage(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_PAINT && gui.accessKeyMode && gui.accessKeys.window == element->window) { + AccessKeyHintsShow(message->painter); + } + + return 0; +} + +void AccessKeyModeEnter(EsWindow *window) { + if (window->hasDialog || gui.menuMode || gui.accessKeyMode || window->windowStyle != ES_WINDOW_NORMAL) { + return; + } + + gui.accessKeyMode = true; + AccessKeysGather(window); + + if (!gui.accessKeys.hintStyle) { + gui.accessKeys.hintStyle = GetStyle(MakeStyleKey(ES_STYLE_ACCESS_KEY_HINT, 0), false); + } + + for (uintptr_t i = 0; i < gui.accessKeys.entries.Length(); i++) { + if (gui.accessKeys.numbers[gui.accessKeys.entries[i].character - 'A'] == 1) { + gui.accessKeys.entries[i].number = -1; + } + } + + gui.accessKeys.window = window; + window->Repaint(true); +} + +void AccessKeyModeExit() { + if (!gui.accessKeyMode) { + return; + } + + gui.accessKeys.entries.Free(); + gui.accessKeys.window->Repaint(true); + EsMemoryZero(gui.accessKeys.numbers, sizeof(gui.accessKeys.numbers)); + gui.accessKeys.typedCharacter = 0; + gui.accessKeys.window = nullptr; + gui.accessKeyMode = false; +} + +void AccessKeyModeHandleKeyPress(EsMessage *message) { + int ic, isc; + ConvertScancodeToCharacter(message->keyboard.scancode, &ic, &isc, false, false); + ic = EsCRTtoupper(ic); + + bool keepAccessKeyModeActive = false; + + if (ic >= 'A' && ic <= 'Z' && !gui.accessKeys.typedCharacter) { + if (gui.accessKeys.numbers[ic - 'A'] > 1) { + keepAccessKeyModeActive = true; + gui.accessKeys.typedCharacter = ic; + } else if (gui.accessKeys.numbers[ic - 'A'] == 1) { + for (uintptr_t i = 0; i < gui.accessKeys.entries.Length(); i++) { + AccessKeyEntry *entry = &gui.accessKeys.entries[i]; + + if (entry->character == ic) { + EsMessage m = { ES_MSG_MOUSE_LEFT_CLICK }; + EsMessageSend(entry->element, &m); + EsElementFocus(entry->element, ES_ELEMENT_FOCUS_ENSURE_VISIBLE | ES_ELEMENT_FOCUS_FROM_KEYBOARD); + + keepAccessKeyModeActive = entry->element->flags & ES_ELEMENT_STICKY_ACCESS_KEY; + } + } + } + } else if (ic >= '0' && ic <= '9' && gui.accessKeys.typedCharacter) { + for (uintptr_t i = 0; i < gui.accessKeys.entries.Length(); i++) { + AccessKeyEntry *entry = &gui.accessKeys.entries[i]; + + if (entry->character == gui.accessKeys.typedCharacter && entry->number == ic - '0') { + EsMessage m = { ES_MSG_MOUSE_LEFT_CLICK }; + EsMessageSend(entry->element, &m); + EsElementFocus(entry->element, ES_ELEMENT_FOCUS_ENSURE_VISIBLE | ES_ELEMENT_FOCUS_FROM_KEYBOARD); + + keepAccessKeyModeActive = entry->element->flags & ES_ELEMENT_STICKY_ACCESS_KEY; + } + } + } + + if (!keepAccessKeyModeActive) { + AccessKeyModeExit(); + } else { + gui.accessKeys.window->Repaint(true); + } +} + +void UIRefreshPrimaryClipboard(EsWindow *window) { + if (window->focused) { + EsMessage m = {}; + m.type = ES_MSG_PRIMARY_CLIPBOARD_UPDATED; + EsMessageSend(window->focused, &m); + } +} + +void UIHandleKeyMessage(EsWindow *window, EsMessage *message) { + if (message->type == ES_MSG_KEY_UP) { + if (message->keyboard.scancode == ES_SCANCODE_LEFT_CTRL ) gui.leftModifiers &= ~ES_MODIFIER_CTRL; + if (message->keyboard.scancode == ES_SCANCODE_LEFT_ALT ) gui.leftModifiers &= ~ES_MODIFIER_ALT; + if (message->keyboard.scancode == ES_SCANCODE_LEFT_SHIFT ) gui.leftModifiers &= ~ES_MODIFIER_SHIFT; + if (message->keyboard.scancode == ES_SCANCODE_LEFT_FLAG ) gui.leftModifiers &= ~ES_MODIFIER_FLAG; + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_CTRL ) gui.rightModifiers &= ~ES_MODIFIER_CTRL; + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_ALT ) gui.rightModifiers &= ~ES_MODIFIER_ALT; + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_SHIFT) gui.rightModifiers &= ~ES_MODIFIER_SHIFT; + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_FLAG ) gui.rightModifiers &= ~ES_MODIFIER_FLAG; + + if (message->keyboard.scancode == ES_SCANCODE_LEFT_ALT && gui.unhandledAltPress) { + AccessKeyModeEnter(window); + } + + if (window->focused) EsMessageSend(window->focused, message); + return; + } + + if (window->targetMenu) { + window = window->targetMenu; + } + + gui.unhandledAltPress = false; + + if (message->keyboard.scancode == ES_SCANCODE_F2 && message->keyboard.modifiers == ES_MODIFIER_ALT) { + EnterDebugger(); + EsPrint("[Alt-F2]\n"); + } + + if (message->keyboard.scancode == ES_SCANCODE_LEFT_CTRL ) gui.leftModifiers |= ES_MODIFIER_CTRL; + if (message->keyboard.scancode == ES_SCANCODE_LEFT_ALT ) gui.leftModifiers |= ES_MODIFIER_ALT; + if (message->keyboard.scancode == ES_SCANCODE_LEFT_SHIFT ) gui.leftModifiers |= ES_MODIFIER_SHIFT; + if (message->keyboard.scancode == ES_SCANCODE_LEFT_FLAG ) gui.leftModifiers |= ES_MODIFIER_FLAG; + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_CTRL ) gui.rightModifiers |= ES_MODIFIER_CTRL; + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_ALT ) gui.rightModifiers |= ES_MODIFIER_ALT; + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_SHIFT) gui.rightModifiers |= ES_MODIFIER_SHIFT; + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_FLAG ) gui.rightModifiers |= ES_MODIFIER_FLAG; + + if (window->windowStyle == ES_WINDOW_MENU && message->keyboard.scancode == ES_SCANCODE_ESCAPE) { + window->Destroy(); + return; + } + + if (gui.menuMode) { + // TODO Check the window is the one that enabled menu mode. + // TODO Escape to close/exit menu mode. + // TODO Left/right to navigate columns/cycle menubar and open/close submenus. + // TODO Up/down to traverse menu. + // TODO Enter to open submenu/invoke item. + return; + } else if (gui.accessKeyMode) { + if (gui.accessKeys.window != window) { + AccessKeyModeExit(); + } else { + AccessKeyModeHandleKeyPress(message); + return; + } + } + + if (window->pressed) { + if (message->keyboard.scancode == ES_SCANCODE_ESCAPE) { + UIMousePressReleased(window, nullptr, false); + return; + } + } + + if (window->focused) { + message->type = ES_MSG_KEY_TYPED; + if (EsMessageSend(window->focused, message) != 0) return; + + EsElement *element = window->focused; + message->type = ES_MSG_KEY_DOWN; + + if (UIMessageSendPropagateToAncestors(element, message)) { + return; + } + } + + if (message->keyboard.scancode == ES_SCANCODE_TAB && (message->keyboard.modifiers & ~ES_MODIFIER_SHIFT) == 0) { + EsElement *element = window->focused ?: window; + EsElement *start = element; + + do element = UITabTraversalDo(element, message->keyboard.modifiers & ES_MODIFIER_SHIFT); + while ((!element->IsFocusable() || (element->flags & ES_ELEMENT_NOT_TAB_TRAVERSABLE)) && element != start); + + EsElementFocus(element, ES_ELEMENT_FOCUS_ENSURE_VISIBLE | ES_ELEMENT_FOCUS_FROM_KEYBOARD); + return; + } + + if (window->focused) { + if (message->keyboard.scancode == ES_SCANCODE_SPACE && message->keyboard.modifiers == 0) { + EsMessage m = { ES_MSG_MOUSE_LEFT_CLICK }; + EsMessageSend(window->focused, &m); + return; + } + } else { + EsMessageSend(window, message); + } + + // TODO Radio group navigation. + + if (window->enterButton && message->keyboard.scancode == ES_SCANCODE_ENTER && !message->keyboard.modifiers + && window->enterButton->onCommand && (~window->enterButton->flags & ES_ELEMENT_DISABLED)) { + window->enterButton->onCommand(window->instance, window->enterButton, window->enterButton->command); + } else if (window->escapeButton && message->keyboard.scancode == ES_SCANCODE_ESCAPE && !message->keyboard.modifiers + && window->escapeButton->onCommand && (~window->escapeButton->flags & ES_ELEMENT_DISABLED)) { + window->escapeButton->onCommand(window->instance, window->escapeButton, window->escapeButton->command); + } + + if (!window->hasDialog) { + // TODO Sort out what commands can be used from within dialogs and menus. + + if (message->keyboard.scancode == ES_SCANCODE_LEFT_ALT) { + gui.unhandledAltPress = true; + return; + } + + if (!gui.keyboardShortcutNames.itemCount) UIInitialiseKeyboardShortcutNamesTable(); + const char *shortcutName = (const char *) HashTableGetShort(&gui.keyboardShortcutNames, message->keyboard.scancode); + + if (shortcutName && window->instance && window->instance->_private) { + APIInstance *instance = (APIInstance *) window->instance->_private; + + char keyboardShortcutString[128]; + size_t bytes = EsStringFormat(keyboardShortcutString, 128, "%z%z%z%z%c", + (message->keyboard.modifiers & ES_MODIFIER_CTRL) ? "Ctrl+" : "", + (message->keyboard.modifiers & ES_MODIFIER_SHIFT) ? "Shift+" : "", + (message->keyboard.modifiers & ES_MODIFIER_ALT) ? "Alt+" : "", + shortcutName, 0) - 1; + + for (uintptr_t i = 0; i < instance->commands.Count(); i++) { + EsCommand *command = instance->commands[i]; + if (!command->cKeyboardShortcut || command->disabled) continue; + const char *position = EsCRTstrstr(command->cKeyboardShortcut, keyboardShortcutString); + if (!position) continue; + + if ((position[bytes] == 0 || position[bytes] == '|') && (position == command->cKeyboardShortcut || position[-1] == '|')) { + if (command->callback) { + command->callback(window->instance, nullptr, command); + } + + return; + } + } + } + } +} + +void UIWindowPaintNow(EsWindow *window, ProcessMessageTiming *timing, bool afterResize) { + if (window->doNotPaint) { + return; + } + + // Calculate the regions to repaint, and then perform painting. + + if (timing) timing->startPaint = EsTimeStampMs(); + + EsRectangle updateRegion = window->updateRegion; + + EsRectangle bounds = ES_RECT_4(0, window->windowWidth, 0, window->windowHeight); + EsRectangleClip(updateRegion, bounds, &updateRegion); + + if (THEME_RECT_VALID(updateRegion)) { + EsPainter painter = {}; + EsPaintTarget target = {}; + + target.fullAlpha = window->windowStyle != ES_WINDOW_NORMAL; + target.width = Width(updateRegion); + target.height = Height(updateRegion); + target.stride = target.width * 4; + target.bits = EsHeapAllocate(target.stride * target.height, false); + target.forWindowManager = true; + + if (!target.bits) { + return; // Insufficient memory for painting. + } + + EsMemoryFaultRange(target.bits, target.stride * target.height); + painter.offsetX -= updateRegion.l; + painter.offsetY -= updateRegion.t; + painter.clip = ES_RECT_4(0, target.width, 0, target.height); + painter.target = ⌖ + + window->updateRegionInProgress = updateRegion; + window->InternalPaint(&painter, ES_FLAGS_DEFAULT); + window->updateRegionInProgress = {}; + if (timing) timing->endPaint = EsTimeStampMs(); + + if (window->visualizeRepaints) { + EsDrawRectangle(&painter, painter.clip, 0, EsRandomU64(), ES_RECT_1(3)); + } + + // Update the screen. + if (timing) timing->startUpdate = EsTimeStampMs(); + EsSyscall(ES_SYSCALL_WINDOW_SET_BITS, window->handle, (uintptr_t) &updateRegion, (uintptr_t) target.bits, + afterResize ? WINDOW_SET_BITS_AFTER_RESIZE : WINDOW_SET_BITS_NORMAL); + if (timing) timing->endUpdate = EsTimeStampMs(); + + EsHeapFree(target.bits); + } + + window->updateRegion = ES_RECT_4(window->windowWidth, 0, window->windowHeight, 0); +} + +bool UISetCursor(EsWindow *window) { + EsCursorStyle cursorStyle = ES_CURSOR_NORMAL; + EsElement *element = window->pressed ?: window->hovered; + + if (element) { + EsMessage m = { ES_MSG_GET_CURSOR }; + + if (ES_HANDLED == EsMessageSend(element, &m)) { + cursorStyle = m.cursorStyle; + } else { + cursorStyle = (EsCursorStyle) element->currentStyle->metrics->cursor; + } + } + + // TODO Make these configurable in the theme file! + + int x, y, ox, oy, w, h; + +#define CURSOR(_constant, _x, _y, _ox, _oy, _w, _h) _constant: { x = _x; y = _y; ox = -_ox; oy = -_oy; w = _w; h = _h; } break + + switch (cursorStyle) { + CURSOR(case ES_CURSOR_TEXT, 84, 60, 4, 10, 11, 22); + CURSOR(case ES_CURSOR_RESIZE_VERTICAL, 44, 12, 4, 11, 11, 24); + CURSOR(case ES_CURSOR_RESIZE_HORIZONTAL, 68, 15, 11, 4, 24, 11); + CURSOR(case ES_CURSOR_RESIZE_DIAGONAL_1, 55, 35, 8, 8, 19, 19); + CURSOR(case ES_CURSOR_RESIZE_DIAGONAL_2, 82, 35, 8, 8, 19, 19); + CURSOR(case ES_CURSOR_SPLIT_VERTICAL, 37, 55, 4, 10, 12, 24); + CURSOR(case ES_CURSOR_SPLIT_HORIZONTAL, 56, 60, 10, 4, 24, 12); + CURSOR(case ES_CURSOR_HAND_HOVER, 131, 14, 8, 1, 21, 26); + CURSOR(case ES_CURSOR_HAND_DRAG, 107, 18, 7, 1, 20, 22); + CURSOR(case ES_CURSOR_HAND_POINT, 159, 14, 5, 1, 21, 26); + CURSOR(case ES_CURSOR_SCROLL_UP_LEFT, 217, 89, 9, 9, 16, 16); + CURSOR(case ES_CURSOR_SCROLL_UP, 193, 87, 5, 11, 13, 18); + CURSOR(case ES_CURSOR_SCROLL_UP_RIGHT, 234, 89, 4, 9, 16, 16); + CURSOR(case ES_CURSOR_SCROLL_LEFT, 175, 93, 11, 5, 18, 13); + CURSOR(case ES_CURSOR_SCROLL_CENTER, 165, 51, 12, 12, 28, 28); + CURSOR(case ES_CURSOR_SCROLL_RIGHT, 194, 106, 4, 4, 18, 13); + CURSOR(case ES_CURSOR_SCROLL_DOWN_LEFT, 216, 106, 10, 4, 16, 16); + CURSOR(case ES_CURSOR_SCROLL_DOWN, 182, 107, 4, 3, 12, 16); + CURSOR(case ES_CURSOR_SCROLL_DOWN_RIGHT, 234, 106, 4, 4, 16, 16); + CURSOR(case ES_CURSOR_SELECT_LINES, 7, 19, 10, 0, 16, 23); + CURSOR(case ES_CURSOR_DROP_TEXT, 11, 48, 1, 1, 21, 28); + CURSOR(case ES_CURSOR_CROSS_HAIR_PICK, 104, 56, 11, 11, 26, 26); + CURSOR(case ES_CURSOR_CROSS_HAIR_RESIZE, 134, 53, 11, 11, 26, 26); + CURSOR(case ES_CURSOR_MOVE_HOVER, 226, 13, 10, 10, 24, 32); + CURSOR(case ES_CURSOR_MOVE_DRAG, 197, 13, 10, 10, 24, 24); + CURSOR(case ES_CURSOR_ROTATE_HOVER, 228, 49, 9, 10, 24, 32); + CURSOR(case ES_CURSOR_ROTATE_DRAG, 198, 49, 9, 10, 22, 22); + CURSOR(case ES_CURSOR_BLANK, 5, 13, 0, 0, 1, 1); + CURSOR(default, 23, 18, 1, 1, 15, 24); + } + + bool _xor = cursorStyle == ES_CURSOR_TEXT; + + return EsSyscall(ES_SYSCALL_WINDOW_SET_CURSOR, window->handle, + (uintptr_t) theming.cursors.bits + x * 4 + y * theming.cursors.stride, + ((0xFF & ox) << 0) | ((0xFF & oy) << 8) | ((0xFF & w) << 16) | ((0xFF & h) << 24), + theming.cursors.stride | (cursorStyle << 24) | ((uint32_t) _xor << 31)); +} + +void UIProcessWindowManagerMessage(EsWindow *window, EsMessage *message, ProcessMessageTiming *timing) { + // Check if the window has been destroyed. + + if (message->type == ES_MSG_WINDOW_DESTROYED) { + if (window->destroyInstanceAfterClose) { + EsMessage m = {}; + m.type = ES_MSG_INSTANCE_DESTROY; + m.instanceDestroy.instance = window->instance; + EsAssert(window->instance->window == window); + window->instance->window = nullptr; + window->instance = nullptr; + EsMessagePost(nullptr, &m); + } + + EsAssert(window->handle == ES_INVALID_HANDLE); + EsHeapFree(window); + return; + } else if (window->handle == ES_INVALID_HANDLE) { + return; + } + + // Begin update. + + window->willUpdate = true; + + // Make sure any elements marked to be destroyed in between updates are actually destroyed, + // before we begin message processing. + + if (window->InternalDestroy()) { + // The window has been destroyed. + return; + } + + ProcessAnimations(); + UIFindHoverElement(window); + + // Process input message. + + if (timing) timing->startLogic = EsTimeStampMs(); + + if (message->type == ES_MSG_MOUSE_MOVED) { + window->mousePosition.x = message->mouseMoved.newPositionX; + window->mousePosition.y = message->mouseMoved.newPositionY; + + if ((!window->activated || window->targetMenu) && window->windowStyle == ES_WINDOW_NORMAL) { + window->hovering = false; + goto skipInputMessage; + } else if (window->dragged) { + if (gui.draggingStarted || DistanceSquared(message->mouseMoved.newPositionX - gui.lastClickX, + message->mouseMoved.newPositionY - gui.lastClickY) >= GetConstantNumber("dragThreshold")) { + EsRectangle bounds = window->dragged->GetWindowBounds(); + message->type = gui.lastClickButton == ES_MSG_MOUSE_LEFT_DOWN ? ES_MSG_MOUSE_LEFT_DRAG + : gui.lastClickButton == ES_MSG_MOUSE_RIGHT_DOWN ? ES_MSG_MOUSE_RIGHT_DRAG + : gui.lastClickButton == ES_MSG_MOUSE_MIDDLE_DOWN ? ES_MSG_MOUSE_MIDDLE_DRAG : (EsMessageType) 0; + EsAssert(message->type); + message->mouseDragged.originalPositionX = gui.lastClickX; + message->mouseDragged.originalPositionY = gui.lastClickY; + message->mouseDragged.newPositionX -= bounds.l; + message->mouseDragged.newPositionY -= bounds.t; + message->mouseDragged.originalPositionX -= bounds.l; + message->mouseDragged.originalPositionY -= bounds.t; + + if (ES_HANDLED == EsMessageSend(window->dragged, message)) { + gui.draggingStarted = true; + } + } + } else { + EsRectangle bounds = window->hovered->GetWindowBounds(); + message->mouseMoved.newPositionX -= bounds.l; + message->mouseMoved.newPositionY -= bounds.t; + EsMessageSend(window->hovered, message); + } + + window->hovering = true; + } else if (message->type == ES_MSG_MOUSE_EXIT) { + window->hovering = false; + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN || message->type == ES_MSG_MOUSE_RIGHT_DOWN || message->type == ES_MSG_MOUSE_MIDDLE_DOWN) { + window->mousePosition.x = message->mouseDown.positionX; + window->mousePosition.y = message->mouseDown.positionY; + + AccessKeyModeExit(); + + if (gui.mouseButtonDown || window->targetMenu) { + goto skipInputMessage; + } + + double timeStampMs = EsTimeStampMs(); + + if (gui.clickChainStartMs + api.global->clickChainTimeoutMs < timeStampMs + || window->hovered != gui.clickChainElement) { + // Start a new click chain. + gui.clickChainStartMs = timeStampMs; + gui.clickChainCount = 1; + gui.clickChainElement = window->hovered; + } else { + gui.clickChainStartMs = timeStampMs; + gui.clickChainCount++; + } + + message->mouseDown.clickChainCount = gui.clickChainCount; + + gui.lastClickX = message->mouseDown.positionX; + gui.lastClickY = message->mouseDown.positionY; + gui.lastClickButton = message->type; + gui.mouseButtonDown = true; + + if ((~window->hovered->flags & ES_ELEMENT_DISABLED) && (~window->hovered->state & UI_STATE_BLOCK_INTERACTION)) { + // If the hovered element is destroyed in response to one of these messages, + // window->hovered will be set to nullptr, so save the element here. + EsElement *element = window->hovered; + + element->state |= UI_STATE_PRESSED; + window->pressed = element; + EsMessage m = { ES_MSG_PRESSED_START }; + EsMessageSend(element, &m); + + EsRectangle bounds = element->GetWindowBounds(); + message->mouseDown.positionX -= bounds.l; + message->mouseDown.positionY -= bounds.t; + + if (ES_REJECTED != UIMessageSendPropagateToAncestors(element, message, &window->dragged)) { + if (window->dragged) { + EsElementFocus(window->dragged, false); + } + } + } + + if (window->hovered != window->focused && window->focused && (~window->focused->state & UI_STATE_LOST_STRONG_FOCUS)) { + EsMessage m = { ES_MSG_STRONG_FOCUS_END }; + window->focused->state |= UI_STATE_LOST_STRONG_FOCUS; + EsMessageSend(window->focused, &m); + } + } else if (message->type == ES_MSG_MOUSE_LEFT_UP || message->type == ES_MSG_MOUSE_RIGHT_UP || message->type == ES_MSG_MOUSE_MIDDLE_UP) { + AccessKeyModeExit(); + + if (gui.mouseButtonDown && gui.lastClickButton == message->type - 1) { + gui.mouseButtonDown = false; + window->dragged = nullptr; + UIMousePressReleased(window, message, true); + } + } else if (message->type == ES_MSG_KEY_UP || message->type == ES_MSG_KEY_DOWN) { + UIHandleKeyMessage(window, message); + + // If this key was on the numpad, translate it to the normal key. + + int numpad = 0, nshift = 0; + uint32_t scancode = message->keyboard.scancode; + bool allowShift = false; + + if (scancode == ES_SCANCODE_NUM_DIVIDE ) { numpad = ES_SCANCODE_SLASH; } + if (scancode == ES_SCANCODE_NUM_MULTIPLY) { numpad = ES_SCANCODE_8; nshift = 1; } + if (scancode == ES_SCANCODE_NUM_SUBTRACT) { numpad = ES_SCANCODE_HYPHEN; } + if (scancode == ES_SCANCODE_NUM_ADD ) { numpad = ES_SCANCODE_EQUALS; nshift = 1; } + if (scancode == ES_SCANCODE_NUM_ENTER ) { numpad = ES_SCANCODE_ENTER; } + + if (message->keyboard.numlock) { + if (scancode == ES_SCANCODE_NUM_POINT) { numpad = ES_SCANCODE_PERIOD; } + if (scancode == ES_SCANCODE_NUM_0 ) { numpad = ES_SCANCODE_0; } + if (scancode == ES_SCANCODE_NUM_1 ) { numpad = ES_SCANCODE_1; } + if (scancode == ES_SCANCODE_NUM_2 ) { numpad = ES_SCANCODE_2; } + if (scancode == ES_SCANCODE_NUM_3 ) { numpad = ES_SCANCODE_3; } + if (scancode == ES_SCANCODE_NUM_4 ) { numpad = ES_SCANCODE_4; } + if (scancode == ES_SCANCODE_NUM_5 ) { numpad = ES_SCANCODE_5; } + if (scancode == ES_SCANCODE_NUM_6 ) { numpad = ES_SCANCODE_6; } + if (scancode == ES_SCANCODE_NUM_7 ) { numpad = ES_SCANCODE_7; } + if (scancode == ES_SCANCODE_NUM_8 ) { numpad = ES_SCANCODE_8; } + if (scancode == ES_SCANCODE_NUM_9 ) { numpad = ES_SCANCODE_9; } + } else { + if (scancode == ES_SCANCODE_NUM_POINT) { numpad = ES_SCANCODE_DELETE; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_0 ) { numpad = ES_SCANCODE_INSERT; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_1 ) { numpad = ES_SCANCODE_END; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_2 ) { numpad = ES_SCANCODE_DOWN_ARROW; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_3 ) { numpad = ES_SCANCODE_PAGE_DOWN; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_4 ) { numpad = ES_SCANCODE_LEFT_ARROW; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_6 ) { numpad = ES_SCANCODE_RIGHT_ARROW; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_7 ) { numpad = ES_SCANCODE_HOME; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_8 ) { numpad = ES_SCANCODE_UP_ARROW; allowShift = true; } + if (scancode == ES_SCANCODE_NUM_9 ) { numpad = ES_SCANCODE_PAGE_UP; allowShift = true; } + } + + if (numpad && ((~message->keyboard.modifiers & ES_MODIFIER_SHIFT) || allowShift)) { + EsMessage m = *message; + m.type = message->type; + m.keyboard.modifiers = message->keyboard.modifiers | (nshift ? ES_MODIFIER_SHIFT : 0); + m.keyboard.scancode = numpad; + m.keyboard.numpad = true; + UIHandleKeyMessage(window, &m); + } + } else if (message->type == ES_MSG_WINDOW_RESIZED) { + AccessKeyModeExit(); + + gui.leftModifiers = gui.rightModifiers = 0; + gui.clickChainStartMs = 0; + + window->receivedFirstResize = true; + + window->width = window->windowWidth = message->windowResized.content.r; + window->height = window->windowHeight = message->windowResized.content.b; + + if (window->windowStyle == ES_WINDOW_CONTAINER) { + EsRectangle opaqueBounds = ES_RECT_4(WINDOW_INSET, window->windowWidth - WINDOW_INSET, + WINDOW_INSET, window->windowHeight - WINDOW_INSET); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, (uintptr_t) &opaqueBounds, 0, ES_WINDOW_PROPERTY_OPAQUE_BOUNDS); + } else if (window->windowStyle == ES_WINDOW_INSPECTOR) { + EsRectangle opaqueBounds = ES_RECT_4(0, window->windowWidth, 0, window->windowHeight); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, (uintptr_t) &opaqueBounds, 0, ES_WINDOW_PROPERTY_OPAQUE_BOUNDS); + } + + if (!message->windowResized.hidden) { + EsElementRelayout(window); + window->Repaint(true); + } + + EsMessageSend(window, message); + + for (uintptr_t i = 0; i < window->sizeAlternatives.Length(); i++) { + SizeAlternative *alternative = &window->sizeAlternatives[i]; + bool belowThreshold = window->width < alternative->widthThreshold * theming.scale + || window->height < alternative->heightThreshold * theming.scale; + EsElementSetHidden(alternative->small, !belowThreshold); + EsElementSetHidden(alternative->big, belowThreshold); + } + } else if (message->type == ES_MSG_WINDOW_DEACTIVATED) { + AccessKeyModeExit(); + + if (window->windowStyle == ES_WINDOW_MENU) { + window->Destroy(); + } else if (window->windowStyle == ES_WINDOW_CONTAINER) { + // Redraw window borders. + window->SetStyle(ES_STYLE_CONTAINER_WINDOW_INACTIVE); + window->Repaint(true); + } + + window->activated = false; + window->hovering = false; + + if (window->focused) { + window->inactiveFocus = window->focused; + window->inactiveFocus->Repaint(true); + UIRemoveFocusFromElement(window->focused); + window->focused = nullptr; + } + + EsMessageSend(window, message); + } else if (message->type == ES_MSG_WINDOW_ACTIVATED) { + AccessKeyModeExit(); + + gui.leftModifiers = gui.rightModifiers = 0; + gui.clickChainStartMs = 0; + + window->activated = true; + EsMessage m = { ES_MSG_WINDOW_ACTIVATED }; + EsMessageSend(window, &m); + + if (window->windowStyle == ES_WINDOW_CONTAINER) { + // Redraw window borders. + window->SetStyle(ES_STYLE_CONTAINER_WINDOW_ACTIVE); + window->Repaint(true); + } + + if (!window->focused && window->inactiveFocus) { + EsElementFocus(window->inactiveFocus, false); + window->inactiveFocus->Repaint(true); + window->inactiveFocus = nullptr; + } + + UIRefreshPrimaryClipboard(window); + } else if (message->type == ES_MSG_PRIMARY_CLIPBOARD_UPDATED) { + UIRefreshPrimaryClipboard(window); + } + + skipInputMessage:; + + if (timing) timing->endLogic = EsTimeStampMs(); + + // Destroy, relayout, and repaint elements as necessary. + + if (window->InternalDestroy()) { + // The window has been destroyed. + return; + } + + UIFindHoverElement(window); + + bool changedCursor = UISetCursor(window); + + if (window->receivedFirstResize || window->windowStyle != ES_WINDOW_NORMAL) { + if (timing) timing->startLayout = EsTimeStampMs(); + + window->InternalMove(window->width, window->height, 0, 0); + + if (window->ensureVisible) { + EsElement *child = window->ensureVisible, *e = window->ensureVisible; + + while (e->parent) { + EsMessage m = { ES_MSG_ENSURE_VISIBLE }; + m.child = child; + e = e->parent; + + if (ES_HANDLED == EsMessageSend(e, &m)) { + child = e; + } + } + + window->ensureVisible = nullptr; + } + + if (window->processCheckVisible) { + for (uintptr_t i = 0; i < window->checkVisible.Length(); i++) { + EsElement *element = window->checkVisible[i]; + EsAssert(element->state & UI_STATE_CHECK_VISIBLE); + EsRectangle bounds = element->GetWindowBounds(); + bool offScreen = bounds.r < 0 || bounds.b < 0 || bounds.l >= element->window->width || bounds.t >= element->window->height; + if (!offScreen) continue; + element->state &= ~UI_STATE_CHECK_VISIBLE; + window->checkVisible.Delete(i); + i--; + EsMessage m = { ES_MSG_NOT_VISIBLE }; + EsMessageSend(element, &m); + } + + window->processCheckVisible = false; + } + + if (timing) timing->endLayout = EsTimeStampMs(); + } + + if (THEME_RECT_VALID(window->updateRegion) && window->width == (int) window->windowWidth && window->height == (int) window->windowHeight) { + UIWindowPaintNow(window, timing, message->type == ES_MSG_WINDOW_RESIZED); + } else if (changedCursor) { + EsSyscall(ES_SYSCALL_SCREEN_FORCE_UPDATE, 0, 0, 0, 0); + } + + if (window->instance) { + APIInstance *instance = (APIInstance *) window->instance->_private; + EsUndoEndGroup(instance->activeUndoManager); + } + + // Free any unused styles. + + FreeUnusedStyles(); + + // Finish update. + + window->willUpdate = false; +} + +// --------------------------------- List view. + +#include "list_view.cpp" + +// --------------------------------- Inspector. + +struct InspectorElementEntry { + EsElement *element; + EsRectangle takenBounds, givenBounds; + int depth; +}; + +struct InspectorWindow : EsInstance { + EsInstance *instance; + + EsWindow *window; + + EsListView *elementList; + Array elements; + InspectorElementEntry hoveredElement; + char *cCategoryFilter; + + intptr_t selectedElement; + EsButton *alignH[6]; + EsButton *alignV[6]; + EsButton *direction[4]; + EsTextbox *contentTextbox; + EsButton *addChildButton; + EsButton *addSiblingButton; + EsButton *visualizeRepaints; + EsButton *visualizeLayoutBounds; + EsButton *visualizePaintSteps; + EsListView *listEvents; + EsTextbox *textboxCategoryFilter; +}; + +EsListViewColumn inspectorElementListColumns[] = { + { "Name", -1, 0, 300 }, + { "Bounds", -1, 0, 200 }, + { "Information", -1, 0, 200 }, +}; + +int InspectorElementItemCallback(EsElement *element, EsMessage *message) { + InspectorWindow *inspector = (InspectorWindow *) element->instance; + + if (message->type == ES_MSG_HOVERED_START) { + InspectorElementEntry *entry = &inspector->elements[EsListViewGetIndexFromItem(element).u]; + if (entry->element->parent) entry->element->parent->Repaint(true); + else entry->element->Repaint(true); + inspector->hoveredElement = *entry; + } else if (message->type == ES_MSG_HOVERED_END || message->type == ES_MSG_DESTROY) { + InspectorElementEntry *entry = &inspector->elements[EsListViewGetIndexFromItem(element).u]; + if (entry->element->parent) entry->element->parent->Repaint(true); + else entry->element->Repaint(true); + inspector->hoveredElement = {}; + } + + return 0; +} + +void InspectorUpdateEditor(InspectorWindow *inspector) { + EsElement *e = inspector->selectedElement == -1 ? nullptr : inspector->elements[inspector->selectedElement].element; + + bool isStack = e && e->messageClass == ProcessPanelMessage && !(e->flags & (ES_PANEL_Z_STACK | ES_PANEL_TABLE | ES_PANEL_SWITCHER)); + bool alignHLeft = e ? (e->flags & ES_CELL_H_LEFT) : false, alignHRight = e ? (e->flags & ES_CELL_H_RIGHT) : false; + bool alignHExpand = e ? (e->flags & ES_CELL_H_EXPAND) : false, alignHShrink = e ? (e->flags & ES_CELL_H_SHRINK) : false; + bool alignHPush = e ? (e->flags & ES_CELL_H_PUSH) : false; + bool alignVTop = e ? (e->flags & ES_CELL_V_TOP) : false, alignVBottom = e ? (e->flags & ES_CELL_V_BOTTOM) : false; + bool alignVExpand = e ? (e->flags & ES_CELL_V_EXPAND) : false, alignVShrink = e ? (e->flags & ES_CELL_V_SHRINK) : false; + bool alignVPush = e ? (e->flags & ES_CELL_V_PUSH) : false; + bool stackHorizontal = isStack && (e->flags & ES_PANEL_HORIZONTAL); + bool stackReverse = isStack && (e->flags & ES_PANEL_REVERSE); + + EsButtonSetCheck(inspector->alignH[0], (EsCheckState) (e && alignHLeft && !alignHRight), false); + EsButtonSetCheck(inspector->alignH[1], (EsCheckState) (e && alignHLeft == alignHRight), false); + EsButtonSetCheck(inspector->alignH[2], (EsCheckState) (e && !alignHLeft && alignHRight), false); + EsButtonSetCheck(inspector->alignH[3], (EsCheckState) (e && alignHExpand), false); + EsButtonSetCheck(inspector->alignH[4], (EsCheckState) (e && alignHShrink), false); + EsButtonSetCheck(inspector->alignH[5], (EsCheckState) (e && alignHPush), false); + + EsButtonSetCheck(inspector->alignV[0], (EsCheckState) (e && alignVTop && !alignVBottom), false); + EsButtonSetCheck(inspector->alignV[1], (EsCheckState) (e && alignVTop == alignVBottom), false); + EsButtonSetCheck(inspector->alignV[2], (EsCheckState) (e && !alignVTop && alignVBottom), false); + EsButtonSetCheck(inspector->alignV[3], (EsCheckState) (e && alignVExpand), false); + EsButtonSetCheck(inspector->alignV[4], (EsCheckState) (e && alignVShrink), false); + EsButtonSetCheck(inspector->alignV[5], (EsCheckState) (e && alignVPush), false); + + EsButtonSetCheck(inspector->direction[0], (EsCheckState) (isStack && stackHorizontal && stackReverse), false); + EsButtonSetCheck(inspector->direction[1], (EsCheckState) (isStack && stackHorizontal && !stackReverse), false); + EsButtonSetCheck(inspector->direction[2], (EsCheckState) (isStack && !stackHorizontal && stackReverse), false); + EsButtonSetCheck(inspector->direction[3], (EsCheckState) (isStack && !stackHorizontal && !stackReverse), false); + + EsElementSetDisabled(inspector->alignH[0], !e); + EsElementSetDisabled(inspector->alignH[1], !e); + EsElementSetDisabled(inspector->alignH[2], !e); + EsElementSetDisabled(inspector->alignH[3], !e); + EsElementSetDisabled(inspector->alignH[4], !e); + EsElementSetDisabled(inspector->alignH[5], !e); + EsElementSetDisabled(inspector->alignV[0], !e); + EsElementSetDisabled(inspector->alignV[1], !e); + EsElementSetDisabled(inspector->alignV[2], !e); + EsElementSetDisabled(inspector->alignV[3], !e); + EsElementSetDisabled(inspector->alignV[4], !e); + EsElementSetDisabled(inspector->alignV[5], !e); + EsElementSetDisabled(inspector->direction[0], !isStack); + EsElementSetDisabled(inspector->direction[1], !isStack); + EsElementSetDisabled(inspector->direction[2], !isStack); + EsElementSetDisabled(inspector->direction[3], !isStack); + EsElementSetDisabled(inspector->addChildButton, !isStack); + EsElementSetDisabled(inspector->addSiblingButton, !e || !e->parent); + + EsElementSetDisabled(inspector->textboxCategoryFilter, !e); + + EsTextboxSelectAll(inspector->contentTextbox); + EsTextboxInsert(inspector->contentTextbox, "", 0, false); + + if (e) { +#if 0 + for (uintptr_t i = 0; i < sizeof(builtinStyles) / sizeof(builtinStyles[0]); i++) { + if (e->currentStyleKey.partHash == CalculateCRC64(EsLiteral(builtinStyles[i]))) { + EsTextboxInsert(inspector->styleTextbox, builtinStyles[i], -1, false); + break; + } + } +#endif + + if (e->messageClass == ProcessButtonMessage) { + EsButton *button = (EsButton *) e; + EsElementSetDisabled(inspector->contentTextbox, false); + EsTextboxInsert(inspector->contentTextbox, button->label, button->labelBytes, false); + } else if (e->messageClass == ProcessTextDisplayMessage) { + EsTextDisplay *display = (EsTextDisplay *) e; + EsElementSetDisabled(inspector->contentTextbox, false); + EsTextboxInsert(inspector->contentTextbox, display->contents, display->textRuns[display->textRunCount].offset, false); + } else { + EsElementSetDisabled(inspector->contentTextbox, true); + } + } else { + EsElementSetDisabled(inspector->contentTextbox, true); + } +} + +int InspectorElementListCallback(EsElement *element, EsMessage *message) { + InspectorWindow *inspector = (InspectorWindow *) element->instance; + + if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) { + int column = message->getContent.column, index = message->getContent.index.i; + EsAssert(index >= 0 && index < (int) inspector->elements.Length()); + InspectorElementEntry *entry = &inspector->elements[index]; + + if (column == 0) { + EsBufferFormat(message->getContent.buffer, "%z", entry->element->cName); + } else if (column == 1) { + EsBufferFormat(message->getContent.buffer, "%R", entry->element->GetWindowBounds(false)); + } else if (column == 2) { + EsMessage m = *message; + m.type = ES_MSG_GET_INSPECTOR_INFORMATION; + EsMessageSend(entry->element, &m); + } + + return ES_HANDLED; + } else if (message->type == ES_MSG_LIST_VIEW_GET_INDENT) { + message->getIndent.indent = inspector->elements[message->getIndent.index.i].depth; + return ES_HANDLED; + } else if (message->type == ES_MSG_LIST_VIEW_CREATE_ITEM) { + message->createItem.item->messageUser = InspectorElementItemCallback; + return ES_HANDLED; + } else if (message->type == ES_MSG_LIST_VIEW_SELECT) { + if (inspector->selectedElement != -1) { + inspector->elements[inspector->selectedElement].element->state &= ~UI_STATE_INSPECTING; + } + + inspector->selectedElement = message->selectItem.isSelected ? message->selectItem.index.i : -1; + + if (inspector->selectedElement != -1) { + EsElement *e = inspector->elements[inspector->selectedElement].element; + e->state |= UI_STATE_INSPECTING; + InspectorNotifyElementEvent(e, nullptr, "Viewing events from '%z'.\n", e->cName); + } + + InspectorUpdateEditor(inspector); + return ES_HANDLED; + } else if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED) { + message->selectItem.isSelected = message->selectItem.index.i == inspector->selectedElement; + return ES_HANDLED; + } + + return 0; +} + +int InspectorContentTextboxCallback(EsElement *element, EsMessage *message) { + InspectorWindow *inspector = (InspectorWindow *) element->instance; + + if (message->type == ES_MSG_TEXTBOX_EDIT_END) { + size_t newContentBytes; + char *newContent = EsTextboxGetContents(inspector->contentTextbox, &newContentBytes); + EsElement *e = inspector->elements[inspector->selectedElement].element; + + if (e->messageClass == ProcessButtonMessage) { + EsButton *button = (EsButton *) e; + HeapDuplicate((void **) &button->label, newContent, newContentBytes); + button->labelBytes = newContentBytes; + } else if (e->messageClass == ProcessTextDisplayMessage) { + EsTextDisplay *display = (EsTextDisplay *) e; + EsTextDisplaySetContents(display, newContent, newContentBytes); + } else { + EsAssert(false); + } + + EsElementUpdateContentSize(e); + if (e->parent) EsElementUpdateContentSize(e->parent); + EsHeapFree(newContent); + return ES_HANDLED; + } + + return 0; +} + +int InspectorTextboxCategoryFilterCallback(EsElement *element, EsMessage *message) { + InspectorWindow *inspector = (InspectorWindow *) element->instance; + + if (message->type == ES_MSG_TEXTBOX_UPDATED) { + EsHeapFree(inspector->cCategoryFilter); + inspector->cCategoryFilter = EsTextboxGetContents((EsTextbox *) element); + } + + return 0; +} + +InspectorWindow *InspectorGet(EsElement *element) { + if (!element->window || !element->instance) return nullptr; + APIInstance *instance = (APIInstance *) element->instance->_private; + InspectorWindow *inspector = instance->attachedInspector; + if (!inspector || inspector->instance->window != element->window) return nullptr; + return inspector; +} + +void InspectorNotifyElementEvent(EsElement *element, const char *cCategory, const char *cFormat, ...) { + if (~element->state & UI_STATE_INSPECTING) return; + InspectorWindow *inspector = InspectorGet(element); + if (!inspector) return; + if (inspector->cCategoryFilter && inspector->cCategoryFilter[0] && cCategory && EsCRTstrcmp(cCategory, inspector->cCategoryFilter)) return; + va_list arguments; + va_start(arguments, cFormat); + char _buffer[256]; + EsBuffer buffer = { .out = (uint8_t *) _buffer, .bytes = sizeof(_buffer) }; + if (cCategory) EsBufferFormat(&buffer, "%z: ", cCategory); + EsBufferFormatV(&buffer, cFormat, arguments); + va_end(arguments); + EsListViewInsertFixedItem(inspector->listEvents, _buffer, buffer.position); + EsListViewScrollToEnd(inspector->listEvents); +} + +void InspectorNotifyElementContentChanged(EsElement *element) { + InspectorWindow *inspector = InspectorGet(element); + if (!inspector) return; + + for (uintptr_t i = 0; i < inspector->elements.Length(); i++) { + if (inspector->elements[i].element == element) { + EsListViewInvalidateContent(inspector->elementList, 0, i); + return; + } + } + + EsAssert(false); +} + +void InspectorNotifyElementMoved(EsElement *element, EsRectangle takenBounds) { + InspectorWindow *inspector = InspectorGet(element); + if (!inspector) return; + + for (uintptr_t i = 0; i < inspector->elements.Length(); i++) { + if (inspector->elements[i].element == element) { + inspector->elements[i].takenBounds = takenBounds; + inspector->elements[i].givenBounds = takenBounds; // TODO. + EsListViewInvalidateContent(inspector->elementList, 0, i); + return; + } + } + + EsAssert(false); +} + +void InspectorNotifyElementDestroyed(EsElement *element) { + InspectorWindow *inspector = InspectorGet(element); + if (!inspector) return; + + for (uintptr_t i = 0; i < inspector->elements.Length(); i++) { + if (inspector->elements[i].element == element) { + if (inspector->selectedElement == (intptr_t) i) { + inspector->selectedElement = -1; + InspectorUpdateEditor(inspector); + } else if (inspector->selectedElement > (intptr_t) i) { + inspector->selectedElement--; + } + + EsListViewRemove(inspector->elementList, 0, i, i); + inspector->elements.Delete(i); + return; + } + } + + EsAssert(false); +} + +void InspectorNotifyElementCreated(EsElement *element) { + InspectorWindow *inspector = InspectorGet(element); + if (!inspector) return; + + ptrdiff_t indexInParent = -1; + + for (uintptr_t i = 0; i < element->parent->children.Length(); i++) { + if (element->parent->children[i] == element) { + indexInParent = i; + break; + } + } + + EsAssert(indexInParent != -1); + + ptrdiff_t insertAfterIndex = -1; + + for (uintptr_t i = 0; i < inspector->elements.Length(); i++) { + if (indexInParent == 0) { + if (inspector->elements[i].element == element->parent) { + insertAfterIndex = i; + break; + } + } else { + if (inspector->elements[i].element == element->parent->children[indexInParent - 1]) { + insertAfterIndex = i; + int baseDepth = inspector->elements[i++].depth; + + for (; i < inspector->elements.Length(); i++) { + if (inspector->elements[i].depth > baseDepth) { + insertAfterIndex++; + } else { + break; + } + } + + break; + } + } + } + + EsAssert(insertAfterIndex != -1); + + int depth = 0; + EsElement *ancestor = element->parent; + + while (ancestor) { + depth++; + ancestor = ancestor->parent; + } + + if (inspector->selectedElement > insertAfterIndex) { + inspector->selectedElement++; + } + + InspectorElementEntry entry; + entry.element = element; + entry.depth = depth; + inspector->elements.Insert(entry, insertAfterIndex + 1); + EsListViewInsert(inspector->elementList, 0, insertAfterIndex + 1, insertAfterIndex + 1); +} + +void InspectorFindElementsRecursively(InspectorWindow *inspector, EsElement *element, int depth) { + InspectorElementEntry entry = {}; + entry.element = element; + entry.depth = depth; + inspector->elements.Add(entry); + + for (uintptr_t i = 0; i < element->children.Length(); i++) { + InspectorFindElementsRecursively(inspector, element->children[i], depth + 1); + } +} + +void InspectorRefreshElementList(InspectorWindow *inspector) { + EsListViewRemoveAll(inspector->elementList, 0); + inspector->elements.Free(); + InspectorFindElementsRecursively(inspector, inspector->instance->window, 0); + EsListViewInsert(inspector->elementList, 0, 0, inspector->elements.Length() - 1); +} + +void InspectorNotifyElementPainted(EsElement *element, EsPainter *painter) { + InspectorWindow *inspector = InspectorGet(element); + if (!inspector) return; + + InspectorElementEntry *entry = inspector->hoveredElement.element ? &inspector->hoveredElement : nullptr; + if (!entry) return; + + EsRectangle bounds = ES_RECT_4(painter->offsetX, painter->offsetX + painter->width, + painter->offsetY, painter->offsetY + painter->height); + + if (entry->element == element) { + EsDrawRectangle(painter, bounds, 0x607F7FFF, 0x60FFFF7F, element->currentStyle->insets); + } else if (entry->element->parent == element) { + if ((element->flags & ES_CELL_FILL) != ES_CELL_FILL) { + EsRectangle rectangle = entry->givenBounds; + rectangle.l += bounds.l, rectangle.r += bounds.l; + rectangle.t += bounds.t, rectangle.b += bounds.t; + // EsDrawBlock(painter, rectangle, 0x20FF7FFF); + } + } +} + +#define INSPECTOR_ALIGN_COMMAND(name, clear, set, toggle) \ +void name (EsInstance *instance, EsElement *, EsCommand *) { \ + InspectorWindow *inspector = (InspectorWindow *) instance; \ + EsElement *e = inspector->elements[inspector->selectedElement].element; \ + if (toggle) e->flags ^= set; \ + else { e->flags &= ~(clear); e->flags |= set; } \ + EsElementUpdateContentSize(e); \ + if (e->parent) EsElementUpdateContentSize(e->parent); \ + inspector->elementList->Repaint(true); \ + InspectorUpdateEditor(inspector); \ +} + +INSPECTOR_ALIGN_COMMAND(InspectorHAlignLeft, ES_CELL_H_LEFT | ES_CELL_H_RIGHT, ES_CELL_H_LEFT, false); +INSPECTOR_ALIGN_COMMAND(InspectorHAlignCenter, ES_CELL_H_LEFT | ES_CELL_H_RIGHT, ES_CELL_H_LEFT | ES_CELL_H_RIGHT, false); +INSPECTOR_ALIGN_COMMAND(InspectorHAlignRight, ES_CELL_H_LEFT | ES_CELL_H_RIGHT, ES_CELL_H_RIGHT, false); +INSPECTOR_ALIGN_COMMAND(InspectorHAlignExpand, 0, ES_CELL_H_EXPAND, true); +INSPECTOR_ALIGN_COMMAND(InspectorHAlignShrink, 0, ES_CELL_H_SHRINK, true); +INSPECTOR_ALIGN_COMMAND(InspectorHAlignPush, 0, ES_CELL_H_PUSH, true); +INSPECTOR_ALIGN_COMMAND(InspectorVAlignTop, ES_CELL_V_TOP | ES_CELL_V_BOTTOM, ES_CELL_V_TOP, false); +INSPECTOR_ALIGN_COMMAND(InspectorVAlignCenter, ES_CELL_V_TOP | ES_CELL_V_BOTTOM, ES_CELL_V_TOP | ES_CELL_V_BOTTOM, false); +INSPECTOR_ALIGN_COMMAND(InspectorVAlignBottom, ES_CELL_V_TOP | ES_CELL_V_BOTTOM, ES_CELL_V_BOTTOM, false); +INSPECTOR_ALIGN_COMMAND(InspectorVAlignExpand, 0, ES_CELL_V_EXPAND, true); +INSPECTOR_ALIGN_COMMAND(InspectorVAlignShrink, 0, ES_CELL_V_SHRINK, true); +INSPECTOR_ALIGN_COMMAND(InspectorVAlignPush, 0, ES_CELL_V_PUSH, true); +INSPECTOR_ALIGN_COMMAND(InspectorDirectionLeft, ES_PANEL_HORIZONTAL | ES_PANEL_REVERSE | ES_ELEMENT_LAYOUT_HINT_HORIZONTAL | ES_ELEMENT_LAYOUT_HINT_REVERSE, + ES_PANEL_HORIZONTAL | ES_PANEL_REVERSE | ES_ELEMENT_LAYOUT_HINT_HORIZONTAL | ES_ELEMENT_LAYOUT_HINT_REVERSE, false); +INSPECTOR_ALIGN_COMMAND(InspectorDirectionRight, ES_PANEL_HORIZONTAL | ES_PANEL_REVERSE | ES_ELEMENT_LAYOUT_HINT_HORIZONTAL | ES_ELEMENT_LAYOUT_HINT_REVERSE, + ES_PANEL_HORIZONTAL | ES_ELEMENT_LAYOUT_HINT_HORIZONTAL, false); +INSPECTOR_ALIGN_COMMAND(InspectorDirectionUp, ES_PANEL_HORIZONTAL | ES_PANEL_REVERSE | ES_ELEMENT_LAYOUT_HINT_HORIZONTAL | ES_ELEMENT_LAYOUT_HINT_REVERSE, + ES_PANEL_REVERSE | ES_ELEMENT_LAYOUT_HINT_REVERSE, false); +INSPECTOR_ALIGN_COMMAND(InspectorDirectionDown, ES_PANEL_HORIZONTAL | ES_PANEL_REVERSE | ES_ELEMENT_LAYOUT_HINT_HORIZONTAL | ES_ELEMENT_LAYOUT_HINT_REVERSE, 0, false); + +void InspectorVisualizeRepaints(EsInstance *instance, EsElement *, EsCommand *) { + InspectorWindow *inspector = (InspectorWindow *) instance; + EsWindow *window = inspector->instance->window; + window->visualizeRepaints = !window->visualizeRepaints; + EsButtonSetCheck(inspector->visualizeRepaints, window->visualizeRepaints ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false); +} + +void InspectorVisualizePaintSteps(EsInstance *instance, EsElement *, EsCommand *) { + InspectorWindow *inspector = (InspectorWindow *) instance; + EsWindow *window = inspector->instance->window; + window->visualizePaintSteps = !window->visualizePaintSteps; + EsButtonSetCheck(inspector->visualizePaintSteps, window->visualizePaintSteps ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false); +} + +void InspectorVisualizeLayoutBounds(EsInstance *instance, EsElement *, EsCommand *) { + InspectorWindow *inspector = (InspectorWindow *) instance; + EsWindow *window = inspector->instance->window; + window->visualizeLayoutBounds = !window->visualizeLayoutBounds; + EsButtonSetCheck(inspector->visualizeLayoutBounds, window->visualizeLayoutBounds ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false); + EsElementRepaint(window); +} + +void InspectorAddElement2(EsMenu *menu, EsGeneric context) { + InspectorWindow *inspector = (InspectorWindow *) menu->instance; + if (inspector->selectedElement == -1) return; + EsElement *e = inspector->elements[inspector->selectedElement].element; + int asSibling = context.u & 0x80; + context.u &= ~0x80; + + if (asSibling) { + EsElementInsertAfter(e); + e = e->parent; + } + + if (context.u == 1) { + EsButtonCreate(e); + } else if (context.u == 2) { + EsPanelCreate(e); + } else if (context.u == 3) { + EsSpacerCreate(e); + } else if (context.u == 4) { + EsTextboxCreate(e); + } else if (context.u == 5) { + EsTextDisplayCreate(e); + } +} + +void InspectorAddElement(EsInstance *, EsElement *element, EsCommand *) { + EsMenu *menu = EsMenuCreate(element, ES_FLAGS_DEFAULT); + EsMenuAddItem(menu, 0, "Add button", -1, InspectorAddElement2, element->userData.u | 1); + EsMenuAddItem(menu, 0, "Add panel", -1, InspectorAddElement2, element->userData.u | 2); + EsMenuAddItem(menu, 0, "Add spacer", -1, InspectorAddElement2, element->userData.u | 3); + EsMenuAddItem(menu, 0, "Add textbox", -1, InspectorAddElement2, element->userData.u | 4); + EsMenuAddItem(menu, 0, "Add text display", -1, InspectorAddElement2, element->userData.u | 5); + EsMenuShow(menu); +} + +void InspectorSetup(EsWindow *window) { + InspectorWindow *inspector = (InspectorWindow *) EsHeapAllocate(sizeof(InspectorWindow), true); // TODO Freeing this. + inspector->window = window; + InstanceSetup(inspector); + inspector->instance = window->instance; + window->instance = inspector; + + inspector->selectedElement = -1; + + EsPanel *panel = EsPanelCreate(window, ES_CELL_FILL, ES_STYLE_PANEL_FILLED); + + { + EsPanel *toolbar = EsPanelCreate(panel, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_TOOLBAR); + inspector->visualizeRepaints = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR, 0, "Visualize repaints"); + EsButtonOnCommand(inspector->visualizeRepaints, InspectorVisualizeRepaints); + inspector->visualizeLayoutBounds = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR, 0, "Visualize layout bounds"); + EsButtonOnCommand(inspector->visualizeLayoutBounds, InspectorVisualizeLayoutBounds); + inspector->visualizePaintSteps = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR, 0, "Visualize paint steps"); + EsButtonOnCommand(inspector->visualizePaintSteps, InspectorVisualizePaintSteps); + } + + inspector->elementList = EsListViewCreate(panel, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_SINGLE_SELECT); + inspector->elementList->messageUser = InspectorElementListCallback; + EsListViewSetColumns(inspector->elementList, inspectorElementListColumns, sizeof(inspectorElementListColumns) / sizeof(EsListViewColumn)); + EsListViewInsertGroup(inspector->elementList, 0); + + { + EsPanel *toolbar = EsPanelCreate(panel, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_TOOLBAR); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + EsTextDisplayCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, "Horizontal:"); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + inspector->alignH[0] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->alignH[0], ES_ICON_ALIGN_HORIZONTAL_LEFT); + EsButtonOnCommand(inspector->alignH[0], InspectorHAlignLeft); + inspector->alignH[1] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->alignH[1], ES_ICON_ALIGN_HORIZONTAL_CENTER); + EsButtonOnCommand(inspector->alignH[1], InspectorHAlignCenter); + inspector->alignH[2] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->alignH[2], ES_ICON_ALIGN_HORIZONTAL_RIGHT); + EsButtonOnCommand(inspector->alignH[2], InspectorHAlignRight); + inspector->alignH[3] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED, 0, "Expand"); + EsButtonOnCommand(inspector->alignH[3], InspectorHAlignExpand); + inspector->alignH[4] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED, 0, "Shrink"); + EsButtonOnCommand(inspector->alignH[4], InspectorHAlignShrink); + inspector->alignH[5] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED, 0, "Push"); + EsButtonOnCommand(inspector->alignH[5], InspectorHAlignPush); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + EsTextDisplayCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, "Vertical:"); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + inspector->alignV[0] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->alignV[0], ES_ICON_ALIGN_VERTICAL_TOP); + EsButtonOnCommand(inspector->alignV[0], InspectorVAlignTop); + inspector->alignV[1] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->alignV[1], ES_ICON_ALIGN_VERTICAL_CENTER); + EsButtonOnCommand(inspector->alignV[1], InspectorVAlignCenter); + inspector->alignV[2] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->alignV[2], ES_ICON_ALIGN_VERTICAL_BOTTOM); + EsButtonOnCommand(inspector->alignV[2], InspectorVAlignBottom); + inspector->alignV[3] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED, 0, "Expand"); + EsButtonOnCommand(inspector->alignV[3], InspectorVAlignExpand); + inspector->alignV[4] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED, 0, "Shrink"); + EsButtonOnCommand(inspector->alignV[4], InspectorVAlignShrink); + inspector->alignV[5] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED, 0, "Push"); + EsButtonOnCommand(inspector->alignV[5], InspectorVAlignPush); + } + + { + EsPanel *toolbar = EsPanelCreate(panel, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_TOOLBAR); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + EsTextDisplayCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, "Stack:"); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + inspector->direction[0] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->direction[0], ES_ICON_GO_PREVIOUS); + EsButtonOnCommand(inspector->direction[0], InspectorDirectionLeft); + inspector->direction[1] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->direction[1], ES_ICON_GO_NEXT); + EsButtonOnCommand(inspector->direction[1], InspectorDirectionRight); + inspector->direction[2] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->direction[2], ES_ICON_GO_UP); + EsButtonOnCommand(inspector->direction[2], InspectorDirectionUp); + inspector->direction[3] = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_ELEMENT_DISABLED); + EsButtonSetIcon(inspector->direction[3], ES_ICON_GO_DOWN); + EsButtonOnCommand(inspector->direction[3], InspectorDirectionDown); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 25, 0); + inspector->addChildButton = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_BUTTON_DROPDOWN | ES_ELEMENT_DISABLED | ES_BUTTON_COMPACT, nullptr, "Add child... "); + EsButtonOnCommand(inspector->addChildButton, InspectorAddElement); + inspector->addSiblingButton = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR | ES_BUTTON_DROPDOWN | ES_ELEMENT_DISABLED | ES_BUTTON_COMPACT, nullptr, "Add sibling... "); + inspector->addSiblingButton->userData.i = 0x80; + EsButtonOnCommand(inspector->addSiblingButton, InspectorAddElement); + } + + { + EsPanel *toolbar = EsPanelCreate(panel, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_TOOLBAR); + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 5, 0); + EsTextDisplayCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, "Content:"); + inspector->contentTextbox = EsTextboxCreate(toolbar, ES_ELEMENT_DISABLED | ES_TEXTBOX_EDIT_BASED); + inspector->contentTextbox->messageUser = InspectorContentTextboxCallback; + EsSpacerCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, 25, 0); + EsTextDisplayCreate(toolbar, ES_FLAGS_DEFAULT, nullptr, "Event category filter:"); + inspector->textboxCategoryFilter = EsTextboxCreate(toolbar, ES_ELEMENT_DISABLED); + inspector->textboxCategoryFilter->messageUser = InspectorTextboxCategoryFilterCallback; + } + + { + inspector->listEvents = EsListViewCreate(panel, ES_CELL_FILL | ES_LIST_VIEW_CHOICE_SELECT | ES_LIST_VIEW_FIXED_ITEMS, ES_STYLE_LIST_CHOICE_BORDERED); + } + + InspectorRefreshElementList(inspector); + + APIInstance *instance = (APIInstance *) inspector->instance->_private; + instance->attachedInspector = inspector; +} diff --git a/desktop/icons.header b/desktop/icons.header new file mode 100644 index 0000000..d7ceb48 --- /dev/null +++ b/desktop/icons.header @@ -0,0 +1,1067 @@ +enum EsStandardIcon { // Taken from the elementary icon pack, see res/Icons for license. + ES_ICON_NONE + ES_ICON_ACTION_UNAVAILABLE_SYMBOLIC + ES_ICON_ADDRESS_BOOK_NEW + ES_ICON_ADDRESS_BOOK_NEW_SYMBOLIC + ES_ICON_ALIGN_HORIZONTAL_CENTER + ES_ICON_ALIGN_HORIZONTAL_CENTER_SYMBOLIC + ES_ICON_ALIGN_HORIZONTAL_LEFT + ES_ICON_ALIGN_HORIZONTAL_LEFT_SYMBOLIC + ES_ICON_ALIGN_HORIZONTAL_LEFT_TO_ANCHOR + ES_ICON_ALIGN_HORIZONTAL_LEFT_TO_ANCHOR_SYMBOLIC + ES_ICON_ALIGN_HORIZONTAL_RIGHT + ES_ICON_ALIGN_HORIZONTAL_RIGHT_SYMBOLIC + ES_ICON_ALIGN_HORIZONTAL_RIGHT_TO_ANCHOR + ES_ICON_ALIGN_HORIZONTAL_RIGHT_TO_ANCHOR_SYMBOLIC + ES_ICON_ALIGN_VERTICAL_BOTTOM + ES_ICON_ALIGN_VERTICAL_BOTTOM_SYMBOLIC + ES_ICON_ALIGN_VERTICAL_BOTTOM_TO_ANCHOR + ES_ICON_ALIGN_VERTICAL_BOTTOM_TO_ANCHOR_SYMBOLIC + ES_ICON_ALIGN_VERTICAL_CENTER + ES_ICON_ALIGN_VERTICAL_CENTER_SYMBOLIC + ES_ICON_ALIGN_VERTICAL_TOP + ES_ICON_ALIGN_VERTICAL_TOP_SYMBOLIC + ES_ICON_ALIGN_VERTICAL_TOP_TO_ANCHOR + ES_ICON_ALIGN_VERTICAL_TOP_TO_ANCHOR_SYMBOLIC + ES_ICON_APPLICATION_ADD_SYMBOLIC + ES_ICON_APPOINTMENT_NEW + ES_ICON_APPOINTMENT_NEW_SYMBOLIC + ES_ICON_APPOINTMENT_SYMBOLIC + ES_ICON_BOOKMARK_NEW + ES_ICON_BOOKMARK_NEW_SYMBOLIC + ES_ICON_BROWSER_DOWNLOAD + ES_ICON_BROWSER_DOWNLOAD_SYMBOLIC + ES_ICON_CALL_START + ES_ICON_CALL_START_SYMBOLIC + ES_ICON_CALL_STOP + ES_ICON_CALL_STOP_SYMBOLIC + ES_ICON_COLOR_FILL + ES_ICON_COLOR_GRADIENT + ES_ICON_COLOR_GRADIENT_MESH + ES_ICON_COLOR_SELECT_SYMBOLIC + ES_ICON_CONTACT_NEW + ES_ICON_CONTACT_NEW_SYMBOLIC + ES_ICON_DISTRIBUTE_HORIZONTAL_CENTER + ES_ICON_DISTRIBUTE_HORIZONTAL_GAPS + ES_ICON_DISTRIBUTE_HORIZONTAL_LEFT + ES_ICON_DISTRIBUTE_HORIZONTAL_RIGHT + ES_ICON_DISTRIBUTE_VERTICAL_BOTTOM + ES_ICON_DISTRIBUTE_VERTICAL_CENTER + ES_ICON_DISTRIBUTE_VERTICAL_GAPS + ES_ICON_DISTRIBUTE_VERTICAL_TOP + ES_ICON_DOCUMENT_EDIT + ES_ICON_DOCUMENT_EDIT_SYMBOLIC + ES_ICON_DOCUMENT_EXPORT + ES_ICON_DOCUMENT_EXPORT_SYMBOLIC + ES_ICON_DOCUMENT_IMPORT + ES_ICON_DOCUMENT_IMPORT_SYMBOLIC + ES_ICON_DOCUMENT_NEW + ES_ICON_DOCUMENT_NEW_SYMBOLIC + ES_ICON_DOCUMENT_OPEN_RECENT + ES_ICON_DOCUMENT_OPEN_RECENT_SYMBOLIC + ES_ICON_DOCUMENT_OPEN_SYMBOLIC + ES_ICON_DOCUMENT_PAGE_SETUP + ES_ICON_DOCUMENT_PAGE_SETUP_SYMBOLIC + ES_ICON_DOCUMENT_PRINT_PREVIEW + ES_ICON_DOCUMENT_PRINT_PREVIEW_SYMBOLIC + ES_ICON_DOCUMENT_PRINT_SYMBOLIC + ES_ICON_DOCUMENT_PROPERTIES + ES_ICON_DOCUMENT_PROPERTIES_SYMBOLIC + ES_ICON_DOCUMENT_REVERT + ES_ICON_DOCUMENT_REVERT_SYMBOLIC + ES_ICON_DOCUMENT_SAVE_AS + ES_ICON_DOCUMENT_SAVE_AS_SYMBOLIC + ES_ICON_DOCUMENT_SAVE_SYMBOLIC + ES_ICON_DOCUMENT_SEND + ES_ICON_DOCUMENT_SEND_SYMBOLIC + ES_ICON_DRAW_CUBOID + ES_ICON_DRAW_ELLIPSE + ES_ICON_DRAW_ERASER + ES_ICON_DRAW_FREEHAND + ES_ICON_DRAW_PATH + ES_ICON_DRAW_POLYGON_STAR + ES_ICON_DRAW_RECTANGLE + ES_ICON_DRAW_SPIRAL + ES_ICON_DRAW_TEXT + ES_ICON_EDIT_CLEAR + ES_ICON_EDIT_CLEAR_ALL_SYMBOLIC + ES_ICON_EDIT_CLEAR_SYMBOLIC + ES_ICON_EDIT_COPY + ES_ICON_EDIT_COPY_SYMBOLIC + ES_ICON_EDIT_CUT + ES_ICON_EDIT_CUT_SYMBOLIC + ES_ICON_EDIT_DELETE_SYMBOLIC + ES_ICON_EDIT_FIND + ES_ICON_EDIT_FIND_REPLACE + ES_ICON_EDIT_FIND_REPLACE_SYMBOLIC + ES_ICON_EDIT_FIND_SYMBOLIC + ES_ICON_EDIT_FLAG + ES_ICON_EDIT_FLAG_SYMBOLIC + ES_ICON_EDIT_MARK + ES_ICON_EDIT_PASTE + ES_ICON_EDIT_PASTE_SYMBOLIC + ES_ICON_EDIT_REDO + ES_ICON_EDIT_REDO_SYMBOLIC + ES_ICON_EDIT_SELECT_ALL + ES_ICON_EDIT_SELECT_ALL_SYMBOLIC + ES_ICON_EDIT_SELECT_SYMBOLIC + ES_ICON_EDIT_UNDO + ES_ICON_EDIT_UNDO_ARCHIVE + ES_ICON_EDIT_UNDO_SYMBOLIC + ES_ICON_ERROR_CORRECT_SYMBOLIC + ES_ICON_EVENT_NEW + ES_ICON_FIND_LOCATION + ES_ICON_FIND_LOCATION_SYMBOLIC + ES_ICON_FOLDER_COPY + ES_ICON_FOLDER_MOVE + ES_ICON_FOLDER_NEW + ES_ICON_FOLDER_NEW_SYMBOLIC + ES_ICON_FONT_SELECT_SYMBOLIC + ES_ICON_FORMAT_INDENT_LESS + ES_ICON_FORMAT_INDENT_LESS_SYMBOLIC + ES_ICON_FORMAT_INDENT_MORE + ES_ICON_FORMAT_INDENT_MORE_SYMBOLIC + ES_ICON_FORMAT_JUSTIFY_CENTER + ES_ICON_FORMAT_JUSTIFY_CENTER_SYMBOLIC + ES_ICON_FORMAT_JUSTIFY_FILL + ES_ICON_FORMAT_JUSTIFY_FILL_SYMBOLIC + ES_ICON_FORMAT_JUSTIFY_LEFT + ES_ICON_FORMAT_JUSTIFY_LEFT_SYMBOLIC + ES_ICON_FORMAT_JUSTIFY_RIGHT + ES_ICON_FORMAT_JUSTIFY_RIGHT_SYMBOLIC + ES_ICON_FORMAT_TEXT_BOLD + ES_ICON_FORMAT_TEXT_BOLD_ES_SYMBOLIC + ES_ICON_FORMAT_TEXT_BOLD_FR_SYMBOLIC + ES_ICON_FORMAT_TEXT_BOLD_SYMBOLIC + ES_ICON_FORMAT_TEXT_CLEAR_FORMATTING_SYMBOLIC + ES_ICON_FORMAT_TEXT_DIRECTION_LTR_SYMBOLIC + ES_ICON_FORMAT_TEXT_HIGHLIGHT + ES_ICON_FORMAT_TEXT_ITALIC + ES_ICON_FORMAT_TEXT_ITALIC_ES_SYMBOLIC + ES_ICON_FORMAT_TEXT_ITALIC_SYMBOLIC + ES_ICON_FORMAT_TEXT_LARGER_SYMBOLIC + ES_ICON_FORMAT_TEXT_NONE + ES_ICON_FORMAT_TEXT_SMALLER_SYMBOLIC + ES_ICON_FORMAT_TEXT_STRIKETHROUGH + ES_ICON_FORMAT_TEXT_STRIKETHROUGH_FR_SYMBOLIC + ES_ICON_FORMAT_TEXT_STRIKETHROUGH_SYMBOLIC + ES_ICON_FORMAT_TEXT_UNDERLINE + ES_ICON_FORMAT_TEXT_UNDERLINE_FR_SYMBOLIC + ES_ICON_FORMAT_TEXT_UNDERLINE_SYMBOLIC + ES_ICON_GO_BOTTOM + ES_ICON_GO_BOTTOM_SYMBOLIC + ES_ICON_GO_DOWN + ES_ICON_GO_DOWN_SYMBOLIC + ES_ICON_GO_FIRST + ES_ICON_GO_FIRST_SYMBOLIC + ES_ICON_GO_HOME_SYMBOLIC + ES_ICON_GO_JUMP + ES_ICON_GO_JUMP_SYMBOLIC + ES_ICON_GO_LAST + ES_ICON_GO_LAST_SYMBOLIC + ES_ICON_GO_NEXT + ES_ICON_GO_NEXT_SYMBOLIC + ES_ICON_GO_PREVIOUS + ES_ICON_GO_PREVIOUS_SYMBOLIC + ES_ICON_GO_TOP + ES_ICON_GO_TOP_SYMBOLIC + ES_ICON_GO_UP + ES_ICON_GO_UP_SYMBOLIC + ES_ICON_HELP_ABOUT + ES_ICON_HELP_ABOUT_SYMBOLIC + ES_ICON_HELP_CONTENTS + ES_ICON_HELP_CONTENTS_SYMBOLIC + ES_ICON_HELP_INFO_SYMBOLIC + ES_ICON_IMAGE_ADJUST + ES_ICON_IMAGE_AUTO_ADJUST + ES_ICON_IMAGE_CROP + ES_ICON_IMAGE_CROP_SYMBOLIC + ES_ICON_IMAGE_RED_EYE + ES_ICON_IMAGE_RED_EYE_SYMBOLIC + ES_ICON_INSERT_IMAGE + ES_ICON_INSERT_IMAGE_SYMBOLIC + ES_ICON_INSERT_LINK + ES_ICON_INSERT_LINK_SYMBOLIC + ES_ICON_INSERT_OBJECT + ES_ICON_INSERT_OBJECT_SYMBOLIC + ES_ICON_INSERT_TEXT_SYMBOLIC + ES_ICON_LIST_ADD + ES_ICON_LIST_ADD_SYMBOLIC + ES_ICON_LIST_REMOVE + ES_ICON_LIST_REMOVE_SYMBOLIC + ES_ICON_MAIL_ARCHIVE + ES_ICON_MAIL_FORWARD + ES_ICON_MAIL_FORWARD_SYMBOLIC + ES_ICON_MAIL_MARK_IMPORTANT + ES_ICON_MAIL_MARK_IMPORTANT_SYMBOLIC + ES_ICON_MAIL_MARK_JUNK + ES_ICON_MAIL_MARK_JUNK_SYMBOLIC + ES_ICON_MAIL_MARK_NOTJUNK + ES_ICON_MAIL_MARK_NOTJUNK_SYMBOLIC + ES_ICON_MAIL_MESSAGE_NEW + ES_ICON_MAIL_MESSAGE_NEW_SYMBOLIC + ES_ICON_MAIL_MOVE + ES_ICON_MAIL_MOVE_SYMBOLIC + ES_ICON_MAIL_REPLY_ALL + ES_ICON_MAIL_REPLY_ALL_SYMBOLIC + ES_ICON_MAIL_REPLY_SENDER + ES_ICON_MAIL_REPLY_SENDER_SYMBOLIC + ES_ICON_MAIL_SEND + ES_ICON_MAIL_SEND_RECEIVE_SYMBOLIC + ES_ICON_MAIL_SEND_SYMBOLIC + ES_ICON_MARK_LOCATION_SYMBOLIC + ES_ICON_MEDIA_EJECT + ES_ICON_MEDIA_EJECT_SYMBOLIC + ES_ICON_MEDIA_EQ_SYMBOLIC + ES_ICON_MEDIA_PLAYBACK_PAUSE + ES_ICON_MEDIA_PLAYBACK_PAUSE_SYMBOLIC + ES_ICON_MEDIA_PLAYBACK_START + ES_ICON_MEDIA_PLAYBACK_START_SYMBOLIC + ES_ICON_MEDIA_PLAYBACK_STOP + ES_ICON_MEDIA_PLAYBACK_STOP_SYMBOLIC + ES_ICON_MEDIA_RECORD + ES_ICON_MEDIA_RECORD_SYMBOLIC + ES_ICON_MEDIA_SEEK_BACKWARD + ES_ICON_MEDIA_SEEK_BACKWARD_SYMBOLIC + ES_ICON_MEDIA_SEEK_FORWARD + ES_ICON_MEDIA_SEEK_FORWARD_SYMBOLIC + ES_ICON_MEDIA_SKIP_BACKWARD + ES_ICON_MEDIA_SKIP_FORWARD + ES_ICON_MEDIA_VIEW_SUBTITLES_SYMBOLIC + ES_ICON_NODE_ADD + ES_ICON_NODE_ALIGN_HORIZONTAL + ES_ICON_NODE_ALIGN_VERTICAL + ES_ICON_NODE_BREAK + ES_ICON_NODE_CUSP + ES_ICON_NODE_DELETE + ES_ICON_NODE_DELETE_SEGMENT + ES_ICON_NODE_DISTRIBUTE_HORIZONTAL + ES_ICON_NODE_DISTRIBUTE_VERTICAL + ES_ICON_NODE_INSERT + ES_ICON_NODE_JOIN + ES_ICON_NODE_JOIN_SEGMENT + ES_ICON_NODE_SMOOTH + ES_ICON_NODE_SYMMETRIC + ES_ICON_OBJECT_FLIP_HORIZONTAL + ES_ICON_OBJECT_FLIP_HORIZONTAL_SYMBOLIC + ES_ICON_OBJECT_FLIP_VERTICAL + ES_ICON_OBJECT_FLIP_VERTICAL_SYMBOLIC + ES_ICON_OBJECT_GROUP + ES_ICON_OBJECT_GROUP_SYMBOLIC + ES_ICON_OBJECT_INVERSE + ES_ICON_OBJECT_INVERSE_SYMBOLIC + ES_ICON_OBJECT_MERGE + ES_ICON_OBJECT_ROTATE_LEFT + ES_ICON_OBJECT_ROTATE_LEFT_SYMBOLIC + ES_ICON_OBJECT_ROTATE_RIGHT + ES_ICON_OBJECT_ROTATE_RIGHT_SYMBOLIC + ES_ICON_OBJECT_SELECT_SYMBOLIC + ES_ICON_OBJECT_STRAIGHTEN + ES_ICON_OBJECT_TO_PATH + ES_ICON_OBJECT_UNGROUP + ES_ICON_OBJECT_UNGROUP_SYMBOLIC + ES_ICON_OPEN_MENU + ES_ICON_OPEN_MENU_SYMBOLIC + ES_ICON_PAN_DOWN_SYMBOLIC + ES_ICON_PANE_HIDE_SYMBOLIC + ES_ICON_PAN_END_SYMBOLIC + ES_ICON_PANE_SHOW_SYMBOLIC + ES_ICON_PAN_START_SYMBOLIC + ES_ICON_PAN_UP_SYMBOLIC + ES_ICON_PATH_BREAK_APART + ES_ICON_PATH_BREAK_APART_SYMBOLIC + ES_ICON_PATH_COMBINE + ES_ICON_PATH_COMBINE_SYMBOLIC + ES_ICON_PATH_DIFFERENCE + ES_ICON_PATH_DIFFERENCE_SYMBOLIC + ES_ICON_PATH_DIVISION + ES_ICON_PATH_DIVISION_SYMBOLIC + ES_ICON_PATH_EXCLUSION + ES_ICON_PATH_EXCLUSION_SYMBOLIC + ES_ICON_PATH_INTERSECTION + ES_ICON_PATH_INTERSECTION_SYMBOLIC + ES_ICON_PATH_UNION + ES_ICON_PATH_UNION_SYMBOLIC + ES_ICON_PROCESS_STOP + ES_ICON_PROCESS_STOP_SYMBOLIC + ES_ICON_SEGMENT_CURVE + ES_ICON_SEGMENT_LINE + ES_ICON_SELECTION_ADD + ES_ICON_SELECTION_BOTTOM + ES_ICON_SELECTION_BOTTOM_SYMBOLIC + ES_ICON_SELECTION_CHECKED + ES_ICON_SELECTION_END_SYMBOLIC + ES_ICON_SELECTION_LOWER + ES_ICON_SELECTION_LOWER_SYMBOLIC + ES_ICON_SELECTION_RAISE + ES_ICON_SELECTION_RAISE_SYMBOLIC + ES_ICON_SELECTION_REMOVE + ES_ICON_SELECTION_START_SYMBOLIC + ES_ICON_SELECTION_TOP + ES_ICON_SELECTION_TOP_SYMBOLIC + ES_ICON_SEND_TO + ES_ICON_SEND_TO_SYMBOLIC + ES_ICON_STAR_NEW_SYMBOLIC + ES_ICON_STROKE_TO_PATH + ES_ICON_SYSTEM_LOCK_SCREEN + ES_ICON_SYSTEM_LOCK_SCREEN_SYMBOLIC + ES_ICON_SYSTEM_LOG_OUT + ES_ICON_SYSTEM_REBOOT + ES_ICON_SYSTEM_RUN + ES_ICON_SYSTEM_RUN_SYMBOLIC + ES_ICON_SYSTEM_SHUTDOWN + ES_ICON_SYSTEM_SHUTDOWN_SYMBOLIC + ES_ICON_SYSTEM_SUSPEND + ES_ICON_TAB_NEW_SYMBOLIC + ES_ICON_TAG_NEW + ES_ICON_TAG_NEW_SYMBOLIC + ES_ICON_TOOL_MEASURE + ES_ICON_TOOL_NODE_EDITOR + ES_ICON_TOOLS_CHECK_SPELLING_SYMBOLIC + ES_ICON_TOOLS_TIMER_SYMBOLIC + ES_ICON_VIEW_COLUMN_SYMBOLIC + ES_ICON_VIEW_CONTINUOUS_SYMBOLIC + ES_ICON_VIEW_DUAL_SYMBOLIC + ES_ICON_VIEW_FILTER_SYMBOLIC + ES_ICON_VIEW_FULLSCREEN_SYMBOLIC + ES_ICON_VIEW_GRID_SYMBOLIC + ES_ICON_VIEW_LIST_COMPACT_SYMBOLIC + ES_ICON_VIEW_LIST_IMAGES_SYMBOLIC + ES_ICON_VIEW_LIST_SYMBOLIC + ES_ICON_VIEW_LIST_VIDEO_SYMBOLIC + ES_ICON_VIEW_MORE_HORIZONTAL_SYMBOLIC + ES_ICON_VIEW_MORE_SYMBOLIC + ES_ICON_VIEW_PAGED_SYMBOLIC + ES_ICON_VIEW_PIN_SYMBOLIC + ES_ICON_VIEW_READER + ES_ICON_VIEW_READER_SYMBOLIC + ES_ICON_VIEW_REFRESH + ES_ICON_VIEW_REFRESH_SYMBOLIC + ES_ICON_VIEW_RESTORE_SYMBOLIC + ES_ICON_VIEW_SORT_ASCENDING_SYMBOLIC + ES_ICON_VIEW_SORT_DESCENDING_SYMBOLIC + ES_ICON_WINDOW_CLOSE + ES_ICON_WINDOW_CLOSE_SYMBOLIC + ES_ICON_WINDOW_MAXIMIZE_SYMBOLIC + ES_ICON_WINDOW_MINIMIZE_SYMBOLIC + ES_ICON_WINDOW_NEW + ES_ICON_WINDOW_NEW_SYMBOLIC + ES_ICON_WINDOW_POP_OUT_SYMBOLIC + ES_ICON_WINDOW_RESTORE_SYMBOLIC + ES_ICON_ZOOM_FIT_BEST + ES_ICON_ZOOM_FIT_BEST_SYMBOLIC + ES_ICON_ZOOM_IN + ES_ICON_ZOOM_IN_SYMBOLIC + ES_ICON_ZOOM_ORIGINAL + ES_ICON_ZOOM_ORIGINAL_SYMBOLIC + ES_ICON_ZOOM_OUT + ES_ICON_ZOOM_OUT_SYMBOLIC + ES_ICON_ACCESSORIES_CALCULATOR + ES_ICON_ACCESSORIES_CALCULATOR_SYMBOLIC + ES_ICON_ACCESSORIES_SCREENSHOT + ES_ICON_ACCESSORIES_TEXT_EDITOR + ES_ICON_ACCESSORIES_TEXT_EDITOR_SYMBOLIC + ES_ICON_APPLICATION_DEFAULT_ICON + ES_ICON_ARCHIVE_MANAGER + ES_ICON_INTERNET_CHAT + ES_ICON_INTERNET_CHAT_SYMBOLIC + ES_ICON_INTERNET_MAIL + ES_ICON_INTERNET_MAIL_SYMBOLIC + ES_ICON_INTERNET_NEWS_READER + ES_ICON_INTERNET_NEWS_READER_SYMBOLIC + ES_ICON_INTERNET_WEB_BROWSER + ES_ICON_INTERNET_WEB_BROWSER_SYMBOLIC + ES_ICON_MULTIMEDIA_AUDIO_PLAYER + ES_ICON_MULTIMEDIA_PHOTO_MANAGER + ES_ICON_MULTIMEDIA_VIDEO_PLAYER + ES_ICON_OFFICE_ADDRESS_BOOK + ES_ICON_OFFICE_CALENDAR + ES_ICON_OFFICE_CALENDAR_SYMBOLIC + ES_ICON_ONBOARD + ES_ICON_POSTSCRIPT_VIEWER + ES_ICON_PREFERENCES_DESKTOP + ES_ICON_PREFERENCES_DESKTOP_FONT + ES_ICON_SYSTEM_FILE_MANAGER + ES_ICON_SYSTEM_OS_INSTALLER + ES_ICON_SYSTEM_SOFTWARE_INSTALL + ES_ICON_SYSTEM_SOFTWARE_INSTALL_SYMBOLIC + ES_ICON_SYSTEM_SOFTWARE_UPDATE + ES_ICON_SYSTEM_SOFTWARE_UPDATE_SYMBOLIC + ES_ICON_SYSTEM_USERS + ES_ICON_SYSTEM_USERS_SYMBOLIC + ES_ICON_UTILITIES_SYSTEM_MONITOR + ES_ICON_UTILITIES_TERMINAL + ES_ICON_UTILITIES_TERMINAL_SYMBOLIC + ES_ICON_APPLICATIONS_ACCESSORIES + ES_ICON_APPLICATIONS_AUDIO_SYMBOLIC + ES_ICON_APPLICATIONS_DEVELOPMENT + ES_ICON_APPLICATIONS_DEVELOPMENT_SYMBOLIC + ES_ICON_APPLICATIONS_EDUCATION + ES_ICON_APPLICATIONS_EDUCATION_SYMBOLIC + ES_ICON_APPLICATIONS_ENGINEERING_SYMBOLIC + ES_ICON_APPLICATIONS_FONTS + ES_ICON_APPLICATIONS_GAMES + ES_ICON_APPLICATIONS_GAMES_SYMBOLIC + ES_ICON_APPLICATIONS_GRAPHICS + ES_ICON_APPLICATIONS_GRAPHICS_SYMBOLIC + ES_ICON_APPLICATIONS_INTERFACEDESIGN + ES_ICON_APPLICATIONS_INTERNET_SYMBOLIC + ES_ICON_APPLICATIONS_MULTIMEDIA + ES_ICON_APPLICATIONS_MULTIMEDIA_SYMBOLIC + ES_ICON_APPLICATIONS_OFFICE + ES_ICON_APPLICATIONS_OFFICE_SYMBOLIC + ES_ICON_APPLICATIONS_OTHER + ES_ICON_APPLICATIONS_OTHER_SYMBOLIC + ES_ICON_APPLICATIONS_PHOTOGRAPHY + ES_ICON_APPLICATIONS_SCIENCE + ES_ICON_APPLICATIONS_SCIENCE_SYMBOLIC + ES_ICON_APPLICATIONS_UTILITIES + ES_ICON_APPLICATIONS_UTILITIES_SYMBOLIC + ES_ICON_APPLICATIONS_VIDEO_SYMBOLIC + ES_ICON_BUG + ES_ICON_BUG_SYMBOLIC + ES_ICON_EMOJI_ACTIVITY_SYMBOLIC + ES_ICON_EMOJI_BODY_SYMBOLIC + ES_ICON_EMOJI_FOOD_SYMBOLIC + ES_ICON_EMOJI_NATURE_SYMBOLIC + ES_ICON_EMOJI_OBJECTS_SYMBOLIC + ES_ICON_EMOJI_TRAVEL_SYMBOLIC + ES_ICON_EVENT_BIRTHDAY_SYMBOLIC + ES_ICON_PREFERENCES_BLUETOOTH_SYMBOLIC + ES_ICON_PREFERENCES_COLOR + ES_ICON_PREFERENCES_COLOR_SYMBOLIC + ES_ICON_PREFERENCES_DESKTOP_ACCESSIBILITY + ES_ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_POINTING + ES_ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_SYMBOLIC + ES_ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_ZOOM + ES_ICON_PREFERENCES_DESKTOP_APPLICATIONS + ES_ICON_PREFERENCES_DESKTOP_DISPLAY + ES_ICON_PREFERENCES_DESKTOP_DISPLAY_SYMBOLIC + ES_ICON_PREFERENCES_DESKTOP_KEYBOARD + ES_ICON_PREFERENCES_DESKTOP_KEYBOARD_SYMBOLIC + ES_ICON_PREFERENCES_DESKTOP_LOCALE + ES_ICON_PREFERENCES_DESKTOP_LOCALE_SYMBOLIC + ES_ICON_PREFERENCES_DESKTOP_ONLINE_ACCOUNTS + ES_ICON_PREFERENCES_DESKTOP_ONLINE_ACCOUNTS_SYMBOLIC + ES_ICON_PREFERENCES_DESKTOP_PERIPHERALS + ES_ICON_PREFERENCES_DESKTOP_SOUND + ES_ICON_PREFERENCES_DESKTOP_WALLPAPER + ES_ICON_PREFERENCES_DESKTOP_WORKSPACES + ES_ICON_PREFERENCES_OTHER_SYMBOLIC + ES_ICON_PREFERENCES_SYSTEM + ES_ICON_PREFERENCES_SYSTEM_NETWORK + ES_ICON_PREFERENCES_SYSTEM_NETWORK_SYMBOLIC + ES_ICON_PREFERENCES_SYSTEM_NOTIFICATIONS + ES_ICON_PREFERENCES_SYSTEM_PARENTAL_CONTROLS + ES_ICON_PREFERENCES_SYSTEM_PARENTAL_CONTROL_SYMBOLIC + ES_ICON_PREFERENCES_SYSTEM_POWER + ES_ICON_PREFERENCES_SYSTEM_POWER_SYMBOLIC + ES_ICON_PREFERENCES_SYSTEM_PRIVACY_HOUSEKEEPING + ES_ICON_PREFERENCES_SYSTEM_SHARING + ES_ICON_PREFERENCES_SYSTEM_SHARING_SYMBOLIC + ES_ICON_PREFERENCES_SYSTEM_TIME + ES_ICON_PREFERENCES_SYSTEM_TIME_SYMBOLIC + ES_ICON_PREFERENCES_SYSTEM_WINDOWS + ES_ICON_AC_ADAPTER_SYMBOLIC + ES_ICON_AUDIO_CARD_SYMBOLIC + ES_ICON_AUDIO_HEADPHONES + ES_ICON_AUDIO_HEADPHONES_SYMBOLIC + ES_ICON_AUDIO_HEADSETS + ES_ICON_AUDIO_HEADSET_SYMBOLIC + ES_ICON_AUDIO_INPUT_MICROPHONE + ES_ICON_AUDIO_INPUT_MICROPHONE_SYMBOLIC + ES_ICON_AUDIO_SPEAKER_CENTER + ES_ICON_AUDIO_SPEAKER_CENTER_BACK + ES_ICON_AUDIO_SPEAKER_CENTER_BACK_TESTING + ES_ICON_AUDIO_SPEAKER_CENTER_TESTING + ES_ICON_AUDIO_SPEAKER_LEFT + ES_ICON_AUDIO_SPEAKER_LEFT_BACK + ES_ICON_AUDIO_SPEAKER_LEFT_BACK_TESTING + ES_ICON_AUDIO_SPEAKER_LEFT_SIDE + ES_ICON_AUDIO_SPEAKER_LEFT_SIDE_TESTING + ES_ICON_AUDIO_SPEAKER_LEFT_TESTING + ES_ICON_AUDIO_SPEAKER_RIGHT + ES_ICON_AUDIO_SPEAKER_RIGHT_BACK + ES_ICON_AUDIO_SPEAKER_RIGHT_BACK_TESTING + ES_ICON_AUDIO_SPEAKER_RIGHT_SIDE + ES_ICON_AUDIO_SPEAKER_RIGHT_SIDE_TESTING + ES_ICON_AUDIO_SPEAKER_RIGHT_TESTING + ES_ICON_AUDIO_SPEAKERS + ES_ICON_AUDIO_SPEAKERS_SYMBOLIC + ES_ICON_AUDIO_SUBWOOFER + ES_ICON_AUDIO_SUBWOOFER_TESTING + ES_ICON_BATTERY + ES_ICON_BATTERY_SYMBOLIC + ES_ICON_BLUETOOTH + ES_ICON_BLUETOOTH_SYMBOLIC + ES_ICON_CAMERA_PHOTO + ES_ICON_CAMERA_PHOTO_SYMBOLIC + ES_ICON_CAMERA_VIDEO + ES_ICON_CAMERA_VIDEO_SYMBOLIC + ES_ICON_CAMERA_WEB + ES_ICON_CAMERA_WEB_SYMBOLIC + ES_ICON_COLORIMETER_COLORHUG_SYMBOLIC + ES_ICON_COMPUTER_LAPTOP + ES_ICON_COMPUTER_LAPTOP_SYMBOLIC + ES_ICON_DISPLAY_PROJECTOR_SYMBOLIC + ES_ICON_DRIVE_HARDDISK + ES_ICON_DRIVE_HARDDISK_IEEE1394_SYMBOLIC + ES_ICON_DRIVE_HARDDISK_SOLIDSTATE + ES_ICON_DRIVE_HARDDISK_SOLIDSTATE_SYMBOLIC + ES_ICON_DRIVE_HARDDISK_SYMBOLIC + ES_ICON_DRIVE_MULTIDISK_SYMBOLIC + ES_ICON_DRIVE_OPTICAL_SYMBOLIC + ES_ICON_DRIVE_REMOVABLE_MEDIA + ES_ICON_DRIVE_REMOVABLE_MEDIA_SYMBOLIC + ES_ICON_DRIVE_REMOVABLE_MEDIA_USB + ES_ICON_FINGERPRINT + ES_ICON_FINGERPRINT_SYMBOLIC + ES_ICON_GNOME_DEV_PRINTER_NEW + ES_ICON_INPUT_DIALPAD_SYMBOLIC + ES_ICON_INPUT_GAMING + ES_ICON_INPUT_GAMING_SYMBOLIC + ES_ICON_INPUT_KEYBOARD + ES_ICON_INPUT_KEYBOARD_SYMBOLIC + ES_ICON_INPUT_MOUSE + ES_ICON_INPUT_MOUSE_SYMBOLIC + ES_ICON_INPUT_TABLET + ES_ICON_INPUT_TABLET_SYMBOLIC + ES_ICON_INPUT_TOUCHPAD + ES_ICON_INPUT_TOUCHPAD_SYMBOLIC + ES_ICON_MEDIA_FLASH_CF + ES_ICON_MEDIA_FLASH_MS + ES_ICON_MEDIA_FLASH_SYMBOLIC + ES_ICON_MEDIA_FLOPPY_SYMBOLIC + ES_ICON_MEDIA_MEMORY + ES_ICON_MEDIA_MEMORY_SD + ES_ICON_MEDIA_MEMORY_SEMBOLIC + ES_ICON_MEDIA_MEMORY_SM + ES_ICON_MEDIA_OPTICAL + ES_ICON_MEDIA_OPTICAL_SYMBOLIC + ES_ICON_MEDIA_REMOVABLE_SYMBOLIC + ES_ICON_MEDIA_TAPE_SYMBOLIC + ES_ICON_MEDIA_ZIP_SYMBOLIC + ES_ICON_MODEM + ES_ICON_MODEM_SYMBOLIC + ES_ICON_MULTIMEDIA_PLAYER + ES_ICON_MULTIMEDIA_PLAYER_SYMBOLIC + ES_ICON_NETWORK_CELLULAR + ES_ICON_NETWORK_FIREWALL + ES_ICON_NETWORK_VPN + ES_ICON_NETWORK_WIRED + ES_ICON_NETWORK_WIRELESS + ES_ICON_NETWORK_WIRELESS_HOTSPOT + ES_ICON_NM_DEVICE_WWAN + ES_ICON_PDA_SYMBOLIC + ES_ICON_PHONE + ES_ICON_PHONE_SYMBOLIC + ES_ICON_PRINTER + ES_ICON_PRINTER_NETWORK + ES_ICON_PRINTER_SYMBOLIC + ES_ICON_SCANNER + ES_ICON_SCANNER_SYMBOLIC + ES_ICON_TABLET + ES_ICON_TABLET_SYMBOLIC + ES_ICON_TV_SYMBOLIC + ES_ICON_UNINTERRUPTIBLE_POWER_SUPPLY + ES_ICON_UNINTERRUPTIBLE_POWER_SUPPLY_SYMBOLIC + ES_ICON_VIDEO_DISPLAY + ES_ICON_VIDEO_DISPLAY_SYMBOLIC + ES_ICON_EMBLEM_DEFAULT_SYMBOLIC + ES_ICON_EMBLEM_DOCUMENTS_SYMBOLIC + ES_ICON_EMBLEM_FAVORITE_SYMBOLIC + ES_ICON_EMBLEM_IMPORTANT_SYMBOLIC + ES_ICON_EMBLEM_MUSIC_SYMBOLIC + ES_ICON_EMBLEM_OK_SYMBOLIC + ES_ICON_EMBLEM_PHOTOS_SYMBOLIC + ES_ICON_EMBLEM_READONLY + ES_ICON_EMBLEM_SHARED_SYMBOLIC + ES_ICON_EMBLEM_SYMBOLIC_LINK + ES_ICON_EMBLEM_SYNCHRONIZED + ES_ICON_EMBLEM_SYNCHRONIZING_SYMBOLIC + ES_ICON_EMBLEM_UNREADABLE + ES_ICON_EMBLEM_VIDEOS_SYMBOLIC + ES_ICON_FACE_ANGEL + ES_ICON_FACE_ANGEL_SYMBOLIC + ES_ICON_FACE_ANGRY + ES_ICON_FACE_ANGRY_SYMBOLIC + ES_ICON_FACE_COOL + ES_ICON_FACE_COOL_SYMBOLIC + ES_ICON_FACE_CRYING + ES_ICON_FACE_CRYING_SYMBOLIC + ES_ICON_FACE_DEVILISH + ES_ICON_FACE_DEVILISH_SYMBOLIC + ES_ICON_FACE_EMBARRASSED + ES_ICON_FACE_EMBARRASSED_SYMBOLIC + ES_ICON_FACE_HEART + ES_ICON_FACE_HEART_BROKEN + ES_ICON_FACE_HEART_BROKEN_SYMBOLIC + ES_ICON_FACE_HEART_SYMBOLIC + ES_ICON_FACE_KISS + ES_ICON_FACE_KISS_SYMBOLIC + ES_ICON_FACE_LAUGH + ES_ICON_FACE_LAUGH_SYMBOLIC + ES_ICON_FACE_MONKEY_SYMBOLIC + ES_ICON_FACE_PLAIN + ES_ICON_FACE_PLAIN_SYMBOLIC + ES_ICON_FACE_RASPBERRY + ES_ICON_FACE_RASPBERRY_SYMBOLIC + ES_ICON_FACE_SAD + ES_ICON_FACE_SAD_SYMBOLIC + ES_ICON_FACE_SICK + ES_ICON_FACE_SICK_SYMBOLIC + ES_ICON_FACE_SMILE + ES_ICON_FACE_SMILE_BIG + ES_ICON_FACE_SMILE_BIG_SYMBOLIC + ES_ICON_FACE_SMILE_SYMBOLIC + ES_ICON_FACE_SMIRK + ES_ICON_FACE_SMIRK_SYMBOLIC + ES_ICON_FACE_SURPRISE + ES_ICON_FACE_SURPRISE_SYMBOLIC + ES_ICON_FACE_TIRED + ES_ICON_FACE_TIRED_SYMBOLIC + ES_ICON_FACE_UNCERTAIN + ES_ICON_FACE_UNCERTAIN_SYMBOLIC + ES_ICON_FACE_WINK + ES_ICON_FACE_WINK_SYMBOLIC + ES_ICON_FACE_WORRIED + ES_ICON_FACE_WORRIED_SYMBOLIC + ES_ICON_APPLICATION_CERTIFICATE_SYMBOLIC + ES_ICON_APPLICATION_EPUB_ZIP + ES_ICON_APPLICATION_ILLUSTRATOR + ES_ICON_APPLICATION_JAVASCRIPT + ES_ICON_APPLICATION_MSWORD + ES_ICON_APPLICATION_OCTET_STREAM + ES_ICON_APPLICATION_PDF + ES_ICON_APPLICATION_PGP + ES_ICON_APPLICATION_RSS_XML_SYMBOLIC + ES_ICON_APPLICATION_VND + ES_ICON_APPLICATION_X_APPLIANCE_SYMBOLIC + ES_ICON_APPLICATION_X_BITTORRENT + ES_ICON_APPLICATION_X_CD_IMAGE + ES_ICON_APPLICATION_X_DESKTOP + ES_ICON_APPLICATION_X_EXECUTABLE_SYMBOLIC + ES_ICON_APPLICATION_X_FICTIONBOOK_XML + ES_ICON_APPLICATION_X_FIRMWARE + ES_ICON_APPLICATION_X_FIRMWARE_SYMBOLIC + ES_ICON_APPLICATION_X_FLASH_VIDEO + ES_ICON_APPLICATION_X_MS_DOS_EXECUTABLE + ES_ICON_APPLICATION_X_PARTIAL_DOWNLOAD + ES_ICON_APPLICATION_X_PHP + ES_ICON_APPLICATION_X_RUBY + ES_ICON_AUDIO_X_GENERIC + ES_ICON_AUDIO_X_GENERIC_SYMBOLIC + ES_ICON_AUDIO_X_PLAYLIST + ES_ICON_EXTENSION + ES_ICON_FONT_X_GENERIC + ES_ICON_FONT_X_GENERIC_SYMBOLIC + ES_ICON_IMAGE_VND + ES_ICON_IMAGE_X_GENERIC + ES_ICON_IMAGE_X_GENERIC_SYMBOLIC + ES_ICON_IMAGE_X_XCF + ES_ICON_INTERNET_FEED + ES_ICON_MODEL + ES_ICON_OFFICE_CONTACT + ES_ICON_OFFICE_DATABASE + ES_ICON_PACKAGE_X_GENERIC + ES_ICON_PACKAGE_X_GENERIC_SYMBOLIC + ES_ICON_PAYMENT_CARD + ES_ICON_PAYMENT_CARD_AMEX + ES_ICON_PAYMENT_CARD_DINERS_CLUB + ES_ICON_PAYMENT_CARD_DISCOVER + ES_ICON_PAYMENT_CARD_JCB + ES_ICON_PAYMENT_CARD_MASTERCARD + ES_ICON_PAYMENT_CARD_SYMBOLIC + ES_ICON_PAYMENT_CARD_UNIONPAY + ES_ICON_PAYMENT_CARD_VISA + ES_ICON_TEXT + ES_ICON_TEXT_CSS + ES_ICON_TEXT_HTML + ES_ICON_TEXT_HTML_SYMBOLIC + ES_ICON_TEXT_MARKDOWN + ES_ICON_TEXT_X_BIBTEX + ES_ICON_TEXT_X_CHANGELOG + ES_ICON_TEXT_X_CHDR + ES_ICON_TEXT_X_COPYING + ES_ICON_TEXT_X_COPYING_SYMBOLIC + ES_ICON_TEXT_X_CSRC + ES_ICON_TEXT_X_GENERIC_SYMBOLIC + ES_ICON_TEXT_X_GENERIC_TEMPLATE + ES_ICON_TEXT_X_GETTEXT_TRANSLATION + ES_ICON_TEXT_X_GETTEXT_TRANSLATION_TEMPLATE + ES_ICON_TEXT_X_GO + ES_ICON_TEXT_X_INSTALL + ES_ICON_TEXT_X_MAKEFILE + ES_ICON_TEXT_X_PREVIEW + ES_ICON_TEXT_X_PYTHON + ES_ICON_TEXT_X_README + ES_ICON_TEXT_X_SASS + ES_ICON_TEXT_X_SCRIPT + ES_ICON_TEXT_X_SSA + ES_ICON_TEXT_X_TEX + ES_ICON_TEXT_X_VALA + ES_ICON_UNKNOWN + ES_ICON_VIDEO_X_GENERIC + ES_ICON_VIDEO_X_GENERIC_SYMBOLIC + ES_ICON_X_OFFICE_ADDRESS_BOOK_SYMBOLIC + ES_ICON_X_OFFICE_DOCUMENT + ES_ICON_X_OFFICE_DOCUMENT_SYMBOLIC + ES_ICON_X_OFFICE_DOCUMENT_TEMPLATE + ES_ICON_X_OFFICE_DRAWING + ES_ICON_X_OFFICE_DRAWING_SYMBOLIC + ES_ICON_X_OFFICE_DRAWING_TEMPLATE + ES_ICON_X_OFFICE_PRESENTATION + ES_ICON_X_OFFICE_PRESENTATION_SYMBOLIC + ES_ICON_X_OFFICE_PRESENTATION_TEMPLATE + ES_ICON_X_OFFICE_SPREADSHEET + ES_ICON_X_OFFICE_SPREADSHEET_SYMBOLIC + ES_ICON_X_OFFICE_SPREADSHEET_TEMPLATE + ES_ICON_BOOKMARK_MISSING + ES_ICON_DISTRIBUTOR_LOGO + ES_ICON_DISTRIBUTOR_LOGO_SYMBOLIC + ES_ICON_FOLDER + ES_ICON_FOLDER_DOCUMENTS + ES_ICON_FOLDER_DOCUMENTS_OPEN + ES_ICON_FOLDER_DOCUMENTS_SYMBOLIC + ES_ICON_FOLDER_DOWNLOAD + ES_ICON_FOLDER_DOWNLOAD_OPEN + ES_ICON_FOLDER_DOWNLOAD_SYMBOLIC + ES_ICON_FOLDER_MUSIC + ES_ICON_FOLDER_MUSIC_OPEN + ES_ICON_FOLDER_MUSIC_SYMBOLIC + ES_ICON_FOLDER_OPEN + ES_ICON_FOLDER_PICTURES + ES_ICON_FOLDER_PICTURES_OPEN + ES_ICON_FOLDER_PICTURES_SYMBOLIC + ES_ICON_FOLDER_PUBLICSHARE + ES_ICON_FOLDER_PUBLICSHARE_OPEN + ES_ICON_FOLDER_PUBLICSHARE_SYMBOLIC + ES_ICON_FOLDER_RECENT + ES_ICON_FOLDER_RECENT_SYMBOLIC + ES_ICON_FOLDER_REMOTE + ES_ICON_FOLDER_REMOTE_OPEN + ES_ICON_FOLDER_SAVED_SEARCH + ES_ICON_FOLDER_SYMBOLIC + ES_ICON_FOLDER_TAG + ES_ICON_FOLDER_TEMPLATES + ES_ICON_FOLDER_TEMPLATES_OPEN + ES_ICON_FOLDER_TEMPLATES_SYMBOLIC + ES_ICON_FOLDER_VIDEOS + ES_ICON_FOLDER_VIDEOS_OPEN + ES_ICON_FOLDER_VIDEOS_SYMBOLIC + ES_ICON_INTERNET_RADIO + ES_ICON_INTERNET_RADIO_SYMBOLIC + ES_ICON_LIBRARY_AUDIOBOOK + ES_ICON_LIBRARY_PLACES + ES_ICON_LIBRARY_PODCAST + ES_ICON_MAIL_INBOX + ES_ICON_MAIL_INBOX_SYMBOLIC + ES_ICON_MAIL_MAILBOX + ES_ICON_MAIL_MAILBOX_SYMBOLIC + ES_ICON_MAIL_OUTBOX + ES_ICON_MAIL_OUTBOX_SYMBOLIC + ES_ICON_NETWORK_SERVER_SYMBOLIC + ES_ICON_PLAYLIST + ES_ICON_PLAYLIST_AUTOMATIC + ES_ICON_PLAYLIST_QUEUE + ES_ICON_PLAYLIST_QUEUE_SYMBOLIC + ES_ICON_PLAYLIST_SIMILAR + ES_ICON_PLAYLIST_SYMBOLIC + ES_ICON_TAG_SYMBOLIC + ES_ICON_USER_BOOKMARKS_SYMBOLIC + ES_ICON_USER_HOME + ES_ICON_USER_HOME_OPEN + ES_ICON_USER_HOME_SYMBOLIC + ES_ICON_USER_TRASH + ES_ICON_USER_TRASH_FULL + ES_ICON_USER_TRASH_SYMBOLIC + ES_ICON_AIRPLANE_MODE + ES_ICON_AIRPLANE_MODE_SYMBOLIC + ES_ICON_ALARM_SYMBOLIC + ES_ICON_APPOINTMENT_MISSED + ES_ICON_APPOINTMENT_MISSED_SYMBOLIC + ES_ICON_APPOINTMENT_SOON + ES_ICON_APPOINTMENT_SOON_SYMBOLIC + ES_ICON_AUDIO_VOLUME_HIGH_SYMBOLIC + ES_ICON_AUDIO_VOLUME_LOW_SYMBOLIC + ES_ICON_AUDIO_VOLUME_MEDIUM_SYMBOLIC + ES_ICON_AUDIO_VOLUME_MUTED_BLOCKING_SYMBOLIC + ES_ICON_AUDIO_VOLUME_MUTED_SYMBOLIC + ES_ICON_AVATAR_DEFAULT + ES_ICON_AVATAR_DEFAULT_SYMBOLIC + ES_ICON_BATTERY_AC_ADAPTER + ES_ICON_BATTERY_AC_ADAPTER_SYMBOLIC + ES_ICON_BATTERY_CAUTION + ES_ICON_BATTERY_CAUTION_CHARGING + ES_ICON_BATTERY_CAUTION_CHARGING_SYMBOLIC + ES_ICON_BATTERY_CAUTION_SYMBOLIC + ES_ICON_BATTERY_EMPTY + ES_ICON_BATTERY_EMPTY_CHARGING + ES_ICON_BATTERY_EMPTY_CHARGING_SYMBOLIC + ES_ICON_BATTERY_EMPTY_SYMBOLIC + ES_ICON_BATTERY_FULL + ES_ICON_BATTERY_FULL_CHARGED + ES_ICON_BATTERY_FULL_CHARGED_SYMBOLIC + ES_ICON_BATTERY_FULL_CHARGING + ES_ICON_BATTERY_FULL_CHARGING_SYMBOLIC + ES_ICON_BATTERY_FULL_SYMBOLIC + ES_ICON_BATTERY_GOOD + ES_ICON_BATTERY_GOOD_CHARGING + ES_ICON_BATTERY_GOOD_CHARGING_SYMBOLIC + ES_ICON_BATTERY_GOOD_SYMBOLIC + ES_ICON_BATTERY_LOW + ES_ICON_BATTERY_LOW_CHARGING + ES_ICON_BATTERY_LOW_CHARGING_SYMBOLIC + ES_ICON_BATTERY_LOW_SYMBOLIC + ES_ICON_BATTERY_MISSING + ES_ICON_BATTERY_MISSING_SYMBOLIC + ES_ICON_BLUETOOTH_ACTIVE_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED + ES_ICON_BLUETOOTH_DISABLED_10_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_20_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_30_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_40_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_50_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_60_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_70_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_80_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_90_SYMBOLIC + ES_ICON_BLUETOOTH_DISABLED_SYMBOLIC + ES_ICON_BLUETOOTH_PAIRED_SYMBOLIC + ES_ICON_CALL_MISSED_SYMBOLIC + ES_ICON_CHANGES_ALLOW + ES_ICON_CHANGES_ALLOW_SYMBOLIC + ES_ICON_CHANGES_PREVENT_SYMBOLIC + ES_ICON_CHANNEL_INSECURE_SYMBOLIC + ES_ICON_CHANNEL_SECURE_SYMBOLIC + ES_ICON_CHECK_ACTIVE_SYMBOLIC + ES_ICON_CHECKBOX_CHECKED_SYMBOLIC + ES_ICON_CHECKBOX_MIXED_SYMBOLIC + ES_ICON_CHECKBOX_SYMBOLIC + ES_ICON_CHECK_MIXED_SYMBOLIC + ES_ICON_COMPUTER_FAIL_SYMBOLIC + ES_ICON_CONTENT_LOADING_SYMBOLIC + ES_ICON_DAYTIME_SUNRISE_SYMBOLIC + ES_ICON_DAYTIME_SUNSET_SYMBOLIC + ES_ICON_DIALOG_ERROR + ES_ICON_DIALOG_ERROR_SYMBOLIC + ES_ICON_DIALOG_INFORMATION + ES_ICON_DIALOG_INFORMATION_SYMBOLIC + ES_ICON_DIALOG_PASSWORD + ES_ICON_DIALOG_PASSWORD_SYMBOLIC + ES_ICON_DIALOG_WARNING + ES_ICON_DIALOG_WARNING_SYMBOLIC + ES_ICON_DISPLAY_BRIGHTNESS_SYMBOLIC + ES_ICON_FOLDER_OPEN_SYMBOLIC + ES_ICON_FOLDER_VISITING_SYMBOLIC + ES_ICON_IMAGE_LOADING + ES_ICON_IMAGE_MISSING + ES_ICON_INPUT_KEYBOARD_CAPSLOCK_SYMBOLIC + ES_ICON_INPUT_KEYBOARD_NUMLOCK_SYMBOLIC + ES_ICON_KEYBOARD_BRIGHTNESS_SYMBOLIC + ES_ICON_LOCATION_ACTIVE_SYMBOLIC + ES_ICON_LOCATION_DISABLED_SYMBOLIC + ES_ICON_LOCATION_INACTIVE_SYMBOLIC + ES_ICON_LOCKED + ES_ICON_MAIL_ATTACHMENT_SYMBOLIC + ES_ICON_MAIL_FORWARDED_SYMBOLIC + ES_ICON_MAIL_IMPORTANT_SYMBOLIC + ES_ICON_MAIL_READ_SYMBOLIC + ES_ICON_MAIL_REPLIED_SYMBOLIC + ES_ICON_MAIL_UNREAD + ES_ICON_MAIL_UNREAD_SYMBOLIC + ES_ICON_MEDIA_PLAYLIST_CONSECUTIVE_SYMBOLIC + ES_ICON_MEDIA_PLAYLIST_NO_REPEAT_SYMBOLIC + ES_ICON_MEDIA_PLAYLIST_REPEAT + ES_ICON_MEDIA_PLAYLIST_REPEAT_SONG_SYMBOLIC + ES_ICON_MEDIA_PLAYLIST_REPEAT_SYMBOLIC + ES_ICON_MEDIA_PLAYLIST_SHUFFLE_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_HIGH_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_LOW_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MEDIUM_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_10_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_20_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_30_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_40_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_50_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_60_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_70_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_80_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_90_SYMBOLIC + ES_ICON_MICROPHONE_SENSITIVITY_MUTED_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_ACQUIRING_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_CONNECTED_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_NO_ROUTE_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_OFFLINE_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_EXCELLENT_SECURE_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_EXCELLENT_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_GOOD_SECURE_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_GOOD_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_NONE_SECURE_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_NONE_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_OK_SECURE_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_OK_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_WEAK_SECURE_SYMBOLIC + ES_ICON_NETWORK_CELLULAR_SIGNAL_WEAK_SYMBOLIC + ES_ICON_NETWORK_ERROR + ES_ICON_NETWORK_ERROR_SYMBOLIC + ES_ICON_NETWORK_IDLE + ES_ICON_NETWORK_OFFLINE_SYMBOLIC + ES_ICON_NETWORK_VPN_ACQUIRING_SYMBOLIC + ES_ICON_NETWORK_VPN_LOCK_SYMBOLIC + ES_ICON_NETWORK_VPN_SYMBOLIC + ES_ICON_NETWORK_WIRED_ACQUIRING_SYMBOLIC + ES_ICON_NETWORK_WIRED_DISCONNECTED + ES_ICON_NETWORK_WIRED_NO_ROUTE_SYMBOLIC + ES_ICON_NETWORK_WIRED_OFFLINE_SYMBOLIC + ES_ICON_NETWORK_WIRED_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_ACQUIRING_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_CONNECTED_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_ENCRYPTED_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_HOTSPOT_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_NO_ROUTE_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_OFFLINE_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_EXCELLENT + ES_ICON_NETWORK_WIRELESS_SIGNAL_EXCELLENT_SECURE_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_EXCELLENT_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_GOOD + ES_ICON_NETWORK_WIRELESS_SIGNAL_GOOD_SECURE_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_GOOD_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_NONE_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_OK + ES_ICON_NETWORK_WIRELESS_SIGNAL_OK_SECURE_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_OK_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_WEAK + ES_ICON_NETWORK_WIRELESS_SIGNAL_WEAK_SECURE_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SIGNAL_WEAK_SYMBOLIC + ES_ICON_NETWORK_WIRELESS_SYMBOLIC + ES_ICON_NIGHT_LIGHT + ES_ICON_NIGHT_LIGHT_DISABLED_10_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_20_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_30_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_40_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_50_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_60_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_70_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_80_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_90_SYMBOLIC + ES_ICON_NIGHT_LIGHT_DISABLED_SYMBOLIC + ES_ICON_NIGHT_LIGHT_SYMBOLIC + ES_ICON_NM_NO_CONNECTION + ES_ICON_NM_SIGNAL_0 + ES_ICON_NM_SIGNAL_0_SECURE + ES_ICON_NM_SIGNAL_100 + ES_ICON_NM_SIGNAL_100_SECURE + ES_ICON_NM_SIGNAL_25 + ES_ICON_NM_SIGNAL_25_SECURE + ES_ICON_NM_SIGNAL_50 + ES_ICON_NM_SIGNAL_50_SECURE + ES_ICON_NM_SIGNAL_75 + ES_ICON_NM_SIGNAL_75_SECURE + ES_ICON_NM_VPN_ACTIVE_LOCK + ES_ICON_NM_VPN_LOCK + ES_ICON_NON_STARRED + ES_ICON_NON_STARRED_SYMBOLIC + ES_ICON_NOTIFICATION_AUDIO_VOLUME_HIGH + ES_ICON_NOTIFICATION_AUDIO_VOLUME_LOW + ES_ICON_NOTIFICATION_AUDIO_VOLUME_MEDIUM + ES_ICON_NOTIFICATION_AUDIO_VOLUME_MUTED + ES_ICON_NOTIFICATION_DEVICE_EJECT + ES_ICON_NOTIFICATION_DISABLED + ES_ICON_NOTIFICATION_DISABLED_10_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_20_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_30_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_40_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_50_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_60_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_70_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_80_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_90_SYMBOLIC + ES_ICON_NOTIFICATION_DISABLED_SYMBOLIC + ES_ICON_NOTIFICATION_DISPLAY_BRIGHTNESS + ES_ICON_NOTIFICATION_KEYBOARD_BRIGHTNESS + ES_ICON_NOTIFICATION_NETWORK_ETHERNET_DISCONNECTED + ES_ICON_NOTIFICATION_NETWORK_WIRED + ES_ICON_NOTIFICATION_NETWORK_WIRELESS + ES_ICON_NOTIFICATION_NETWORK_WIRELESS_DISCONNECTED + ES_ICON_NOTIFICATION_NETWORK_WIRELESS_DISCONNECTED_SYMBOLIC + ES_ICON_NOTIFICATION_NETWORK_WIRELESS_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_10_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_20_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_30_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_40_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_50_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_60_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_70_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_80_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_90_SYMBOLIC + ES_ICON_NOTIFICATION_NEW_SYMBOLIC + ES_ICON_NOTIFICATION_SYMBOLIC + ES_ICON_PAGER_CHECKED_SYMBOLIC + ES_ICON_PRINTER_ERROR + ES_ICON_PRINTER_ERROR_SYMBOLIC + ES_ICON_PRINTER_PRINTING_SYMBOLIC + ES_ICON_PRINTER_WARNING_SYMBOLIC + ES_ICON_PROCESS_COMPLETED + ES_ICON_PROCESS_COMPLETED_SYMBOLIC + ES_ICON_PROCESS_ERROR_SYMBOLIC + ES_ICON_PROCESS_WORKING_SYMBOLIC + ES_ICON_RADIO_CHECKED_SYMBOLIC + ES_ICON_RADIO_MIXED_SYMBOLIC + ES_ICON_RADIO_SYMBOLIC + ES_ICON_ROTATION_ALLOWED_SYMBOLIC + ES_ICON_ROTATION_LOCKED_SYMBOLIC + ES_ICON_SECURITY_HIGH + ES_ICON_SECURITY_HIGH_SYMBOLIC + ES_ICON_SECURITY_LOW + ES_ICON_SECURITY_LOW_SYMBOLIC + ES_ICON_SECURITY_MEDIUM + ES_ICON_SECURITY_MEDIUM_SYMBOLIC + ES_ICON_SEMI_STARRED + ES_ICON_SEMI_STARRED_SYMBOLIC + ES_ICON_SOFTWARE_UPDATE_AVAILABLE_SYMBOLIC + ES_ICON_SOFTWARE_UPDATE_URGENT_SYMBOLIC + ES_ICON_STARRED + ES_ICON_STARRED_SYMBOLIC + ES_ICON_TASK_DUE_SYMBOLIC + ES_ICON_TASK_PAST_DUE_SYMBOLIC + ES_ICON_TEST + ES_ICON_TOUCHPAD_DISABLED_SYMBOLIC + ES_ICON_USER_AVAILABLE + ES_ICON_USER_AVAILABLE_SYMBOLIC + ES_ICON_USER_AWAY + ES_ICON_USER_AWAY_SYMBOLIC + ES_ICON_USER_BUSY + ES_ICON_USER_BUSY_SYMBOLIC + ES_ICON_USER_IDLE_SYMBOLIC + ES_ICON_USER_INVISIBLE + ES_ICON_USER_INVISIBLE_SYMBOLIC + ES_ICON_USER_OFFLINE + ES_ICON_USER_OFFLINE_SYMBOLIC + ES_ICON_USER_STATUS_PENDING_SYMBOLIC + ES_ICON_USER_TRASH_FULL_SYMBOLIC + ES_ICON_USER_TYPING + ES_ICON_VIEW_PRIVATE + ES_ICON_VIEW_PRIVATE_SYMBOLIC + ES_ICON_VIEW_WRAPPED_SYMBOLIC + ES_ICON_WEATHER_CLEAR_NIGHT_SYMBOLIC + ES_ICON_WEATHER_CLEAR_SYMBOLIC + ES_ICON_WEATHER_FEW_CLOUDS_NIGHT_SYMBOLIC + ES_ICON_WEATHER_FEW_CLOUDS_SYMBOLIC + ES_ICON_WEATHER_FOG_NIGHT_SYMBOLIC + ES_ICON_WEATHER_FOG_SYMBOLIC + ES_ICON_WEATHER_OVERCAST_NIGHT_SYMBOLIC + ES_ICON_WEATHER_OVERCAST_SYMBOLIC + ES_ICON_WEATHER_SEVERE_ALERT_SYMBOLIC + ES_ICON_WEATHER_SHOWERS_NIGHT_SYMBOLIC + ES_ICON_WEATHER_SHOWERS_SCATTERED_NIGHT_SYMBOLIC + ES_ICON_WEATHER_SHOWERS_SCATTERED_SYMBOLIC + ES_ICON_WEATHER_SHOWERS_SYMBOLIC + ES_ICON_WEATHER_SNOW_NIGHT_SYMBOLIC + ES_ICON_WEATHER_SNOW_SYMBOLIC + ES_ICON_WEATHER_STORM_NIGHT_SYMBOLIC + ES_ICON_WEATHER_STORM_SYMBOLIC + ES_ICON_WEATHER_STORM_TORNADO_NIGHT_SYMBOLIC + ES_ICON_WEATHER_STORM_TORNADO_SYMBOLIC + ES_ICON_WEATHER_WINDY_SYMBOLIC +} diff --git a/desktop/list_view.cpp b/desktop/list_view.cpp new file mode 100644 index 0000000..50b25d5 --- /dev/null +++ b/desktop/list_view.cpp @@ -0,0 +1,2616 @@ +// TODO RMB click/drag. +// TODO Consistent int64_t/intptr_t. +// TODO Drag and drop. +// TODO GetFirstIndex/GetLastIndex assume that every group is non-empty. + +struct ListViewItemElement : EsElement { + uintptr_t index; // Index into the visible items array. +}; + +struct ListViewItem { + ListViewItemElement *element; + int32_t group; + int32_t size; + EsGeneric index; + uint8_t indent; + bool startAtSecondColumn; + bool isHeader, isFooter; + bool showSearchHighlight; +}; + +struct ListViewGroup { + // TODO Empty groups. + uint64_t itemCount; + int64_t totalSize; + uint32_t flags; + bool initialised; +}; + +struct ListViewFixedItem { + char *string; + size_t stringBytes; + EsGeneric data; +}; + +int ListViewProcessItemMessage(EsElement *element, EsMessage *message); + +struct EsListView : EsElement { + ScrollPane scroll; + + uint64_t totalItemCount; + uint64_t totalSize; + Array groups; + Array visibleItems; + + const EsStyle *itemStyle, *headerItemStyle, *footerItemStyle; + int64_t fixedWidth, fixedHeight; + int64_t fixedHeaderSize, fixedFooterSize; + + // TODO Updating these when the style changes. + UIStyle *primaryCellStyle; + UIStyle *secondaryCellStyle; + + bool hasFocusedItem; + int32_t focusedItemGroup; + EsGeneric focusedItemIndex; + + bool hasAnchorItem; + int32_t anchorItemGroup; + EsGeneric anchorItemIndex; + + // Valid only during Z-order messages. + Array zOrderItems; + + EsElement *selectionBox; + bool hasSelectionBoxAnchor; + int64_t selectionBoxAnchorX, selectionBoxAnchorY, + selectionBoxPositionX, selectionBoxPositionY; + + bool firstLayout; + + char searchBuffer[64]; + size_t searchBufferBytes; + uint64_t searchBufferLastKeyTime; + + char *emptyMessage; + size_t emptyMessageBytes; + + EsElement *columnHeader; + EsListViewColumn *columns; + size_t columnCount; + int columnResizingOriginalWidth; + // TODO Updating this when the style changes. + int64_t totalColumnWidth; + + EsTextbox *inlineTextbox; + int32_t inlineTextboxGroup; + EsGeneric inlineTextboxIndex; + + int maximumItemsPerBand; + + // Fixed item storage: + Array fixedItems; + ptrdiff_t fixedItemSelection; + + inline EsRectangle GetListBounds() { + EsRectangle bounds = GetBounds(); + + if (columnHeader) { + bounds.t += columnHeader->currentStyle->preferredHeight; + } + + return bounds; + } + + int CompareIndices(int32_t groupIndex, EsGeneric left, EsGeneric right) { + if (left.u == right.u) { + return 0; + } + + if (~flags & ES_LIST_VIEW_NON_LINEAR) { + if (left.i > right.i) return 1; + if (left.i < right.i) return -1; + } + + EsMessage m = { ES_MSG_LIST_VIEW_COMPARE_INDICES }; + m.compareIndices.group = groupIndex; + m.compareIndices.left = left; + m.compareIndices.right = right; + EsAssert(EsMessageSend(this, &m) == ES_HANDLED); // Could not compare indices. + return m.compareIndices.result; + } + + inline void GetFirstIndex(EsMessage *message) { + EsAssert(message->iterateIndex.group < (int32_t) groups.Length()); // Invalid group index. + EsAssert(groups[message->iterateIndex.group].itemCount); // No items in the group. + + if (flags & ES_LIST_VIEW_NON_LINEAR) { + message->type = ES_MSG_LIST_VIEW_FIRST_INDEX; + EsAssert(ES_HANDLED == EsMessageSend(this, message)); // First index message not handled. + } else { + message->iterateIndex.index.i = 0; + } + } + + inline EsGeneric GetFirstIndex(int32_t group) { + EsMessage m = {}; + m.iterateIndex.group = group; + GetFirstIndex(&m); + return m.iterateIndex.index; + } + + inline void GetLastIndex(EsMessage *message) { + EsAssert(message->iterateIndex.group < (int32_t) groups.Length()); // Invalid group index. + EsAssert(groups[message->iterateIndex.group].itemCount); // No items in the group. + + if (flags & ES_LIST_VIEW_NON_LINEAR) { + message->type = ES_MSG_LIST_VIEW_LAST_INDEX; + EsAssert(ES_HANDLED == EsMessageSend(this, message)); // First index message not handled. + } else { + message->iterateIndex.index.i = groups[message->iterateIndex.group].itemCount - 1; + } + } + + inline EsGeneric GetLastIndex(int32_t group) { + EsMessage m = {}; + m.iterateIndex.group = group; + GetLastIndex(&m); + return m.iterateIndex.index; + } + + inline bool IterateForwards(EsMessage *message) { + if (flags & ES_LIST_VIEW_NON_LINEAR) { + message->type = ES_MSG_LIST_VIEW_NEXT_INDEX; + int response = EsMessageSend(this, message); + EsAssert(0 != response); // Next index message not handled. + return response == ES_HANDLED; + } else { + if (message->iterateIndex.index.u == groups[message->iterateIndex.group].itemCount - 1) { + if (message->iterateIndex.group == (int32_t) groups.Length() - 1) { + return false; + } + + message->iterateIndex.group++; + message->iterateIndex.index.i = 0; + } else { + message->iterateIndex.index.i++; + } + + return true; + } + } + + inline bool IterateBackwards(EsMessage *message) { + if (flags & ES_LIST_VIEW_NON_LINEAR) { + message->type = ES_MSG_LIST_VIEW_PREVIOUS_INDEX; + int response = EsMessageSend(this, message); + EsAssert(0 != response); // Previous index message not handled. + return response == ES_HANDLED; + } else { + if (message->iterateIndex.index.u == 0) { + if (message->iterateIndex.group == 0) { + return false; + } + + message->iterateIndex.group--; + message->iterateIndex.index.i = groups[message->iterateIndex.group].itemCount - 1; + } else { + message->iterateIndex.index.i--; + } + + return true; + } + } + + int64_t CountItems(int32_t groupIndex, EsGeneric firstIndex, EsGeneric lastIndex) { + if (firstIndex.u == lastIndex.u) { + return 1; + } + + if (~flags & ES_LIST_VIEW_NON_LINEAR) { + return lastIndex.i - firstIndex.i + 1; + } + + { + EsMessage m = { ES_MSG_LIST_VIEW_COUNT_ITEMS }; + m.itemRange.group = groupIndex; + m.itemRange.firstIndex = firstIndex; + m.itemRange.lastIndex = lastIndex; + + if (ES_HANDLED == EsMessageSend(this, &m)) { + return m.itemRange.result; + } + } + + EsMessage m = {}; + m.iterateIndex.group = groupIndex; + m.iterateIndex.index = firstIndex; + + int64_t count = 1; + + while (true) { + IterateForwards(&m); + EsAssert(groupIndex == m.iterateIndex.group); // Index range did not exist in group. + count++; + + if (m.iterateIndex.index.u == lastIndex.u) { + return count; + } + } + } + + int64_t MeasureItems(int32_t groupIndex, EsGeneric firstIndex, EsGeneric lastIndex, int64_t *count = nullptr) { + int64_t _tempCount = -1; + if (!count) count = &_tempCount; + + if (~flags & ES_LIST_VIEW_NON_LINEAR) { + if (*count == -1) { + *count = lastIndex.i - firstIndex.i + 1; + } else { + EsAssert(*count == lastIndex.i - firstIndex.i + 1); // Invalid item count. + } + } + + bool haveCount = *count != -1; + bool variableSize = flags & ES_LIST_VIEW_VARIABLE_SIZE; + + if (!variableSize) { + if (!haveCount) { + *count = CountItems(groupIndex, firstIndex, lastIndex); + } + + ListViewGroup *group = &groups[groupIndex]; + int64_t normalCount = *count; + int64_t additionalSize = 0; + + if ((group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) && firstIndex.u == 0) { + normalCount--; + additionalSize += fixedHeaderSize; + } + + if ((group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) && lastIndex.u == group->itemCount - 1) { + normalCount--; + additionalSize += fixedFooterSize; + } + + return additionalSize + normalCount * (flags & ES_LIST_VIEW_HORIZONTAL ? fixedWidth : fixedHeight); + } + + if (firstIndex.u != lastIndex.u) { + EsMessage m = { ES_MSG_LIST_VIEW_MEASURE_RANGE }; + m.itemRange.group = groupIndex; + m.itemRange.firstIndex = firstIndex; + m.itemRange.lastIndex = lastIndex; + + if (ES_HANDLED == EsMessageSend(this, &m)) { + return m.itemRange.result; + } + } + + EsMessage m = {}; + m.iterateIndex.group = groupIndex; + m.iterateIndex.index = firstIndex; + int64_t total = 0; + int64_t _count = 0; + + while (true) { + EsMessage m2 = { ES_MSG_LIST_VIEW_MEASURE_ITEM }; + m2.measureItem.group = groupIndex; + m2.measureItem.index = m.iterateIndex.index; + EsAssert(ES_HANDLED == EsMessageSend(this, &m2)); // Variable height list view must be able to measure items. + total += m2.measureItem.result; + _count++; + + if (m.iterateIndex.index.u == lastIndex.u) { + if (*count != -1) EsAssert(*count == _count); // Invalid item count. + else *count = _count; + return total; + } + + IterateForwards(&m); + EsAssert(groupIndex == m.iterateIndex.group); // Index range did not exist in group. + } + } + + void GetItemPosition(int32_t groupIndex, EsGeneric index, int64_t *_position, int64_t *_itemSize) { + int64_t gapBetweenGroup = currentStyle->gapMajor, + gapBetweenItems = (flags & ES_LIST_VIEW_TILED) ? currentStyle->gapWrap : currentStyle->gapMinor, + fixedSize = (flags & ES_LIST_VIEW_VARIABLE_SIZE) ? 0 : (flags & ES_LIST_VIEW_HORIZONTAL ? fixedWidth : fixedHeight), + startInset = flags & ES_LIST_VIEW_HORIZONTAL ? currentStyle->insets.l : currentStyle->insets.t; + + int64_t position = (flags & ES_LIST_VIEW_HORIZONTAL ? -scroll.position[0] : -scroll.position[1]) + startInset, + itemSize = 0; + + EsGeneric targetIndex = index; + + for (int32_t i = 0; i < groupIndex; i++) { + position += groups[i].totalSize + gapBetweenGroup; + } + + ListViewGroup *group = &groups[groupIndex]; + + if ((group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) && index.u == 0) { + itemSize = fixedHeaderSize; + } else if ((group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) && index.u == group->itemCount - 1) { + position += group->totalSize - fixedFooterSize; + itemSize = fixedFooterSize; + } else if ((~flags & ES_LIST_VIEW_NON_LINEAR) && (~flags & ES_LIST_VIEW_VARIABLE_SIZE)) { + // TODO MAP_TO_LINEAR if non-linear but fixed size. + + intptr_t linearIndex = index.i; + + if (group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) { + linearIndex--; + position += fixedHeaderSize + gapBetweenItems; + } + + linearIndex /= GetItemsPerBand(); + position += (fixedSize + gapBetweenItems) * linearIndex; + itemSize = fixedSize; + } else { + EsAssert(~flags & ES_LIST_VIEW_TILED); // Tiled list views must be linear and fixed-size.; + + EsMessage index = {}; + index.type = ES_MSG_LIST_VIEW_FIND_POSITION; + index.iterateIndex.group = groupIndex; + index.iterateIndex.index = targetIndex; + + if (ES_HANDLED == EsMessageSend(this, &index)) { + position += index.iterateIndex.position; + } else { + if (group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) { + position += fixedHeaderSize + gapBetweenItems; + } + + bool forwards; + ListViewItem *reference = visibleItems.Length() ? visibleItems.array : nullptr; + + bool closerToStartThanReference = reference && targetIndex.i < reference->index.i / 2; + bool closerToEndThanReference = reference && targetIndex.i > reference->index.i / 2 + (intptr_t) group->itemCount / 2; + if (flags & ES_LIST_VIEW_NON_LINEAR) closerToStartThanReference = closerToEndThanReference = false; + + if (reference && reference->group == groupIndex && !closerToStartThanReference && !closerToEndThanReference) { + index.iterateIndex.index = reference->index; + position = (flags & ES_LIST_VIEW_HORIZONTAL) ? reference->element->offsetX : reference->element->offsetY; + forwards = CompareIndices(groupIndex, reference->index, targetIndex) < 0; + + EsMessage firstIndex = {}; + firstIndex.iterateIndex.group = groupIndex; + GetFirstIndex(&firstIndex); + + if (index.iterateIndex.index == firstIndex.iterateIndex.index) { + forwards = true; + } + } else if ((~flags & ES_LIST_VIEW_NON_LINEAR) && targetIndex.u > group->itemCount / 2) { + GetLastIndex(&index); + position += group->totalSize; + position -= MeasureItems(index.iterateIndex.group, index.iterateIndex.index, index.iterateIndex.index); + forwards = false; + } else { + GetFirstIndex(&index); + forwards = true; + } + + while (index.iterateIndex.index.u != targetIndex.u) { + int64_t size = MeasureItems(index.iterateIndex.group, index.iterateIndex.index, index.iterateIndex.index); + position += forwards ? (size + gapBetweenItems) : -(size + gapBetweenItems); + EsAssert((forwards ? IterateForwards(&index) : IterateBackwards(&index)) && index.iterateIndex.group == groupIndex); + // Could not find the item in the group. + } + + itemSize = MeasureItems(index.iterateIndex.group, index.iterateIndex.index, index.iterateIndex.index); + } + } + + *_position = position; + *_itemSize = itemSize; + } + + void EnsureItemVisible(int32_t groupIndex, EsGeneric index, bool alignTop) { + EsRectangle contentBounds = GetListBounds(); + + int64_t startInset = flags & ES_LIST_VIEW_HORIZONTAL ? currentStyle->insets.l : currentStyle->insets.t, + endInset = flags & ES_LIST_VIEW_HORIZONTAL ? currentStyle->insets.r : currentStyle->insets.b, + contentSize = flags & ES_LIST_VIEW_HORIZONTAL ? Width(contentBounds) : Height(contentBounds); + + int64_t position, itemSize; + GetItemPosition(groupIndex, index, &position, &itemSize); + + if (position >= 0 && position + itemSize <= contentSize - endInset) { + return; + } + + if (alignTop) { + if (flags & ES_LIST_VIEW_HORIZONTAL) { + scroll.SetX(scroll.position[0] + position - startInset); + } else { + scroll.SetY(scroll.position[1] + position - startInset); + } + } else { + if (flags & ES_LIST_VIEW_HORIZONTAL) { + scroll.SetX(scroll.position[0] + position + itemSize - contentSize + endInset); + } else { + scroll.SetY(scroll.position[1] + position + itemSize - contentSize + endInset); + } + } + } + + EsMessage FindFirstVisibleItem(int64_t *_position, int64_t position, ListViewItem *reference, bool *noItems) { + int64_t gapBetweenGroup = currentStyle->gapMajor, + gapBetweenItems = (flags & ES_LIST_VIEW_TILED) ? currentStyle->gapWrap : currentStyle->gapMinor, + fixedSize = (flags & ES_LIST_VIEW_VARIABLE_SIZE) ? 0 : (flags & ES_LIST_VIEW_HORIZONTAL ? fixedWidth : fixedHeight); + + // Find the group. + // TODO Faster searching when there are many groups. + + int32_t groupIndex = 0; + bool foundGroup = false; + + for (; groupIndex < (int32_t) groups.Length(); groupIndex++) { + ListViewGroup *group = &groups[groupIndex]; + int64_t totalSize = group->totalSize; + + if (position + totalSize > 0) { + foundGroup = true; + break; + } + + position += totalSize + gapBetweenGroup; + } + + if (!foundGroup) { + if (noItems) { + *noItems = true; + return {}; + } else { + EsAssert(false); // Could not find the first visible item with the given scroll. + } + } + + EsMessage index = {}; + index.iterateIndex.group = groupIndex; + + // Can we go directly to the item? + + if ((~flags & ES_LIST_VIEW_NON_LINEAR) && (~flags & ES_LIST_VIEW_VARIABLE_SIZE)) { + // TODO MAP_FROM_LINEAR message if non-linear but fixed size. + + index.iterateIndex.index.i = 0; + intptr_t addHeader = 0; + + ListViewGroup *group = &groups[groupIndex]; + + if (group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) { + if (position + fixedHeaderSize > 0) { + *_position = position; + return index; + } + + position += fixedHeaderSize + gapBetweenItems; + addHeader = 1; + } + + intptr_t band = -position / (fixedSize + gapBetweenItems); + if (band < 0) band = 0; + position += band * (fixedSize + gapBetweenItems); + + if (flags & ES_LIST_VIEW_TILED) { + band *= GetItemsPerBand(); + } + + index.iterateIndex.index.i = band + addHeader; + + if (index.iterateIndex.index.i >= (intptr_t) group->itemCount) { + index.iterateIndex.index.i = group->itemCount - 1; + } + + *_position = position; + return index; + } + + EsAssert(~flags & ES_LIST_VIEW_TILED); // Trying to use TILED mode with NON_LINEAR or VARIABLE_SIZE mode. + + // Try asking the application to find the item. + + index.type = ES_MSG_LIST_VIEW_FIND_INDEX; + index.iterateIndex.position = -position; + + if (ES_HANDLED == EsMessageSend(this, &index)) { + *_position = -index.iterateIndex.position; + return index; + } + + // Find the item within the group, manually. + + bool forwards; + + if (reference && reference->group == groupIndex) { + int64_t referencePosition = (flags & ES_LIST_VIEW_HORIZONTAL) ? reference->element->offsetX : reference->element->offsetY; + + if (AbsoluteInteger64(referencePosition) < AbsoluteInteger64(position) + && AbsoluteInteger64(referencePosition) < AbsoluteInteger64(position + groups[groupIndex].totalSize)) { + index.iterateIndex.index = reference->index; + position = referencePosition; // Use previous first visible item as reference. + forwards = position < 0; + + EsMessage firstIndex = {}; + firstIndex.iterateIndex.group = groupIndex; + GetFirstIndex(&firstIndex); + + if (index.iterateIndex.index == firstIndex.iterateIndex.index) { + forwards = true; + } + + goto gotReference; + } + } + + if (position + groups[groupIndex].totalSize / 2 >= 0) { + GetFirstIndex(&index); // Use start of group as reference. + forwards = true; + } else { + GetLastIndex(&index); // Use end of group as reference + position += groups[groupIndex].totalSize; + position -= MeasureItems(index.iterateIndex.group, index.iterateIndex.index, index.iterateIndex.index); + forwards = false; + } + + gotReference:; + + if (forwards) { + // Iterate forwards from reference point. + + while (true) { + int64_t size = fixedSize ?: MeasureItems(index.iterateIndex.group, index.iterateIndex.index, index.iterateIndex.index); + + if (position + size > 0) { + *_position = position; + return index; + } + + EsAssert(IterateForwards(&index) && index.iterateIndex.group == groupIndex); + // No items in the group are visible. Maybe invalid scroll position? + position += size + gapBetweenItems; + } + } else { + // Iterate backwards from reference point. + + while (true) { + if (position <= 0 || !IterateBackwards(&index)) { + *_position = position; + return index; + } + + int64_t size = fixedSize ?: MeasureItems(index.iterateIndex.group, index.iterateIndex.index, index.iterateIndex.index); + EsAssert(index.iterateIndex.group == groupIndex); + // No items in the group are visible. Maybe invalid scroll position? + position -= size + gapBetweenItems; + } + } + } + + void Populate() { + // TODO Keep one item before and after the viewport, so tab traversal on custom elements works. + // TODO Always keep an item if it has FOCUS_WITHIN. + // - But maybe we shouldn't allow focusable elements in a list view. + + if (!totalItemCount) { + return; + } + + EsRectangle contentBounds = GetListBounds(); + int64_t contentSize = flags & ES_LIST_VIEW_HORIZONTAL ? Width(contentBounds) : Height(contentBounds); + int64_t scroll = EsCRTfloor(flags & ES_LIST_VIEW_HORIZONTAL ? (this->scroll.position[0] - currentStyle->insets.l) + : (this->scroll.position[1] - currentStyle->insets.t)); + + int64_t position = 0; + bool noItems = false; + EsMessage currentItem = FindFirstVisibleItem(&position, -scroll, visibleItems.Length() ? visibleItems.array : nullptr, &noItems); + uintptr_t visibleIndex = 0; + + int64_t wrapLimit = GetWrapLimit(); + int64_t fixedMinorSize = (flags & ES_LIST_VIEW_HORIZONTAL) ? fixedHeight : fixedWidth; + intptr_t itemsPerBand = GetItemsPerBand(); + intptr_t itemInBand = 0; + int64_t computedMinorGap = currentStyle->gapMinor; + int64_t minorPosition = 0; + int64_t centerOffset = (flags & ES_LIST_VIEW_CENTER_TILES) + ? (wrapLimit - itemsPerBand * (fixedMinorSize + currentStyle->gapMinor) + currentStyle->gapMinor) / 2 : 0; + + while (visibleIndex < visibleItems.Length()) { + // Remove visible items no longer visible, before the viewport. + + ListViewItem *visibleItem = &visibleItems[visibleIndex]; + int64_t visibleItemPosition = flags & ES_LIST_VIEW_HORIZONTAL ? visibleItem->element->offsetX : visibleItem->element->offsetY; + if (visibleItemPosition >= position) break; + visibleItem->element->index = visibleIndex; + visibleItem->element->Destroy(); + visibleItems.Delete(visibleIndex); + } + + while (position < contentSize && !noItems) { + ListViewItem *visibleItem = visibleIndex == visibleItems.Length() ? nullptr : &visibleItems[visibleIndex]; + + if (visibleItem && visibleItem->index == currentItem.iterateIndex.index + && visibleItem->group == currentItem.iterateIndex.group) { + // This is already a visible item. + + if (~flags & ES_LIST_VIEW_TILED) { + int64_t expectedPosition = (flags & ES_LIST_VIEW_HORIZONTAL) + ? visibleItem->element->offsetX - contentBounds.l + : visibleItem->element->offsetY - contentBounds.t; + + if (position < expectedPosition - 1 || position > expectedPosition + 1) { + EsPrint("Item in unexpected position: expected %d, got %d; index %d, scroll %d.\n", + expectedPosition, position, visibleItem->index.i, scroll); + EsAssert(false); + } + } + } else { + // Add a new visible item. + + ListViewItem empty = {}; + visibleItems.Insert(empty, visibleIndex); + visibleItem = &visibleItems[visibleIndex]; + + visibleItem->group = currentItem.iterateIndex.group; + visibleItem->index = currentItem.iterateIndex.index; + visibleItem->size = MeasureItems(visibleItem->group, visibleItem->index, visibleItem->index); + + ListViewGroup *group = &groups[visibleItem->group]; + const EsStyle *style = nullptr; + + if ((group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) && visibleItem->index.i == 0 ) { + style = headerItemStyle; + visibleItem->isHeader = true; + } else if ((group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) && visibleItem->index.i == (intptr_t) group->itemCount - 1) { + style = footerItemStyle; + visibleItem->isFooter = true; + } else { + if (group->flags & ES_LIST_VIEW_GROUP_INDENT) { + visibleItem->indent++; + } + + style = itemStyle; + } + + visibleItem->element = (ListViewItemElement *) EsHeapAllocate(sizeof(ListViewItemElement), true); + visibleItem->element->Initialise(this, ES_CELL_FILL, nullptr, style); + visibleItem->element->index = visibleIndex; + visibleItem->element->cName = "list view item"; + + visibleItem->element->messageClass = ListViewProcessItemMessage; + + if (hasFocusedItem && visibleItem->group == focusedItemGroup && visibleItem->index.u == focusedItemIndex.u) { + visibleItem->element->customStyleState |= THEME_STATE_FOCUSED_ITEM; + } + + if (state & UI_STATE_FOCUSED) { + visibleItem->element->customStyleState |= THEME_STATE_LIST_FOCUSED; + } + + EsMessage m = {}; + + m.type = ES_MSG_LIST_VIEW_IS_SELECTED; + m.selectItem.group = visibleItem->group; + m.selectItem.index = visibleItem->index; + EsMessageSend(this, &m); + if (m.selectItem.isSelected) visibleItem->element->customStyleState |= THEME_STATE_SELECTED; + + m.type = ES_MSG_LIST_VIEW_CREATE_ITEM; + m.createItem.group = visibleItem->group; + m.createItem.index = visibleItem->index; + m.createItem.item = visibleItem->element; + EsMessageSend(this, &m); + + m.type = ES_MSG_LIST_VIEW_GET_INDENT; + m.getIndent.group = visibleItem->group; + m.getIndent.index = visibleItem->index; + m.getIndent.indent = 0; + EsMessageSend(this, &m); + visibleItem->indent += m.getIndent.indent; + + SelectPreview(visibleItems.Length() - 1); + + visibleItem->element->MaybeRefreshStyle(); + } + + visibleItem->element->index = visibleIndex; + + // Update the item's position. + + ListViewGroup *group = &groups[visibleItem->group]; + + if ((flags & ES_LIST_VIEW_TILED) && !visibleItem->isHeader && !visibleItem->isFooter) { + if (flags & ES_LIST_VIEW_HORIZONTAL) { + visibleItem->element->InternalMove(fixedWidth, fixedHeight, + position + contentBounds.l, minorPosition + currentStyle->insets.t + contentBounds.t + centerOffset); + } else { + visibleItem->element->InternalMove(fixedWidth, fixedHeight, + minorPosition + currentStyle->insets.l + contentBounds.l + centerOffset, position + contentBounds.t); + } + + minorPosition += computedMinorGap + fixedMinorSize; + itemInBand++; + + bool endOfGroup = ((group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) && currentItem.iterateIndex.index.u == group->itemCount - 2) + || (currentItem.iterateIndex.index.u == group->itemCount - 1); + + if (itemInBand == itemsPerBand || endOfGroup) { + minorPosition = 0; + itemInBand = 0; + position += (flags & ES_LIST_VIEW_HORIZONTAL) ? visibleItem->element->width : visibleItem->element->height; + if (!endOfGroup || (group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER)) position += currentStyle->gapWrap; + } + } else { + if (flags & ES_LIST_VIEW_HORIZONTAL) { + visibleItem->element->InternalMove( + visibleItem->size, + Height(contentBounds) - currentStyle->insets.t - currentStyle->insets.b - visibleItem->indent * currentStyle->gapWrap, + position + contentBounds.l, + currentStyle->insets.t - this->scroll.position[1] + visibleItem->indent * currentStyle->gapWrap + contentBounds.t); + position += visibleItem->element->width; + } else if (flags & ES_LIST_VIEW_COLUMNS) { + int indent = visibleItem->indent * currentStyle->gapWrap; + int firstColumn = columns[0].width + secondaryCellStyle->gapMajor; + visibleItem->startAtSecondColumn = indent > firstColumn; + if (indent > firstColumn) indent = firstColumn; + visibleItem->element->InternalMove( + totalColumnWidth - indent, + visibleItem->size, + indent - this->scroll.position[0] + contentBounds.l + currentStyle->insets.l, + position + contentBounds.t); + position += visibleItem->element->height; + } else { + int indent = visibleItem->indent * currentStyle->gapWrap + currentStyle->insets.l; + visibleItem->element->InternalMove(Width(contentBounds) - indent - currentStyle->insets.r, visibleItem->size, + indent + contentBounds.l - this->scroll.position[0], position + contentBounds.t); + position += visibleItem->element->height; + } + + if ((flags & ES_LIST_VIEW_TILED) && (group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) && currentItem.iterateIndex.index.u == 0) { + position += currentStyle->gapWrap; + } + } + + // Go to the next item. + + visibleIndex++; + int32_t previousGroup = currentItem.iterateIndex.group; + if (!IterateForwards(¤tItem)) break; + position += previousGroup == currentItem.iterateIndex.group ? (flags & ES_LIST_VIEW_TILED ? 0 : currentStyle->gapMinor) : currentStyle->gapMajor; + } + + while (visibleIndex < visibleItems.Length()) { + // Remove visible items no longer visible, after the viewport. + + ListViewItem *visibleItem = &visibleItems[visibleIndex]; + visibleItem->element->index = visibleIndex; + visibleItem->element->Destroy(); + visibleItems.Delete(visibleIndex); + } + } + + void Wrap(bool autoScroll) { + if (~flags & ES_LIST_VIEW_TILED) return; + + totalSize = 0; + + intptr_t itemsPerBand = GetItemsPerBand(); + + for (uintptr_t i = 0; i < groups.Length(); i++) { + ListViewGroup *group = &groups[i]; + int64_t groupSize = 0; + + intptr_t itemCount = group->itemCount; + + if (group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) { + groupSize += fixedHeaderSize + currentStyle->gapWrap; + itemCount--; + } + + if (group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) { + groupSize += fixedFooterSize + currentStyle->gapWrap; + itemCount--; + } + + intptr_t bandsInGroup = (itemCount + itemsPerBand - 1) / itemsPerBand; + groupSize += (((flags & ES_LIST_VIEW_HORIZONTAL) ? fixedWidth : fixedHeight) + currentStyle->gapWrap) * bandsInGroup; + groupSize -= currentStyle->gapWrap; + group->totalSize = groupSize; + + totalSize += groupSize + (group == &groups.Last() ? 0 : currentStyle->gapMajor); + } + + scroll.Refresh(); + + if (visibleItems.Length() && autoScroll) { + EnsureItemVisible(visibleItems[0].group, visibleItems[0].index, true); + } + } + + void InsertSpace(int64_t space, uintptr_t beforeItem) { + if (!space) return; + + if (flags & ES_LIST_VIEW_TILED) { + EsElementUpdateContentSize(this); + return; + } + + int64_t currentScroll = (flags & ES_LIST_VIEW_HORIZONTAL) ? scroll.position[0] : scroll.position[1]; + int64_t scrollLimit = (flags & ES_LIST_VIEW_HORIZONTAL) ? scroll.limit[0] : scroll.limit[1]; + + totalSize += space; + + if (((beforeItem == 0 && currentScroll) || currentScroll == scrollLimit) && firstLayout && space > 0 && scrollLimit) { + scroll.Refresh(); + + if (flags & ES_LIST_VIEW_HORIZONTAL) { + scroll.SetX(scroll.position[0] + space, false); + } else { + scroll.SetY(scroll.position[1] + space, false); + } + } else { + for (uintptr_t i = beforeItem; i < visibleItems.Length(); i++) { + ListViewItem *item = &visibleItems[i]; + + if (flags & ES_LIST_VIEW_HORIZONTAL) { + item->element->offsetX += space; + } else { + item->element->offsetY += space; + } + } + + scroll.Refresh(); + } + + EsElementUpdateContentSize(this); + } + + void SetSelected(int32_t fromGroup, EsGeneric fromIndex, int32_t toGroup, EsGeneric toIndex, + bool select, bool toggle, + intptr_t period = 0, intptr_t periodBegin = 0, intptr_t periodEnd = 0) { + if (!select && (flags & ES_LIST_VIEW_CHOICE_SELECT)) { + return; + } + + if (!select && (flags & ES_LIST_VIEW_SINGLE_SELECT)) { + EsMessage m = {}; + m.type = ES_MSG_LIST_VIEW_SELECT; + m.selectItem.isSelected = false; + fixedItemSelection = -1; + EsMessageSend(this, &m); + return; + } + + if (fromGroup == toGroup && CompareIndices(fromGroup, fromIndex, toIndex) > 0) { + EsGeneric temp = fromIndex; + fromIndex = toIndex; + toIndex = temp; + } else if (fromGroup > toGroup) { + int32_t temp1 = fromGroup; + fromGroup = toGroup; + toGroup = temp1; + EsGeneric temp2 = fromIndex; + fromIndex = toIndex; + toIndex = temp2; + } + + EsMessage start = {}, end = {}; + start.iterateIndex.group = fromGroup; + end.iterateIndex.group = fromGroup; + + for (; start.iterateIndex.group <= toGroup; start.iterateIndex.group++, end.iterateIndex.group++) { + if (start.iterateIndex.group == fromGroup) { + start.iterateIndex.index = fromIndex; + } else { + GetFirstIndex(&start); + } + + if (end.iterateIndex.group == toGroup) { + end.iterateIndex.index = toIndex; + } else { + GetLastIndex(&end); + } + + EsMessage m = { ES_MSG_LIST_VIEW_SELECT_RANGE }; + m.selectRange.group = start.iterateIndex.group; + m.selectRange.fromIndex = start.iterateIndex.index; + m.selectRange.toIndex = end.iterateIndex.index; + m.selectRange.select = select; + m.selectRange.toggle = toggle; + + if (!period && 0 != EsMessageSend(this, &m)) { + continue; + } + + intptr_t linearIndex = 0; + + while (true) { + m.selectItem.group = start.iterateIndex.group; + m.selectItem.index = start.iterateIndex.index; + m.selectItem.isSelected = select; + + if (period) { + ListViewGroup *group = &groups[m.selectItem.group]; + intptr_t i = linearIndex; + + if (group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) { + if (linearIndex == 0) { + goto process; + } else { + i--; + } + } + + if (group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) { + if (linearIndex == (intptr_t) group->itemCount - 1) { + goto process; + } + } + + i %= period; + + if (i < periodBegin || i > periodEnd) { + goto ignore; + } + } + + process:; + + if (toggle) { + m.type = ES_MSG_LIST_VIEW_IS_SELECTED; + EsMessageSend(this, &m); + m.selectItem.isSelected = !m.selectItem.isSelected; + } + + m.type = ES_MSG_LIST_VIEW_SELECT; + fixedItemSelection = m.selectItem.index.u; + EsMessageSend(this, &m); + + ignore:; + + if (start.iterateIndex.index == end.iterateIndex.index) { + break; + } + + IterateForwards(&start); + linearIndex++; + EsAssert(start.iterateIndex.group == end.iterateIndex.group); // The from and to selection indices in the group were incorrectly ordered. + } + } + } + + void SelectPreview(intptr_t singleItem = -1) { + if (!hasSelectionBoxAnchor) { + return; + } + + int64_t x1 = selectionBoxPositionX, x2 = selectionBoxAnchorX, + y1 = selectionBoxPositionY, y2 = selectionBoxAnchorY; + + if (x1 > x2) { int64_t temp = x1; x1 = x2; x2 = temp; } + if (y1 > y2) { int64_t temp = y1; y1 = y2; y2 = temp; } + + x1 -= scroll.position[0], x2 -= scroll.position[0]; + y1 -= scroll.position[1], y2 -= scroll.position[1]; + + EsRectangle bounds = GetListBounds(); + + if (x1 < -1000) x1 = -1000; + if (x2 < -1000) x2 = -1000; + if (y1 < -1000) y1 = -1000; + if (y2 < -1000) y2 = -1000; + + if (x1 > bounds.r + 1000) x1 = bounds.r + 1000; + if (x2 > bounds.r + 1000) x2 = bounds.r + 1000; + if (y1 > bounds.b + 1000) y1 = bounds.b + 1000; + if (y2 > bounds.b + 1000) y2 = bounds.b + 1000; + + selectionBox->InternalMove(x2 - x1, y2 - y1, x1, y1); + + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + if (singleItem != -1) { + i = singleItem; + } + + EsMessage m = { ES_MSG_LIST_VIEW_IS_SELECTED }; + m.selectItem.index = visibleItems[i].index; + m.selectItem.group = visibleItems[i].group; + EsMessageSend(this, &m); + + EsElement *item = visibleItems[i].element; + + if (x1 < item->offsetX + item->width && x2 >= item->offsetX && y1 < item->offsetY + item->height && y2 >= item->offsetY) { + if (EsKeyboardIsCtrlHeld()) { + m.selectItem.isSelected = !m.selectItem.isSelected; + } else { + m.selectItem.isSelected = true; + } + } + + if (m.selectItem.isSelected) { + item->customStyleState |= THEME_STATE_SELECTED; + } else { + item->customStyleState &= ~THEME_STATE_SELECTED; + } + + item->MaybeRefreshStyle(); + + if (singleItem != -1) { + break; + } + } + } + + intptr_t GetItemsPerBand() { + if (~flags & ES_LIST_VIEW_TILED) { + return 1; + } else { + int64_t wrapLimit = GetWrapLimit(); + int64_t fixedMinorSize = (flags & ES_LIST_VIEW_HORIZONTAL) ? fixedHeight : fixedWidth; + intptr_t itemsPerBand = fixedMinorSize && ((fixedMinorSize + currentStyle->gapMinor) < wrapLimit) + ? (wrapLimit / (fixedMinorSize + currentStyle->gapMinor)) : 1; + return MinimumInteger(itemsPerBand, maximumItemsPerBand); + } + } + + void SelectBox(int64_t x1, int64_t x2, int64_t y1, int64_t y2, bool toggle) { + if (!totalItemCount) { + return; + } + + EsRectangle contentBounds = GetListBounds(); + int64_t offset = 0; + EsMessage start, end; + bool noItems = false; + + if (flags & ES_LIST_VIEW_HORIZONTAL) { + if (y1 >= contentBounds.b - currentStyle->insets.b || y2 < contentBounds.t + currentStyle->insets.t) { + return; + } + } else if (flags & ES_LIST_VIEW_COLUMNS) { + if (x1 >= contentBounds.l + currentStyle->insets.l + totalColumnWidth || x2 < contentBounds.l + currentStyle->insets.l) { + return; + } + } else { + if (x1 >= contentBounds.r - currentStyle->insets.r || x2 < contentBounds.l + currentStyle->insets.l) { + return; + } + } + + // TODO Use reference for FindFirstVisibleItem. + + bool adjustStart = false, adjustEnd = false; + int r1 = (flags & ES_LIST_VIEW_HORIZONTAL) ? currentStyle->insets.l - x1 : currentStyle->insets.t - y1 + scroll.fixedViewport[1]; + int r2 = (flags & ES_LIST_VIEW_HORIZONTAL) ? currentStyle->insets.l - x2 : currentStyle->insets.t - y2 + scroll.fixedViewport[1]; + start = FindFirstVisibleItem(&offset, r1, nullptr, &noItems); + if (noItems) return; + adjustStart = -offset >= MeasureItems(start.iterateIndex.group, start.iterateIndex.index, start.iterateIndex.index); + end = FindFirstVisibleItem(&offset, r2, nullptr, &noItems); + adjustEnd = !noItems; + if (noItems) { end.iterateIndex.group = groups.Length() - 1; GetLastIndex(&end); } + + if (flags & ES_LIST_VIEW_TILED) { + int64_t wrapLimit = GetWrapLimit(); + int64_t fixedMinorSize = (flags & ES_LIST_VIEW_HORIZONTAL) ? fixedHeight : fixedWidth; + intptr_t itemsPerBand = GetItemsPerBand(); + int64_t computedMinorGap = (wrapLimit - itemsPerBand * fixedMinorSize) / (itemsPerBand + 1); + int64_t minorStartOffset = computedMinorGap + ((flags & ES_LIST_VIEW_HORIZONTAL) ? currentStyle->insets.t : currentStyle->insets.l); + intptr_t startInBand = (((flags & ES_LIST_VIEW_HORIZONTAL) ? y1 : x1) - minorStartOffset) / (fixedMinorSize + computedMinorGap); + intptr_t endInBand = (((flags & ES_LIST_VIEW_HORIZONTAL) ? y2 : x2) - minorStartOffset) / (fixedMinorSize + computedMinorGap); + + if (adjustStart) { + ListViewGroup *group = &groups[start.iterateIndex.group]; + + if (((group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) && start.iterateIndex.index.u == 0) + || ((group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) && start.iterateIndex.index.u == group->itemCount - 1)) { + IterateForwards(&start); + } else { + for (intptr_t i = 0; i < itemsPerBand; i++) { + if ((group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) && start.iterateIndex.index.u == group->itemCount - 1) { + break; + } + + IterateForwards(&start); + } + } + } + + if (adjustEnd) { + ListViewGroup *group = &groups[end.iterateIndex.group]; + + if (((group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) && end.iterateIndex.index.u == 0) + || ((group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) && end.iterateIndex.index.u == group->itemCount - 1)) { + } else { + for (intptr_t i = 0; i < itemsPerBand - 1; i++) { + if ((group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) && end.iterateIndex.index.u == group->itemCount - 1) { + IterateBackwards(&end); + break; + } + + IterateForwards(&end); + } + } + } + + SetSelected(start.iterateIndex.group, start.iterateIndex.index, end.iterateIndex.group, end.iterateIndex.index, true, toggle, + itemsPerBand, startInBand, endInBand); + } else { + if (adjustStart) { + IterateForwards(&start); + } + + SetSelected(start.iterateIndex.group, start.iterateIndex.index, end.iterateIndex.group, end.iterateIndex.index, true, toggle); + } + } + + void UpdateVisibleItemSelectionState(uintptr_t i) { + EsMessage m = {}; + m.type = ES_MSG_LIST_VIEW_IS_SELECTED; + m.selectItem.group = visibleItems[i].group; + m.selectItem.index = visibleItems[i].index; + EsMessageSend(this, &m); + + if (m.selectItem.isSelected) { + visibleItems[i].element->customStyleState |= THEME_STATE_SELECTED; + } else { + visibleItems[i].element->customStyleState &= ~THEME_STATE_SELECTED; + } + + visibleItems[i].element->MaybeRefreshStyle(); + } + + void UpdateVisibleItemsSelectionState() { + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + UpdateVisibleItemSelectionState(i); + } + } + + void Select(int32_t group, EsGeneric index, bool range, bool toggle, bool moveAnchorOnly) { + if ((~flags & ES_LIST_VIEW_SINGLE_SELECT) && (~flags & ES_LIST_VIEW_MULTI_SELECT) && (~flags & ES_LIST_VIEW_CHOICE_SELECT)) { + return; + } + + if (!totalItemCount) { + return; + } + + if (!hasAnchorItem || (~flags & ES_LIST_VIEW_MULTI_SELECT)) { + range = false; + } + + bool emptySpace = false; + + if (group == -1) { + // Clicked on empty space. + if (range || toggle) return; + emptySpace = true; + } + + if (!range && !emptySpace) { + hasAnchorItem = true; + anchorItemGroup = group; + anchorItemIndex = index; + } + + if (moveAnchorOnly) { + return; + } + + if (!toggle) { + // Clear existing selection. + SetSelected(0, GetFirstIndex(0), groups.Length() - 1, GetLastIndex(groups.Length() - 1), false, false); + } + + if (range) { + // Select range. + SetSelected(anchorItemGroup, anchorItemIndex, group, index, true, false); + } else if (toggle) { + // Toggle single item. + SetSelected(group, index, group, index, false, true); + } else if (!emptySpace) { + // Select single item. + SetSelected(group, index, group, index, true, false); + } + + UpdateVisibleItemsSelectionState(); + } + + int ProcessItemMessage(uintptr_t visibleIndex, EsMessage *message, ListViewItemElement *element) { + ListViewItem *item = &visibleItems[visibleIndex]; + + if (message->type == ES_MSG_PAINT) { + EsMessage m = { ES_MSG_LIST_VIEW_GET_CONTENT }; + uint8_t _buffer[512]; + EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; + m.getContent.buffer = &buffer; + m.getContent.index = item->index; + m.getContent.group = item->group; + + EsTextSelection selection = {}; + selection.hideCaret = true; + + if (searchBufferBytes && item->showSearchHighlight) { + // TODO We might need to store the matched bytes per item, because of case insensitivity. + selection.caret1 = searchBufferBytes; + selection.hideCaret = false; + } + + if (flags & ES_LIST_VIEW_COLUMNS) { + EsRectangle bounds = EsRectangleAddBorder(element->GetBounds(), element->currentStyle->insets); + + for (uintptr_t i = item->startAtSecondColumn ? 1 : 0; i < columnCount; i++) { + m.getContent.column = i; + m.getContent.icon = 0; + buffer.position = 0; + + bounds.r = bounds.l + columns[i].width + - element->currentStyle->insets.r - element->currentStyle->insets.l; + + if (i == 0) { + bounds.r -= item->indent * currentStyle->gapWrap; + } + + EsRectangle drawBounds = { bounds.l + message->painter->offsetX, bounds.r + message->painter->offsetX, + bounds.t + message->painter->offsetY, bounds.b + message->painter->offsetY }; + + if (EsRectangleClip(drawBounds, message->painter->clip, nullptr) + && ES_HANDLED == EsMessageSend(this, &m)) { + UIStyle *style = i ? secondaryCellStyle : primaryCellStyle; + + uint8_t previousTextAlign = style->textAlign; + + if (columns[i].flags & ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED) { + style->textAlign ^= ES_TEXT_H_RIGHT | ES_TEXT_H_LEFT; + } + + style->PaintText(message->painter, element, bounds, + (char *) _buffer, buffer.position, m.getContent.icon, + (columns[i].flags & ES_LIST_VIEW_COLUMN_TABULAR) ? ES_DRAW_CONTENT_TABULAR : ES_FLAGS_DEFAULT, + i ? nullptr : &selection); + style->textAlign = previousTextAlign; + } + + bounds.l += columns[i].width + secondaryCellStyle->gapMajor; + + if (i == 0) { + bounds.l -= item->indent * currentStyle->gapWrap; + } + } + } else { + if (flags & ES_LIST_VIEW_TILED) { + m.type = ES_MSG_LIST_VIEW_GET_SUMMARY; + if (ES_HANDLED == EsMessageSend(this, &m)) goto standardPaint; + m.type = ES_MSG_LIST_VIEW_GET_CONTENT; + } + + if (ES_HANDLED == EsMessageSend(this, &m)) goto standardPaint; + + return 0; + + standardPaint:; + + if (inlineTextbox && inlineTextboxGroup == item->group && inlineTextboxIndex.u == item->index.u) { + buffer.position = 0; + } + + EsDrawContent(message->painter, element, element->GetBounds(), + (char *) _buffer, buffer.position, m.getContent.icon, + m.getContent.richText ? ES_DRAW_CONTENT_RICH_TEXT : ES_FLAGS_DEFAULT, + &selection); + } + } else if (message->type == ES_MSG_LAYOUT) { + if (element->GetChildCount()) { + EsElement *child = element->GetChild(0); + EsRectangle bounds = element->GetBounds(); + child->InternalMove(bounds.r - bounds.l, bounds.b - bounds.t, bounds.l, bounds.t); + } + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + EsElementFocus(this); + + if (hasFocusedItem) { + ListViewItem *oldFocus = FindVisibleItem(focusedItemGroup, focusedItemIndex); + + if (oldFocus) { + oldFocus->element->customStyleState &= ~THEME_STATE_FOCUSED_ITEM; + oldFocus->element->MaybeRefreshStyle(); + } + } + + hasFocusedItem = true; + focusedItemGroup = item->group; + focusedItemIndex = item->index; + element->customStyleState |= THEME_STATE_FOCUSED_ITEM; + + Select(item->group, item->index, EsKeyboardIsShiftHeld(), EsKeyboardIsCtrlHeld(), false); + + if (message->mouseDown.clickChainCount == 2 && !EsKeyboardIsShiftHeld() && !EsKeyboardIsCtrlHeld()) { + EsMessage m = { ES_MSG_LIST_VIEW_CHOOSE_ITEM }; + m.chooseItem.group = item->group; + m.chooseItem.index = item->index; + EsMessageSend(this, &m); + } + } else if (message->type == ES_MSG_MOUSE_RIGHT_DOWN) { + EsMessage m = { ES_MSG_LIST_VIEW_IS_SELECTED }; + m.selectItem.index = item->index; + m.selectItem.group = item->group; + EsMessageSend(this, &m); + + if (!m.selectItem.isSelected) { + Select(item->group, item->index, EsKeyboardIsShiftHeld(), EsKeyboardIsCtrlHeld(), false); + } + + m.type = ES_MSG_LIST_VIEW_CONTEXT_MENU; + EsMessageSend(this, &m); + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + if (flags & ES_LIST_VIEW_CHOICE_SELECT) { + window->pressed = this; + ProcessMessage(message); + } + } else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) { + EsMessage m = { ES_MSG_LIST_VIEW_GET_CONTENT }; + uint8_t _buffer[256]; + EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; + m.getContent.buffer = &buffer; + m.getContent.index = item->index; + m.getContent.group = item->group; + EsMessageSend(this, &m); + EsBufferFormat(message->getContent.buffer, "index %d '%s'", item->index.u, buffer.position, buffer.out); + } else { + return 0; + } + + return ES_HANDLED; + } + + inline int GetWrapLimit() { + EsRectangle bounds = GetListBounds(); + return (flags & ES_LIST_VIEW_HORIZONTAL) + ? bounds.b - bounds.t - currentStyle->insets.b - currentStyle->insets.t + : bounds.r - bounds.l - currentStyle->insets.r - currentStyle->insets.l; + } + + ListViewItem *FindVisibleItem(int32_t group, EsGeneric index) { + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + ListViewItem *item = &visibleItems[i]; + + if (item->group == group && item->index.u == index.u) { + return item; + } + } + + return nullptr; + } + + bool Search() { + uint8_t _buffer[64]; + + if (!hasFocusedItem) { + // Select the first item in the list. + KeyInput(ES_SCANCODE_DOWN_ARROW, false, false, false, true); + if (!hasFocusedItem) return false; + } + + EsMessage m = { ES_MSG_LIST_VIEW_SEARCH }; + m.searchItem.index = focusedItemIndex; + m.searchItem.group = focusedItemGroup; + m.searchItem.query = searchBuffer; + m.searchItem.queryBytes = searchBufferBytes; + int response = EsMessageSend(this, &m); + + if (response == ES_REJECTED) { + return false; + } + + ListViewItem *oldFocus = FindVisibleItem(focusedItemGroup, focusedItemIndex); + + if (oldFocus) { + oldFocus->element->customStyleState &= ~THEME_STATE_FOCUSED_ITEM; + oldFocus->element->MaybeRefreshStyle(); + } + + bool found = false; + + if (response == ES_HANDLED) { + focusedItemIndex = m.searchItem.index; + focusedItemGroup = m.searchItem.group; + found = true; + } else { + EsMessage m = { ES_MSG_LIST_VIEW_GET_CONTENT }; + EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; + m.getContent.buffer = &buffer; + m.getContent.index = focusedItemIndex; + m.getContent.group = focusedItemGroup; + EsMessage m2 = {}; + m2.iterateIndex.index = focusedItemIndex; + m2.iterateIndex.group = focusedItemGroup; + + do { + buffer.position = 0; + EsMessageSend(this, &m); + + if (EsStringStartsWith((char *) _buffer, buffer.position, searchBuffer, searchBufferBytes, true)) { + found = true; + break; + } + + if (!IterateForwards(&m2)) { + m2.iterateIndex.group = 0; + GetFirstIndex(&m2); + } + + m.getContent.index = m2.iterateIndex.index; + m.getContent.group = m2.iterateIndex.group; + } while (m.getContent.index.u != focusedItemIndex.u || m.getContent.group != focusedItemGroup); + + focusedItemIndex = m.getContent.index; + focusedItemGroup = m.getContent.group; + EnsureItemVisible(focusedItemGroup, focusedItemIndex, false); + } + + ListViewItem *newFocus = FindVisibleItem(focusedItemGroup, focusedItemIndex); + + if (newFocus) { + newFocus->element->customStyleState |= THEME_STATE_FOCUSED_ITEM; + newFocus->element->MaybeRefreshStyle(); + } + + { + EsMessage m = { ES_MSG_LIST_VIEW_GET_CONTENT }; + EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; + m.getContent.buffer = &buffer; + + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + ListViewItem *item = &visibleItems[i]; + m.getContent.index = item->index; + m.getContent.group = item->group; + buffer.position = 0; + EsMessageSend(this, &m); + bool shouldShowSearchHighlight = EsStringStartsWith((char *) _buffer, buffer.position, searchBuffer, searchBufferBytes, true); + + if (shouldShowSearchHighlight || (!shouldShowSearchHighlight && item->showSearchHighlight)) { + item->showSearchHighlight = shouldShowSearchHighlight; + item->element->Repaint(true); + } + } + } + + Select(-1, 0, false, false, false); + Select(focusedItemGroup, focusedItemIndex, false, false, false); + return found; + } + + bool KeyInput(int scancode, bool ctrl, bool alt, bool shift, bool keepSearchBuffer = false) { + if (!totalItemCount || alt) { + return false; + } + + if (scancode == ES_SCANCODE_BACKSPACE && searchBufferBytes) { + searchBufferBytes = 0; + Search(); + return true; + } + + bool isNext = false, + isPrevious = false, + isNextBand = false, + isPreviousBand = false, + isHome = scancode == ES_SCANCODE_HOME, + isEnd = scancode == ES_SCANCODE_END, + isPageUp = scancode == ES_SCANCODE_PAGE_UP, + isPageDown = scancode == ES_SCANCODE_PAGE_DOWN, + isSpace = scancode == ES_SCANCODE_SPACE, + isEnter = scancode == ES_SCANCODE_ENTER; + + if (flags & ES_LIST_VIEW_HORIZONTAL) { + isNext = scancode == ES_SCANCODE_DOWN_ARROW; + isNextBand = scancode == ES_SCANCODE_RIGHT_ARROW; + isPrevious = scancode == ES_SCANCODE_UP_ARROW; + isPreviousBand = scancode == ES_SCANCODE_LEFT_ARROW; + } else { + isNext = scancode == ES_SCANCODE_RIGHT_ARROW; + isNextBand = scancode == ES_SCANCODE_DOWN_ARROW; + isPrevious = scancode == ES_SCANCODE_LEFT_ARROW; + isPreviousBand = scancode == ES_SCANCODE_UP_ARROW; + } + + if (hasSelectionBoxAnchor) { + if (scancode == ES_SCANCODE_UP_ARROW) scroll.SetY(scroll.position[1] - GetConstantNumber("scrollKeyMovement")); + if (scancode == ES_SCANCODE_DOWN_ARROW) scroll.SetY(scroll.position[1] + GetConstantNumber("scrollKeyMovement")); + if (scancode == ES_SCANCODE_LEFT_ARROW) scroll.SetX(scroll.position[0] - GetConstantNumber("scrollKeyMovement")); + if (scancode == ES_SCANCODE_RIGHT_ARROW) scroll.SetX(scroll.position[0] + GetConstantNumber("scrollKeyMovement")); + if (scancode == ES_SCANCODE_PAGE_UP) scroll.SetY(scroll.position[1] - Height(GetBounds())); + if (scancode == ES_SCANCODE_PAGE_DOWN) scroll.SetY(scroll.position[1] + Height(GetBounds())); + + if (flags & ES_LIST_VIEW_HORIZONTAL) { + if (scancode == ES_SCANCODE_HOME) scroll.SetX(0); + if (scancode == ES_SCANCODE_END) scroll.SetX(scroll.limit[0]); + } else { + if (scancode == ES_SCANCODE_HOME) scroll.SetY(0); + if (scancode == ES_SCANCODE_END) scroll.SetY(scroll.limit[1]); + } + } else if (isPrevious || isNext || isHome || isEnd || isPageUp || isPageDown || isNextBand || isPreviousBand) { + ListViewItem *oldFocus = FindVisibleItem(focusedItemGroup, focusedItemIndex); + + if (oldFocus) { + oldFocus->element->customStyleState &= ~THEME_STATE_FOCUSED_ITEM; + oldFocus->element->MaybeRefreshStyle(); + } + + EsMessage m = {}; + + if (hasFocusedItem && (isPrevious || isNext || isPageUp || isPageDown || isNextBand || isPreviousBand)) { + m.iterateIndex.group = focusedItemGroup; + m.iterateIndex.index = focusedItemIndex; + + uintptr_t itemsPerBand = GetItemsPerBand(); + + for (uintptr_t i = 0; i < ((isPageUp || isPageDown) ? (10 * itemsPerBand) : (isNextBand || isPreviousBand) ? itemsPerBand : 1); i++) { + if (isNext || isPageDown || isNextBand) IterateForwards(&m); + else IterateBackwards(&m); + } + } else { + if (isNext || isNextBand || isHome) { + m.iterateIndex.group = 0; + GetFirstIndex(&m); + } else { + m.iterateIndex.group = groups.Length() - 1; + GetLastIndex(&m); + } + } + + hasFocusedItem = true; + focusedItemGroup = m.iterateIndex.group; + focusedItemIndex = m.iterateIndex.index; + + ListViewItem *newFocus = FindVisibleItem(focusedItemGroup, focusedItemIndex); + + if (newFocus) { + newFocus->element->customStyleState |= THEME_STATE_FOCUSED_ITEM; + newFocus->element->MaybeRefreshStyle(); + } + + if (!keepSearchBuffer) ClearSearchBuffer(); + EnsureItemVisible(focusedItemGroup, focusedItemIndex, isPrevious || isHome || isPageUp || isPreviousBand); + Select(focusedItemGroup, focusedItemIndex, shift, ctrl, ctrl && !shift); + return true; + } else if (isSpace && ctrl && !shift && hasFocusedItem) { + Select(focusedItemGroup, focusedItemIndex, false, true, false); + return true; + } else if (isEnter && hasFocusedItem && !shift && !ctrl && !alt) { + EsMessage m = { ES_MSG_LIST_VIEW_CHOOSE_ITEM }; + m.chooseItem.group = focusedItemGroup; + m.chooseItem.index = focusedItemIndex; + EsMessageSend(this, &m); + return true; + } else if (!ctrl && !alt) { + uint64_t currentTime = EsTimeStamp() / (api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] * 1000); + + if (searchBufferLastKeyTime + GetConstantNumber("listViewSearchBufferTimeout") < currentTime) { + searchBufferBytes = 0; + } + + StartAnimating(); + searchBufferLastKeyTime = currentTime; + int ic, isc; + ConvertScancodeToCharacter(scancode, &ic, &isc, false, false); + int character = shift ? isc : ic; + + if (character != -1 && searchBufferBytes + 4 < sizeof(searchBuffer)) { + utf8_encode(character, searchBuffer + searchBufferBytes); + size_t previousSearchBufferBytes = searchBufferBytes; + searchBufferBytes += utf8_length_char(searchBuffer + searchBufferBytes); + if (!Search()) searchBufferBytes = previousSearchBufferBytes; + return true; + } + } + + return false; + } + + void ClearSearchBuffer() { + searchBufferBytes = 0; + + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + if (visibleItems[i].showSearchHighlight) { + visibleItems[i].showSearchHighlight = false; + visibleItems[i].element->Repaint(true); + } + } + } + + void DragSelect() { + EsRectangle bounds = GetWindowBounds(); + EsPoint mouse = EsMouseGetPosition(window); + + if (mouse.x < bounds.l) mouse.x = bounds.l; + if (mouse.x >= bounds.r) mouse.x = bounds.r - 1; + + if (visibleItems.Length()) { + int32_t start = visibleItems[0].element->GetWindowBounds().t; + int32_t end = visibleItems.Last().element->GetWindowBounds().b; + if (mouse.y < start) mouse.y = start; + if (mouse.y >= end) mouse.y = end - 1; + } + + EsElement *hoverItem = UIFindHoverElementRecursively(this, bounds.l - offsetX, bounds.t - offsetY, mouse); + + if (hoverItem && hoverItem->messageClass == ListViewProcessItemMessage) { + EsMessage m = {}; + m.type = ES_MSG_MOUSE_LEFT_DOWN; + EsMessageSend(hoverItem, &m); + } + } + + void MoveInlineTextbox(ListViewItem *item) { + UIStyle *style = item->element->currentStyle; + + if (flags & ES_LIST_VIEW_COLUMNS) { + int offset = primaryCellStyle->metrics->iconSize + primaryCellStyle->gapMinor + + style->insets.l - inlineTextbox->currentStyle->insets.l; + inlineTextbox->InternalMove(columns[0].width - offset, item->element->height, + item->element->offsetX + offset, item->element->offsetY); + } else if (flags & ES_LIST_VIEW_TILED) { + if (style->metrics->layoutVertical) { + int height = inlineTextbox->currentStyle->preferredHeight; + int textStart = style->metrics->iconSize + style->gapMinor + style->insets.t; + int textEnd = item->element->height - style->insets.b; + int offset = (textStart + textEnd - height) / 2; + inlineTextbox->InternalMove(item->element->width - style->insets.r - style->insets.l, height, + item->element->offsetX + style->insets.l, item->element->offsetY + offset); + } else { + int textboxInset = inlineTextbox->currentStyle->insets.l; + int offset = style->metrics->iconSize + style->gapMinor + + style->insets.l - textboxInset; + int height = inlineTextbox->currentStyle->preferredHeight; + inlineTextbox->InternalMove(item->element->width - offset - style->insets.r + textboxInset, height, + item->element->offsetX + offset, + item->element->offsetY + (item->element->height - height) / 2); + } + } else { + inlineTextbox->InternalMove(item->element->width, item->element->height, + item->element->offsetX, item->element->offsetY); + } + } + + int ProcessMessage(EsMessage *message) { + scroll.ReceivedMessage(message); + + if (message->type == ES_MSG_GET_WIDTH || message->type == ES_MSG_GET_HEIGHT) { + if (flags & ES_LIST_VIEW_HORIZONTAL) { + message->measure.width = totalSize + currentStyle->insets.l + currentStyle->insets.r; + } else { + message->measure.height = totalSize + currentStyle->insets.t + currentStyle->insets.b; + + if (flags & ES_LIST_VIEW_COLUMNS) { + message->measure.width = totalColumnWidth + currentStyle->insets.l + currentStyle->insets.r; + } + } + } else if (message->type == ES_MSG_LAYOUT) { + firstLayout = true; + Wrap(message->layout.sizeChanged); + Populate(); + + if (columnHeader) { + EsRectangle bounds = GetBounds(); + columnHeader->InternalMove(Width(bounds), columnHeader->currentStyle->preferredHeight, 0, 0); + } + + if (inlineTextbox) { + ListViewItem *item = FindVisibleItem(inlineTextboxGroup, inlineTextboxIndex); + if (item) MoveInlineTextbox(item); + } + } else if (message->type == ES_MSG_SCROLL_X || message->type == ES_MSG_SCROLL_Y) { + int64_t delta = message->scrollbarMoved.scroll - message->scrollbarMoved.previous; + + if ((message->type == ES_MSG_SCROLL_X) == ((flags & ES_LIST_VIEW_HORIZONTAL) ? true : false)) { + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + if (flags & ES_LIST_VIEW_HORIZONTAL) visibleItems[i].element->offsetX -= delta; + else visibleItems[i].element->offsetY -= delta; + } + } + + Populate(); + Repaint(true); + + if (columnHeader) { + EsElementRelayout(columnHeader); + } + + if (selectionBox) { + EsPoint position = EsMouseGetPosition(this); + selectionBoxPositionX = position.x + scroll.position[0]; + selectionBoxPositionY = position.y + scroll.position[1]; + SelectPreview(); + } + } else if (message->type == ES_MSG_DESTROY) { + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + visibleItems[i].element->Destroy(); + } + + for (uintptr_t i = 0; i < fixedItems.Length(); i++) { + EsHeapFree(fixedItems[i].string); + } + + primaryCellStyle->CloseReference(); + secondaryCellStyle->CloseReference(); + fixedItems.Free(); + visibleItems.Free(); + groups.Free(); + } else if (message->type == ES_MSG_KEY_UP) { + if (message->keyboard.scancode == ES_SCANCODE_LEFT_CTRL || message->keyboard.scancode == ES_SCANCODE_RIGHT_CTRL) { + SelectPreview(); + } + } else if (message->type == ES_MSG_KEY_DOWN) { + if (message->keyboard.scancode == ES_SCANCODE_LEFT_CTRL || message->keyboard.scancode == ES_SCANCODE_RIGHT_CTRL) { + SelectPreview(); + } + + return KeyInput(message->keyboard.scancode, + message->keyboard.modifiers & ES_MODIFIER_CTRL, + message->keyboard.modifiers & ES_MODIFIER_ALT, + message->keyboard.modifiers & ES_MODIFIER_SHIFT) + ? ES_HANDLED : 0; + } else if (message->type == ES_MSG_FOCUSED_START) { + if (!hasFocusedItem && groups.Length() && (message->focus.flags & ES_ELEMENT_FOCUS_FROM_KEYBOARD)) { + hasFocusedItem = true; + focusedItemGroup = 0; + focusedItemIndex = GetFirstIndex(focusedItemGroup); + } + + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + ListViewItem *item = &visibleItems[i]; + item->element->customStyleState |= THEME_STATE_LIST_FOCUSED; + + if (hasFocusedItem && focusedItemGroup == item->group && focusedItemIndex.u == item->index.u) { + item->element->customStyleState |= THEME_STATE_FOCUSED_ITEM; + } + + item->element->MaybeRefreshStyle(); + } + + EsCommand *command = EsCommandByID(instance, ES_COMMAND_SELECT_ALL); + command->data = this; + + EsCommandSetCallback(command, [] (EsInstance *, EsElement *, EsCommand *command) { + EsListView *list = (EsListView *) command->data.p; + if (!list->groups.Length() || !list->totalItemCount) return; + list->SetSelected(0, list->GetFirstIndex(0), list->groups.Length() - 1, list->GetLastIndex(list->groups.Length() - 1), true, false); + list->UpdateVisibleItemsSelectionState(); + }); + + EsCommandSetDisabled(command, false); + } else if (message->type == ES_MSG_FOCUSED_END) { + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + ListViewItem *item = &visibleItems[i]; + item->element->customStyleState &= ~(THEME_STATE_LIST_FOCUSED | THEME_STATE_FOCUSED_ITEM); + item->element->MaybeRefreshStyle(); + } + + EsCommandSetCallback(EsCommandByID(instance, ES_COMMAND_SELECT_ALL), nullptr); + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + Select(-1, 0, EsKeyboardIsShiftHeld(), EsKeyboardIsCtrlHeld(), false); + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + if (selectionBox) { + Repaint(false, ES_RECT_4(selectionBox->offsetX, selectionBox->offsetX + selectionBox->width, + selectionBox->offsetY, selectionBox->offsetY + selectionBox->height)); + + if (!hasSelectionBoxAnchor) { + hasSelectionBoxAnchor = true; + selectionBoxAnchorX = message->mouseDragged.originalPositionX + scroll.position[0]; + selectionBoxAnchorY = message->mouseDragged.originalPositionY + scroll.position[1]; + + if (gui.lastClickButton == ES_MSG_MOUSE_LEFT_DOWN) { + Select(-1, 0, EsKeyboardIsShiftHeld(), EsKeyboardIsCtrlHeld(), false); + } + } + + EsElementSetDisabled(selectionBox, false); + + selectionBoxPositionX = message->mouseDragged.newPositionX + scroll.position[0]; + selectionBoxPositionY = message->mouseDragged.newPositionY + scroll.position[1]; + + SelectPreview(); + } else if (flags & ES_LIST_VIEW_CHOICE_SELECT) { + DragSelect(); + } + } else if (message->type == ES_MSG_MOUSE_LEFT_UP || message->type == ES_MSG_MOUSE_RIGHT_UP) { + if (selectionBox) { + EsElementSetDisabled(selectionBox, true); + + if (hasSelectionBoxAnchor) { + hasSelectionBoxAnchor = false; + + int64_t x1 = selectionBoxPositionX, x2 = selectionBoxAnchorX, + y1 = selectionBoxPositionY, y2 = selectionBoxAnchorY; + if (x1 > x2) { int64_t temp = x1; x1 = x2; x2 = temp; } + if (y1 > y2) { int64_t temp = y1; y1 = y2; y2 = temp; } + + SelectBox(x1, x2, y1, y2, EsKeyboardIsCtrlHeld()); + } + + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + EsMessage m = { ES_MSG_LIST_VIEW_IS_SELECTED }; + m.selectItem.index = visibleItems[i].index; + m.selectItem.group = visibleItems[i].group; + EsMessageSend(this, &m); + + EsElement *item = visibleItems[i].element; + + if (m.selectItem.isSelected) { + item->customStyleState |= THEME_STATE_SELECTED; + } else { + item->customStyleState &= ~THEME_STATE_SELECTED; + } + + item->MaybeRefreshStyle(); + } + } + } else if (message->type == ES_MSG_Z_ORDER) { + uintptr_t index = message->zOrder.index; + + if (index < visibleItems.Length()) { + EsAssert(zOrderItems.Length() == visibleItems.Length()); + message->zOrder.child = zOrderItems[index]; + return ES_HANDLED; + } else { + index -= visibleItems.Length(); + } + + if (selectionBox) { if (index == 0) return message->zOrder.child = selectionBox, ES_HANDLED; else index--; } + if (columnHeader) { if (index == 0) return message->zOrder.child = columnHeader, ES_HANDLED; else index--; } + if (inlineTextbox) { if (index == 0) return message->zOrder.child = inlineTextbox, ES_HANDLED; else index--; } + + message->zOrder.child = nullptr; + } else if (message->type == ES_MSG_PAINT && !totalItemCount && emptyMessageBytes) { + UIStyle *style = GetStyle(MakeStyleKey(ES_STYLE_TEXT_LABEL_SECONDARY, 0), true); + EsTextPlanProperties properties = {}; + properties.flags = ES_TEXT_H_CENTER | ES_TEXT_V_CENTER | ES_TEXT_WRAP | ES_TEXT_PLAN_SINGLE_USE; + EsTextRun textRun[2] = {}; + style->GetTextStyle(&textRun[0].style); + textRun[1].offset = emptyMessageBytes; + EsRectangle bounds = EsPainterBoundsInset(message->painter); + EsTextPlan *plan = EsTextPlanCreate(&properties, bounds, emptyMessage, textRun, 1); + EsDrawText(message->painter, plan, bounds); + } else if (message->type == ES_MSG_ANIMATE) { + if (scroll.dragScrolling && (flags & ES_LIST_VIEW_CHOICE_SELECT)) { + DragSelect(); + } + + uint64_t currentTime = EsTimeStamp() / (api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] * 1000); + int64_t remainingTime = searchBufferLastKeyTime + GetConstantNumber("listViewSearchBufferTimeout") - currentTime; + + if (remainingTime < 0) { + ClearSearchBuffer(); + } else { + message->animate.waitMs = remainingTime; + message->animate.complete = false; + } + } else if (message->type == ES_MSG_BEFORE_Z_ORDER) { + EsAssert(!zOrderItems.Length()); + intptr_t focused = -1, hovered = -1; + + for (uintptr_t i = 0; i < visibleItems.Length(); i++) { + if (hasFocusedItem && visibleItems[i].index.u == focusedItemIndex.u && visibleItems[i].group == focusedItemGroup) { + focused = i; + } else if (visibleItems[i].element->state & UI_STATE_HOVERED) { + hovered = i; + } else { + zOrderItems.Add(visibleItems[i].element); + } + } + + if (hovered != -1) { + zOrderItems.Add(visibleItems[hovered].element); + } + + if (focused != -1) { + zOrderItems.Add(visibleItems[focused].element); + } + } else if (message->type == ES_MSG_AFTER_Z_ORDER) { + zOrderItems.Free(); + } else if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT && (flags & ES_LIST_VIEW_FIXED_ITEMS)) { + uintptr_t index = message->getContent.index.u; + EsAssert(index < fixedItems.Length()); + EsBufferFormat(message->getContent.buffer, "%s", fixedItems[index].stringBytes, fixedItems[index].string); + } else if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED && (flags & ES_LIST_VIEW_FIXED_ITEMS)) { + message->selectItem.isSelected = message->selectItem.index.i == fixedItemSelection; + } else { + return 0; + } + + return ES_HANDLED; + } +}; + +int ListViewProcessMessage(EsElement *element, EsMessage *message) { + return ((EsListView *) element)->ProcessMessage(message); +} + +int ListViewProcessItemMessage(EsElement *_element, EsMessage *message) { + ListViewItemElement *element = (ListViewItemElement *) _element; + return ((EsListView *) element->parent)->ProcessItemMessage(element->index, message, element); +} + +void EsListViewChangeStyles(EsListView *view, const EsStyle *style, const EsStyle *itemStyle, + const EsStyle *headerItemStyle, const EsStyle *footerItemStyle, uint32_t addFlags, uint32_t removeFlags) { + // TODO Animating changes. + + bool wasTiledView = view->flags & ES_LIST_VIEW_TILED; + + EsAssert(!(addFlags & removeFlags)); + view->flags |= addFlags; + view->flags &= ~(uint64_t) removeFlags; + + bool horizontal = view->flags & ES_LIST_VIEW_HORIZONTAL; + + if (style) view->SetStyle(style, true); + if (itemStyle) view->itemStyle = itemStyle; + if (headerItemStyle) view->headerItemStyle = headerItemStyle; + if (footerItemStyle) view->footerItemStyle = footerItemStyle; + + GetPreferredSizeFromStylePart(view->itemStyle, &view->fixedWidth, &view->fixedHeight); + GetPreferredSizeFromStylePart(view->headerItemStyle, horizontal ? &view->fixedHeaderSize : nullptr, horizontal ? nullptr : &view->fixedHeaderSize); + GetPreferredSizeFromStylePart(view->footerItemStyle, horizontal ? &view->fixedFooterSize : nullptr, horizontal ? nullptr : &view->fixedFooterSize); + + if ((view->flags & ES_LIST_VIEW_MULTI_SELECT) && !view->selectionBox) { + view->selectionBox = EsCustomElementCreate(view, ES_CELL_FILL | ES_ELEMENT_DISABLED | ES_ELEMENT_NO_HOVER, ES_STYLE_LIST_SELECTION_BOX); + view->selectionBox->cName = "selection box"; + } else if ((~view->flags & ES_LIST_VIEW_MULTI_SELECT) && view->selectionBox) { + EsElementDestroy(view->selectionBox); + view->selectionBox = nullptr; + } + + if ((view->flags & ES_LIST_VIEW_COLUMNS) && !view->columnHeader) { + view->columnHeader = EsCustomElementCreate(view, ES_CELL_FILL, ES_STYLE_LIST_COLUMN_HEADER); + view->columnHeader->cName = "column header"; + view->columnHeader->userData = view; + + view->columnHeader->messageUser = [] (EsElement *element, EsMessage *message) { + EsListView *view = (EsListView *) element->userData.p; + + if (message->type == ES_MSG_LAYOUT) { + int x = view->currentStyle->insets.l - view->scroll.position[0]; + + for (uintptr_t i = 0; i < element->children.Length(); i += 2) { + EsElement *item = element->children[i], *splitter = element->children[i + 1]; + EsListViewColumn *column = view->columns + item->userData.u; + int splitterLeft = splitter->currentStyle->preferredWidth - view->secondaryCellStyle->gapMajor; + item->InternalMove(column->width - splitterLeft, element->height, x, 0); + splitter->InternalMove(splitter->currentStyle->preferredWidth, element->height, x + column->width - splitterLeft, 0); + x += column->width + view->secondaryCellStyle->gapMajor; + } + } + + return 0; + }; + + view->scroll.fixedViewport[1] = view->columnHeader->currentStyle->preferredHeight; + } else if ((~view->flags & ES_LIST_VIEW_COLUMNS) && view->columnHeader) { + EsElementDestroy(view->columnHeader); + view->columnHeader = nullptr; + view->scroll.fixedViewport[1] = 0; + } + + // It's safe to use SCROLL_MODE_AUTO even in tiled mode, + // because decreasing the secondary axis can only increase the primary axis. + + uint8_t scrollXMode = 0, scrollYMode = 0; + + if (view->flags & ES_LIST_VIEW_COLUMNS) { + scrollXMode = SCROLL_MODE_AUTO; + scrollYMode = SCROLL_MODE_AUTO; + } else if (view->flags & ES_LIST_VIEW_HORIZONTAL) { + scrollXMode = SCROLL_MODE_AUTO; + } else { + scrollYMode = SCROLL_MODE_AUTO; + } + + view->scroll.Setup(view, scrollXMode, scrollYMode, SCROLL_X_DRAG | SCROLL_Y_DRAG); + + // Remove existing visible items; the list will need to be repopulated. + + for (uintptr_t i = view->visibleItems.Length(); i > 0; i--) { + view->visibleItems[i - 1].element->Destroy(); + } + + view->visibleItems.SetLength(0); + + // Remeasure each group. + + if (wasTiledView) { + view->totalSize = 0; + + for (uintptr_t i = 0; i < view->groups.Length(); i++) { + view->groups[i].totalSize = 0; + } + } + + int64_t spaceDelta = 0; + + for (uintptr_t i = 0; i < view->groups.Length(); i++) { + if (!view->groups[i].itemCount) continue; + spaceDelta -= view->groups[i].totalSize; + view->groups[i].totalSize = view->MeasureItems(i, view->GetFirstIndex(i), view->GetLastIndex(i)); + spaceDelta += view->groups[i].totalSize; + } + + view->InsertSpace(spaceDelta, 0); + + EsElementRelayout(view); +} + +EsListView *EsListViewCreate(EsElement *parent, uint64_t flags, const EsStyle *style, + const EsStyle *itemStyle, const EsStyle *headerItemStyle, const EsStyle *footerItemStyle) { + EsListView *view = (EsListView *) EsHeapAllocate(sizeof(EsListView), true); + + view->primaryCellStyle = GetStyle(MakeStyleKey(ES_STYLE_LIST_PRIMARY_CELL, 0), false); + view->secondaryCellStyle = GetStyle(MakeStyleKey(ES_STYLE_LIST_SECONDARY_CELL, 0), false); + + view->Initialise(parent, flags | ES_ELEMENT_FOCUSABLE | ES_ELEMENT_CENTER_ACCESS_KEY_HINT, ListViewProcessMessage, style ?: ES_STYLE_LIST_VIEW); + view->cName = "list view"; + + view->fixedItemSelection = -1; + view->maximumItemsPerBand = INT_MAX; + + if (!itemStyle) { + if (flags & ES_LIST_VIEW_CHOICE_SELECT) itemStyle = ES_STYLE_LIST_CHOICE_ITEM; + else if (flags & ES_LIST_VIEW_TILED) itemStyle = ES_STYLE_LIST_ITEM_TILE; + else itemStyle = ES_STYLE_LIST_ITEM; + } + + EsListViewChangeStyles(view, nullptr, itemStyle, headerItemStyle ?: ES_STYLE_LIST_ITEM_GROUP_HEADER, + footerItemStyle ?: ES_STYLE_LIST_ITEM_GROUP_FOOTER, ES_FLAGS_DEFAULT, ES_FLAGS_DEFAULT); + + return view; +} + +void EsListViewInsertGroup(EsListView *view, int32_t group, uint32_t flags) { + EsMessageMutexCheck(); + + // Add the group. + + ListViewGroup empty = { .flags = flags }; + EsAssert(group <= (int32_t) view->groups.Length()); // Invalid group index. + view->groups.Insert(empty, group); + + // Update the group index on visible items. + + uintptr_t firstVisibleItemToMove = view->visibleItems.Length(); + + for (uintptr_t i = 0; i < view->visibleItems.Length(); i++) { + ListViewItem *item = &view->visibleItems[i]; + + if (item->group >= group) { + item->group++; + + if (i < firstVisibleItemToMove) { + firstVisibleItemToMove = i; + } + } + } + + // Insert gap between groups. + + view->InsertSpace(view->groups.Length() > 1 ? view->currentStyle->gapMajor : 0, firstVisibleItemToMove); + + // Create header and footer items. + + int64_t additionalItems = ((flags & ES_LIST_VIEW_GROUP_HAS_HEADER) ? 1 : 0) + ((flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) ? 1 : 0); + if (additionalItems) EsListViewInsert(view, group, 0, additionalItems - 1, additionalItems); + view->groups[group].initialised = true; +} + +void EsListViewInsert(EsListView *view, int32_t groupIndex, EsGeneric firstIndex, EsGeneric lastIndex, int64_t count) { + EsMessageMutexCheck(); + + bool pushIndices = false; + + if (~view->flags & ES_LIST_VIEW_NON_LINEAR) { + // Skip check for non-linear views, because it'd be expensive. + EsAssert(firstIndex.i <= lastIndex.i); // Invalid item index range. + + pushIndices = true; + } + + // Get the group. + + EsAssert(groupIndex < (int32_t) view->groups.Length()); // Invalid group index. + ListViewGroup *group = &view->groups[groupIndex]; + + if (group->initialised) { + if (group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) { + EsAssert(firstIndex.i > 0); // Cannot insert before group header. + } + + if (group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) { + EsAssert(firstIndex.i < (intptr_t) group->itemCount); // Cannot insert after group footer. + } + } + + // Add the items to the group. + + bool alreadySetItemCount = false; + bool addedFirstItemInGroup = !group->itemCount; + + if (count != -1) { + // Setting the item count early is necessary for MeasureItems when adding the group header/footer items. + alreadySetItemCount = true; + group->itemCount += count; + } + + int64_t totalSizeOfItems = view->MeasureItems(groupIndex, firstIndex, lastIndex, &count); + int64_t sizeToAdd = (count - (addedFirstItemInGroup ? 1 : 0)) * view->currentStyle->gapMinor + totalSizeOfItems; + + if (!alreadySetItemCount) group->itemCount += count; + group->totalSize += sizeToAdd; + view->totalItemCount += count; + + // Update indices of visible items. + + uintptr_t firstVisibleItemToMove = view->visibleItems.Length(); + + if (view->hasFocusedItem && view->focusedItemGroup == groupIndex && pushIndices) { + if (view->CompareIndices(groupIndex, view->focusedItemIndex, firstIndex) >= 0) { + view->focusedItemIndex.i += count; + } + } + + if (view->hasAnchorItem && view->anchorItemGroup == groupIndex && pushIndices) { + if (view->CompareIndices(groupIndex, view->anchorItemIndex, firstIndex) >= 0) { + view->anchorItemIndex.i += count; + } + } + + for (uintptr_t i = 0; i < view->visibleItems.Length(); i++) { + ListViewItem *item = &view->visibleItems[i]; + + if (item->group < groupIndex) { + continue; + } else if (item->group > groupIndex) { + if (i < firstVisibleItemToMove) { + firstVisibleItemToMove = i; + } + + break; + } + + if (view->flags & ES_LIST_VIEW_NON_LINEAR) { + int result = 1; + + if (firstVisibleItemToMove >= i) { + result = view->CompareIndices(groupIndex, item->index, lastIndex); + } + + EsAssert(result != 0); // Adding item already in the list. + + if (result > 0) { + if (i < firstVisibleItemToMove) { + firstVisibleItemToMove = i; + } + } + } else { + if (item->index.i >= firstIndex.i) { + item->index.i += count; + + if (i < firstVisibleItemToMove) { + firstVisibleItemToMove = i; + } + } + } + } + + // Insert the space for the items. + + view->InsertSpace(sizeToAdd, firstVisibleItemToMove); +} + +void EsListViewRemove(EsListView *view, int32_t groupIndex, EsGeneric firstIndex, EsGeneric lastIndex, int64_t count) { + EsMessageMutexCheck(); + + bool pushIndices = false; + + if (~view->flags & ES_LIST_VIEW_NON_LINEAR) { + // Skip check for non-linear views, because it'd be expensive. + EsAssert(firstIndex.i <= lastIndex.i); // Invalid item index range. + + pushIndices = true; + } + + // Get the group. + + EsAssert(groupIndex < (int32_t) view->groups.Length()); // Invalid group index. + ListViewGroup *group = &view->groups[groupIndex]; + + if (group->initialised) { + if (group->flags & ES_LIST_VIEW_GROUP_HAS_HEADER) { + EsAssert(firstIndex.i > 0); // Cannot remove the group header. + } + + if (group->flags & ES_LIST_VIEW_GROUP_HAS_FOOTER) { + EsAssert(lastIndex.i < (intptr_t) group->itemCount - 1); // Cannot remove the group footer. + } + } + + // Remove the items from the group. + + int64_t totalSizeOfItems = view->MeasureItems(groupIndex, firstIndex, lastIndex, &count); + int64_t sizeToRemove = (int64_t) group->itemCount == count ? group->totalSize + : (count * view->currentStyle->gapMinor + totalSizeOfItems); + + group->itemCount -= count; + group->totalSize -= sizeToRemove; + view->totalItemCount -= count; + + // Update indices of visible items, + // and remove deleted items. + + uintptr_t firstVisibleItemToMove = view->visibleItems.Length(); + + if (view->hasFocusedItem && view->focusedItemGroup == groupIndex) { + if (view->CompareIndices(groupIndex, view->focusedItemIndex, firstIndex) >= 0 + && view->CompareIndices(groupIndex, view->focusedItemIndex, lastIndex) <= 0) { + view->hasFocusedItem = false; + } else if (pushIndices) { + view->focusedItemIndex.i -= count; + } + } + + if (view->hasAnchorItem && view->anchorItemGroup == groupIndex) { + if (view->CompareIndices(groupIndex, view->focusedItemIndex, firstIndex) >= 0 + && view->CompareIndices(groupIndex, view->anchorItemIndex, lastIndex) <= 0) { + view->hasAnchorItem = false; + } else if (pushIndices) { + view->anchorItemIndex.i -= count; + } + } + + for (uintptr_t i = 0; i < view->visibleItems.Length(); i++) { + ListViewItem *item = &view->visibleItems[i]; + + if (item->group < groupIndex) { + continue; + } else if (item->group > groupIndex) { + if (i < firstVisibleItemToMove) { + firstVisibleItemToMove = i; + } + + break; + } + + if (view->flags & ES_LIST_VIEW_NON_LINEAR) { + int r1 = view->CompareIndices(groupIndex, item->index, firstIndex); + int r2 = view->CompareIndices(groupIndex, item->index, lastIndex); + + if (r1 < 0) EsAssert(r2 < 0); // Invalid index order. + if (r2 > 0) EsAssert(r1 > 0); // Invalid index order. + + if (r2 > 0) { + if (i < firstVisibleItemToMove) { + firstVisibleItemToMove = i; + } + } else if (r1 >= 0 && r2 <= 0) { + item->element->index = i; + item->element->Destroy(); + view->visibleItems.Delete(i); + i--; + } + } else { + if (item->index.i > lastIndex.i) { + item->index.i -= count; + + if (i < firstVisibleItemToMove) { + firstVisibleItemToMove = i; + } + } else if (item->index.i >= firstIndex.i && item->index.i <= lastIndex.i) { + item->element->index = i; + item->element->Destroy(); + view->visibleItems.Delete(i); + i--; + } + } + } + + // Remove the space of the items. + + view->InsertSpace(-sizeToRemove, firstVisibleItemToMove); +} + +void EsListViewRemoveAll(EsListView *view, int32_t group) { + EsMessageMutexCheck(); + + if (view->groups[group].itemCount) { + EsListViewRemove(view, group, view->GetFirstIndex(group), view->GetLastIndex(group), view->groups[group].itemCount); + } +} + +int ListViewColumnHeaderItemMessage(EsElement *element, EsMessage *message) { + EsListView *view = (EsListView *) element->parent->parent; + EsListViewColumn *column = view->columns + element->userData.u; + + if (message->type == ES_MSG_PAINT) { + EsMessage m = { ES_MSG_LIST_VIEW_GET_COLUMN_SORT }; + m.getColumnSort.index = element->userData.u; + int sort = EsMessageSend(view, &m); + EsDrawContent(message->painter, element, element->GetBounds(), + column->title, column->titleBytes, 0, + sort == ES_LIST_VIEW_COLUMN_SORT_ASCENDING ? ES_DRAW_CONTENT_MARKER_UP_ARROW + : sort == ES_LIST_VIEW_COLUMN_SORT_DESCENDING ? ES_DRAW_CONTENT_MARKER_DOWN_ARROW : ES_FLAGS_DEFAULT); + } else if (message->type == ES_MSG_MOUSE_LEFT_CLICK && (column->flags & ES_LIST_VIEW_COLUMN_HAS_MENU)) { + EsMessage m = { ES_MSG_LIST_VIEW_COLUMN_MENU }; + m.columnMenu.source = element; + m.columnMenu.index = element->userData.u; + EsMessageSend(view, &m); + } else { + return 0; + } + + return ES_HANDLED; +} + +void EsListViewSetColumns(EsListView *view, EsListViewColumn *columns, size_t columnCount) { + EsMessageMutexCheck(); + + EsAssert(view->flags & ES_LIST_VIEW_COLUMNS); // List view does not have columns flag set. + + EsElementDestroyContents(view->columnHeader); + + view->columns = columns; + view->columnCount = columnCount; + + view->totalColumnWidth = -view->secondaryCellStyle->gapMajor; + + for (uintptr_t i = 0; i < columnCount; i++) { + EsElement *columnHeaderItem = EsCustomElementCreate(view->columnHeader, ES_CELL_FILL, + (columns[i].flags & ES_LIST_VIEW_COLUMN_HAS_MENU) ? ES_STYLE_LIST_COLUMN_HEADER_ITEM_HAS_MENU : ES_STYLE_LIST_COLUMN_HEADER_ITEM); + + columnHeaderItem->messageUser = ListViewColumnHeaderItemMessage; + columnHeaderItem->cName = "column header item"; + columnHeaderItem->userData = i; + + if (!columns[i].width) { + columns[i].width = (i ? view->secondaryCellStyle : view->primaryCellStyle)->preferredWidth; + } + + EsElement *splitter = EsCustomElementCreate(view->columnHeader, ES_CELL_FILL, ES_STYLE_LIST_COLUMN_HEADER_SPLITTER); + + splitter->messageUser = [] (EsElement *element, EsMessage *message) { + EsListViewColumn *column = (EsListViewColumn *) element->userData.p; + EsListView *view = (EsListView *) element->parent->parent; + + if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + view->columnResizingOriginalWidth = column->width; + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + int width = message->mouseDragged.newPositionX - message->mouseDragged.originalPositionX + view->columnResizingOriginalWidth; + int minimumWidth = element->currentStyle->metrics->minimumWidth; + if (width < minimumWidth) width = minimumWidth; + + view->totalColumnWidth += width - column->width; + column->width = width; + EsElementRelayout(element->parent); + EsElementRelayout(view); + } else { + return 0; + } + + return ES_HANDLED; + }, + + splitter->cName = "column header splitter"; + splitter->userData = columns + i; + + view->totalColumnWidth += columns[i].width + view->secondaryCellStyle->gapMajor; + } + + view->scroll.Refresh(); +} + +void EsListViewContentChanged(EsListView *view) { + EsMessageMutexCheck(); + + view->searchBufferLastKeyTime = 0; + view->searchBufferBytes = 0; + + view->scroll.SetX(0); + view->scroll.SetY(0); + + EsListViewInvalidateAll(view); +} + +void EsListViewFocusItem(EsListView *view, int32_t group, EsGeneric index) { + ListViewItem *oldFocus = view->FindVisibleItem(view->focusedItemGroup, view->focusedItemIndex); + + if (oldFocus) { + oldFocus->element->customStyleState &= ~THEME_STATE_FOCUSED_ITEM; + oldFocus->element->MaybeRefreshStyle(); + } + + view->hasFocusedItem = true; + view->focusedItemGroup = group; + view->focusedItemIndex = index; + + ListViewItem *newFocus = view->FindVisibleItem(view->focusedItemGroup, view->focusedItemIndex); + + if (newFocus) { + newFocus->element->customStyleState |= THEME_STATE_FOCUSED_ITEM; + newFocus->element->MaybeRefreshStyle(); + } + + view->EnsureItemVisible(group, index, false); +} + +bool EsListViewGetFocusedItem(EsListView *view, int32_t *group, EsGeneric *index) { + if (view->hasFocusedItem) { + if (group) *group = view->focusedItemGroup; + if (index) *index = view->focusedItemIndex; + } + + return view->hasFocusedItem; +} + +void EsListViewSelect(EsListView *view, int32_t group, EsGeneric index) { + EsMessageMutexCheck(); + + view->Select(group, index, false, false, false); +} + +void EsListViewSetEmptyMessage(EsListView *view, const char *message, ptrdiff_t messageBytes) { + EsMessageMutexCheck(); + if (messageBytes == -1) messageBytes = EsCStringLength(message); + HeapDuplicate((void **) &view->emptyMessage, message, messageBytes); + view->emptyMessageBytes = messageBytes; + + if (!view->totalItemCount) { + view->Repaint(true); + } +} + +EsGeneric EsListViewGetIndexFromItem(EsElement *_element, int32_t *group) { + ListViewItemElement *element = (ListViewItemElement *) _element; + EsListView *view = (EsListView *) element->parent; + EsAssert(element->index < view->visibleItems.Length()); + if (group) *group = view->visibleItems[element->index].group; + return view->visibleItems[element->index].index; +} + +void EsListViewInvalidateAll(EsListView *view) { + view->UpdateVisibleItemsSelectionState(); + view->Repaint(true); +} + +void EsListViewInvalidateContent(EsListView *view, int32_t group, EsGeneric index) { + for (uintptr_t i = 0; i < view->visibleItems.Length(); i++) { + if (view->visibleItems[i].group == group && view->visibleItems[i].index.u == index.u) { + view->UpdateVisibleItemSelectionState(i); + view->visibleItems[i].element->Repaint(true); + break; + } + } +} + +void EsListViewInsertFixedItem(EsListView *view, const char *string, ptrdiff_t stringBytes, EsGeneric data, intptr_t index) { + EsAssert(view->flags & ES_LIST_VIEW_FIXED_ITEMS); + + if (stringBytes == -1) { + stringBytes = EsCStringLength(string); + } + + if (!view->groups.Length()) { + EsListViewInsertGroup(view, 0, ES_FLAGS_DEFAULT); + } + + if (index == -1) { + index = view->fixedItems.Length(); + } + + EsAssert(index >= 0 && index <= (intptr_t) view->fixedItems.Length()); + ListViewFixedItem item = {}; + item.data = data; + HeapDuplicate((void **) &item.string, string, stringBytes); + item.stringBytes = stringBytes; + view->fixedItems.Insert(item, index); + + EsListViewInsert(view, 0, index, index); +} + +bool EsListViewSelectFixedItem(EsListView *view, EsGeneric data) { + EsAssert(view->flags & ES_LIST_VIEW_FIXED_ITEMS); + EsMessageMutexCheck(); + + for (uintptr_t i = 0; i < view->fixedItems.Length(); i++) { + if (view->fixedItems[i].data.u == data.u) { + EsListViewSelect(view, 0, i); + return true; + } + } + + return false; +} + +bool EsListViewGetSelectedFixedItem(EsListView *view, EsGeneric *data) { + EsAssert(view->flags & ES_LIST_VIEW_FIXED_ITEMS); + EsMessageMutexCheck(); + + if (view->fixedItemSelection == -1 || view->fixedItemSelection >= (intptr_t) view->fixedItems.Length()) { + return false; + } else { + *data = view->fixedItems[view->fixedItemSelection].data; + return true; + } +} + +int ListViewInlineTextboxMessage(EsElement *element, EsMessage *message) { + int response = ProcessTextboxMessage(element, message); + + if (message->type == ES_MSG_DESTROY) { + EsListView *view = (EsListView *) EsElementGetLayoutParent(element); + view->inlineTextbox = nullptr; + ListViewItem *item = view->FindVisibleItem(view->inlineTextboxGroup, view->inlineTextboxIndex); + if (item) EsElementRepaint(item->element); + EsElementFocus(view); + } + + return response; +} + +EsTextbox *EsListViewCreateInlineTextbox(EsListView *view, int32_t group, EsGeneric index, uint32_t flags) { + if (view->inlineTextbox) { + view->inlineTextbox->Destroy(); + } + + view->inlineTextboxGroup = group; + view->inlineTextboxIndex = index; + view->EnsureItemVisible(group, index, true); + + uint64_t textboxFlags = ES_CELL_FILL | ES_TEXTBOX_EDIT_BASED | ES_TEXTBOX_ALLOW_TABS; + + if (flags & ES_LIST_VIEW_INLINE_TEXTBOX_REJECT_EDIT_IF_FOCUS_LOST) { + textboxFlags |= ES_TEXTBOX_REJECT_EDIT_IF_LOST_FOCUS; + } + + view->inlineTextbox = EsTextboxCreate(view, textboxFlags, ES_STYLE_TEXTBOX_INLINE); + EsAssert(view->inlineTextbox->messageClass == ProcessTextboxMessage); + view->inlineTextbox->messageClass = ListViewInlineTextboxMessage; + + if (flags & ES_LIST_VIEW_INLINE_TEXTBOX_COPY_EXISTING_TEXT) { + EsMessage m = { ES_MSG_LIST_VIEW_GET_CONTENT }; + uint8_t _buffer[256]; + EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; + m.getContent.buffer = &buffer; + m.getContent.index = index; + m.getContent.group = group; + EsMessageSend(view, &m); + EsTextboxInsert(view->inlineTextbox, (char *) _buffer, buffer.position); + EsTextboxSelectAll(view->inlineTextbox); + } + + if (view->searchBufferBytes) { + view->searchBufferBytes = 0; + EsElementRepaint(view); + } + + EsElementRelayout(view); + EsElementFocus(view->inlineTextbox); + EsTextboxStartEdit(view->inlineTextbox); + + return view->inlineTextbox; +} + +void EsListViewScrollToEnd(EsListView *view) { + if (view->flags & ES_LIST_VIEW_HORIZONTAL) { + view->scroll.SetX(view->scroll.limit[0]); + } else { + view->scroll.SetY(view->scroll.limit[1]); + } +} + +void EsListViewEnumerateVisibleItems(EsListView *view, EsListViewEnumerateVisibleItemsCallbackFunction callback) { + for (uintptr_t i = 0; i < view->visibleItems.Length(); i++) { + callback(view, view->visibleItems[i].element, view->visibleItems[i].group, view->visibleItems[i].index); + } +} + +void EsListViewSetMaximumItemsPerBand(EsListView *view, int maximumItemsPerBand) { + view->maximumItemsPerBand = maximumItemsPerBand; +} diff --git a/desktop/os.header b/desktop/os.header new file mode 100644 index 0000000..170f9ba --- /dev/null +++ b/desktop/os.header @@ -0,0 +1,2399 @@ +opaque_type EsElement EsElementPublic; +opaque_type EsPanel EsElement; +opaque_type EsWindow EsElement; +opaque_type EsScrollbar EsElement; +opaque_type EsButton EsElement; +opaque_type EsTextDisplay EsElement; +opaque_type EsIconDisplay EsElement; +opaque_type EsTextbox EsElement; +opaque_type EsListView EsElement; +opaque_type EsMenu EsElement; +opaque_type EsColorWell EsElement; +opaque_type EsSplitter EsElement; +opaque_type EsImageDisplay EsElement; +opaque_type EsListDisplay EsElement; +opaque_type EsCanvasPane EsElement; +opaque_type EsTextPlan none; +opaque_type EsPaintTarget none; +opaque_type EsUndoManager none; +opaque_type EsHeap none; +opaque_type EsFileStore none; + +type_name uint8_t EsNodeType; +type_name intptr_t EsError; +type_name uintptr_t EsHandle; +type_name uint64_t EsFileOffset; +type_name int64_t EsFileOffsetDifference; +type_name uint64_t EsAudioDeviceID; +type_name uint16_t EsFontFamily; +type_name uint64_t EsTimer; + +define ES_SCANCODE_A (0x04) +define ES_SCANCODE_B (0x05) +define ES_SCANCODE_C (0x06) +define ES_SCANCODE_D (0x07) +define ES_SCANCODE_E (0x08) +define ES_SCANCODE_F (0x09) +define ES_SCANCODE_G (0x0A) +define ES_SCANCODE_H (0x0B) +define ES_SCANCODE_I (0x0C) +define ES_SCANCODE_J (0x0D) +define ES_SCANCODE_K (0x0E) +define ES_SCANCODE_L (0x0F) +define ES_SCANCODE_M (0x10) +define ES_SCANCODE_N (0x11) +define ES_SCANCODE_O (0x12) +define ES_SCANCODE_P (0x13) +define ES_SCANCODE_Q (0x14) +define ES_SCANCODE_R (0x15) +define ES_SCANCODE_S (0x16) +define ES_SCANCODE_T (0x17) +define ES_SCANCODE_U (0x18) +define ES_SCANCODE_V (0x19) +define ES_SCANCODE_W (0x1A) +define ES_SCANCODE_X (0x1B) +define ES_SCANCODE_Y (0x1C) +define ES_SCANCODE_Z (0x1D) + +define ES_SCANCODE_1 (0x1E) +define ES_SCANCODE_2 (0x1F) +define ES_SCANCODE_3 (0x20) +define ES_SCANCODE_4 (0x21) +define ES_SCANCODE_5 (0x22) +define ES_SCANCODE_6 (0x23) +define ES_SCANCODE_7 (0x24) +define ES_SCANCODE_8 (0x25) +define ES_SCANCODE_9 (0x26) +define ES_SCANCODE_0 (0x27) + +define ES_SCANCODE_ENTER (0x28) +define ES_SCANCODE_ESCAPE (0x29) +define ES_SCANCODE_BACKSPACE (0x2A) +define ES_SCANCODE_TAB (0x2B) +define ES_SCANCODE_SPACE (0x2C) + +define ES_SCANCODE_HYPHEN (0x2D) +define ES_SCANCODE_EQUALS (0x2E) +define ES_SCANCODE_LEFT_BRACE (0x2F) +define ES_SCANCODE_RIGHT_BRACE (0x30) +define ES_SCANCODE_COMMA (0x36) +define ES_SCANCODE_PERIOD (0x37) +define ES_SCANCODE_SLASH (0x38) +define ES_SCANCODE_PUNCTUATION_1 (0x31) // On US keyboard, \| +define ES_SCANCODE_PUNCTUATION_2 (0x32) // Not on US keyboard +define ES_SCANCODE_PUNCTUATION_3 (0x33) // On US keyboard, ;: +define ES_SCANCODE_PUNCTUATION_4 (0x34) // On US keyboard, '" +define ES_SCANCODE_PUNCTUATION_5 (0x35) // On US keyboard, `~ +define ES_SCANCODE_PUNCTUATION_6 (0x64) // Not on US keyboard + +define ES_SCANCODE_F1 (0x3A) +define ES_SCANCODE_F2 (0x3B) +define ES_SCANCODE_F3 (0x3C) +define ES_SCANCODE_F4 (0x3D) +define ES_SCANCODE_F5 (0x3E) +define ES_SCANCODE_F6 (0x3F) +define ES_SCANCODE_F7 (0x40) +define ES_SCANCODE_F8 (0x41) +define ES_SCANCODE_F9 (0x42) +define ES_SCANCODE_F10 (0x43) +define ES_SCANCODE_F11 (0x44) +define ES_SCANCODE_F12 (0x45) +define ES_SCANCODE_F13 (0x68) +define ES_SCANCODE_F14 (0x69) +define ES_SCANCODE_F15 (0x6A) +define ES_SCANCODE_F16 (0x6B) +define ES_SCANCODE_F17 (0x6C) +define ES_SCANCODE_F18 (0x6D) +define ES_SCANCODE_F19 (0x6E) +define ES_SCANCODE_F20 (0x6F) +define ES_SCANCODE_F21 (0x70) +define ES_SCANCODE_F22 (0x71) +define ES_SCANCODE_F23 (0x72) +define ES_SCANCODE_F24 (0x73) + +define ES_SCANCODE_CAPS_LOCK (0x39) +define ES_SCANCODE_PRINT_SCREEN (0x46) +define ES_SCANCODE_SCROLL_LOCK (0x47) +define ES_SCANCODE_PAUSE (0x48) +define ES_SCANCODE_INSERT (0x49) +define ES_SCANCODE_HOME (0x4A) +define ES_SCANCODE_PAGE_UP (0x4B) +define ES_SCANCODE_DELETE (0x4C) +define ES_SCANCODE_END (0x4D) +define ES_SCANCODE_PAGE_DOWN (0x4E) +define ES_SCANCODE_RIGHT_ARROW (0x4F) +define ES_SCANCODE_LEFT_ARROW (0x50) +define ES_SCANCODE_DOWN_ARROW (0x51) +define ES_SCANCODE_UP_ARROW (0x52) +define ES_SCANCODE_NUM_LOCK (0x53) +define ES_SCANCODE_CONTEXT_MENU (0x65) +define ES_SCANCODE_SYSTEM_REQUEST (0x9A) + +define ES_SCANCODE_ACTION_EXECUTE (0x74) +define ES_SCANCODE_ACTION_HELP (0x75) +define ES_SCANCODE_ACTION_MENU (0x76) +define ES_SCANCODE_ACTION_SELECT (0x77) +define ES_SCANCODE_ACTION_STOP (0x78) +define ES_SCANCODE_ACTION_AGAIN (0x79) +define ES_SCANCODE_ACTION_UNDO (0x7A) +define ES_SCANCODE_ACTION_CUT (0x7B) +define ES_SCANCODE_ACTION_COPY (0x7C) +define ES_SCANCODE_ACTION_PASTE (0x7D) +define ES_SCANCODE_ACTION_FIND (0x7E) +define ES_SCANCODE_ACTION_CANCEL (0x9B) +define ES_SCANCODE_ACTION_CLEAR (0x9C) +define ES_SCANCODE_ACTION_PRIOR (0x9D) +define ES_SCANCODE_ACTION_RETURN (0x9E) +define ES_SCANCODE_ACTION_SEPARATOR (0x9F) + +define ES_SCANCODE_MM_MUTE (0x7F) +define ES_SCANCODE_MM_LOUDER (0x80) +define ES_SCANCODE_MM_QUIETER (0x81) +define ES_SCANCODE_MM_NEXT (0x103) +define ES_SCANCODE_MM_PREVIOUS (0x104) +define ES_SCANCODE_MM_STOP (0x105) +define ES_SCANCODE_MM_PAUSE (0x106) +define ES_SCANCODE_MM_SELECT (0x107) +define ES_SCANCODE_MM_EMAIL (0x108) +define ES_SCANCODE_MM_CALC (0x109) +define ES_SCANCODE_MM_FILES (0x10A) + +define ES_SCANCODE_INTERNATIONAL_1 (0x87) +define ES_SCANCODE_INTERNATIONAL_2 (0x88) +define ES_SCANCODE_INTERNATIONAL_3 (0x89) +define ES_SCANCODE_INTERNATIONAL_4 (0x8A) +define ES_SCANCODE_INTERNATIONAL_5 (0x8B) +define ES_SCANCODE_INTERNATIONAL_6 (0x8C) +define ES_SCANCODE_INTERNATIONAL_7 (0x8D) +define ES_SCANCODE_INTERNATIONAL_8 (0x8E) +define ES_SCANCODE_INTERNATIONAL_9 (0x8F) + +define ES_SCANCODE_HANGUL_ENGLISH_TOGGLE (0x90) +define ES_SCANCODE_HANJA_CONVERSION (0x91) +define ES_SCANCODE_KATAKANA (0x92) +define ES_SCANCODE_HIRAGANA (0x93) +define ES_SCANCODE_HANKAKU_ZENKAKU_TOGGLE (0x94) +define ES_SCANCODE_ALTERNATE_ERASE (0x99) + +define ES_SCANCODE_THOUSANDS_SEPARATOR (0xB2) +define ES_SCANCODE_DECIMAL_SEPARATOR (0xB3) +define ES_SCANCODE_CURRENCY_UNIT (0xB4) +define ES_SCANCODE_CURRENCY_SUBUNIT (0xB5) + +define ES_SCANCODE_NUM_DIVIDE (0x54) +define ES_SCANCODE_NUM_MULTIPLY (0x55) +define ES_SCANCODE_NUM_SUBTRACT (0x56) +define ES_SCANCODE_NUM_ADD (0x57) +define ES_SCANCODE_NUM_ENTER (0x58) +define ES_SCANCODE_NUM_1 (0x59) +define ES_SCANCODE_NUM_2 (0x5A) +define ES_SCANCODE_NUM_3 (0x5B) +define ES_SCANCODE_NUM_4 (0x5C) +define ES_SCANCODE_NUM_5 (0x5D) +define ES_SCANCODE_NUM_6 (0x5E) +define ES_SCANCODE_NUM_7 (0x5F) +define ES_SCANCODE_NUM_8 (0x60) +define ES_SCANCODE_NUM_9 (0x61) +define ES_SCANCODE_NUM_0 (0x62) +define ES_SCANCODE_NUM_POINT (0x63) +define ES_SCANCODE_NUM_EQUALS (0x67) +define ES_SCANCODE_NUM_COMMA (0x82) +define ES_SCANCODE_NUM_00 (0xB0) +define ES_SCANCODE_NUM_000 (0xB1) +define ES_SCANCODE_NUM_LEFT_PAREN (0xB6) +define ES_SCANCODE_NUM_RIGHT_PAREN (0xB7) +define ES_SCANCODE_NUM_LEFT_BRACE (0xB8) +define ES_SCANCODE_NUM_RIGHT_BRACE (0xB9) +define ES_SCANCODE_NUM_TAB (0xBA) +define ES_SCANCODE_NUM_BACKSPACE (0xBB) +define ES_SCANCODE_NUM_A (0xBC) +define ES_SCANCODE_NUM_B (0xBD) +define ES_SCANCODE_NUM_C (0xBE) +define ES_SCANCODE_NUM_D (0xBF) +define ES_SCANCODE_NUM_E (0xC0) +define ES_SCANCODE_NUM_F (0xC1) +define ES_SCANCODE_NUM_XOR (0xC2) +define ES_SCANCODE_NUM_CARET (0xC3) +define ES_SCANCODE_NUM_PERCENT (0xC4) +define ES_SCANCODE_NUM_LESS_THAN (0xC5) +define ES_SCANCODE_NUM_GREATER_THAN (0xC6) +define ES_SCANCODE_NUM_AMPERSAND (0xC7) +define ES_SCANCODE_NUM_DOUBLE_AMPERSAND (0xC8) +define ES_SCANCODE_NUM_BAR (0xC9) +define ES_SCANCODE_NUM_DOUBLE_BAR (0xCA) +define ES_SCANCODE_NUM_COLON (0xCB) +define ES_SCANCODE_NUM_HASH (0xCC) +define ES_SCANCODE_NUM_SPACE (0xCD) +define ES_SCANCODE_NUM_AT (0xCE) +define ES_SCANCODE_NUM_EXCLAMATION_MARK (0xCF) +define ES_SCANCODE_NUM_MEMORY_STORE (0xD0) +define ES_SCANCODE_NUM_MEMORY_RECALL (0xD1) +define ES_SCANCODE_NUM_MEMORY_CLEAR (0xD2) +define ES_SCANCODE_NUM_MEMORY_ADD (0xD3) +define ES_SCANCODE_NUM_MEMORY_SUBTRACT (0xD4) +define ES_SCANCODE_NUM_MEMORY_MULTIPLY (0xD5) +define ES_SCANCODE_NUM_MEMORY_DIVIDE (0xD6) +define ES_SCANCODE_NUM_NEGATE (0xD7) +define ES_SCANCODE_NUM_CLEAR_ALL (0xD8) +define ES_SCANCODE_NUM_CLEAR (0xD9) +define ES_SCANCODE_NUM_BINARY (0xDA) +define ES_SCANCODE_NUM_OCTAL (0xDB) +define ES_SCANCODE_NUM_DECIMAL (0xDC) +define ES_SCANCODE_NUM_HEXADECIMAL (0xDD) + +define ES_SCANCODE_LEFT_CTRL (0xE0) +define ES_SCANCODE_LEFT_SHIFT (0xE1) +define ES_SCANCODE_LEFT_ALT (0xE2) +define ES_SCANCODE_LEFT_FLAG (0xE3) +define ES_SCANCODE_RIGHT_CTRL (0xE4) +define ES_SCANCODE_RIGHT_SHIFT (0xE5) +define ES_SCANCODE_RIGHT_ALT (0xE6) +define ES_SCANCODE_RIGHT_FLAG (0xE7) + +define ES_SCANCODE_ACPI_POWER (0x100) +define ES_SCANCODE_ACPI_SLEEP (0x101) +define ES_SCANCODE_ACPI_WAKE (0x102) + +define ES_SCANCODE_WWW_SEARCH (0x10B) +define ES_SCANCODE_WWW_HOME (0x10C) +define ES_SCANCODE_WWW_BACK (0x10D) +define ES_SCANCODE_WWW_FORWARD (0x10E) +define ES_SCANCODE_WWW_STOP (0x10F) +define ES_SCANCODE_WWW_REFRESH (0x110) +define ES_SCANCODE_WWW_STARRED (0x111) + +define ES_PROCESS_STATE_ALL_THREADS_TERMINATED (1) +define ES_PROCESS_STATE_TERMINATING (2) +define ES_PROCESS_STATE_CRASHED (4) +define ES_PROCESS_STATE_PINGED (8) + +define ES_FLAGS_DEFAULT (0) +define ES_SUCCESS (-1) + +// TODO Cleanup. +define ES_ERROR_BUFFER_TOO_SMALL (-2) +define ES_ERROR_UNKNOWN (-7) +define ES_ERROR_NO_MESSAGES_AVAILABLE (-9) +define ES_ERROR_MESSAGE_QUEUE_FULL (-10) +define ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME (-14) +define ES_ERROR_PATH_NOT_TRAVERSABLE (-15) +define ES_ERROR_FILE_ALREADY_EXISTS (-19) +define ES_ERROR_FILE_DOES_NOT_EXIST (-20) +define ES_ERROR_DRIVE_ERROR_FILE_DAMAGED (-21) +define ES_ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS (-22) +define ES_ERROR_FILE_PERMISSION_NOT_GRANTED (-23) +define ES_ERROR_FILE_IN_EXCLUSIVE_USE (-24) +define ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE (-25) +define ES_ERROR_INCORRECT_NODE_TYPE (-26) +define ES_ERROR_EVENT_NOT_SET (-27) +define ES_ERROR_FILE_HAS_WRITERS (-28) +define ES_ERROR_TIMEOUT_REACHED (-29) +define ES_ERROR_FILE_ON_READ_ONLY_VOLUME (-32) +define ES_ERROR_INVALID_DIMENSIONS (-34) +define ES_ERROR_DRIVE_CONTROLLER_REPORTED (-35) +define ES_ERROR_COULD_NOT_ISSUE_PACKET (-36) +define ES_ERROR_HANDLE_TABLE_FULL (-37) +define ES_ERROR_COULD_NOT_RESIZE_FILE (-38) +define ES_ERROR_DIRECTORY_NOT_EMPTY (-39) +define ES_ERROR_NODE_DELETED (-41) +define ES_ERROR_VOLUME_MISMATCH (-43) +define ES_ERROR_TARGET_WITHIN_SOURCE (-44) +define ES_ERROR_TARGET_INVALID_TYPE (-45) +define ES_ERROR_MALFORMED_NODE_PATH (-47) +define ES_ERROR_TARGET_IS_SOURCE (-49) +define ES_ERROR_INVALID_NAME (-50) +define ES_ERROR_CORRUPT_DATA (-51) +define ES_ERROR_INSUFFICIENT_RESOURCES (-52) +define ES_ERROR_UNSUPPORTED_FEATURE (-53) +define ES_ERROR_FILE_TOO_FRAGMENTED (-54) +define ES_ERROR_DRIVE_FULL (-55) +define ES_ERROR_COULD_NOT_RESOLVE_SYMBOL (-56) +define ES_ERROR_ALREADY_EMBEDDED (-57) +define ES_ERROR_EVENT_SINK_OVERFLOW (-58) +define ES_ERROR_EVENT_SINK_DUPLICATE (-59) +define ES_ERROR_UNSUPPORTED_CONVERSION (-60) +define ES_ERROR_SOURCE_EMPTY (-61) +define ES_ERROR_UNSUPPORTED_EXECUTABLE (-62) +define ES_ERROR_NO_ADDRESS_FOR_DOMAIN_NAME (-63) +define ES_ERROR_NO_CONNECTED_NETWORK_INTERFACES (-64) +define ES_ERROR_BAD_DOMAIN_NAME (-65) +define ES_ERROR_LOST_IP_ADDRESS (-66) +define ES_ERROR_CONNECTION_RESET (-67) +define ES_ERROR_CONNECTION_REFUSED (-68) +define ES_ERROR_ILLEGAL_PATH (-69) +define ES_ERROR_INVALID_CLIPBOARD (-70) +define ES_ERROR_NODE_NOT_LOADED (-71) +define ES_ERROR_DIRECTORY_ENTRY_BEING_REMOVED (-72) + +define ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND (0) +define ES_SYSTEM_CONSTANT_NO_FANCY_GRAPHICS (1) +define ES_SYSTEM_CONSTANT_RIGHT_TO_LEFT (2) +define ES_SYSTEM_CONSTANT_WINDOW_INSET (3) +define ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT (4) +define ES_SYSTEM_CONSTANT_UI_SCALE (5) +define ES_SYSTEM_CONSTANT_BORDER_THICKNESS (6) +define ES_SYSTEM_CONSTANT_OPTIMAL_WORK_QUEUE_THREAD_COUNT (7) +define ES_SYSTEM_CONSTANT_COUNT (8) + +define ES_INVALID_HANDLE ((EsHandle) (0)) +define ES_CURRENT_THREAD ((EsHandle) (0x10)) +define ES_CURRENT_PROCESS ((EsHandle) (0x11)) + +define ES_WAIT_NO_TIMEOUT (-1) +define ES_MAX_WAIT_COUNT (8) +define ES_MAX_EVENT_FORWARD_COUNT (4) // The maximum number of event sinks an event can be forwarded to. +define ES_MAX_EVENT_SINK_BUFFER_SIZE (256) // The maximum number of events an event sink can capture. TODO Make this configurable in EsEventSinkCreate? + +define ES_MAX_DIRECTORY_CHILD_NAME_LENGTH (256) + +define ES_PROCESS_EXECUTABLE_NOT_LOADED (0) +define ES_PROCESS_EXECUTABLE_FAILED_TO_LOAD (1) +define ES_PROCESS_EXECUTABLE_LOADED (2) + +define ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH (31) +define ES_SYSTEM_SNAPSHOT_PROCESSES (1) + +define ES_HANDLED (-1) +define ES_REJECTED (-2) + +define ES_LIST_VIEW_COLUMN_SORT_ASCENDING (1) +define ES_LIST_VIEW_COLUMN_SORT_DESCENDING (2) + +define ES_SHARED_MEMORY_NAME_MAX_LENGTH (32) +define ES_MAP_OBJECT_ALL (0) + +define ES_TEXT_H_LEFT (1 << 0) // Keep in sync with designer.c. +define ES_TEXT_H_CENTER (1 << 1) +define ES_TEXT_H_RIGHT (1 << 2) +define ES_TEXT_V_TOP (1 << 3) +define ES_TEXT_V_CENTER (1 << 4) +define ES_TEXT_V_BOTTOM (1 << 5) +define ES_TEXT_ELLIPSIS (1 << 6) +define ES_TEXT_WRAP (1 << 7) +define ES_TEXT_PLAN_SINGLE_USE (1 << 8) +define ES_TEXT_PLAN_TRIM_SPACES (1 << 9) +define ES_TEXT_PLAN_RTL (1 << 10) +define ES_TEXT_PLAN_CLIP_UNBREAKABLE_LINES (1 << 11) +define ES_TEXT_PLAN_NO_FONT_SUBSTITUTION (1 << 12) + +define ES_FILE_READ_SHARED (0x1) // Read-only. The file can still be opened for writing. +define ES_FILE_READ (0x2) // Read-only. The file will not openable for writing. This will fail if the file is already opened for writing. +define ES_FILE_WRITE (0x4) // Read-write. The file can still be opened for writing. This will fail if the file is already opened for exclusive writing. +define ES_FILE_WRITE_EXCLUSIVE (0x8) // Read-write. The file will not openable for writing. This will fail if the file is already opened for writing. + +define ES_NODE_FILE (0) +define ES_NODE_DIRECTORY (0x10) +define ES_NODE_INVALID (0x20) + +define ES_NODE_FAIL_IF_FOUND (0x001000) +define ES_NODE_FAIL_IF_NOT_FOUND (0x002000) +define ES_NODE_PREVENT_RESIZE (0x004000) +define ES_NODE_CREATE_DIRECTORIES (0x008000) // Create the directories leading to the file, if they don't already exist. + +define _ES_NODE_FROM_WRITE_EXCLUSIVE (0x020000) +define _ES_NODE_DIRECTORY_WRITE (0x040000) +define _ES_NODE_NO_WRITE_BASE (0x080000) + +define ES_DIRECTORY_CHILDREN_UNKNOWN ((EsFileOffsetDifference) (-1)) + +define ES_MEMORY_OPEN_FAIL_IF_FOUND (0x1000) +define ES_MEMORY_OPEN_FAIL_IF_NOT_FOUND (0x2000) + +define ES_MAP_OBJECT_READ_WRITE (0) +define ES_MAP_OBJECT_READ_ONLY (1) +define ES_MAP_OBJECT_COPY_ON_WRITE (2) + +define ES_STRING_FORMAT_ENOUGH_SPACE ((_EsLongConstant) (-1)) + +// Flags set with %f. +define ES_STRING_FORMAT_SIMPLE (1 << 0) + +define ES_PERMISSION_NETWORKING (1 << 0) +define ES_PERMISSION_PROCESS_CREATE (1 << 2) +define ES_PERMISSION_PROCESS_OPEN (1 << 3) +define ES_PERMISSION_SCREEN_MODIFY (1 << 4) +define ES_PERMISSION_SHUTDOWN (1 << 5) +define ES_PERMISSION_TAKE_SYSTEM_SNAPSHOT (1 << 6) +define ES_PERMISSION_SYSTEM_CONFIGURATION_WRITE (1 << 7) +define ES_PERMISSION_GET_VOLUME_INFORMATION (1 << 8) +define ES_PERMISSION_WINDOW_MANAGER (1 << 9) +define ES_PERMISSION_POSIX_SUBSYSTEM (1 << 10) +define ES_PERMISSION_ALL ((_EsLongConstant) (-1)) +define ES_PERMISSION_INHERIT ((_EsLongConstant) (1) << 63) + +define ES_PANEL_BAND_SIZE_DEFAULT (-1) + +// Element flags - bits 0-31 for custom use; bits 32-63 common to all elements. + +define ES_ELEMENT_FOCUSABLE ((_EsLongConstant) (1) << 32) +define ES_ELEMENT_HIDDEN ((_EsLongConstant) (1) << 33) // Hides the element and descendents. + // Also prevents the element and descendents from taking focus or being hovered/pressed. +define ES_ELEMENT_DISABLED ((_EsLongConstant) (1) << 34) // Prevents the element from taking focus or being pressed. +define ES_ELEMENT_DEBUG ((_EsLongConstant) (1) << 35) // Prints some extra debug information about the element. +define ES_ELEMENT_NO_CLIP ((_EsLongConstant) (1) << 36) // Do not clip children to the element's bounds. +define ES_ELEMENT_NO_HOVER ((_EsLongConstant) (1) << 37) // For z-stacked elements. Can still hover descendents and overlapped siblings/parent. + // Override HIT_TEST to return false to prevent hovering descendents. +define ES_ELEMENT_NO_HOVER_DESCENDENTS ((_EsLongConstant) (1) << 38) // Prevent hovering over any descendents. +define ES_ELEMENT_BLOCK_FOCUS ((_EsLongConstant) (1) << 39) // This element and descendents cannot take focus. +define ES_ELEMENT_NOT_TAB_TRAVERSABLE ((_EsLongConstant) (1) << 40) // Use with ES_ELEMENT_FOCUSABLE to indicate the element cannot be focused from tab traversal. +define ES_ELEMENT_CENTER_ACCESS_KEY_HINT ((_EsLongConstant) (1) << 41) // TODO Make this more customizable with a message perhaps? +define ES_ELEMENT_LAYOUT_HINT_HORIZONTAL ((_EsLongConstant) (1) << 42) // Hint for autoCorners and autoBorders. +define ES_ELEMENT_LAYOUT_HINT_REVERSE ((_EsLongConstant) (1) << 43) // Hint for autoCorners and autoBorders; and tab traversal. +define ES_ELEMENT_STICKY_ACCESS_KEY ((_EsLongConstant) (1) << 44) // Don't exit access key mode after using the access key. +define ES_ELEMENT_NON_CLIENT ((_EsLongConstant) (1) << 45) + +// For children of splitters: +define ES_CELL_COLLAPSABLE ((_EsLongConstant) (1) << 51) + +define ES_CELL_H_PUSH ((_EsLongConstant) (1) << 54) +define ES_CELL_H_EXPAND ((_EsLongConstant) (1) << 55) +define ES_CELL_H_SHRINK ((_EsLongConstant) (1) << 56) +define ES_CELL_H_LEFT ((_EsLongConstant) (1) << 57) +define ES_CELL_H_RIGHT ((_EsLongConstant) (1) << 58) +define ES_CELL_V_PUSH ((_EsLongConstant) (1) << 59) +define ES_CELL_V_EXPAND ((_EsLongConstant) (1) << 60) +define ES_CELL_V_SHRINK ((_EsLongConstant) (1) << 61) +define ES_CELL_V_TOP ((_EsLongConstant) (1) << 62) +define ES_CELL_V_BOTTOM ((_EsLongConstant) (1) << 63) + +define ES_PANEL_STACK (0) // Default. +define ES_PANEL_SWITCHER (1 << 0) +define ES_PANEL_Z_STACK (1 << 1) +define ES_PANEL_TABLE (1 << 2) + +define ES_PANEL_H_SCROLL_FIXED (1 << 4) +define ES_PANEL_V_SCROLL_FIXED (1 << 5) +define ES_PANEL_H_SCROLL_AUTO (1 << 6) +define ES_PANEL_V_SCROLL_AUTO (1 << 7) + +// For ES_PANEL_TABLE and ES_PANEL_STACK. +define ES_PANEL_VERTICAL (0) // Default. +define ES_PANEL_HORIZONTAL (1 << 8) +define ES_PANEL_REVERSE (1 << 9) // Reverse layout is not supported with ES_PANEL_TABLE yet. + +// For ES_PANEL_TABLE. +define ES_PANEL_H_LEFT (1 << 16) +define ES_PANEL_H_RIGHT (1 << 17) +define ES_PANEL_H_CENTER (1 << 18) +define ES_PANEL_H_JUSTIFY (1 << 19) +define ES_PANEL_V_TOP (1 << 20) +define ES_PANEL_V_BOTTOM (1 << 21) +define ES_PANEL_V_CENTER (1 << 22) +define ES_PANEL_V_JUSTIFY (1 << 23) + +define ES_TEXTBOX_MULTILINE (1 << 0) +define ES_TEXTBOX_EDIT_BASED (1 << 1) +define ES_TEXTBOX_MARGIN (1 << 2) +define ES_TEXTBOX_NO_SMART_CONTEXT_MENUS (1 << 3) +define ES_TEXTBOX_ALLOW_TABS (1 << 4) +define ES_TEXTBOX_REJECT_EDIT_IF_LOST_FOCUS (1 << 5) + +define ES_TEXTBOX_FIND_BACKWARDS (1 << 0) + +define ES_TEXTBOX_GET_CONTENTS_SELECTED_ONLY (1 << 0) + +// First few bits reserved for the check state. +define ES_BUTTON_DEFAULT (1 << 3) +define ES_BUTTON_MENU_ITEM (1 << 4) +define ES_BUTTON_NOT_FOCUSABLE (1 << 5) +define ES_BUTTON_TOOLBAR (1 << 6) +define ES_BUTTON_DROPDOWN (1 << 7) +define ES_BUTTON_COMPACT (1 << 8) +define ES_MENU_ITEM_HEADER (1 << 9) +define ES_BUTTON_CHECKBOX (1 << 10) +define ES_BUTTON_RADIOBOX (1 << 11) +define ES_BUTTON_CANCEL (1 << 12) +define ES_BUTTON_PUSH (1 << 13) +define ES_MENU_ITEM_CHECKED (1 << 14) + +define ES_COLOR_WELL_HAS_OPACITY (1 << 0) + +define ES_SCROLLBAR_VERTICAL (0 << 0) +define ES_SCROLLBAR_HORIZONTAL (1 << 0) + +define ES_SPLITTER_VERTICAL (0 << 0) +define ES_SPLITTER_HORIZONTAL (1 << 0) + +define ES_LIST_VIEW_HORIZONTAL (1 << 0) // Layout horizontally instead of vertically. +define ES_LIST_VIEW_VARIABLE_SIZE (1 << 1) // Each item can be a different size. + // You need to respond to the LIST_VIEW_MEASURE_ITEM message. + // The size of items cannot depend on the size of the parent. +define ES_LIST_VIEW_TILED (1 << 2) // Multiple items per band. Incompatible with variable size items, columns mode and non-linear mode. +define ES_LIST_VIEW_NON_LINEAR (1 << 3) // Indices within a group are arbitrary values. They must be stable. + // You need to respond to LIST_VIEW_NEXT_INDEX, LIST_VIEW_PREVIOUS_INDEX, + // LIST_VIEW_COMPARE_INDICES, LIST_VIEW_FIRST_INDEX, and LIST_VIEW_LAST_INDEX messages. + // If the flag is not set, indices are consecutive within a group, starting at 0. + // These are non-stable, but are updated automatically when items are inserted/removed. +define ES_LIST_VIEW_SINGLE_SELECT (1 << 4) // One item can be selected. By default, selections are disabled. +define ES_LIST_VIEW_MULTI_SELECT (1 << 5) // Multiple items can be selected. +define ES_LIST_VIEW_CHOICE_SELECT (1 << 6) // Exactly one item is always selected. Dragging on the list view causes the selection to 'slide' between items. +define ES_LIST_VIEW_COLUMNS (1 << 7) // Display a column header and let items have multiple values. Incompatible with horizontal and tiled layouts. +define ES_LIST_VIEW_FIXED_ITEMS (1 << 8) // Use the fixed item API rather than the callback API. +define ES_LIST_VIEW_CENTER_TILES (1 << 9) // Center tiled items. + +define ES_LIST_VIEW_GROUP_HAS_HEADER (1 << 0) // The first item in the group is a header. +define ES_LIST_VIEW_GROUP_HAS_FOOTER (1 << 1) // The last item in the group is a footer. +define ES_LIST_VIEW_GROUP_INDENT (1 << 2) // Indent the group's items (excluding the header and footer). +define ES_LIST_VIEW_GROUP_COLLAPSABLE (1 << 3) // The group can be collapsed. + +define ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED (1 << 0) // The column's contents is right-aligned. +define ES_LIST_VIEW_COLUMN_HAS_MENU (1 << 1) // The header can be clicked to open a menu. +define ES_LIST_VIEW_COLUMN_TABULAR (1 << 2) // Use tabular text figures (so that digits are aligned). + +define ES_MENU_AT_CURSOR (1 << 0) +define ES_MENU_MAXIMUM_HEIGHT (1 << 1) + +define ES_FONT_SANS (0xFFFF) +define ES_FONT_SERIF (0xFFFE) +define ES_FONT_MONOSPACED (0xFFFD) + +define ES_FONT_REGULAR (4) +define ES_FONT_BOLD (7) + +define ES_TEXT_FIGURE_DEFAULT (0) +define ES_TEXT_FIGURE_OLD (1) +define ES_TEXT_FIGURE_TABULAR (2) + +define ES_TEXT_DECORATION_UNDERLINE (1 << 0) +define ES_TEXT_DECORATION_STRIKE_THROUGH (1 << 1) + +define ES_TEXT_DISPLAY_RICH_TEXT (1 << 0) +define ES_TEXT_DISPLAY_PREFORMATTED (1 << 1) // Prevents trimming of trailing/leading whitespace. +define ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION (1 << 2) + +define ES_LIST_DISPLAY_BULLETED (0 << 0) // Default. +define ES_LIST_DISPLAY_NUMBERED (1 << 0) +define ES_LIST_DISPLAY_LOWER_ALPHA (2 << 0) +define ES_LIST_DISPLAY_CUSTOM_MARKER (0xFF << 0) // Sends ES_MSG_LIST_DISPLAY_GET_MARKER. +define ES_LIST_DISPLAY_MARKER_TYPE_MASK (0xFF << 0) + +define ES_IMAGE_DISPLAY_DECODE_WHEN_NEEDED (1 << 0) // The image is only kept in its decoded state when the display is on-screen. +define ES_IMAGE_DISPLAY_MANUAL_SIZE (1 << 1) // The display will be manually sized; its size does not depend on the loaded image. + +define ES_COMMAND_SYSTEM_START (0xF0000000) +define ES_COMMAND_DELETE (0xF0000001) +define ES_COMMAND_SELECT_ALL (0xF0000002) +define ES_COMMAND_CUT (0xF0000003) +define ES_COMMAND_COPY (0xF0000004) +define ES_COMMAND_PASTE (0xF0000005) +define ES_COMMAND_UNDO (0xF0000006) +define ES_COMMAND_REDO (0xF0000007) +define ES_COMMAND_SAVE (0xF0000008) +define ES_COMMAND_SHOW_IN_FILE_MANAGER (0xF0000009) + +// Some common layouts... +define ES_CELL_FILL (ES_CELL_H_FILL | ES_CELL_V_FILL) +define ES_CELL_H_FILL (ES_CELL_H_PUSH | ES_CELL_H_EXPAND | ES_CELL_H_SHRINK) +define ES_CELL_V_FILL (ES_CELL_V_PUSH | ES_CELL_V_EXPAND | ES_CELL_V_SHRINK) +define ES_CELL_CENTER (ES_CELL_H_CENTER | ES_CELL_V_CENTER) +define ES_CELL_PUSH (ES_CELL_H_PUSH | ES_CELL_V_PUSH) +define ES_CELL_EXPAND (ES_CELL_H_EXPAND | ES_CELL_V_EXPAND) +define ES_CELL_CORNER (ES_CELL_H_LEFT | ES_CELL_V_TOP) +define ES_CELL_SHRINK (ES_CELL_H_SHRINK | ES_CELL_V_SHRINK) +define ES_CELL_H_CENTER (ES_CELL_H_LEFT | ES_CELL_H_RIGHT) +define ES_CELL_V_CENTER (ES_CELL_V_TOP | ES_CELL_V_BOTTOM) + +// Mask bits for EsThemeMetrics: +define ES_THEME_METRICS_INSETS (1 << 0) +define ES_THEME_METRICS_CLIP_INSETS (1 << 1) +define ES_THEME_METRICS_GLOBAL_OFFSET (1 << 2) +define ES_THEME_METRICS_CLIP_ENABLED (1 << 3) +define ES_THEME_METRICS_CURSOR (1 << 4) +define ES_THEME_METRICS_ENTRANCE_TRANSITION (1 << 5) +define ES_THEME_METRICS_EXIT_TRANSITION (1 << 6) +define ES_THEME_METRICS_ENTRANCE_DURATION (1 << 7) +define ES_THEME_METRICS_EXIT_DURATION (1 << 8) +define ES_THEME_METRICS_PREFERRED_WIDTH (1 << 9) +define ES_THEME_METRICS_PREFERRED_HEIGHT (1 << 10) +define ES_THEME_METRICS_MINIMUM_WIDTH (1 << 11) +define ES_THEME_METRICS_MINIMUM_HEIGHT (1 << 12) +define ES_THEME_METRICS_MAXIMUM_WIDTH (1 << 13) +define ES_THEME_METRICS_MAXIMUM_HEIGHT (1 << 14) +define ES_THEME_METRICS_GAP_MAJOR (1 << 15) +define ES_THEME_METRICS_GAP_MINOR (1 << 16) +define ES_THEME_METRICS_GAP_WRAP (1 << 17) +define ES_THEME_METRICS_GAP_ALL (ES_THEME_METRICS_GAP_MAJOR | ES_THEME_METRICS_GAP_MINOR | ES_THEME_METRICS_GAP_WRAP) +define ES_THEME_METRICS_TEXT_COLOR (1 << 18) +define ES_THEME_METRICS_SELECTED_BACKGROUND (1 << 19) +define ES_THEME_METRICS_SELECTED_TEXT (1 << 20) +define ES_THEME_METRICS_ICON_COLOR (1 << 21) +define ES_THEME_METRICS_TEXT_ALIGN (1 << 22) +define ES_THEME_METRICS_TEXT_SIZE (1 << 23) +define ES_THEME_METRICS_FONT_FAMILY (1 << 24) +define ES_THEME_METRICS_FONT_WEIGHT (1 << 25) +define ES_THEME_METRICS_ICON_SIZE (1 << 26) +define ES_THEME_METRICS_IS_ITALIC (1 << 27) +define ES_THEME_METRICS_ELLIPSIS (1 << 28) +define ES_THEME_METRICS_LAYOUT_VERTICAL (1 << 29) + +define ES_WINDOW_MOVE_MAXIMISED (1 << 0) +define ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN (1 << 1) +define ES_WINDOW_MOVE_HIDDEN (1 << 2) +define ES_WINDOW_MOVE_ALWAYS_ON_TOP (1 << 3) +define ES_WINDOW_MOVE_AT_BOTTOM (1 << 4) +define ES_WINDOW_MOVE_UPDATE_SCREEN (1 << 5) +define ES_WINDOW_MOVE_DYNAMIC (1 << 6) + +define ES_WINDOW_SOLID_TRUE (1 << 0) +define ES_WINDOW_SOLID_NO_ACTIVATE (1 << 1) +define ES_WINDOW_SOLID_NO_BRING_TO_FRONT (1 << 2) + +define ES_THEME_CURSORS_WIDTH (264) +define ES_THEME_CURSORS_HEIGHT (128) +define ES_THEME_CURSORS_NAME "Desktop.ThemeCursors" + +define ES_TEXTBOX_MOVE_CARET_SINGLE (2) +define ES_TEXTBOX_MOVE_CARET_WORD (3) +define ES_TEXTBOX_MOVE_CARET_LINE (4) +define ES_TEXTBOX_MOVE_CARET_VERTICAL (5) +define ES_TEXTBOX_MOVE_CARET_ALL (6) +define ES_TEXTBOX_MOVE_CARET_FIRST_ONLY (1 << 8) +define ES_TEXTBOX_MOVE_CARET_SECOND_ONLY (1 << 9) +define ES_TEXTBOX_MOVE_CARET_BACKWARDS (1 << 10) +define ES_TEXTBOX_MOVE_CARET_STRONG_WHITESPACE (1 << 11) + +define ES_GAME_CONTROLLER_MAX_COUNT (16) + +define ES_DOMAIN_NAME_MAX_LENGTH (255) +define ES_ECHO_REQUEST_MAX_LENGTH (48) + +define ES_CONNECTION_OPEN_WAIT (1 << 0) + +define ES_FILE_CONTROL_NOTIFY_MONITORS (1 << 0) +define ES_FILE_CONTROL_FLUSH (1 << 1) + +define ES_ELEMENT_UPDATE_CONTENT_WIDTH (1 << 0) +define ES_ELEMENT_UPDATE_CONTENT_HEIGHT (1 << 1) + +define ES_DIALOG_ALERT_OK_BUTTON (1 << 0) + +define ES_MEMORY_RESERVE_COMMIT_ALL (1 << 0) + +define ES_PANEL_SWITCHER_DESTROY_PREVIOUS_AFTER_TRANSITION (1 << 0) + +define ES_ELEMENT_TRANSITION_ENTRANCE (1 << 0) + +define ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE (1 << 0) + +define ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C (1) +define ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI (2) + +define ES_DRAW_LINE_CAP_ROUND (1 << 0) +define ES_DRAW_LINE_CAP_SQUARE (1 << 1) + +define ES_INSTANCE_CLASS_VIEWER (0) // Default. +define ES_INSTANCE_CLASS_EDITOR (1) + +define ES_MOUNT_POINT_MAX_COUNT (256) + +define ES_DRIVE_TYPE_OTHER (0) +define ES_DRIVE_TYPE_HDD (1) +define ES_DRIVE_TYPE_SSD (2) +define ES_DRIVE_TYPE_CDROM (3) +define ES_DRIVE_TYPE_USB_MASS_STORAGE (4) + +define ES_ELEMENT_FOCUS_ENSURE_VISIBLE (1 << 0) +define ES_ELEMENT_FOCUS_FROM_KEYBOARD (1 << 1) + +define ES_APPLICATION_STARTUP_MANUAL_PATH (1 << 0) +define ES_APPLICATION_STARTUP_SINGLE_INSTANCE_IN_PROCESS (1 << 1) + +define ES_LIST_VIEW_INLINE_TEXTBOX_COPY_EXISTING_TEXT (1 << 0) +define ES_LIST_VIEW_INLINE_TEXTBOX_REJECT_EDIT_IF_FOCUS_LOST (1 << 1) + +define ES_DRAW_CONTENT_MARKER_DOWN_ARROW (1 << 0) +define ES_DRAW_CONTENT_MARKER_UP_ARROW (1 << 1) +define ES_DRAW_CONTENT_TABULAR (1 << 2) +define ES_DRAW_CONTENT_RICH_TEXT (1 << 3) + +define ES_MODIFIER_CTRL (1 << 0) +define ES_MODIFIER_SHIFT (1 << 1) +define ES_MODIFIER_ALT (1 << 2) +define ES_MODIFIER_FLAG (1 << 3) + +define ES_PROCESS_CREATE_PAUSED (1 << 0) + +define ES_THREAD_EVENT_MUTEX_ACQUIRE (1) +define ES_THREAD_EVENT_MUTEX_RELEASE (2) + +define ES_WINDOW_PROPERTY_SOLID (0x01) // Standard window properties. +define ES_WINDOW_PROPERTY_OPAQUE_BOUNDS (0x02) +define ES_WINDOW_PROPERTY_BLUR_BOUNDS (0x03) +define ES_WINDOW_PROPERTY_ALPHA (0x04) +define ES_WINDOW_PROPERTY_FOCUSED (0x05) +define ES_WINDOW_PROPERTY_MATERIAL (0x06) +define ES_WINDOW_PROPERTY_EMBED (0x07) +define ES_WINDOW_PROPERTY_OBJECT (0x81) // Embedded window properties. +define ES_WINDOW_PROPERTY_EMBED_OWNER (0x82) +define ES_WINDOW_PROPERTY_RESIZE_CLEAR_COLOR (0x83) + +define ES_DRAW_BITMAP_OPAQUE (0xFFFF) +define ES_DRAW_BITMAP_XOR (0xFFFE) +define ES_DRAW_BITMAP_BLEND (0) + +include desktop/icons.header + +enum EsFatalError { + ES_FATAL_ERROR_ABORT + ES_FATAL_ERROR_INCORRECT_FILE_ACCESS + ES_FATAL_ERROR_INCORRECT_NODE_TYPE + ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS + ES_FATAL_ERROR_INVALID_BUFFER + ES_FATAL_ERROR_INVALID_HANDLE + ES_FATAL_ERROR_INVALID_MEMORY_REGION + ES_FATAL_ERROR_OUT_OF_RANGE // A parameter exceeds a limit, or is not a valid choice from an enumeration. + ES_FATAL_ERROR_PROCESSOR_EXCEPTION + ES_FATAL_ERROR_RECURSIVE_BATCH + ES_FATAL_ERROR_UNKNOWN_SYSCALL + ES_FATAL_ERROR_COUNT +} + +enum EsSyscallType { + // Memory. + + ES_SYSCALL_MEMORY_ALLOCATE + ES_SYSCALL_MEMORY_FREE + ES_SYSCALL_MEMORY_SHARE + ES_SYSCALL_MEMORY_MAP_OBJECT + ES_SYSCALL_MEMORY_OPEN + ES_SYSCALL_MEMORY_COMMIT + ES_SYSCALL_MEMORY_FAULT_RANGE + + // Processing. + + ES_SYSCALL_PROCESS_CREATE + ES_SYSCALL_PROCESS_GET_CREATION_ARGUMENT + ES_SYSCALL_THREAD_TERMINATE + ES_SYSCALL_THREAD_CREATE + ES_SYSCALL_WAIT + ES_SYSCALL_PROCESS_TERMINATE + ES_SYSCALL_EVENT_CREATE + ES_SYSCALL_EVENT_SET + ES_SYSCALL_EVENT_RESET + ES_SYSCALL_PROCESS_PAUSE + ES_SYSCALL_PROCESS_CRASH + ES_SYSCALL_THREAD_GET_ID + ES_SYSCALL_PROCESS_GET_STATE + ES_SYSCALL_YIELD_SCHEDULER + ES_SYSCALL_SLEEP + ES_SYSCALL_PROCESS_OPEN + ES_SYSCALL_PROCESS_SET_TLS + ES_SYSCALL_PROCESS_GET_TLS + ES_SYSCALL_PROCESS_GET_STATUS + ES_SYSCALL_EVENT_FORWARD + ES_SYSCALL_EVENT_SINK_CREATE + ES_SYSCALL_EVENT_SINK_POP + ES_SYSCALL_EVENT_SINK_PUSH + ES_SYSCALL_THREAD_STACK_SIZE + ES_SYSCALL_PROCESS_SHARE + + // Windowing. + + ES_SYSCALL_MESSAGE_GET + ES_SYSCALL_MESSAGE_POST + ES_SYSCALL_MESSAGE_WAIT + + ES_SYSCALL_CURSOR_POSITION_GET + ES_SYSCALL_CURSOR_POSITION_SET + ES_SYSCALL_GAME_CONTROLLER_STATE_POLL + ES_SYSCALL_EYEDROP_START + + ES_SYSCALL_SCREEN_WORK_AREA_SET + ES_SYSCALL_SCREEN_WORK_AREA_GET + ES_SYSCALL_SCREEN_BOUNDS_GET + ES_SYSCALL_SCREEN_FORCE_UPDATE + + ES_SYSCALL_WINDOW_CREATE + ES_SYSCALL_WINDOW_CLOSE + ES_SYSCALL_WINDOW_REDRAW + ES_SYSCALL_WINDOW_MOVE + ES_SYSCALL_WINDOW_GET_ID + ES_SYSCALL_WINDOW_GET_BOUNDS + ES_SYSCALL_WINDOW_SET_BITS + ES_SYSCALL_WINDOW_SET_CURSOR + ES_SYSCALL_WINDOW_SET_PROPERTY + + ES_SYSCALL_MESSAGE_DESKTOP + + ES_SYSCALL_CLIPBOARD_ADD + ES_SYSCALL_CLIPBOARD_HAS + ES_SYSCALL_CLIPBOARD_READ + + // IO. + + ES_SYSCALL_NODE_OPEN + ES_SYSCALL_FILE_READ_SYNC + ES_SYSCALL_FILE_WRITE_SYNC + ES_SYSCALL_FILE_RESIZE + ES_SYSCALL_FILE_GET_SIZE + ES_SYSCALL_DIRECTORY_ENUMERATE + ES_SYSCALL_NODE_DELETE + ES_SYSCALL_NODE_MOVE + ES_SYSCALL_FILE_CONTROL + ES_SYSCALL_NODE_SHARE + ES_SYSCALL_VOLUME_GET_INFORMATION + + // Networking. + + ES_SYSCALL_DOMAIN_NAME_RESOLVE + ES_SYSCALL_ECHO_REQUEST + ES_SYSCALL_CONNECTION_OPEN + ES_SYSCALL_CONNECTION_POLL + ES_SYSCALL_CONNECTION_NOTIFY + + // IPC. + + ES_SYSCALL_CONSTANT_BUFFER_READ + ES_SYSCALL_CONSTANT_BUFFER_SHARE + ES_SYSCALL_CONSTANT_BUFFER_CREATE + ES_SYSCALL_PIPE_CREATE + ES_SYSCALL_PIPE_WRITE + ES_SYSCALL_PIPE_READ + + // System information. + + ES_SYSCALL_SYSTEM_GET_CONSTANTS + ES_SYSCALL_SYSTEM_TAKE_SNAPSHOT + ES_SYSCALL_SYSTEM_CONFIGURATION_WRITE + ES_SYSCALL_SYSTEM_CONFIGURATION_READ + + // Misc. + + ES_SYSCALL_PRINT + ES_SYSCALL_HANDLE_CLOSE + ES_SYSCALL_BATCH + ES_SYSCALL_SHUTDOWN + ES_SYSCALL_POSIX + ES_SYSCALL_DEBUG_COMMAND + + // End. + + ES_SYSCALL_COUNT +} + +enum EsMessageType { + // Window manager messages (don't rearrange; see SendMessageToWindow in kernel/window_manager.cpp): + ES_MSG_WM_START = 0x1000 + ES_MSG_MOUSE_MOVED = 0x1001 + ES_MSG_WINDOW_ACTIVATED = 0x1002 + ES_MSG_WINDOW_DEACTIVATED = 0x1003 + ES_MSG_WINDOW_DESTROYED = 0x1004 + ES_MSG_MOUSE_EXIT = 0x1006 + ES_MSG_WINDOW_RESIZED = 0x1007 + ES_MSG_MOUSE_LEFT_DOWN = 0x1008 // Return ES_REJECTED to prevent taking focus, even if ES_ELEMENT_FOCUSABLE is set. Propagates. + ES_MSG_MOUSE_LEFT_UP = 0x1009 // Propagates. + ES_MSG_MOUSE_RIGHT_DOWN = 0x100A // Propagates. + ES_MSG_MOUSE_RIGHT_UP = 0x100B // Propagates. + ES_MSG_MOUSE_MIDDLE_DOWN = 0x100C // Propagates. + ES_MSG_MOUSE_MIDDLE_UP = 0x100D // Propagates. + ES_MSG_KEY_DOWN = 0x100E // Propagates to ancestors if unhandled. + ES_MSG_KEY_UP = 0x100F + ES_MSG_UPDATE_WINDOW = 0x1010 + ES_MSG_PRIMARY_CLIPBOARD_UPDATED = 0x1011 + ES_MSG_WM_END = 0x13FF + + // Internal GUI messages: // None of these should be sent directly. + ES_MSG_PAINT = 0x2000 // Paint the element using the painter specified in the message. + ES_MSG_PAINT_BACKGROUND = 0x2001 // Paint the element's background. Sent before ES_MSG_PAINT. + // If unhandled, the background is drawn using the default settings. + // The width/height parameters of EsPainter may be larger than expected - this includes the 'non-client' area. + ES_MSG_GET_CURSOR = 0x2003 // Get the cursor for the element. + ES_MSG_ANIMATE = 0x2004 // Animate the element. Returns the number of microseconds to wait for the next frame, + // or whether the animation is complete. + ES_MSG_Z_ORDER = 0x2005 // Get the child of an element based on its Z-order. + ES_MSG_DESTROY = 0x2006 // The element has been marked to be destroyed. Free any resources allocated. + // Sent after the parent receives its ES_MSG_REMOVE_CHILD message. + ES_MSG_GET_WIDTH = 0x2007 // Measure the element's width. If known, the height is specified. + ES_MSG_GET_HEIGHT = 0x2008 // Measure the element's height. If known, the width is specified. + ES_MSG_LAYOUT = 0x2009 // The size of the element has been updated. Layout the element's children. + ES_MSG_ENSURE_VISIBLE = 0x200A // Center the specified child (where possible) in your scrolled viewport. + ES_MSG_ADD_CHILD = 0x200B // An element has been created with this element as its parent. + ES_MSG_REMOVE_CHILD = 0x200C // An element has been destroyed with this element as its parent. + // Sent before the child receives its ES_MSG_DESTROY message. + // It will be removed from the `children` later (but before the next ES_MSG_LAYOUT message is received). + ES_MSG_PRE_ADD_CHILD = 0x200D // An element has been created with this element as its parent, but is not yet added to the parent. + ES_MSG_HIT_TEST = 0x200E // For non-rectangular elements: test whether a pixel should be considered inside the element. Set response to ES_HANDLED. + ES_MSG_KEY_TYPED = 0x2011 // Sent to the focused element when a key is pressed. + ES_MSG_SCROLL_X = 0x2012 // The element has been horizontally scrolled. + ES_MSG_SCROLL_Y = 0x2013 // The element has been vertically scrolled. + ES_MSG_STRONG_FOCUS_END = 0x2014 // Sent once when the user 'clicks off' the element, even if a new element was not necessarily focused. + ES_MSG_BEFORE_Z_ORDER = 0x2015 // Sent before a batch of Z_ORDER messages. + ES_MSG_AFTER_Z_ORDER = 0x2016 // Sent after a batch of Z_ORDER messages. + ES_MSG_PAINT_CHILDREN = 0x2017 // Paint the element's children. Useful for animations, with EsPaintTargetTake/Return. + ES_MSG_DESTROY_CONTENTS = 0x2018 // Sent after EsElementDestroyContents is called. + ES_MSG_GET_INSPECTOR_INFORMATION = 0x2019 // Get a string containing information about the element to display in the inspector. + ES_MSG_NOT_VISIBLE = 0x2020 // Sent to elements in the check visible list when they move off-screen. + ES_MSG_GET_CHILD_STYLE_VARIANT = 0x2021 // Allows the parent of an element to customize its default style. + ES_MSG_PAINT_ICON = 0x2022 // Sent during EsDrawContent. + ES_MSG_MOUSE_LEFT_CLICK = 0x2023 // Indicates the element has been "clicked" (might be different for other input devices). + ES_MSG_MOUSE_RIGHT_CLICK = 0x2024 // Right click, similar to LEFT_CLICK above. + ES_MSG_MOUSE_MIDDLE_CLICK = 0x2025 // Middle click, similar to LEFT_CLICK above. + ES_MSG_MOUSE_LEFT_DRAG = 0x2026 // Left button is pressed and the mouse is moving. + // Only starts being sent after a threshold is reached. + // This will NOT be sent if the element did not handle LEFT_DOWN. + ES_MSG_MOUSE_RIGHT_DRAG = 0x2027 // Similar to LEFT_DRAG above, but for the right button. + ES_MSG_MOUSE_MIDDLE_DRAG = 0x2028 // Similar to LEFT_DRAG above, but for the middle button. + + // State change messages: (causes a style refresh) + ES_MSG_STATE_CHANGE_MESSAGE_START = 0x2080 + ES_MSG_HOVERED_START = 0x2081 // Sent when the mouse starts hovering over an element. + ES_MSG_HOVERED_END = 0x2082 // Opposite of ES_MSG_HOVERED_START. Sent before ES_MSG_HOVERED_START is sent to the new hovered element. + ES_MSG_PRESSED_START = 0x2083 // Sent when an element is pressed. + ES_MSG_PRESSED_END = 0x2084 // Opposite of ES_MSG_PRESSED_START. + ES_MSG_FOCUSED_START = 0x2085 // Sent when an element is focused. + ES_MSG_FOCUSED_END = 0x2086 // Opposite of ES_MSG_FOCUSED_START. + ES_MSG_FOCUS_WITHIN_START = 0x2087 // Sent when an element is focused. + ES_MSG_FOCUS_WITHIN_END = 0x2088 // Opposite of ES_MSG_FOCUSED_START. + ES_MSG_STATE_CHANGE_MESSAGE_END = 0x20FF + + // Element messages: + ES_MSG_SCROLLBAR_MOVED = 0x3000 // The scrollbar has been moved. + ES_MSG_CHECK_UPDATED = 0x3001 // Button's check state has changed. See message->checkState. + ES_MSG_RADIO_GROUP_UPDATED = 0x3002 // Sent to all siblings of a radiobox when it is checked, so they can uncheck themselves. + ES_MSG_COLOR_CHANGED = 0x3003 // Color well's color has changed. See message->colorChanged. + ES_MSG_LIST_DISPLAY_GET_MARKER = 0x3004 // Get the string for a marker in an EsListDisplay. See message->getContent. + ES_MSG_REORDER_ITEM_TEST = 0x3005 + + // Desktop messages: + ES_MSG_POWER_BUTTON_PRESSED = 0x4801 + ES_MSG_EMBEDDED_WINDOW_DESTROYED = 0x4802 + ES_MSG_SET_SCREEN_RESOLUTION = 0x4803 + ES_MSG_REGISTER_FILE_SYSTEM = 0x4804 + ES_MSG_UNREGISTER_FILE_SYSTEM = 0x4805 + ES_MSG_DESKTOP = 0x4806 + + // Messages sent from Desktop to application instances: + ES_MSG_TAB_INSPECT_UI = 0x4A01 + ES_MSG_TAB_CLOSE_REQUEST = 0x4A02 + ES_MSG_INSTANCE_SAVE_RESPONSE = 0x4A03 // Sent by Desktop after an application requested to save its document. + ES_MSG_INSTANCE_DOCUMENT_RENAMED = 0x4A04 + ES_MSG_INSTANCE_DOCUMENT_UPDATED = 0x4A05 + + // Debugger messages: + ES_MSG_APPLICATION_CRASH = 0x4C00 + ES_MSG_PROCESS_TERMINATED = 0x4C01 + + // Undo item messages: + ES_MSG_UNDO_CANCEL = 0x4D00 + ES_MSG_UNDO_INVOKE = 0x4D01 + ES_MSG_UNDO_TO_STRING = 0x4D02 + + // Misc messages: + ES_MSG_EYEDROP_REPORT = 0x5001 + ES_MSG_SYSTEM_CONSTANT_UPDATED = 0x5002 + ES_MSG_TIMER = 0x5003 + ES_MSG_PING = 0x5004 // Sent by Desktop to check processes are processing messages. + ES_MSG_WAKEUP = 0x5005 // Sent to wakeup the message thread, so that it can process locally posted messages. + + // File Manager messages: + ES_MSG_FILE_MANAGER_FILE_MODIFIED = 0x5100 + + // Textbox messages: + ES_MSG_TEXTBOX_UPDATED = 0x5200 + ES_MSG_TEXTBOX_EDIT_START = 0x5201 // Set ES_TEXTBOX_EDIT_BASED to receive. + ES_MSG_TEXTBOX_EDIT_END = 0x5202 // Set ES_TEXTBOX_EDIT_BASED to receive. + ES_MSG_TEXTBOX_NUMBER_DRAG_START = 0x5203 // For EsTextboxUseNumberOverlay. + ES_MSG_TEXTBOX_NUMBER_DRAG_END = 0x5204 // For EsTextboxUseNumberOverlay. + ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA = 0x5205 // For EsTextboxUseNumberOverlay. + ES_MSG_TEXTBOX_NUMBER_UPDATED = 0x5206 // For EsTextboxUseNumberOverlay with defaultBehaviour=true. + ES_MSG_TEXTBOX_GET_BREADCRUMB = 0x5207 // For EsTextboxUseBreadcrumbOverlay. + ES_MSG_TEXTBOX_ACTIVATE_BREADCRUMB = 0x5208 // For EsTextboxUseBreadcrumbOverlay. + + // List view messages: + ES_MSG_LIST_VIEW_COMPARE_INDICES = 0x5300 + ES_MSG_LIST_VIEW_NEXT_INDEX = 0x5301 + ES_MSG_LIST_VIEW_PREVIOUS_INDEX = 0x5302 + ES_MSG_LIST_VIEW_FIRST_INDEX = 0x5303 + ES_MSG_LIST_VIEW_LAST_INDEX = 0x5304 + ES_MSG_LIST_VIEW_FIND_INDEX = 0x5305 + ES_MSG_LIST_VIEW_COUNT_ITEMS = 0x5306 + ES_MSG_LIST_VIEW_MEASURE_RANGE = 0x5307 + ES_MSG_LIST_VIEW_MEASURE_ITEM = 0x5308 + ES_MSG_LIST_VIEW_CREATE_ITEM = 0x5309 + ES_MSG_LIST_VIEW_GET_CONTENT = 0x530A + ES_MSG_LIST_VIEW_GET_INDENT = 0x530B + ES_MSG_LIST_VIEW_FIND_POSITION = 0x530C + ES_MSG_LIST_VIEW_IS_SELECTED = 0x530D + ES_MSG_LIST_VIEW_SELECT = 0x530E + ES_MSG_LIST_VIEW_SELECT_RANGE = 0x530F + ES_MSG_LIST_VIEW_CHOOSE_ITEM = 0x5310 + ES_MSG_LIST_VIEW_SEARCH = 0x5311 + ES_MSG_LIST_VIEW_CONTEXT_MENU = 0x5312 + ES_MSG_LIST_VIEW_COLUMN_MENU = 0x5313 + ES_MSG_LIST_VIEW_GET_SUMMARY = 0x5314 + ES_MSG_LIST_VIEW_GET_COLUMN_SORT = 0x5315 + + // Application messages: + ES_MSG_APPLICATION_EXIT = 0x7001 + ES_MSG_INSTANCE_CREATE = 0x7002 + ES_MSG_INSTANCE_OPEN = 0x7003 + ES_MSG_INSTANCE_SAVE = 0x7004 + ES_MSG_INSTANCE_DESTROY = 0x7005 + + // User messages: + ES_MSG_USER_START = 0x8000 + ES_MSG_USER_END = 0xBFFF +} + +enum EsCursorStyle { + ES_CURSOR_NORMAL + ES_CURSOR_TEXT + ES_CURSOR_RESIZE_VERTICAL + ES_CURSOR_RESIZE_HORIZONTAL + ES_CURSOR_RESIZE_DIAGONAL_1 // '/' + ES_CURSOR_RESIZE_DIAGONAL_2 // '\' + ES_CURSOR_SPLIT_VERTICAL + ES_CURSOR_SPLIT_HORIZONTAL + ES_CURSOR_HAND_HOVER + ES_CURSOR_HAND_DRAG + ES_CURSOR_HAND_POINT + ES_CURSOR_SCROLL_UP_LEFT + ES_CURSOR_SCROLL_UP + ES_CURSOR_SCROLL_UP_RIGHT + ES_CURSOR_SCROLL_LEFT + ES_CURSOR_SCROLL_CENTER + ES_CURSOR_SCROLL_RIGHT + ES_CURSOR_SCROLL_DOWN_LEFT + ES_CURSOR_SCROLL_DOWN + ES_CURSOR_SCROLL_DOWN_RIGHT + ES_CURSOR_SELECT_LINES + ES_CURSOR_DROP_TEXT + ES_CURSOR_CROSS_HAIR_PICK + ES_CURSOR_CROSS_HAIR_RESIZE + ES_CURSOR_MOVE_HOVER + ES_CURSOR_MOVE_DRAG + ES_CURSOR_ROTATE_HOVER + ES_CURSOR_ROTATE_DRAG + ES_CURSOR_BLANK + ES_CURSOR_COUNT +} + +enum EsWindowStyle { + ES_WINDOW_NORMAL + ES_WINDOW_CONTAINER + ES_WINDOW_MENU + ES_WINDOW_TIP + ES_WINDOW_PLAIN + ES_WINDOW_INSPECTOR +} + +enum EsCheckState { + ES_CHECK_UNCHECKED = 0 + ES_CHECK_CHECKED = 1 + ES_CHECK_INDETERMINATE = 2 +} + +enum EsTransitionType { + ES_TRANSITION_NONE + ES_TRANSITION_SLIDE_UP + ES_TRANSITION_SLIDE_DOWN + ES_TRANSITION_COVER_UP + ES_TRANSITION_COVER_DOWN + ES_TRANSITION_SQUISH_UP + ES_TRANSITION_SQUISH_DOWN + ES_TRANSITION_ZOOM_OUT + ES_TRANSITION_ZOOM_IN + ES_TRANSITION_ZOOM_OUT_LIGHT + ES_TRANSITION_ZOOM_IN_LIGHT + ES_TRANSITION_REVEAL_UP + ES_TRANSITION_REVEAL_DOWN + ES_TRANSITION_FADE_IN + ES_TRANSITION_FADE_OUT + ES_TRANSITION_SLIDE_UP_OVER + ES_TRANSITION_SLIDE_DOWN_OVER + ES_TRANSITION_SLIDE_UP_UNDER + ES_TRANSITION_SLIDE_DOWN_UNDER +} + +enum EsMemoryProtection { + ES_MEMORY_PROTECTION_READ_ONLY + ES_MEMORY_PROTECTION_READ_WRITE + ES_MEMORY_PROTECTION_EXECUTABLE +} + +enum EsClipboard { + ES_CLIPBOARD_PRIMARY +} + +function_pointer int EsUICallbackFunction(struct EsElement *element, struct EsMessage *message); + +struct EsBuffer { + union { const uint8_t *in; uint8_t *out; }; + size_t position, bytes; + void *context; + bool error, canGrow; +}; + +struct EsElementPublic { + EsUICallbackFunction messageUser; + EsCString cName; + EsGeneric userData; + char accessKey; // Upper-case. + + // These fields are read-only! + EsWindow *window; + ES_INSTANCE_TYPE *instance; + uint64_t flags; // Bits 0-31: specific to the type of element; bits 32-63: common to all elements. +}; + +struct EsBatchCall { + EsSyscallType index; + bool stopBatchIfError; + union { uintptr_t argument0, returnValue; }; + uintptr_t argument1, argument2, argument3; +} + +struct EsThreadInformation { + EsHandle handle; + uint64_t tid; +} + +struct EsProcessInformation { + EsHandle handle; + uintptr_t pid; + EsThreadInformation mainThread; +} + +struct EsUniqueIdentifier { + // Don't mess with this structure, it's used in filesystems. + uint8_t d[16]; +} + +struct EsFileInformation { + EsHandle handle; + EsFileOffset size; + EsError error; +} + +struct EsDirectoryChild { + char name[ES_MAX_DIRECTORY_CHILD_NAME_LENGTH]; + size_t nameBytes; + EsNodeType type; + EsFileOffsetDifference fileSize; // -1 if unsupported. + EsFileOffsetDifference directoryChildren; // ES_DIRECTORY_CHILDREN_UNKNOWN if unsupported. +} + +struct EsPoint { + int32_t x; + int32_t y; +} + +struct EsRectangle { + int32_t l; // Inclusive. + int32_t r; // Exclusive. + int32_t t; // Inclusive. + int32_t b; // Exclusive. +} + +struct EsSpinlock { + volatile uint8_t state; +} + +struct EsMutex { + EsHandle event; + EsSpinlock spinlock; + volatile uint8_t state; + volatile uint32_t queued; +} + +struct EsCrashReason { + EsFatalError errorCode; + EsSyscallType duringSystemCall; +} + +struct EsProcessState { + EsCrashReason crashReason; + uint64_t id; + uint8_t executableState; + uint8_t flags; +} + +struct EsPainter { + EsRectangle clip; + int offsetX, offsetY, width, height; + void *style; + EsPaintTarget *target; +} + +struct EsDebuggerMessage { + EsHandle process; + EsCrashReason reason; +} + +struct EsSnapshotProcessesItem { + int64_t pid, memoryUsage, cpuTimeSlices, idleTimeSlices, handleCount; + char name[ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH]; + uint8_t nameBytes; + bool isKernel; +} + +struct EsSnapshotProcesses { + size_t count; + EsSnapshotProcessesItem processes[]; +} + +struct EsMountPoint { + char prefix[16]; + size_t prefixBytes; + EsHandle base; + bool write; +}; + +struct EsProcessCreationArguments { + EsHandle executable; + + const void *environmentBlock; + size_t environmentBlockBytes; + + EsGeneric creationArgument; + uint64_t permissions; + + EsMountPoint *initialMountPoints; + size_t initialMountPointCount; + + uint64_t flags; +}; + +struct EsInstance { + // Read-only variables. + void *_private; + EsWindow *window; + EsUndoManager *undoManager; +}; + +struct EsPanelBand { + int preferredSize, minimumSize, maximumSize; + int push, pull; // Similar to flex-grow and flex-shrink from CSS. +} + +struct EsThemeMetrics { + uint64_t mask; + EsRectangle insets, clipInsets; + EsRectangle globalOffset; + int clipEnabled, cursor, entranceTransition, exitTransition; + int entranceDuration, exitDuration; + int preferredWidth, preferredHeight; + int minimumWidth, minimumHeight; + int maximumWidth, maximumHeight; + int gapMajor, gapMinor, gapWrap; + uint32_t textColor, selectedBackground, selectedText, iconColor; + int textAlign, textSize, fontFamily, fontWeight, iconSize; + bool isItalic, ellipsis, layoutVertical; +}; + +struct EsThemeAppearance { + bool enabled; + uint32_t backgroundColor; + uint32_t borderColor; + EsRectangle borderSize; +}; + +struct EsStyle { + void *inherit; + EsThemeMetrics metrics; + EsThemeAppearance appearance; +}; + +include desktop/styles.header + +struct EsFont { + EsFontFamily family; + uint8_t weight; + bool italic; +} + +struct EsTextStyle { + // TODO Indicating RTL/vertical writing modes. + // TODO Support for features. + // TODO Support for variable fonts. + + EsFont font; + uint16_t size, baselineOffset; + + int8_t tracking; + uint8_t figures; + bool alternateDirection; + + // Render properties: + uint8_t blur; + uint8_t decorations; + uint32_t color; + uint32_t decorationsColor; +}; + +struct EsTextRun { + EsTextStyle style; + uint32_t offset; +}; + +struct EsTextPlanProperties { + EsCString cLanguage; + uint32_t flags; + int maxLines; // Set to 0 for no limit. +}; + +struct EsTextSelection { + ptrdiff_t caret0, caret1; + bool hideCaret, snapCaretToInsets; + uint32_t foreground, background; +}; + +function_pointer uint32_t EsFragmentShaderCallbackFunction(int x, int y, struct EsStyledBox *box); + +struct EsStyledBox { + EsRectangle bounds, clip; + uint32_t backgroundColor, backgroundColor2; + EsFragmentShaderCallbackFunction fragmentShader; + uint32_t borderColor; + EsRectangle borders; + int cornerRadiusTopLeft, cornerRadiusTopRight, cornerRadiusBottomLeft, cornerRadiusBottomRight; +}; + +struct EsArena { + // Arenas are not thread-safe! + // You can use different arenas in different threads, though. + void *firstEmptySlot, *firstBlock; + size_t slotsPerBlock, slotSize, blockSize; +}; + +struct EsCalculationValue { + bool error; + double number; +}; + +function_pointer void EsCommandCallbackFunction(ES_INSTANCE_TYPE *instance, EsElement *element, struct EsCommand *command); + +struct EsCommand { + EsElement **elements; + EsCommandCallbackFunction callback; + bool disabled, registered, allocated; + EsCheckState check; + uint32_t stableID; + EsCString cKeyboardShortcut; + EsGeneric data; +}; + +struct EsListViewColumn { + STRING title; + uint32_t flags; + int width; +}; + +struct EsApplicationStartupInformation { + int64_t id; + STRING filePath; + EsWindow *targetWindow; + uint32_t flags; + EsHandle readHandle; // Internal use. +}; + +struct EsINIState { + char *buffer, *sectionClass, *section, *key, *value; + size_t bytes, sectionClassBytes, sectionBytes, keyBytes, valueBytes; +}; + +struct EsSystemConfigurationItem { + char *key, *value; + size_t keyBytes, valueBytes; +}; + +struct EsSystemConfigurationGroup { + char *section, *sectionClass; + size_t sectionBytes, sectionClassBytes; + EsSystemConfigurationItem *items; + size_t itemCount; +}; + +struct EsAnalogInput { + uint8_t x, y, z; +}; + +struct EsGameControllerState { + uint64_t id; + uint8_t buttonCount, analogCount; // Number of buttons and analog inputs. + uint8_t directionalPad; // Directions given from 0-7, starting at up, going clockwise. 15 indicates unpressed. + uint32_t buttons; // Bitset of pressed buttons. + EsAnalogInput analog[8]; +}; + +struct EsPCIDevice { + uint32_t deviceID; + uint8_t classCode, subclassCode, progIF; + uint8_t bus, slot, function; + uint8_t interruptPin, interruptLine; + size_t baseAddressesSizes[6]; + uint32_t baseAddresses[6]; + char driverName[64]; + size_t driverNameBytes; +}; + +struct EsAddress { + union { + struct { + uint32_t ipv4; + uint16_t port; + }; + + uint8_t d[20]; + }; +}; + +struct EsConnection { + EsAddress address; + size_t receiveBufferBytes; + size_t sendBufferBytes; + + uint8_t *receiveBuffer; + uint8_t *sendBuffer; + + uintptr_t receiveWritePointer; + uintptr_t sendReadPointer; + bool open; + EsError error; + + uintptr_t receiveReadPointer; + uintptr_t sendWritePointer; + + EsHandle handle; +}; + +struct EsFileMenuSettings { +}; + +struct EsInstanceClassEditorSettings { + STRING newDocumentFileName; // The default file name to use when creating a new document. + STRING newDocumentTitle; // The title to show in the file menu if the document has not been saved. + uint32_t documentIconID; +}; + +struct EsInstanceClassViewerSettings { +}; + +struct _EsNodeInformation { + EsHandle handle; + EsFileOffset fileSize; + EsFileOffsetDifference directoryChildren; + EsNodeType type; +}; + +struct EsVolumeInformation { + char label[64]; + uint8_t labelBytes; + uint8_t driveType; + uint64_t id; + EsFileOffset spaceTotal; + EsFileOffset spaceUsed; +}; + +// User interface messages. + +struct EsMessageMouseMotion { + int newPositionX; + int newPositionY; + int originalPositionX; // For MOUSE_DRAGGED only. + int originalPositionY; +}; + +struct EsMessageMouseButton { + int positionX; + int positionY; + uint8_t clickChainCount; +}; + +struct EsMessageKeyboard { + uint32_t scancode; + uint8_t modifiers; + bool repeat, numpad, numlock; +}; + +struct EsMessageAnimate { + int64_t deltaMs, waitMs; + bool complete; +}; + +struct EsMessageLayout { + bool sizeChanged; +}; + +struct EsMessageWindowResized { + EsRectangle content; + bool hidden; +}; + +struct EsMessageMeasure { + int width, height; +}; + +struct EsMessageHitTest { + int x, y; + bool inside; +}; + +struct EsMessageZOrder { + uintptr_t index; + EsElement *child; +}; + +struct EsMessageBeforeZOrder { + uintptr_t start, end, nonClient; + EsRectangle clip; +}; + +struct EsMessageItemToString { + EsGeneric item; + STRING text; +}; + +// List view messages. + +struct EsMessageCompareIndices { + int32_t group; + EsGeneric left, right; + int result; +}; + +struct EsMessageIterateIndex { + int32_t group; + EsGeneric index; + + // FIND_INDEX and FIND_POSITION: (TODO Pass the reference item?) + int64_t position; +}; + +struct EsMessageItemRange { + int32_t group; + EsGeneric firstIndex, lastIndex; + int64_t result; +}; + +struct EsMessageMeasureItem { + int32_t group; + EsGeneric index; + int64_t result; +}; + +struct EsMessageCreateItem { + int32_t group; + EsGeneric index; + EsElement *item; +}; + +struct EsMessageGetContent { + EsGeneric index; + int32_t group; + uint32_t icon; + EsBuffer *buffer; + bool richText; + uint8_t column; +}; + +struct EsMessageGetIndent { + int32_t group; + EsGeneric index; + + uint8_t indent; +}; + +struct EsMessageSelectRange { + EsGeneric fromIndex, toIndex; + int32_t group; + bool select, toggle; +}; + +struct EsMessageSelectItem { + int32_t group; + EsGeneric index; + bool isSelected; +}; + +struct EsMessageChooseItem { + int32_t group; + EsGeneric index; +}; + +struct EsMessageSearchItem { + int32_t group; + EsGeneric index; + STRING query; +}; + +struct EsMessageFocus { + uint32_t flags; +}; + +struct EsMessageColumnMenu { + uint8_t index; + EsElement *source; +}; + +struct EsMessageGetColumnSort { + uint8_t index; +}; + +// Specific element messages. + +struct EsMessageScrollbarMoved { + int scroll, previous; +}; + +struct EsMessageColorChanged { + uint32_t newColor; + bool pickerClosed; +}; + +struct EsMessageNumberDragDelta { + int delta; + int32_t hoverCharacter; + bool fast; +}; + +struct EsMessageNumberUpdated { + double delta; + double newValue; +}; + +struct EsMessageGetBreadcrumb { + uintptr_t index; // Set response to ES_REJECTED if this equals the number of breadcrumbs. + EsBuffer *buffer; +}; + +struct EsMessageEndEdit { + bool rejected; +}; + +// Instance messages. + +struct EsMessageInstanceOpen { + ES_INSTANCE_TYPE *instance; + EsFileStore *file; + STRING name; + bool update; +}; + +struct EsMessageInstanceSave { + ES_INSTANCE_TYPE *instance; + EsFileStore *file; +}; + +struct EsMessageInstanceDestroy { + ES_INSTANCE_TYPE *instance; +}; + +// Internal system messages. + +struct EsMessageProcessCrash { + EsCrashReason reason; + EsHandle process; + uintptr_t pid; +}; + +struct EsMessageDesktop { + uint64_t windowID; + EsHandle buffer; + size_t bytes; +}; + +struct EsMessageEyedrop { + uint32_t color; + bool cancelled; +}; + +struct EsMessageCreateInstance { + EsHandle window; + EsHandle data; + size_t dataBytes; +}; + +struct EsMessageTabOperation { + uint64_t id; + EsHandle handle; + union { size_t bytes; bool isSource; }; + EsError error; +}; + +struct EsMessageSystemConstantUpdated { + uintptr_t index; + uint64_t newValue; +}; + +struct EsMessageRegisterFileSystem { + EsHandle rootDirectory; + bool isBootFileSystem; + EsMountPoint *mountPoint; +}; + +struct EsMessageUnregisterFileSystem { + uint64_t id; + EsMountPoint *mountPoint; +}; + +// Message structure. + +struct EsMessageUser { + EsGeneric context1, context2, context3, context4; +}; + +struct EsMessage { + EsMessageType type; + + union { + struct { uintptr_t _size[4]; } _size; // EsMessagePost supports messages at most 4 pointers in size. + EsMessageUser user; // For application specific messages. + + // User interface messages: + EsMessageMouseMotion mouseMoved; + EsMessageMouseMotion mouseDragged; + EsMessageMouseButton mouseDown; + EsMessageKeyboard keyboard; + EsMessageWindowResized windowResized; + EsMessageAnimate animate; + EsMessageLayout layout; + EsMessageMeasure measure; + EsMessageHitTest hitTest; + EsPainter *painter; + EsElement *child; + EsCursorStyle cursorStyle; + EsMessageZOrder zOrder; + EsMessageBeforeZOrder beforeZOrder; + EsMessageItemToString itemToString; + EsMessageFocus focus; + const EsStyle *childStyleVariant; + + // List view messages: + EsMessageCompareIndices compareIndices; + EsMessageIterateIndex iterateIndex; + EsMessageItemRange itemRange; + EsMessageMeasureItem measureItem; + EsMessageCreateItem createItem; + EsMessageGetContent getContent; + EsMessageGetIndent getIndent; + EsMessageSelectRange selectRange; + EsMessageSelectItem selectItem; + EsMessageChooseItem chooseItem; + EsMessageSearchItem searchItem; + EsMessageColumnMenu columnMenu; + EsMessageGetColumnSort getColumnSort; + + // Specific element messages: + EsMessageScrollbarMoved scrollbarMoved; + EsMessageColorChanged colorChanged; + EsMessageNumberDragDelta numberDragDelta; + EsMessageNumberUpdated numberUpdated; + EsMessageGetBreadcrumb getBreadcrumb; + EsMessageEndEdit endEdit; + uintptr_t activateBreadcrumb; + EsCheckState checkState; + + // Instance messages: + EsMessageInstanceOpen instanceOpen; + EsMessageInstanceSave instanceSave; + EsMessageInstanceDestroy instanceDestroy; + + // Internal messages: + void *_argument; + EsMessageProcessCrash crash; + EsMessageSystemConstantUpdated systemConstantUpdated; + EsMessageDesktop desktop; + EsMessageEyedrop eyedrop; + EsMessageCreateInstance createInstance; + EsMessageTabOperation tabOperation; + EsMessageRegisterFileSystem registerFileSystem; + EsMessageUnregisterFileSystem unregisterFileSystem; + }; +} + +struct _EsMessageWithObject { + void *object; + EsMessage message; +}; + +struct EsThreadEventLogEntry { + char file[31]; + uint8_t fileBytes; + char expression[31]; + uint8_t expressionBytes; + uint8_t event; + uint16_t line; + uint64_t objectID, threadID; +}; + +struct EsMemoryStatistics { + size_t fixedHeapAllocationCount; + size_t fixedHeapTotalSize; + size_t coreHeapAllocationCount; + size_t coreHeapTotalSize; + size_t cachedNodes; + size_t cachedDirectoryEntries; + size_t totalSurfaceBytes; + size_t commitPageable; + size_t commitFixed; + size_t commitLimit; + size_t commitFixedLimit; + size_t commitRemaining; + size_t maximumObjectCachePages; + size_t approximateObjectCacheSize; +}; + +struct EsFontInformation { + char name[96]; + size_t nameBytes; + char category[32]; + size_t categoryBytes; + EsFontFamily id; + uint16_t availableWeightsNormal; + uint16_t availableWeightsItalic; +}; + +// Function pointer types. + +function_pointer void EsThreadEntryFunction(EsGeneric argument); +function_pointer int EsComparisonCallbackFunction(const void *left, const void *right, EsGeneric context); +function_pointer void EsSwapCallbackFunction(const void *left, const void *right, EsGeneric context); +function_pointer int EsCRTComparisonCallback(const void *left, const void *right); +function_pointer void EsTimerCallbackFunction(EsGeneric argument); +function_pointer void EsMenuCallbackFunction(EsMenu *menu, EsGeneric context); +function_pointer void EsUndoCallback(const void *item, EsUndoManager *manager, EsMessage *message); +function_pointer void EsMountPointEnumerationCallbackFunction(const char *prefix, size_t prefixBytes, EsGeneric context); +function_pointer void EsListViewEnumerateVisibleItemsCallbackFunction(EsListView *view, EsElement *item, uint32_t group, EsGeneric index); +function_pointer void EsFontEnumerationCallbackFunction(const EsFontInformation *information, EsGeneric context); + +// System. + +function void EsApplicationStart(const EsApplicationStartupInformation *information); +function void EsApplicationRunTemporary(ES_INSTANCE_TYPE *instance, STRING path); +function EsHandle EsTakeSystemSnapshot(int type, size_t *bufferSize); +function EsInstance *_EsInstanceCreate(size_t bytes, EsMessage *message, STRING name = BLANK_STRING); +function EsError EsHandleClose(EsHandle handle); +function void EsSystemShowShutdownDialog(ES_INSTANCE_TYPE *instance); + +function void EsPOSIXInitialise(int *argc, char ***argv); +function intptr_t EsPOSIXSystemCall(intptr_t n, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4, intptr_t a5, intptr_t a6); +function char *EsPOSIXConvertPath(const char *path, size_t *outNameLength, bool addPOSIXMountPointPrefix); + +function void EsBatch(EsBatchCall *calls, size_t count); +function uintptr_t _EsSyscall(uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e, uintptr_t f); + +// Configuration and settings. + +function uint64_t EsSystemGetConstant(uintptr_t index); + +function EsSystemConfigurationGroup *EsSystemConfigurationReadAll(size_t *groupCount); // Read with the message mutex acquired. +function int64_t EsSystemConfigurationReadInteger(STRING section, STRING key, int64_t defaultValue = 0); +function int64_t EsSystemConfigurationGroupReadInteger(EsSystemConfigurationGroup *group, STRING key, int64_t defaultValue = 0); +function char *EsSystemConfigurationReadString(STRING section, STRING key, size_t *valueBytes = ES_NULL); // Free with EsHeapFree. +function char *EsSystemConfigurationGroupReadString(EsSystemConfigurationGroup *group, STRING key, size_t *valueBytes = ES_NULL); // Free with EsHeapFree. + +// INI files. + +function bool EsINIParse(EsINIState *s); +function bool EsINIPeek(EsINIState *s); +function size_t EsINIFormat(EsINIState *s, char *buffer, size_t bytes); +function void EsINIZeroTerminate(EsINIState *s); + +// File systems. + +function const void *EsEmbeddedFileGet(const char *cName, size_t *byteCount = ES_NULL); + +function ptrdiff_t EsDirectoryEnumerateChildren(STRING path, EsDirectoryChild **buffer); // Free buffer with EsHeapFree. Returns number of children. + +function void *EsFileReadAll(STRING filePath, size_t *fileSize, EsError *error = ES_NULL); // Free with EsHeapFree. +function void *EsFileReadAllFromHandle(EsHandle handle, size_t *fileSize, EsError *error = ES_NULL); // Free with EsHeapFree. +function EsError EsFileWriteAll(STRING filePath, const void *data, size_t fileSize); +function EsError EsFileWriteAllFromHandle(EsHandle handle, const void *data, size_t fileSize); +function EsError EsFileWriteAllGather(STRING filePath, const void **data, size_t *fileSize, size_t gatherCount); +function EsError EsFileWriteAllGatherFromHandle(EsHandle handle, const void **data, size_t *fileSize, size_t gatherCount); +function void *EsFileMap(STRING filePath, size_t *fileSize, uint32_t flags); + +function EsError EsFileControl(EsHandle file, uint32_t flags); +function EsFileInformation EsFileOpen(STRING path, uint32_t flags); +function EsFileOffset EsFileGetSize(EsHandle handle); +function size_t EsFileReadSync(EsHandle file, EsFileOffset offset, size_t size, void *buffer); +function EsError EsFileResize(EsHandle file, EsFileOffset newSize); +function size_t EsFileWriteSync(EsHandle file, EsFileOffset offset, size_t size, const void *buffer); + +function EsError EsPathDelete(STRING path); +function size_t EsPathFindUniqueName(char *buffer, size_t originalBytes, size_t bufferBytes); +function EsError EsPathMove(STRING oldPath, STRING newPath); +function bool EsPathExists(STRING filePath, EsNodeType *type = ES_NULL); // Returns true if the file/directory exists. +function EsError EsPathCreate(STRING filePath, EsNodeType type, bool createLeadingDirectories); +function bool EsPathQueryInformation(STRING filePath, EsDirectoryChild *information); + +function void *EsFileStoreReadAll(EsFileStore *file, size_t *fileSize); // Free with EsHeapFree. +function bool EsFileStoreWriteAll(EsFileStore *file, const void *data, size_t dataBytes); +function EsFileOffsetDifference EsFileStoreGetSize(EsFileStore *file); // Returns -1 on error. +function void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flags); + +// Requires permission_all_files. +function bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, EsVolumeInformation *information); // Returns false if the mount point does not exist. +function void EsMountPointEnumerate(EsMountPointEnumerationCallbackFunction callback, EsGeneric context); +function void _EsPathAnnouncePathMoved(EsInstance *instance, STRING oldPath, STRING newPath); + +// Processes and threads. + +function EsError EsProcessCreate(EsProcessCreationArguments *arguments, EsProcessInformation *information); +function int EsProcessGetExitStatus(EsHandle process); +function uintptr_t EsProcessGetID(EsHandle process); +function void EsProcessGetState(EsHandle process, EsProcessState *state); +function EsHandle EsProcessOpen(uint64_t pid); +function void EsProcessPause(EsHandle process, bool resume); +function void EsProcessTerminate(EsHandle process, int status); +function void EsProcessTerminateCurrent(); +function EsError EsThreadCreate(EsThreadEntryFunction entryFunction, EsThreadInformation *information, EsGeneric argument); +function uint64_t EsThreadGetID(EsHandle thread); // TODO Make this 64-bit. +function void EsThreadTerminate(EsHandle thread); + +// Memory. + +function void *EsArenaAllocate(EsArena *arena, bool zero); // Not thread-safe. +function void EsArenaFree(EsArena *arena, void *pointer); // Not thread-safe. +function void EsArenaInitialise(EsArena *arena, size_t blockSize, size_t itemSize); + +function const void *EsBufferRead(struct EsBuffer *buffer, size_t readBytes); +function const void *EsBufferReadMany(struct EsBuffer *buffer, size_t a, size_t b); +function void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writeBytes); +function void EsBufferFormat(EsBuffer *buffer, EsCString format, ...); // Appends. +function void EsBufferFormatV(EsBuffer *buffer, EsCString format, va_list arguments); // Appends. + +function EsHandle EsConstantBufferCreate(const void *data, size_t dataBytes, EsHandle targetProcess); +function void EsConstantBufferRead(EsHandle constantBuffer, void *output); +function EsHandle EsConstantBufferShare(EsHandle constantBuffer, EsHandle targetProcess); +function size_t EsConstantBufferGetSize(EsHandle constantBuffer); + +function_not_in_kernel void *EsHeapAllocate(size_t size, bool zeroMemory, EsHeap *heap = ES_NULL); +function_not_in_kernel void EsHeapFree(void *address, size_t expectedSize = 0, EsHeap *heap = ES_NULL); +function_not_in_kernel void *EsHeapReallocate(void *oldAddress, size_t newAllocationSize, bool zeroNewSpace, EsHeap *heap = ES_NULL); + +function void EsHeapValidate(); + +function bool EsMemoryCommit(void *pointer, size_t bytes); +function int EsMemoryCompare(const void *a, const void *b, size_t bytes); +function void EsMemoryCopy(void *destination, const void *source, size_t bytes); +function void EsMemoryCopyReverse(void *_destination, void *_source, size_t bytes); +function bool EsMemoryDecommit(void *pointer, size_t bytes); // May fail in low-memory conditions when the commit ranges on the region are fragmented. (Cannot fail if you decommit the entire region.) +function void EsMemoryFaultRange(const void *pointer, size_t bytes, uint32_t flags = ES_FLAGS_DEFAULT); // Simulate a page fault in each page in the range. +function void EsMemoryFill(void *from, void *to, uint8_t byte); +function void EsMemoryMove(void *_start, void *_end, intptr_t amount, bool zeroEmptySpace); +function EsHandle EsMemoryOpen(size_t size, STRING name, unsigned flags); +function void *EsMemoryReserve(size_t size, EsMemoryProtection protection = ES_MEMORY_PROTECTION_READ_WRITE, uint32_t flags = ES_MEMORY_RESERVE_COMMIT_ALL); +function EsHandle EsMemoryShare(EsHandle sharedMemoryRegion, EsHandle targetProcess, bool readOnly); +function uint8_t EsMemorySumBytes(uint8_t *data, size_t bytes); +function void EsMemoryUnreserve(void *pointer, size_t size = 0); // Must cover the entire reserved region. Leave size 0 if you don't know the size. +function void EsMemoryZero(void *destination, size_t bytes); + +function void *EsObjectMap(EsHandle object, uintptr_t offset, size_t size, unsigned flags); + +// Standard functions. + +function void EsAssertionFailure(EsCString cFile, int line); +function EsCalculationValue EsCalculateFromUserExpression(EsCString cExpression); // For user input only; do not rely on consistent behaviour across versions; use with message mutex. +function double EsDoubleParse(STRING string, char **endptr); +function uint8_t EsRandomU8(); +function uint64_t EsRandomU64(); +function int64_t EsIntegerParse(STRING text); // Parses in hexadecimal if the first two characters are '0x'. +function_not_in_kernel void EsPanic(EsCString format, ...); +function_not_in_kernel void EsPrint(EsCString format, ...); +function void EsPrintDirect(STRING string); +function void EsPrintHelloWorld(); +function void EsRandomAddEntropy(uint64_t x); +function void EsRandomSeed(uint64_t x); +function EsRectangle EsRectangleAdd(EsRectangle a, EsRectangle b); +function EsRectangle EsRectangleAddBorder(EsRectangle rectangle, EsRectangle border); +function EsRectangle EsRectangleBounding(EsRectangle a, EsRectangle b); +function EsRectangle EsRectangleCenter(EsRectangle parent, EsRectangle child); +function EsRectangle EsRectangleCut(EsRectangle a, int32_t amount, char side); +function EsRectangle EsRectangleFit(EsRectangle parent, EsRectangle child, bool allowScalingUp); // Preserves aspect ratio. +function EsRectangle EsRectangleIntersection(EsRectangle a, EsRectangle b); +function EsRectangle EsRectangleSplit(EsRectangle *a, int32_t amount, char side, int32_t gap = 0); // Same as EsRectangleCut, but the source rectangle is modified. +function EsRectangle EsRectangleSubtract(EsRectangle a, EsRectangle b); +function EsRectangle EsRectangleTranslate(EsRectangle a, EsRectangle b); +function bool EsRectangleEquals(EsRectangle a, EsRectangle b); +function bool EsRectangleContains(EsRectangle a, int32_t x, int32_t y); +function void EsSort(void *_base, size_t nmemb, size_t size, EsComparisonCallbackFunction compar, EsGeneric argument); +function void EsSortWithSwapCallback(void *_base, size_t nmemb, size_t size, EsComparisonCallbackFunction compar, EsGeneric argument, EsSwapCallbackFunction swap); +function uint64_t EsTimeStamp(); +function double EsTimeStampMs(); + +// Graphics. + +function uint32_t EsColorBlend(uint32_t under, uint32_t over, bool fullAlpha); +function uint32_t EsColorConvertToRGB(float h, float s, float v); // 0 <= hue < 6; 0 <= saturation <= 1; 0 <= value <= 1. +function bool EsColorConvertToHSV(uint32_t color, float *h, float *s, float *v); +function uint32_t EsColorParse(STRING string); + +function void EsDrawBitmap(EsPainter *painter, EsRectangle region, uint32_t *bits, uintptr_t stride, uint16_t mode); // OR mode with alpha. +function void EsDrawBitmapScaled(EsPainter *painter, EsRectangle destinationRegion, EsRectangle sourceRegion, uint32_t *bits, uintptr_t stride, uint16_t alpha); // Set alpha to 0xFFFF if source is opaque. +function void EsDrawBlock(EsPainter *painter, EsRectangle bounds, uint32_t mainColor); +function void EsDrawClear(EsPainter *painter, EsRectangle bounds); +function void EsDrawContent(EsPainter *painter, EsElement *element, EsRectangle rectangle, STRING text, uint32_t iconID = 0, uint32_t flags = ES_FLAGS_DEFAULT, EsTextSelection *selectionProperties = nullptr); +function void EsDrawInvert(EsPainter *painter, EsRectangle bounds); +function void EsDrawLine(EsPainter *painter, float *vertices, size_t vertexCount, uint32_t color, float width, uint32_t flags); // Vertices are pairs of x,y coordinates. +function void EsDrawRectangle(EsPainter *painter, EsRectangle bounds, uint32_t mainColor, uint32_t borderColor, EsRectangle borderSize); +function bool EsDrawStandardIcon(EsPainter *painter, uint32_t id, int size, EsRectangle region, uint32_t color); +function void EsDrawPaintTarget(EsPainter *painter, EsPaintTarget *source, EsRectangle destinationRegion, EsRectangle sourceRegion, uint8_t alpha); +function void EsDrawText(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsRectangle *clip = ES_NULL, EsTextSelection *selectionProperties = ES_NULL); +function void EsDrawTextLayers(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsTextSelection *selectionProperties = ES_NULL); +function void EsDrawVectorFile(EsPainter *painter, EsRectangle bounds, const void *data, size_t dataBytes); + +function uint32_t EsIconIDFromString(STRING string = BLANK_STRING); + +function uint8_t *EsImageLoad(const void *file, size_t fileSize, uint32_t *width, uint32_t *height, int imageChannels); + +function EsRectangle EsPainterBoundsClient(EsPainter *painter); +function EsRectangle EsPainterBoundsInset(EsPainter *painter); + +function void EsPaintTargetClear(EsPaintTarget *target); +function void EsPaintTargetEndDirectAccess(EsPaintTarget *target); +function void EsPaintTargetStartDirectAccess(EsPaintTarget *target, uint32_t **bits, size_t *width, size_t *height, size_t *stride); +function EsPaintTarget *EsPaintTargetCreate(size_t width, size_t height, bool hasAlphaChannel); +function EsPaintTarget *EsPaintTargetCreateFromBitmap(uint32_t *bits, size_t width, size_t height, bool hasAlphaChannel); // Do not access the bits again until calling EsPaintTargetDestroy! +function void EsPaintTargetGetSize(EsPaintTarget *target, size_t *width, size_t *height); +function void EsPaintTargetDestroy(EsPaintTarget *target); + +function int EsTextGetLineHeight(const EsTextStyle *style); +function EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *textRuns, size_t textRunCount); // textRuns should point to an array of (textRunCount + 1) EsTextRuns; the last one should have its offset set to the total number of bytes in the string. The passed string must remain valid until the plan is destroyed. +function int EsTextPlanGetWidth(EsTextPlan *plan); // TODO Public property? +function int EsTextPlanGetHeight(EsTextPlan *plan); // TODO Public property? +function size_t EsTextPlanGetLineCount(EsTextPlan *plan); // TODO Public property? +function void EsTextPlanDestroy(EsTextPlan *plan); +function void EsTextPlanReplaceStyleRenderProperties(EsTextPlan *plan, EsTextStyle *style); // Only render properties - like color or underline, but not font weight - will be replaced. + +function void EsRichTextParse(const char *inString, ptrdiff_t inStringBytes, + char **outString, EsTextRun **outTextRuns, size_t *outTextRunCount, + EsTextStyle *baseStyle); + +function void EsFontDatabaseEnumerate(EsFontEnumerationCallbackFunction callback, EsGeneric context); +function bool EsFontDatabaseLookupByID(EsFontFamily id, EsFontInformation *information); // Returns false if the font does not exist in the database. +function EsFontFamily EsFontDatabaseInsertFile(const EsFontInformation *information, EsFileStore *store); // Don't set the `id` field in EsFontInformation. The assigned ID will be returned. If nameBytes is 0, then the system will not try to match it with an existing font family. Set the corresponding bit in availableWeightsNormal/availableWeightsItalic for the file being added. The request is ignored if the specific variant is already in the database. + +// Networking. + +function EsError EsAddressResolve(STRING domain, uint32_t flags, EsAddress *address); +function void EsConnectionClose(EsConnection *connection); +function void EsConnectionNotify(EsConnection *connection); +function EsError EsConnectionOpen(EsConnection *connection, uint32_t flags); +function void EsConnectionPoll(EsConnection *connection); +function EsError EsConnectionRead(EsConnection *connection, void *buffer, size_t bufferBytes, size_t *bytesRead); // Returns the number of bytes copied into the buffer. +function EsError EsConnectionWriteSync(EsConnection *connection, const void *data, size_t dataBytes); // Waits until all the data has been written into the send buffer. This does *not* flush the send buffer. + +// Input. + +function size_t EsGameControllerStatePoll(EsGameControllerState *buffer); // Returns number of connected controllers. Buffer must have space for ES_GAME_CONTROLLER_MAX_COUNT. + +function uint8_t EsKeyboardGetModifiers(); // Synchronous with respect to message processing. + +function EsPoint EsMouseGetPosition(EsElement *relativeElement = ES_NULL); +function void EsMouseSetPosition(EsWindow *relativeWindow, int x, int y); +function bool EsMouseIsLeftHeld(); +function bool EsMouseIsRightHeld(); +function bool EsMouseIsMiddleHeld(); + +// Synchronisation and timing. + +function EsHandle EsEventCreate(bool autoReset); +function void EsEventForward(EsHandle event, EsHandle eventSink, EsGeneric data); // TODO Forwarding process/thread killed events. +function void EsEventReset(EsHandle event); +function void EsEventSet(EsHandle event); +function EsHandle EsEventSinkCreate(bool ignoreDuplicates); +function EsError EsEventSinkPop(EsHandle eventSink, EsGeneric *data); // Returns ES_ERROR_EVENT_NOT_SET if empty, and ES_ERROR_EVENT_SINK_OVERFLOW if data lost. +function EsError EsEventSinkPush(EsHandle eventSink, EsGeneric data); // Returns ES_ERROR_EVENT_SINK_DUPLICATE if duplicate, and ES_ERROR_EVENT_SINK_OVERFLOW if data lost. +function void EsMutexAcquire(EsMutex *mutex); +function void EsMutexDestroy(EsMutex *mutex); +function void EsMutexRelease(EsMutex *mutex); +function void EsPerformanceTimerPush(); // Stack size should not exceed 100 values. +function double EsPerformanceTimerPop(); // Returns value in seconds. +function void EsSchedulerYield(); +function void EsSleep(uint64_t milliseconds); +function void EsSpinlockAcquire(EsSpinlock *spinlock); +function void EsSpinlockRelease(EsSpinlock *spinlock); +function EsTimer EsTimerSet(uint64_t afterMs, EsTimerCallbackFunction callback, EsGeneric argument); +function void EsTimerCancel(EsTimer id); +function uintptr_t EsWait(EsHandle *objects, size_t objectCount, uintptr_t timeoutMs); + +// Strings. + +function char *EsCStringDuplicate(EsCString string); +function size_t EsCStringLength(EsCString string); +function char *EsStringAllocateAndFormat(size_t *bytes, EsCString format, ...); // Zero-terminated. +function char *EsStringAllocateAndFormatV(size_t *bytes, EsCString format, va_list arguments); +function int EsStringCompare(STRING s1, STRING s2); +function int EsStringCompareRaw(STRING s1, STRING s2); +function ptrdiff_t EsStringFormat(char *buffer, size_t bufferLength, EsCString format, ...); +function const char *EsStringFormatTemporary(EsCString format, ...); // Not thread safe. The result is valid until the next call. Zero-terminated. +function ptrdiff_t EsStringFormatV(char *buffer, size_t bufferLength, EsCString format, va_list arguments); +function bool EsStringFormatAppend(char *buffer, size_t bufferLength, size_t *bufferPosition, EsCString format, ...); // Return false if buffer filled. +function bool EsStringFormatAppendV(char *buffer, size_t bufferLength, size_t *bufferPosition, EsCString format, va_list arguments); +function size_t EsStringLength(const char *string, uint8_t end); +function bool EsStringStartsWith(STRING string, STRING prefix, bool caseInsensitive); +function bool EsStringEndsWith(STRING string, STRING prefix, bool caseInsensitive); +function char *EsStringZeroTerminate(STRING string); // Free with EsHeapFree. +function bool EsUTF8IsValid(const char *input, ptrdiff_t bytes); // Does not check for surrogate characters or overlong sequences of non-ASCII characters. + +// CRT functions. + +function int EsCRTabs(int n); +function float EsCRTacosf(float x); +function float EsCRTasinf(float x); +function float EsCRTatan2f(float y, float x); +function float EsCRTatanf(float x); +function int EsCRTatoi(const char *string); +function void *EsCRTbsearch(const void *key, const void *base, size_t num, size_t size, EsCRTComparisonCallback compar); +function void *EsCRTcalloc(size_t num, size_t size); +function double EsCRTceil(double x); +function float EsCRTceilf(float x); +function float EsCRTcosf(float x); +function double EsCRTexp(double x); +function float EsCRTexp2f(float x); +function double EsCRTfabs(double x); +function float EsCRTfabsf(float x); +function double EsCRTfloor(double x); +function float EsCRTfloorf(float x); +function float EsCRTfmodf(float x, float y); +function void EsCRTfree(void *ptr); +function char *EsCRTgetenv(const char *name); +function int EsCRTisalpha(int c); +function int EsCRTisdigit(int c); +function bool EsCRTisnanf(float f); +function int EsCRTisspace(int c); +function int EsCRTisupper(int c); +function int EsCRTisxdigit(int c); +function void *EsCRTmalloc(size_t size); +function void *EsCRTmemchr(const void *_s, int _c, size_t n); +function int EsCRTmemcmp(const void *s1, const void *s2, size_t n); +function void *EsCRTmemcpy(void *dest, const void *src, size_t n); +function void *EsCRTmemmove(void *dest, const void *src, size_t n); +function void *EsCRTmemset(void *s, int c, size_t n); +function float EsCRTpowf(float x, float y); +function void EsCRTqsort(void *_base, size_t nmemb, size_t size, EsCRTComparisonCallback compar); +function int EsCRTrand(); +function void *EsCRTrealloc(void *ptr, size_t size); +function float EsCRTsinf(float x); +function int EsCRTsnprintf(char *buffer, size_t bufferSize, const char *format, ...); +function int EsCRTsprintf(char *buffer, const char *format, ...); +function double EsCRTsqrt(double x); +function float EsCRTsqrtf(float x); +function char *EsCRTstrcat(char *dest, const char *src); +function char *EsCRTstrchr(const char *s, int c); +function int EsCRTstrcmp(const char *s1, const char *s2); +function char *EsCRTstrcpy(char *dest, const char *src); +function char *EsCRTstrdup(const char *string); +function char *EsCRTstrerror(int errnum); +function size_t EsCRTstrlen(const char *s); +function int EsCRTstrncmp(const char *s1, const char *s2, size_t n); +function char *EsCRTstrncpy(char *dest, const char *src, size_t n); +function size_t EsCRTstrnlen(const char *s, size_t maxlen); +function char *EsCRTstrstr(const char *haystack, const char *needle); +function long EsCRTstrtol(const char *nptr, char **endptr, int base); +function uint64_t EsCRTstrtoul(const char *nptr, char **endptr, int base); +function int EsCRTtolower(int c); +function int EsCRTvsnprintf(char *buffer, size_t bufferSize, const char *format, va_list arguments); + +// Clipboard and undo. + +function EsError EsClipboardAddText(EsClipboard clipboard, STRING text = BLANK_STRING); +function bool EsClipboardHasText(EsClipboard clipboard); +function char *EsClipboardReadText(EsClipboard clipboard, size_t *bytes); + +function void EsUndoClear(EsUndoManager *manager); +function void EsUndoContinueGroup(EsUndoManager *manager); +function void EsUndoEndGroup(EsUndoManager *manager); +function void EsUndoInvokeGroup(EsUndoManager *manager, bool redo); +function bool EsUndoPeek(EsUndoManager *manager, EsUndoCallback *callback, const void **item); +function void EsUndoPop(EsUndoManager *manager); +function void EsUndoPush(EsUndoManager *manager, EsUndoCallback callback, const void *item, size_t itemBytes); +function bool EsUndoInUndo(EsUndoManager *manager); +function bool EsUndoIsEmpty(EsUndoManager *manager, bool redo); +function ES_INSTANCE_TYPE *EsUndoGetInstance(EsUndoManager *manager); + +// Instances and commands. + +function void EsCommandAddButton(EsCommand *command, EsButton *button); +function EsCommand *EsCommandByID(EsInstance *instance, uint32_t stableID); +function EsCommand *EsCommandRegister(EsCommand *command, EsInstance *instance, EsCommandCallbackFunction callback, uint32_t stableID, EsCString cDefaultKeyboardShortcut = ES_NULL, bool enabled = false); // IDs >= 0xF0000000 reserved by the system. +function void EsCommandSetCallback(EsCommand *command, EsCommandCallbackFunction callback); +function void EsCommandSetDisabled(EsCommand *command, bool disabled); +function void EsCommandSetCheck(EsCommand *command, EsCheckState check, bool sendUpdatedMessage); + +function void EsInstanceDestroy(ES_INSTANCE_TYPE *instance); +function void EsInstanceSetActiveUndoManager(ES_INSTANCE_TYPE *instance, EsUndoManager *manager); +function void EsInstanceSetClassEditor(ES_INSTANCE_TYPE *instance, const EsInstanceClassEditorSettings *settings); +function void EsInstanceSetClassViewer(ES_INSTANCE_TYPE *instance, const EsInstanceClassViewerSettings *settings); +function const EsApplicationStartupInformation *EsInstanceGetStartupInformation(ES_INSTANCE_TYPE *instance); +function void EsInstanceOpenComplete(EsMessage *message, bool success, STRING errorText = BLANK_STRING); +function void EsInstanceSaveComplete(EsMessage *message, bool success); + +// Message processing. + +function size_t EsMessageGetInputText(EsMessage *message, char *buffer); // The buffer should be 64 bytes in size. +function void EsMessageMutexAcquire(); +function void EsMessageMutexCheck(); +function void EsMessageMutexRelease(); +function EsError EsMessagePost(EsElement *target, EsMessage *message); +function EsError EsMessagePostRemote(EsHandle process, EsMessage *message); +function int EsMessageSend(EsElement *object, EsMessage *message); +function EsMessage *EsMessageReceive(); + +// User interface elements. + +function void EsElementDraw(EsElement *element, EsPainter *painter); // Actually draw an element onto a painter. +function void EsElementFocus(EsElement *element, uint32_t flags = ES_FLAGS_DEFAULT); +function void EsElementSetDisabled(EsElement *element, bool disabled = true); +function void EsElementSetHidden(EsElement *element, bool hidden = true); +function void EsElementSetCallback(EsElement *element, EsUICallbackFunction callback); +function void EsElementGetSize(EsElement *element, int *width, int *height); +function void EsElementRepaint(EsElement *element, const EsRectangle *region = nullptr); // Mark an element to be repainted. If region is null, then the whole element is repainted. +function void EsElementRepaintForScroll(EsElement *element, EsMessage *message); // Minimal repaint for ES_MSG_SCROLL_X/Y. +function void EsElementRelayout(EsElement *element); +function void EsElementSetCellRange(EsElement *element, int xFrom, int yFrom, int xTo = -1, int yTo = -1); // Use only if the parent is a ES_PANEL_TABLE. +function EsRectangle EsElementGetInsets(EsElement *element); +function EsRectangle EsElementGetInsetSize(EsElement *element); // Get the size of the element, minus the insets. +function EsThemeMetrics EsElementGetMetrics(EsElement *element); +function EsRectangle EsElementGetPreferredSize(EsElement *element); +function void EsElementMove(EsElement *element, int x, int y, int width, int height, bool applyCellLayout = true); // x, y are given relative to the top-left of the parent. +function EsElement *EsElementGetLayoutParent(EsElement *element); +function void EsElementDestroy(EsElement *element); +function void EsElementDestroyContents(EsElement *element); +function bool EsElementStartAnimating(EsElement *element); // Returns false if the element was already animating. +function void EsElementStartTransition(EsElement *element, EsTransitionType transitionType, uint32_t flags = ES_FLAGS_DEFAULT, uint32_t timeMs = 150); // TODO More customization. +function void EsElementInsertAfter(EsElement *element); // The next element created will be inserted after this element. They must have the same parent. Or, if this is the parent of the next element created, then it will be inserted at the start of the parent. +function void EsElementUpdateContentSize(EsElement *element, uint32_t flags = ES_FLAGS_DEFAULT); +function void EsElementGetTextStyle(EsElement *element, EsTextStyle *style); +function EsRectangle EsElementGetWindowBounds(EsElement *element, bool client = true); +function EsRectangle EsElementGetScreenBounds(EsElement *element, bool client = true); + +function EsElement *EsCustomElementCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL); + +// Windows, menus, popups, toolbars and dialogs. + +function EsWindow *EsWindowCreate(ES_INSTANCE_TYPE *instance, EsWindowStyle style); +function EsRectangle EsWindowGetBounds(EsWindow *window); +function EsElement *EsWindowGetToolbar(EsWindow *window, bool createNew = false); +function void EsWindowSwitchToolbar(EsWindow *window, EsElement *toolbar, EsTransitionType transitionType); +function void EsWindowSetIcon(EsWindow *window, uint32_t iconID); +function void EsWindowSetTitle(EsWindow *window, STRING title = BLANK_STRING); +function void EsWindowAddSizeAlternative(EsWindow *window, EsElement *small, EsElement *big, int widthThreshold, int heightThreshold); // Switch between elements when the window size goes below a threshold. + +function EsMenu *EsMenuCreate(EsElement *source, uint64_t flags = ES_FLAGS_DEFAULT); +function EsElement *EsMenuGetSource(EsMenu *menu); // TODO Public property? +function void EsMenuAddItem(EsMenu *menu, uint64_t flags, STRING label = BLANK_STRING, EsMenuCallbackFunction callback = ES_NULL, EsGeneric context = ES_NULL); +function void EsMenuAddCommand(EsMenu *menu, uint64_t flags, STRING label, EsCommand *command); +function void EsMenuAddSeparator(EsMenu *menu); +function void EsMenuNextColumn(EsMenu *menu, uint64_t flags = ES_FLAGS_DEFAULT); +function void EsMenuShow(EsMenu *menu, int fixedWidth = 0, int fixedHeight = 0); +function void EsMenuCloseAll(); +function void EsMenuAddCommandsFromToolbar(EsMenu *menu, EsElement *element); + +function void EsDialogClose(EsWindow *window); +function EsElement *EsDialogShow(EsWindow *window); +function EsElement *EsDialogShowAlert(EsWindow *window, STRING title, STRING content, uint32_t iconID, uint32_t flags = ES_FLAGS_DEFAULT); // Returns the button container. + +function void EsToolbarAddFileMenu(EsElement *element, const EsFileMenuSettings *settings = ES_NULL); + +// Buttons. + +function EsButton *EsButtonCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL, STRING label = BLANK_STRING); + +function void EsButtonSetIcon(EsButton *button, uint32_t iconID); +function void EsButtonSetCheck(EsButton *button, EsCheckState checkState = ES_CHECK_CHECKED, bool sendUpdatedMessage = true); +function EsCheckState EsButtonGetCheck(EsButton *button); +function void EsButtonOnCommand(EsButton *button, EsCommandCallbackFunction callback, EsCommand *command = ES_NULL); // TODO Public property? +function void EsButtonSetCheckBuddy(EsButton *button, EsElement *checkBuddy); // The buddy element is enabled/disabled when the button is checked/unchecked. +function EsElement *EsButtonGetCheckBuddy(EsButton *button); // TODO Public property? + +// Textboxes. + +function EsTextbox *EsTextboxCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL); + +function bool EsTextboxFind(EsTextbox *textbox, STRING string, int32_t *line, int32_t *byte, uint32_t flags); +function void EsTextboxInsert(EsTextbox *textbox, STRING string = BLANK_STRING, bool sendUpdatedMessage = true); // Deletes existing selection first. +function char *EsTextboxGetContents(EsTextbox *textbox, size_t *bytes = ES_NULL, uint32_t flags = ES_FLAGS_DEFAULT); // Result will be zero-terminated; free with EsHeapFree. +function double EsTextboxGetContentsAsDouble(EsTextbox *textbox, uint32_t flags = ES_FLAGS_DEFAULT); +function size_t EsTextboxGetLineLength(EsTextbox *textbox, uintptr_t line = 0); +function void EsTextboxGetSelection(EsTextbox *textbox, int32_t *fromLine, int32_t *fromByte, int32_t *toLine, int32_t *toByte); +function void EsTextboxMoveCaret(EsTextbox *textbox, int32_t line, int32_t byte); +function void EsTextboxSetSelection(EsTextbox *textbox, int32_t fromLine, int32_t fromByte, int32_t toLine, int32_t toByte); +function void EsTextboxSelectAll(EsTextbox *textbox); +function void EsTextboxClear(EsTextbox *textbox, bool sendUpdatedMessage); +function void EsTextboxUseNumberOverlay(EsTextbox *textbox, bool defaultBehaviour); +function void EsTextboxUseBreadcrumbOverlay(EsTextbox *textbox); +function void EsTextboxMoveCaretRelative(EsTextbox *textbox, uint32_t flags); +function void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter = false); +function void EsTextboxSetUndoManager(EsTextbox *textbox, EsUndoManager *manager); +function void EsTextboxGetTextStyle(EsTextbox *textbox, EsTextStyle *textStyle); +function void EsTextboxSetTextStyle(EsTextbox *textbox, const EsTextStyle *textStyle); +function void EsTextboxSetupSyntaxHighlighting(EsTextbox *textbox, uint32_t language, uint32_t *customColors = ES_NULL, size_t customColorCount = 0); +function void EsTextboxStartEdit(EsTextbox *textbox); + +// Panels, spacers and splitters. + +function EsPanel *EsPanelCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL); +function EsElement *EsSpacerCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL, int width = 0, int height = 0); +function EsSplitter *EsSplitterCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL); +function EsCanvasPane *EsCanvasPaneCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL); + +function void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount = 0, EsPanelBand *columns = ES_NULL, EsPanelBand *rows = ES_NULL); +function void EsPanelSetBandsAll(EsPanel *panel, EsPanelBand *column = ES_NULL, EsPanelBand *row = ES_NULL); // Set all the columns/rows to have the same properties. This must be called after the final number of bands has been determined/set! +function void EsPanelTableSetChildCells(EsPanel *panel); // Automatically set the child cells for items in a table. This is only necessary if the number of columns/rows is changed after adding items to a table. + +function void EsPanelSwitchTo(EsPanel *panel, EsElement *targetChild, EsTransitionType transitionType, uint32_t flags = ES_FLAGS_DEFAULT, uint32_t timeMs = 150); // TODO More customization of transitions? +function void EsPanelStartMovementAnimation(EsPanel *panel, uint32_t timeMs = 150); // TODO More customization. + +// Static displays. + +function EsIconDisplay *EsIconDisplayCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL, uint32_t iconID = 0); + +function EsImageDisplay *EsImageDisplayCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL); +function void EsImageDisplayLoadBits(EsImageDisplay *display, const uint32_t *bits, size_t width, size_t height, size_t stride); +function void EsImageDisplayLoadFromMemory(EsImageDisplay *display, const void *buffer, size_t bufferBytes); + +function EsTextDisplay *EsTextDisplayCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL, STRING label = BLANK_STRING); +function void EsTextDisplaySetContents(EsTextDisplay *display, STRING contents = BLANK_STRING); +function void EsTextDisplaySetStyledContents(EsTextDisplay *display, const char *string, EsTextRun *runs, size_t runCount); // See EsTextPlanCreate for how runCount works. +function void EsTextDisplaySetupSyntaxHighlighting(EsTextDisplay *display, uint32_t language, uint32_t *customColors = ES_NULL, size_t customColorCount = 0); + +function EsListDisplay *EsListDisplayCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL); +function void EsListDisplaySetCounterContinuation(EsListDisplay *display, EsListDisplay *previous); +function void EsListDisplaySetCounterStart(EsListDisplay *display, uintptr_t index); // If index = 0, then the first item will be "1." or "(a)". + +function void EsAnnouncementShow(EsWindow *window, uint64_t flags, int32_t x, int32_t y, STRING text = BLANK_STRING); + +// Color wells. + +function EsColorWell *EsColorWellCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, uint32_t colorRGB = 0); + +function uint32_t EsColorWellGetRGB(EsColorWell *well); // TODO Public property? +function void EsColorWellSetRGB(EsColorWell *well, uint32_t colorRGB, bool sendChangedMessage); +function void EsColorWellSetIndeterminate(EsColorWell *well); + +// List views. + +function EsListView *EsListViewCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, + const EsStyle *style = ES_NULL, const EsStyle *itemStyle = ES_NULL, + const EsStyle *headerItemStyle = ES_NULL, const EsStyle *footerItemStyle = ES_NULL); + +function EsGeneric EsListViewGetIndexFromItem(EsElement *element, int32_t *group = ES_NULL); +function void EsListViewEnumerateVisibleItems(EsListView *view, EsListViewEnumerateVisibleItemsCallbackFunction callback); + +function void EsListViewSetColumns(EsListView *view, EsListViewColumn *columns, size_t columnCount); +function void EsListViewSetEmptyMessage(EsListView *view, STRING message = BLANK_STRING); +function void EsListViewSetMaximumItemsPerBand(EsListView *view, int maximumItemsPerBand); +function void EsListViewSelect(EsListView *view, int32_t group, EsGeneric index); +function void EsListViewFocusItem(EsListView *view, int32_t group, EsGeneric index); +function bool EsListViewGetFocusedItem(EsListView *view, int32_t *group, EsGeneric *index); // Returns false if not item was focused. +function void EsListViewInvalidateContent(EsListView *view, int32_t group, EsGeneric index); +function void EsListViewInvalidateAll(EsListView *view); +function void EsListViewContentChanged(EsListView *view); +function void EsListViewChangeStyles(EsListView *view, const EsStyle *style, const EsStyle *itemStyle, + const EsStyle *headerItemStyle, const EsStyle *footerItemStyle, uint32_t addFlags, uint32_t removeFlags); +function void EsListViewScrollToEnd(EsListView *view); + +function EsTextbox *EsListViewCreateInlineTextbox(EsListView *view, int32_t group, EsGeneric index, uint32_t flags = ES_FLAGS_DEFAULT); + +// (Callback items.) +function void EsListViewInsertGroup(EsListView *view, int32_t group, uint32_t flags = ES_FLAGS_DEFAULT); +function void EsListViewInsert(EsListView *view, int32_t group, EsGeneric firstIndex, EsGeneric lastIndex, int64_t count = -1); +function void EsListViewRemove(EsListView *view, int32_t group, EsGeneric firstIndex, EsGeneric lastIndex, int64_t count = -1); +function void EsListViewRemoveAll(EsListView *view, int32_t group); +// (Fixed items.) +function void EsListViewInsertFixedItem(EsListView *view, STRING string = BLANK_STRING, EsGeneric data = ES_NULL, intptr_t index = -1); +function bool EsListViewSelectFixedItem(EsListView *view, EsGeneric data); // Returns false if the item was not found. +function bool EsListViewGetSelectedFixedItem(EsListView *view, EsGeneric *data); // Returns false if no item was selected. diff --git a/desktop/posix.cpp b/desktop/posix.cpp new file mode 100644 index 0000000..1f12ab7 --- /dev/null +++ b/desktop/posix.cpp @@ -0,0 +1,775 @@ +#define ES_API +#define ES_FORWARD(x) x +#define ES_EXTERN_FORWARD extern "C" +#define ES_DIRECT_API +#include + +#ifdef ENABLE_POSIX_SUBSYSTEM + +#include + +extern "C" void *ProcessorTLSRead(uintptr_t offset); +extern "C" void ProcessorTLSWrite(uintptr_t offset, void *value); +extern ptrdiff_t tlsStorageOffset; +EsMountPoint *NodeFindMountPoint(const char *prefix, size_t prefixBytes); +EsProcessStartupInformation *ProcessGetStartupInformation(); + +#define _POSIX_SOURCE +#define _GNU_SOURCE +#define __NEED_struct_iovec +#define __NEED_sigset_t +#define __NEED_struct_timespec +#define __NEED_time_t +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ChildProcess { + uint64_t id; + EsHandle handle; +}; + +char *workingDirectory; +Array childProcesses; + +#ifdef DEBUG_BUILD +double syscallTimeSpent[1024]; +uint64_t syscallCallCount[1024]; +#endif + +const char *syscallNames[] = { + "read", "write", "open", "close", "stat", "fstat", "lstat", "poll", + "lseek", "mmap", "mprotect", "munmap", "brk", "rt_sigaction", "rt_sigprocmask", "rt_sigreturn", + "ioctl", "pread64", "pwrite64", "readv", "writev", "access", "pipe", "select", + "sched_yield", "mremap", "msync", "mincore", "madvise", "shmget", "shmat", "shmctl", + "dup", "dup2", "pause", "nanosleep", "getitimer", "alarm", "setitimer", "getpid", + "sendfile", "socket", "connect", "accept", "sendto", "recvfrom", "sendmsg", "recvmsg", + "shutdown", "bind", "listen", "getsockname", "getpeername", "socketpair", "setsockopt", "getsockopt", + "clone", "fork", "vfork", "execve", "exit", "wait4", "kill", "uname", + "semget", "semop", "semctl", "shmdt", "msgget", "msgsnd", "msgrcv", "msgctl", + "fcntl", "flock", "fsync", "fdatasync", "truncate", "ftruncate", "getdents", "getcwd", + "chdir", "fchdir", "rename", "mkdir", "rmdir", "creat", "link", "unlink", + "symlink", "readlink", "chmod", "fchmod", "chown", "fchown", "lchown", "umask", + "gettimeofday", "getrlimit", "getrusage", "sysinfo", "times", "ptrace", "getuid", "syslog", + "getgid", "setuid", "setgid", "geteuid", "getegid", "setpgid", "getppid", "getpgrp", + "setsid", "setreuid", "setregid", "getgroups", "setgroups", "setresuid", "getresuid", "setresgid", + "getresgid", "getpgid", "setfsuid", "setfsgid", "getsid", "capget", "capset", "rt_sigpending", + "rt_sigtimedwait", "rt_sigqueueinfo", "rt_sigsuspend", "sigaltstack", "utime", "mknod", "uselib", "personality", + "ustat", "statfs", "fstatfs", "sysfs", "getpriority", "setpriority", "sched_setparam", "sched_getparam", + "sched_setscheduler", "sched_getscheduler", "sched_get_priority_max", "sched_get_priority_min", "sched_rr_get_interval", "mlock", "munlock", "mlockall", + "munlockall", "vhangup", "modify_ldt", "pivot_root", "_sysctl", "prctl", "arch_prctl", "adjtimex", + "setrlimit", "chroot", "sync", "acct", "settimeofday", "mount", "umount2", "swapon", + "swapoff", "reboot", "sethostname", "setdomainname", "iopl", "ioperm", "create_module", "init_module", + "delete_module", "get_kernel_syms", "query_module", "quotactl", "nfsservctl", "getpmsg", "putpmsg", "afs_syscall", + "tuxcall", "security", "gettid", "readahead", "setxattr", "lsetxattr", "fsetxattr", "getxattr", + "lgetxattr", "fgetxattr", "listxattr", "llistxattr", "flistxattr", "removexattr", "lremovexattr", "fremovexattr", + "tkill", "time", "futex", "sched_setaffinity", "sched_getaffinity", "set_thread_area", "io_setup", "io_destroy", + "io_getevents", "io_submit", "io_cancel", "get_thread_area", "lookup_dcookie", "epoll_create", "epoll_ctl_old", "epoll_wait_old", + "remap_file_pages", "getdents64", "set_tid_address", "restart_syscall", "semtimedop", "fadvise64", "timer_create", "timer_settime", + "timer_gettime", "timer_getoverrun", "timer_delete", "clock_settime", "clock_gettime", "clock_getres", "clock_nanosleep", "exit_group", + "epoll_wait", "epoll_ctl", "tgkill", "utimes", "vserver", "mbind", "set_mempolicy", "get_mempolicy", + "mq_open", "mq_unlink", "mq_timedsend", "mq_timedreceive", "mq_notify", "mq_getsetattr", "kexec_load", "waitid", + "add_key", "request_key", "keyctl", "ioprio_set", "ioprio_get", "inotify_init", "inotify_add_watch", "inotify_rm_watch", + "migrate_pages", "openat", "mkdirat", "mknodat", "fchownat", "futimesat", "newfstatat", "unlinkat", + "renameat", "linkat", "symlinkat", "readlinkat", "fchmodat", "faccessat", "pselect6", "ppoll", + "unshare", "set_robust_list", "get_robust_list", "splice", "tee", "sync_file_range", "vmsplice", "move_pages", + "utimensat", "epoll_pwait", "signalfd", "timerfd_create", "eventfd", "fallocate", "timerfd_settime", "timerfd_gettime", + "accept4", "signalfd4", "eventfd2", "epoll_create1", "dup3", "pipe2", "inotify_init1", "preadv", + "pwritev", "rt_tgsigqueueinfo", "perf_event_open", "recvmmsg", "fanotify_init", "fanotify_mark", "prlimit64", "name_to_handle_at", + "open_by_handle_at", "clock_adjtime", "syncfs", "sendmmsg", "setns", "getcpu", "process_vm_readv", "process_vm_writev", + "kcmp", "finit_module", "sched_setattr", "sched_getattr", "renameat2", "seccomp", "getrandom", "memfd_create", + "kexec_file_load", "bpf", "execveat", "userfaultfd", "membarrier", "mlock2", "copy_file_range", "preadv2", + "pwritev2", "pkey_mprotect", "pkey_alloc", "pkey_free", "statx", +}; + +extern "C" void ProcessorCheckStackAlignment(); + +char *EsPOSIXConvertPath(const char *path, size_t *outNameLength, bool addPOSIXMountPointPrefix) { + const char *posixNames[2] = { path[0] != '/' ? workingDirectory : nullptr, path }; + size_t posixNameLengths[2] = { path[0] != '/' ? EsCStringLength(workingDirectory) : 0, EsCStringLength(path) }; + + char *name = (char *) EsHeapAllocate(posixNameLengths[0] + posixNameLengths[1] + (addPOSIXMountPointPrefix ? 7 : 0) + 2 /* space for / and NUL; see chdir */, true); + if (!name) return nullptr; + size_t nameLength = 0; + if (addPOSIXMountPointPrefix) name += 7; + + for (uintptr_t i = 0; i < 2; i++) { + while (posixNameLengths[i]) { + const char *entry = posixNames[i]; + size_t entryLength = 0; + + while (posixNameLengths[i]) { + posixNameLengths[i]--; + posixNames[i]++; + if (entry[entryLength] == '/') break; + entryLength++; + } + + if (!entryLength || (entryLength == 1 && entry[0] == '.')) { + // Ignore. + } else if (entryLength == 2 && entry[0] == '.' && entry[1] == '.' && nameLength) { + while (name[--nameLength] != '/'); + } else { + name[nameLength++] = '/'; + EsMemoryCopy(name + nameLength, entry, entryLength); + nameLength += entryLength; + } + } + } + + if (!nameLength) { + nameLength++; + name[0] = '/'; + } + + if (addPOSIXMountPointPrefix) { + name -= 7; + nameLength += 7; + EsMemoryCopy(name, "|POSIX:", 7); + } + + if (outNameLength) *outNameLength = nameLength; + name[nameLength] = 0; + return name; +} + +long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { +#ifdef DEBUG_BUILD + ProcessorCheckStackAlignment(); +#endif + + long returnValue = 0; + _EsPOSIXSyscall syscall = { n, a1, a2, a3, a4, a5, a6 }; + +#ifdef DEBUG_BUILD + double startTime = EsTimeStampMs(); + static double processStartTime = 0; + + if (!processStartTime) { + processStartTime = startTime; + } + + if (n == SYS_exit_group) { + double processExecutionTime = startTime - processStartTime; + + EsPrint("=== System call performance ===\n"); + + int array[sizeof(syscallNames) / sizeof(syscallNames[0])]; + + for (uintptr_t i = 0; i < sizeof(array) / sizeof(array[0]); i++) { + array[i] = i; + } + + EsCRTqsort(array, sizeof(array) / sizeof(array[0]), sizeof(array[0]), [] (const void *_left, const void *_right) { + int left = *(int *) _left, right = *(int *) _right; + if (syscallTimeSpent[left] > syscallTimeSpent[right]) return -1; + if (syscallTimeSpent[left] < syscallTimeSpent[right]) return 1; + return 0; + }); + + double total = 0; + + for (uintptr_t i = 0; i < sizeof(array) / sizeof(array[0]); i++) { + if (!syscallTimeSpent[array[i]]) break; + EsPrint("%z - %Fms - %d calls\n", syscallNames[array[i]], syscallTimeSpent[array[i]], syscallCallCount[array[i]]); + total += syscallTimeSpent[array[i]]; + } + + EsPrint("Total time in system calls: %Fms\n", total); + EsPrint("Total run time of process: %Fms\n", processExecutionTime); + } +#endif + + switch (n) { + case SYS_open: { + size_t pathBytes; + char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false); + syscall.arguments[0] = (long) path; + syscall.arguments[4] = (long) NodeFindMountPoint(EsLiteral("|POSIX:"))->base; + syscall.arguments[6] = (long) pathBytes; + returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); + // EsPrint("SYS_open '%s' with handle %d\n", pathBytes, path, returnValue); + EsHeapFree(path); + } break; + + case SYS_vfork: { + long result = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); + + if (result > 0) { + EsHandle handle = result; + ChildProcess pid = { EsProcessGetID(handle), handle }; + childProcesses.Add(pid); + returnValue = pid.id; + } + } break; + + case SYS_pipe: { + syscall.index = SYS_pipe2; + syscall.arguments[1] = 0; + returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); + } break; + + case SYS_close: { + // EsPrint("SYS_close handle %d\n", a1); + returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); + } break; + + case SYS_pipe2: + case SYS_writev: + case SYS_fcntl: + case SYS_dup2: + case SYS_write: + case SYS_readv: + case SYS_lseek: + case SYS_read: + case SYS_fstat: + case SYS_sysinfo: + case SYS_getdents64: + case SYS_exit_group: + case SYS_ioctl: { + returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); + } break; + + case SYS_chdir: { + char *simplified = EsPOSIXConvertPath((const char *) a1, nullptr, false); + EsHeapFree(workingDirectory); + size_t oldLength = EsCStringLength(simplified); + simplified[oldLength] = '/'; + simplified[oldLength + 1] = 0; + workingDirectory = simplified; + } break; + + case SYS_getpid: { + // Run the system call directly, so that the kernel can handle the vfork()'d case. + returnValue = EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_PROCESS, 0, 0, 0); + } break; + + case SYS_gettid: { + returnValue = EsThreadGetID(ES_CURRENT_THREAD); + } break; + + case SYS_getcwd: { + size_t bytes = EsCStringLength(workingDirectory) + 1; + char *destination = (char *) a1; + + if (bytes > (size_t) a2) { + returnValue = -ERANGE; + } else { + EsMemoryCopy(destination, workingDirectory, bytes); + if (workingDirectory[bytes - 2] == '/' && bytes > 2) destination[bytes - 2] = 0; + returnValue = a1; + } + } break; + + case SYS_getppid: + case SYS_getuid: + case SYS_getgid: + case SYS_getegid: + case SYS_geteuid: { + // TODO. + } break; + + case SYS_getrusage: { + // TODO. + struct rusage *buffer = (struct rusage *) a2; + EsMemoryZero(buffer, sizeof(struct rusage)); + } break; + + case SYS_unlink: { + _EsNodeInformation node; + node.handle = NodeFindMountPoint(EsLiteral("|POSIX:"))->base; + size_t pathBytes; + char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false); + EsError error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_FILE_WRITE_EXCLUSIVE, (uintptr_t) &node); + EsHeapFree(path); + if (error == ES_ERROR_FILE_DOES_NOT_EXIST) returnValue = -ENOENT; + else if (error == ES_ERROR_PATH_NOT_TRAVERSABLE) returnValue = -ENOTDIR; + else if (error == ES_ERROR_FILE_IN_EXCLUSIVE_USE) returnValue = -EBUSY; + else if (error == ES_ERROR_DRIVE_CONTROLLER_REPORTED || error == ES_ERROR_CORRUPT_DATA) returnValue = -EIO; + else if (error != ES_SUCCESS) returnValue = -EACCES; + else { + error = EsSyscall(ES_SYSCALL_NODE_DELETE, node.handle, 0, 0, 0); + EsHandleClose(node.handle); + if (error == ES_ERROR_DRIVE_CONTROLLER_REPORTED || error == ES_ERROR_CORRUPT_DATA) returnValue = -EIO; + else if (error != ES_SUCCESS) returnValue = -EACCES; + } + } break; + + case SYS_truncate: { + _EsNodeInformation node; + node.handle = NodeFindMountPoint(EsLiteral("|POSIX:"))->base; + size_t pathBytes; + char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false); + EsError error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_FILE_WRITE_EXCLUSIVE, (uintptr_t) &node); + EsHeapFree(path); + if (error == ES_ERROR_FILE_DOES_NOT_EXIST) returnValue = -ENOENT; + else if (error == ES_ERROR_PATH_NOT_TRAVERSABLE) returnValue = -ENOTDIR; + else if (error == ES_ERROR_FILE_IN_EXCLUSIVE_USE) returnValue = -EBUSY; + else if (error == ES_ERROR_DRIVE_CONTROLLER_REPORTED || error == ES_ERROR_CORRUPT_DATA) returnValue = -EIO; + else if (error != ES_SUCCESS) returnValue = -EACCES; + else if (node.type == ES_NODE_DIRECTORY) { returnValue = -EISDIR; EsHandleClose(node.handle); } + else { + EsError error = EsFileResize(node.handle, a2); + EsHandleClose(node.handle); + if (error == ES_ERROR_DRIVE_CONTROLLER_REPORTED || error == ES_ERROR_CORRUPT_DATA) returnValue = -EIO; + else if (error != ES_SUCCESS) returnValue = -EACCES; + } + } break; + + case SYS_execve: { + // NOTE We can't use EsHeapAllocate since the system call never returns. + + size_t pathBytes; + char *_path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false); + char *path = (char *) __builtin_alloca(pathBytes); + EsMemoryCopy(path, _path, pathBytes); + + char **argv = (char **) a2; + char **envp = (char **) a3; + + size_t environmentSize = 2; + + for (uintptr_t i = 0; argv[i]; i++) environmentSize += EsCStringLength(argv[i]) + 1; + for (uintptr_t i = 0; envp[i]; i++) environmentSize += EsCStringLength(envp[i]) + 1; + + bool environmentContainsWorkingDirectory = false; + + for (uintptr_t i = 0; envp[i]; i++) { + if (0 == EsMemoryCompare("PWD=", envp[i], 4)) { + environmentContainsWorkingDirectory = true; + break; + } + } + + if (!environmentContainsWorkingDirectory) { + environmentSize += 4 + EsCStringLength(workingDirectory) + 1; + } + + char newEnvironment[environmentSize]; + char *position = newEnvironment; + EsMemoryZero(newEnvironment, environmentSize); + + for (uintptr_t i = 0; argv[i]; i++) { + size_t length = EsCStringLength(argv[i]) + 1; + EsMemoryCopy(position, argv[i], length); + position += length; + } + + position++; + + for (uintptr_t i = 0; envp[i]; i++) { + size_t length = EsCStringLength(envp[i]) + 1; + EsMemoryCopy(position, envp[i], length); + position += length; + } + + if (!environmentContainsWorkingDirectory) { + size_t length = 4 + EsCStringLength(workingDirectory) + 1; + EsMemoryCopy(position, "PWD=", 4); + EsMemoryCopy(position + 4, workingDirectory, EsCStringLength(workingDirectory) + 1); + position += length; + } + + syscall.arguments[0] = (long) path; + syscall.arguments[1] = (long) pathBytes; + syscall.arguments[2] = (long) newEnvironment; + syscall.arguments[3] = (long) environmentSize; + syscall.arguments[4] = (long) NodeFindMountPoint(EsLiteral("|POSIX:"))->base; + + returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); + } break; + + case SYS_access: { + // We don't support file permissions yet, so just check the file exists. + int fd = EsPOSIXSystemCall(SYS_open, a1, O_PATH, 0, 0, 0, 0); + if (fd < 0) returnValue = fd; + else { + returnValue = 0; + EsPOSIXSystemCall(SYS_close, fd, 0, 0, 0, 0, 0); + } + } break; + + case SYS_lstat: + case SYS_stat: { + int fd = EsPOSIXSystemCall(SYS_open, a1, O_PATH, 0, 0, 0, 0); + if (fd < 0) returnValue = fd; + else { + returnValue = EsPOSIXSystemCall(SYS_fstat, fd, a2, 0, 0, 0, 0); + EsPOSIXSystemCall(SYS_close, fd, 0, 0, 0, 0, 0); + } + } break; + + case SYS_readlink: { + if (0 == EsMemoryCompare((void *) a1, EsLiteral("/proc/self/fd/"))) { + // The process is trying to get the path of a file descriptor. + syscall.index = ES_POSIX_SYSCALL_GET_POSIX_FD_PATH; + syscall.arguments[0] = EsCRTatoi((char *) a1 + EsCStringLength("/proc/self/fd/")); + returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); + } else { + // We don't support symbolic links, so the output is the same as the input. + int length = EsCStringLength((char *) a1); + EsMemoryZero((void *) a2, a3); + EsMemoryCopy((void *) a2, (void *) a1, length > a3 ? a3 : length); + returnValue = length > a3 ? a3 : length; + } + } break; + + case SYS_set_tid_address: { + // TODO Support set_child_tid and clear_child_tid addresses. + returnValue = EsThreadGetID(ES_CURRENT_THREAD); + } break; + + case SYS_brk: { + returnValue = -1; + } break; + + case SYS_mremap: { + returnValue = -ENOMEM; + } break; + + case SYS_mmap: { + bool read = a3 & PROT_READ, write = a3 & PROT_WRITE, none = a3 == PROT_NONE; + + if (a4 & MAP_FIXED) { + returnValue = -ENOMEM; + } else if ((a4 == (MAP_ANON | MAP_PRIVATE)) && (a5 == -1) && (a6 == 0) && ((read && write) || none)) { + returnValue = (long) EsMemoryReserve(a2, ES_MEMORY_PROTECTION_READ_WRITE, none ? 0 : ES_MEMORY_RESERVE_COMMIT_ALL); + } else { + EsPanic("Unsupported mmap [%x, %x, %x, %x, %x, %x]\n", a1, a2, a3, a4, a5, a6); + } + + } break; + + case SYS_munmap: { + void *address = (void *) a1; + size_t length = (size_t) a2; + + if (length == 0 || ((uintptr_t) address & (ES_PAGE_SIZE - 1))) { + returnValue = -EINVAL; + } else { + EsMemoryUnreserve(address, length); + } + } break; + + case SYS_mprotect: { + void *address = (void *) a1; + size_t length = (size_t) a2; + int protection = (int) a3; + + if (protection == (PROT_READ | PROT_WRITE)) { + returnValue = EsMemoryCommit(address, length) ? 0 : -ENOMEM; + } else if (protection == 0) { + returnValue = EsMemoryDecommit(address, length) ? 0 : -ENOMEM; + } else { + EsPanic("Unsupported mprotect [%x, %x, %x, %x, %x, %x]\n", a1, a2, a3, a4, a5, a6); + } + } break; + + case SYS_prlimit64: { + // You can't access other process's resources. + if (a1 && a1 != (long) EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_PROCESS, 0, 0, 0)) { + returnValue = -EPERM; + break; + } + + struct rlimit *newLimit = (struct rlimit *) a3; + + if (newLimit && a2 != RLIMIT_STACK) { + returnValue = -EPERM; + break; + } + + struct rlimit *limit = (struct rlimit *) a4; + + if (a2 == RLIMIT_STACK) { + size_t current, maximum; + EsError error = EsSyscall(ES_SYSCALL_THREAD_STACK_SIZE, ES_CURRENT_THREAD, + (uintptr_t) ¤t, (uintptr_t) &maximum, newLimit ? newLimit->rlim_cur : 0); + + if (limit) { + limit->rlim_cur = current; + limit->rlim_max = maximum; + } + + if (error != ES_SUCCESS) returnValue = -EINVAL; + } else if (a2 == RLIMIT_AS) { + if (limit) limit->rlim_cur = limit->rlim_max = RLIM_INFINITY; + } else if (a2 == RLIMIT_RSS) { + if (limit) limit->rlim_cur = limit->rlim_max = 0x10000000; // 256MB. This value is fake. TODO + } else if (a2 == RLIMIT_NOFILE) { + if (limit) limit->rlim_cur = limit->rlim_max = 1048576; + } else { + EsPanic("Unsupported prlimit64 [%x]\n", a2); + } + } break; + + case SYS_setitimer: + case SYS_madvise: + case SYS_umask: + case SYS_chmod: + case SYS_rt_sigaction: + case SYS_rt_sigprocmask: { + // TODO Support signals. + // Ignore. + } break; + + case SYS_clock_gettime: { + // We'll ignore the clockid_t in a1, since we don't have proper timekeeping yet. + struct timespec *tp = (struct timespec *) a2; + uint64_t timeStamp = EsTimeStamp(); + uint64_t unitsPerMicrosecond = EsSystemGetConstant(ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND); + uint64_t microseconds = timeStamp / unitsPerMicrosecond; + tp->tv_sec = microseconds / 1000000; + tp->tv_nsec = (microseconds % 1000000) * 1000; + } break; + + case SYS_wait4: { + if ((a3 & ~3) || a4 || a1 < -1 || !a1) { + EsPanic("Unsupported wait4 [%x/%x/%x/%x]\n", a1, a2, a3, a4); + } + + int *wstatus = (int *) a2; + int options = a3; + + bool foundChild = false; + uintptr_t childIndex = 0; + + if (a1 > 0) { + for (uintptr_t i = 0; i < childProcesses.Length(); i++) { + if (childProcesses[i].id == (uint64_t) a1) { + foundChild = true; + childIndex = i; + break; + } + } + } else if (a1 == -1) { + foundChild = childProcesses.Length(); + } + + if (!foundChild) { + returnValue = -ECHILD; + } else { + returnValue = 0; + + if (~options & 1 /* WNOHANG */) { + if (a1 == -1) { + EsHandle *handles = (EsHandle *) __builtin_alloca(childProcesses.Length() * sizeof(EsHandle)); + + for (uintptr_t i = 0; i < childProcesses.Length(); i++) { + handles[i] = childProcesses[i].handle; + } + + EsWait(handles, childProcesses.Length(), ES_WAIT_NO_TIMEOUT); + } else { + EsWaitSingle(childProcesses[childIndex].handle); + } + } + + for (uintptr_t i = 0; i < childProcesses.Length(); i++) { + if (a1 > 0 && childProcesses[i].id != (uint64_t) a1) { + continue; + } + + EsHandle handle = childProcesses[i].handle; + EsProcessState state; + EsProcessGetState(handle, &state); + + if (state.flags & ES_PROCESS_STATE_ALL_THREADS_TERMINATED) { + returnValue = childProcesses[i].id; + *wstatus = (EsProcessGetExitStatus(handle) & 0xFF) << 8; + EsHandleClose(handle); + childProcesses.Delete(i); + break; + } + } + } + } break; + + case SYS_sched_getaffinity: { + // TODO Getting the correct number of CPUs. + // TODO Getting the affinity for other processes. + cpu_set_t *set = (cpu_set_t *) a3; + EsCRTmemset(set, 0, a2); + CPU_SET(0, set); + } break; + + case SYS_mkdir: { + size_t pathBytes; + char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, true); + EsError error = EsPathCreate(path, pathBytes, ES_NODE_DIRECTORY, false); + if (error == ES_ERROR_INSUFFICIENT_RESOURCES) returnValue = -ENOMEM; + else if (error == ES_ERROR_FILE_ALREADY_EXISTS) returnValue = -EEXIST; + else if (error == ES_ERROR_PATH_NOT_TRAVERSABLE) returnValue = -ENOENT; + else if (error == ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME) returnValue = -ENOENT; + else if (error == ES_ERROR_FILE_ON_READ_ONLY_VOLUME) returnValue = -EPERM; + EsHeapFree(path); + } break; + + case SYS_uname: { + struct utsname *buffer = (struct utsname *) a1; + EsCRTstrcpy(buffer->sysname, "Essence"); + EsCRTstrcpy(buffer->release, "0.0.0"); + EsCRTstrcpy(buffer->version, "0.0.0"); + EsCRTstrcpy(buffer->machine, "Unknown"); + } break; + + case SYS_setpgid: { + if (a1 < 0) { + returnValue = -EINVAL; + } else { + EsHandle process = EsProcessOpen(a1); + + if (process != ES_INVALID_HANDLE) { + syscall.arguments[0] = process; + returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); + EsHandleClose(process); + } else { + returnValue = -ESRCH; + } + } + } break; + + case SYS_rename: { + size_t oldPathBytes; + char *oldPath = EsPOSIXConvertPath((const char *) a1, &oldPathBytes, true); + size_t newPathBytes; + char *newPath = EsPOSIXConvertPath((const char *) a2, &newPathBytes, true); + EsError error = EsPathMove(oldPath, oldPathBytes, newPath, newPathBytes); + EsHeapFree(oldPath); + EsHeapFree(newPath); + // TODO More return values. + if (error == ES_ERROR_FILE_DOES_NOT_EXIST) returnValue = -ENOENT; + else if (error == ES_ERROR_PATH_NOT_TRAVERSABLE) returnValue = -ENOTDIR; + else if (error == ES_ERROR_FILE_IN_EXCLUSIVE_USE) returnValue = -EBUSY; + else if (error == ES_ERROR_DRIVE_CONTROLLER_REPORTED || error == ES_ERROR_CORRUPT_DATA) returnValue = -EIO; + else if (error != ES_SUCCESS) returnValue = -EACCES; + } break; + + case -1000: { + // Update thread local storage: + void *apiTLS = ProcessorTLSRead(tlsStorageOffset); + EsSyscall(ES_SYSCALL_PROCESS_SET_TLS, a1, 0, 0, 0); + tlsStorageOffset = -a2; + ProcessorTLSWrite(tlsStorageOffset, apiTLS); + } break; + + default: { + EsPanic("Unknown linux syscall %d = %z.\nArguments: %x, %x, %x, %x, %x, %x\n", + n, syscallNames[n], a1, a2, a3, a4, a5, a6); + } break; + } + +#ifdef DEBUG_BUILD + double endTime = EsTimeStampMs(); + syscallTimeSpent[n] += endTime - startTime; + syscallCallCount[n]++; +#endif + + // EsPrint(":: %z %x %x %x -> %x; %Fms\n", syscallNames[n], a1, a2, a3, returnValue, endTime - startTime); + + return returnValue; +} + +void EsPOSIXInitialise(int *argc, char ***argv) { + // Get the arguments and environment. + + EsHandle environmentHandle = EsSyscall(ES_SYSCALL_PROCESS_GET_CREATION_ARGUMENT, ES_CURRENT_PROCESS, CREATION_ARGUMENT_ENVIRONMENT, 0, 0); + char *environmentBuffer = (char *) "./application\0\0LANG=en_US.UTF-8\0PWD=/\0HOME=/\0PATH=/Applications/POSIX/bin\0TMPDIR=/Applications/POSIX/tmp\0\0"; + + if (environmentHandle) { + environmentBuffer = (char *) EsHeapAllocate(ARG_MAX, false); + EsConstantBufferRead((EsHandle) environmentHandle, environmentBuffer); + EsHandleClose((EsHandle) environmentHandle); + } + + // Extract the arguments and environment variables. + + uintptr_t position = 0; + char *start = environmentBuffer; + Array _argv = {}; + *argc = 0; + + for (int i = 0; i < 2; i++) { + while (position < ARG_MAX) { + if (!environmentBuffer[position]) { + _argv.Add(start); + start = environmentBuffer + position + 1; + + if (i == 0) { + *argc = *argc + 1; + } + + if (!environmentBuffer[position + 1]) { + start = environmentBuffer + position + 2; + _argv.Add(nullptr); + break; + } + } + + position++; + } + + position += 2; + } + + // Copy the working directory string. + + for (uintptr_t i = *argc + 1; i < _argv.Length(); i++) { + if (_argv[i] && 0 == EsMemoryCompare("PWD=", _argv[i], 4)) { + size_t length = EsCStringLength((char *) _argv[i]) - 4; + workingDirectory = (char *) EsHeapAllocate(length + 2, false); + workingDirectory[length] = 0, workingDirectory[length + 1] = 0; + EsMemoryCopy(workingDirectory, (char *) _argv[i] + 4, length); + if (workingDirectory[length - 1] != '/') workingDirectory[length] = '/'; + } + } + + // Add the auxillary vectors. + + EsProcessStartupInformation *startupInformation = ProcessGetStartupInformation(); + +#ifdef ARCH_X86_64 + Elf64_Phdr *tlsHeader = (Elf64_Phdr *) EsHeapAllocate(sizeof(Elf64_Phdr), true); + tlsHeader->p_type = PT_TLS; + tlsHeader->p_flags = 4 /* read */; + tlsHeader->p_vaddr = startupInformation->tlsImageStart; + tlsHeader->p_filesz = startupInformation->tlsImageBytes; + tlsHeader->p_memsz = startupInformation->tlsBytes; + tlsHeader->p_align = 8; + + _argv.Add((void *) AT_PHNUM); + _argv.Add((void *) 1); + _argv.Add((void *) AT_PHENT); + _argv.Add((void *) sizeof(Elf64_Phdr)); + _argv.Add((void *) AT_PHDR); + _argv.Add((void *) tlsHeader); +#else +#error "no architecture TLS support" +#endif + + _argv.Add((void *) AT_PAGESZ); + _argv.Add((void *) ES_PAGE_SIZE); + + _argv.Add(nullptr); + + // Return argv. + + *argv = (char **) _argv.array; +} + +#endif diff --git a/desktop/prefix.h b/desktop/prefix.h new file mode 100644 index 0000000..8ca89a4 --- /dev/null +++ b/desktop/prefix.h @@ -0,0 +1,371 @@ +// ----------------- Includes: + +#ifndef IncludedEssenceAPIHeader +#define IncludedEssenceAPIHeader + +#include +#ifndef KERNEL +#include +#include +#include +#endif +#include + +// --------- C++/C differences: + +#ifdef __cplusplus + +#define ES_EXTERN_C extern "C" +#define ES_CONSTRUCTOR(x) x +#define ES_NULL nullptr + +// Scoped defer: http://www.gingerbill.org/article/defer-in-cpp.html +template struct _EsDefer4 { F f; _EsDefer4(F f) : f(f) {} ~_EsDefer4() { f(); } }; +template _EsDefer4 _EsDeferFunction(F f) { return _EsDefer4(f); } +#define EsDEFER_1(x, y) x ## y +#define EsDEFER_2(x, y) EsDEFER_1(x, y) +#define EsDEFER_3(x) EsDEFER_2(x, __COUNTER__) +#define _EsDefer5(code) auto EsDEFER_3(_defer_) = _EsDeferFunction([&](){code;}) +#define EsDefer(code) _EsDefer5(code) + +union EsGeneric { + uintptr_t u; + intptr_t i; + void *p; + + inline EsGeneric() = default; + + inline EsGeneric(uintptr_t y) { u = y; } + inline EsGeneric( intptr_t y) { i = y; } + inline EsGeneric(unsigned y) { u = y; } + inline EsGeneric( int y) { i = y; } + inline EsGeneric( void *y) { p = y; } + + inline bool operator==(EsGeneric r) const { return r.u == u; } +}; + +#else + +#define ES_EXTERN_C extern +#define ES_CONSTRUCTOR(x) +#define ES_NULL 0 + +typedef union { + uintptr_t u; + intptr_t i; + void *p; +} EsGeneric; + +typedef struct EsElementPublic EsElementPublic; + +#endif + +// --------- Macros: + +#ifdef ARCH_X86_64 +#define ES_API_BASE ((void **) 0x1000) +#define ES_SHARED_MEMORY_MAXIMUM_SIZE ((size_t) (1024) * 1024 * 1024 * 1024) +#define ES_PAGE_SIZE (4096) +#define ES_PAGE_BITS (12) + +typedef struct EsCRTjmp_buf { + uintptr_t rsp, rbp, rbx, r12, r13, r14, r15, rip; +} EsCRTjmp_buf; + +ES_EXTERN_C int _EsCRTsetjmp(EsCRTjmp_buf *env); +ES_EXTERN_C __attribute__((noreturn)) void _EsCRTlongjmp(EsCRTjmp_buf *env, int val); +#define EsCRTsetjmp(x) _EsCRTsetjmp(&(x)) +#define EsCRTlongjmp(x, y) _EsCRTlongjmp(&(x), (y)) +#endif + +#define EsContainerOf(type, member, pointer) ((type *) ((uint8_t *) pointer - offsetof(type, member))) + +#define ES_CHECK_ERROR(x) (((intptr_t) (x)) < (ES_SUCCESS)) + +#define ES_RECT_1(x) ((EsRectangle) { (int32_t) (x), (int32_t) (x), (int32_t) (x), (int32_t) (x) }) +#define ES_RECT_1I(x) ((EsRectangle) { (int32_t) (x), (int32_t) -(x), (int32_t) (x), (int32_t) -(x) }) +#define ES_RECT_2(x, y) ((EsRectangle) { (int32_t) (x), (int32_t) (x), (int32_t) (y), (int32_t) (y) }) +#define ES_RECT_2I(x, y) ((EsRectangle) { (int32_t) (x), (int32_t) -(x), (int32_t) (y), (int32_t) -(y) }) +#define ES_RECT_2S(x, y) ((EsRectangle) { 0, (int32_t) (x), 0, (int32_t) (y) }) +#define ES_RECT_4(x, y, z, w) ((EsRectangle) { (int32_t) (x), (int32_t) (y), (int32_t) (z), (int32_t) (w) }) +#define ES_RECT_4PD(x, y, w, h) ((EsRectangle) { (int32_t) (x), (int32_t) ((x) + (w)), (int32_t) (y), (int32_t) ((y) + (h)) }) +#define ES_RECT_WIDTH(_r) ((_r).r - (_r).l) +#define ES_RECT_HEIGHT(_r) ((_r).b - (_r).t) +#define ES_RECT_TOTAL_H(_r) ((_r).r + (_r).l) +#define ES_RECT_TOTAL_V(_r) ((_r).b + (_r).t) +#define ES_RECT_SIZE(_r) ES_RECT_WIDTH(_r), ES_RECT_HEIGHT(_r) +#define ES_RECT_TOP_LEFT(_r) (_r).l, (_r).t +#define ES_RECT_BOTTOM_LEFT(_r) (_r).l, (_r).b +#define ES_RECT_BOTTOM_RIGHT(_r) (_r).r, (_r).b +#define ES_RECT_ALL(_r) (_r).l, (_r).r, (_r).t, (_r).b +#define ES_RECT_VALID(_r) (ES_RECT_WIDTH(_r) > 0 && ES_RECT_HEIGHT(_r) > 0) + +#define ES_POINT(x, y) ((EsPoint) { (int32_t) (x), (int32_t) (y) }) + +#define EsKeyboardIsAltHeld() (EsKeyboardGetModifiers() & ES_MODIFIER_ALT) +#define EsKeyboardIsCtrlHeld() (EsKeyboardGetModifiers() & ES_MODIFIER_CTRL) +#define EsKeyboardIsShiftHeld() (EsKeyboardGetModifiers() & ES_MODIFIER_SHIFT) + +#define ES_MEMORY_MOVE_BACKWARDS - + +#define EsWaitSingle(object) EsWait(&object, 1, ES_WAIT_NO_TIMEOUT) +#define EsObjectUnmap EsMemoryUnreserve + +#define EsLiteral(x) (char *) x, EsCStringLength((char *) x) + +#define ES_STYLE_CAST(x) ((EsStyle *) (uintptr_t) (x)) + +#ifndef ES_INSTANCE_TYPE +#define ES_INSTANCE_TYPE struct EsInstance +#else +struct ES_INSTANCE_TYPE; +#endif +#ifdef __cplusplus +#define EsInstanceCreate(_message, ...) (static_cast(_EsInstanceCreate(sizeof(ES_INSTANCE_TYPE), _message, __VA_ARGS__))) +#else +#define EsInstanceCreate(_message, ...) ((ES_INSTANCE_TYPE *) _EsInstanceCreate(sizeof(ES_INSTANCE_TYPE), _message, __VA_ARGS__)) +#endif + +#define ES_SAMPLE_FORMAT_BYTES_PER_SAMPLE(x) \ + ((x) == ES_SAMPLE_FORMAT_U8 ? 1 : (x) == ES_SAMPLE_FORMAT_S16LE ? 2 : 4) + +#define ES_EXTRACT_BITS(value, end, start) (((value) >> (start)) & ((1 << ((end) - (start) + 1)) - 1)) // Moves the bits to the start. +#define ES_ISOLATE_BITS(value, end, start) (((value)) & (((1 << ((end) - (start) + 1)) - 1) << (start))) // Keeps the bits in place. + +#ifndef KERNEL +#ifdef ES_API +ES_EXTERN_C uintptr_t _APISyscall(uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, uintptr_t unused, uintptr_t argument3, uintptr_t argument4); +#define EsSyscall(a, b, c, d, e) _APISyscall((a), (b), (c), 0, (d), (e)) +#define _EsSyscall _APISyscall +#else +#define EsSyscall(a, b, c, d, e) _EsSyscall((a), (b), (c), 0, (d), (e)) +#endif +#endif + +// --------- Algorithms: + +#define ES_MACRO_SORT(_name, _type, _compar, _contextType) void _name(_type *base, size_t nmemb, _contextType context) { \ + (void) context; \ + if (nmemb <= 1) return; \ + \ + if (nmemb <= 16) { \ + for (uintptr_t i = 1; i < nmemb; i++) { \ + for (intptr_t j = i; j > 0; j--) { \ + _type *_left = base + j, *_right = _left - 1; \ + int result; _compar if (result >= 0) break; \ + \ + _type swap = base[j]; \ + base[j] = base[j - 1]; \ + base[j - 1] = swap; \ + } \ + } \ + \ + return; \ + } \ + \ + intptr_t i = -1, j = nmemb; \ + \ + while (true) { \ + _type *_left, *_right = base; \ + int result; \ + \ + while (true) { _left = base + ++i; _compar if (result >= 0) break; } \ + while (true) { _left = base + --j; _compar if (result <= 0) break; } \ + \ + if (i >= j) break; \ + \ + _type swap = base[i]; \ + base[i] = base[j]; \ + base[j] = swap; \ + } \ + \ + _name(base, ++j, context); \ + _name(base + j, nmemb - j, context); \ +} \ + +#define ES_MACRO_SEARCH(_count, _compar, _result, _found) \ + do { \ + if (_count) { \ + intptr_t low = 0; \ + intptr_t high = _count - 1; \ + \ + while (low <= high) { \ + uintptr_t index = ((high - low) >> 1) + low; \ + int result; \ + _compar \ + \ + if (result < 0) { \ + high = index - 1; \ + } else if (result > 0) { \ + low = index + 1; \ + } else { \ + _result = index; \ + _found = true; \ + break; \ + } \ + } \ + \ + if (high < low) { \ + _result = low; \ + _found = false; \ + } \ + } else { \ + _result = 0; \ + _found = false; \ + } \ + } while (0) + +// --------- Misc: + +typedef uint64_t _EsLongConstant; +typedef long double EsLongDouble; +typedef const char *EsCString; + +#ifndef ES_API +ES_EXTERN_C void _init(); +ES_EXTERN_C void _start(); +#endif + +#define EsAssert(x) do { if (!(x)) { EsAssertionFailure(__FILE__, __LINE__); } } while (0) +#define EsCRTassert EsAssert + +#define ES_INFINITY __builtin_inff() +#define ES_PI (3.1415926535897932384626433832795028841971693994) + +// --------- Internal APIs: + +#if defined(ES_API) || defined(KERNEL) + +struct EsProcessStartupInformation { + bool isDesktop; + uintptr_t applicationStartAddress; + uintptr_t tlsImageStart; + uintptr_t tlsImageBytes; + uintptr_t tlsBytes; // All bytes after the image are to be zeroed. +}; + +struct _EsPOSIXSyscall { + intptr_t index; + intptr_t arguments[7]; +}; + +#define BLEND_WINDOW_MATERIAL_NONE (0) +#define BLEND_WINDOW_MATERIAL_GLASS (1) +#define BLEND_WINDOW_MATERIAL_LIGHT_BLUR (2) + +#ifdef ARCH_X86_64 +#define BUNDLE_FILE_MAP_ADDRESS (0x100000000UL) +#endif + +struct BundleHeader { +#define BUNDLE_SIGNATURE (0x63BDAF45) + uint32_t signature; + uint32_t version; + uint32_t fileCount; + uint32_t _unused; + uint64_t mapAddress; +}; + +struct BundleFile { + uint64_t nameCRC64; + uint64_t bytes; + uint64_t offset; +}; + +#ifdef KERNEL +#define K_BOOT_DRIVE "" +#else +#define K_BOOT_DRIVE "0:" +#endif + +#define K_OS_FOLDER K_BOOT_DRIVE "/Essence" +#define K_DESKTOP_EXECUTABLE K_OS_FOLDER "/Desktop.esx" +#define K_SYSTEM_CONFIGURATION K_OS_FOLDER "/System Configuration.ini" + +#define CREATION_ARGUMENT_MAIN (0) +#define CREATION_ARGUMENT_ENVIRONMENT (1) +#define CREATION_ARGUMENT_INITIAL_MOUNT_POINTS (2) + +#define WINDOW_SET_BITS_NORMAL (0) +#define WINDOW_SET_BITS_SCROLL_HORIZONTAL (1) +#define WINDOW_SET_BITS_SCROLL_VERTICAL (2) +#define WINDOW_SET_BITS_AFTER_RESIZE (3) + +#define SHUTDOWN_ACTION_POWER_OFF (1) +#define SHUTDOWN_ACTION_RESTART (2) + +#ifdef __cplusplus +extern "C" const void *EsBufferRead(struct EsBuffer *buffer, size_t readBytes); +extern "C" const void *EsBufferReadMany(struct EsBuffer *buffer, size_t a, size_t b); +extern "C" void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writeBytes); +#define EsBuffer_MEMBER_FUNCTIONS \ + inline const void *Read(size_t readBytes) { return EsBufferRead(this, readBytes); } \ + inline const void *Read(size_t a, size_t b) { return EsBufferReadMany(this, a, b); } \ + inline void *Write(const void *source, size_t writeBytes) { return EsBufferWrite(this, source, writeBytes); } +#endif + +#define ES_POSIX_SYSCALL_GET_POSIX_FD_PATH (0x10000) + +#endif + +// --------- CRT function macros: + +#ifdef ES_CRT_WITHOUT_PREFIX +#define abs EsCRTabs +#define acosf EsCRTacosf +#define asinf EsCRTasinf +#define assert EsCRTassert +#define atan2f EsCRTatan2f +#define atanf EsCRTatanf +#define atoi EsCRTatoi +#define bsearch EsCRTbsearch +#define calloc EsCRTcalloc +#define ceil EsCRTceil +#define ceilf EsCRTceilf +#define cosf EsCRTcosf +#define exp EsCRTexp +#define exp2f EsCRTexp2f +#define fabs EsCRTfabs +#define fabsf EsCRTfabsf +#define floor EsCRTfloor +#define floorf EsCRTfloorf +#define fmodf EsCRTfmodf +#define free EsCRTfree +#define getenv EsCRTgetenv +#define isalpha EsCRTisalpha +#define isdigit EsCRTisdigit +#define isnanf EsCRTisnanf +#define isspace EsCRTisspace +#define isupper EsCRTisupper +#define isxdigit EsCRTisxdigit +#define malloc EsCRTmalloc +#define memchr EsCRTmemchr +#define memcmp EsCRTmemcmp +#define memcpy EsCRTmemcpy +#define memmove EsCRTmemmove +#define memset EsCRTmemset +#define powf EsCRTpowf +#define qsort EsCRTqsort +#define rand EsCRTrand +#define realloc EsCRTrealloc +#define sinf EsCRTsinf +#define snprintf EsCRTsnprintf +#define sprintf EsCRTsprintf +#define sqrt EsCRTsqrt +#define sqrtf EsCRTsqrtf +#define strcat EsCRTstrcat +#define strchr EsCRTstrchr +#define strcmp EsCRTstrcmp +#define strcpy EsCRTstrcpy +#define strdup EsCRTstrdup +#define strerror EsCRTstrerror +#define strlen EsCRTstrlen +#define strncmp EsCRTstrncmp +#define strncpy EsCRTstrncpy +#define strnlen EsCRTstrnlen +#define strstr EsCRTstrstr +#define strtol EsCRTstrtol +#define strtoul EsCRTstrtoul +#define tolower EsCRTtolower +#define vsnprintf EsCRTvsnprintf +#endif diff --git a/desktop/renderer.cpp b/desktop/renderer.cpp new file mode 100644 index 0000000..fbbde89 --- /dev/null +++ b/desktop/renderer.cpp @@ -0,0 +1,925 @@ +// TODO Fix glitches. +// TODO RAST_REPEAT_NORMAL is wrong with negative values. + +#ifdef IN_DESIGNER +#define RAST_ARRAY(x) x * +#define RAST_ARRAY_ADD arrput +#define RAST_ARRAY_CLEAR arrclear +#define RAST_ARRAY_DELETE_SWAP arrdelswap +#define RAST_ARRAY_FREE arrfree +#define RAST_ARRAY_INSERT arrinsn +#define RAST_ARRAY_LAST arrlast +#define RAST_ARRAY_LENGTH arrlen +#define RAST_ARRAY_LENGTH_U arrlenu +#else +#define RAST_ARRAY(x) Array +#define RAST_ARRAY_ADD(x, y) ((x).Add(y)) +#define RAST_ARRAY_CLEAR(x) ((x).SetLength(0)) +#define RAST_ARRAY_DELETE_SWAP(x, y) ((x).DeleteSwap(y)) +#define RAST_ARRAY_FREE(x) ((x).Free()) +#define RAST_ARRAY_INSERT(x, y, z) ((x).InsertMany(y, z)) +#define RAST_ARRAY_LAST(x) ((x).Last()) +#define RAST_ARRAY_LENGTH(x) ((intptr_t) (x).Length()) +#define RAST_ARRAY_LENGTH_U(x) ((x).Length()) +#endif + +typedef struct RastVertex { + float x, y; +} RastVertex; + +typedef struct RastEdge { + float xf, yf, xt, yt; + float dx, dy; + int sign; +} RastEdge; + +typedef struct RastShape { + RAST_ARRAY(RastEdge) edges; /* sorted by yf; yf <= yt */ + int left, right, top, bottom; +} RastShape; + +typedef struct RastSurface { + uint32_t *buffer; + int width, height, stride; + float *area, *areaFill; + bool customBuffer; +} RastSurface; + +typedef enum RastPaintType { + RAST_PAINT_NONE, + RAST_PAINT_SOLID, + RAST_PAINT_CHECKERBOARD, + RAST_PAINT_LINEAR_GRADIENT, + RAST_PAINT_RADIAL_GRADIENT, + RAST_PAINT_ANGULAR_GRADIENT, + RAST_PAINT_NOISE, +} RastPaintType; + +typedef enum RastRepeatMode { + RAST_REPEAT_CLAMP, + RAST_REPEAT_NORMAL, + RAST_REPEAT_MIRROR, +} RastRepeatMode; + +typedef struct RastPaint { + RastPaintType type; + + union { + struct { + uint32_t color; + float alpha; + } solid; + + struct { + uint32_t color1, color2; + float alpha1, alpha2; + int size; + } checkboard; + + struct { + uint32_t *color; + float *alpha; + float transform[6]; + RastRepeatMode repeatMode; + } gradient; + + struct { + uint32_t color; + float minimum, maximum; + } noise; + }; +} RastPaint; + +typedef struct RastGradientStop { + uint32_t color; + float position; +} RastGradientStop; + +typedef struct RastPathSegment { + uintptr_t uptoVertex; +} RastPathSegment; + +typedef struct RastPath { + RAST_ARRAY(RastPathSegment) segments; + RAST_ARRAY(RastVertex) vertices; +} RastPath; + +typedef enum RastLineJoinMode { + // Determines how convex segments are joined. + // Concave segments are always mitered with infinite limit. + + RAST_LINE_JOIN_MITER, // Force bevels with miterLimit = 0. + RAST_LINE_JOIN_ROUND, +} RastLineJoinMode; + +typedef enum RastLineCapMode { + RAST_LINE_CAP_FLAT, + RAST_LINE_CAP_SQUARE, + RAST_LINE_CAP_ROUND, +} RastLineCapMode; + +typedef struct RastContourStyle { + float internalWidth, externalWidth; + RastLineJoinMode joinMode; + float miterLimit; + RastLineCapMode capMode; + // TODO Markers. +} RastContourStyle; + +typedef struct RastDash { + float length, gap; + RastContourStyle *style; +} RastDash; + +#define RAST_ADD_VERTEX_MINIMUM_DISTANCE_SQUARED (0.1f * 0.1f) +#define RAST_GRADIENT_COLORS (256) +#define RAST_ROUND_TOLERANCE (0.25f) +#define RAST_FLATTEN_TOLERANCE (0.25f) +#define RAST_GRADIENT_NOISE (0.005f) + +#define RAST_AVERAGE_VERTICES(a, b) { ((a).x + (b).x) * 0.5f, ((a).y + (b).y) * 0.5f } + +bool RastSurfaceInitialise(RastSurface *surface, int width, int height, bool customBuffer) { + surface->width = width; + surface->height = height; + surface->stride = 4 * width; + surface->area = (float *) EsHeapAllocate(sizeof(float) * width, true); + surface->areaFill = (float *) EsHeapAllocate(sizeof(float) * (width + 1), true); + surface->customBuffer = customBuffer; + + if (!customBuffer) { + surface->buffer = (uint32_t *) EsHeapAllocate(4 * width * height, true); + } + + return surface->buffer && surface->area && surface->areaFill; +} + +void RastSurfaceDestroy(RastSurface *surface) { + EsHeapFree(surface->area); + EsHeapFree(surface->areaFill); + + if (!surface->customBuffer) { + EsHeapFree(surface->buffer); + } +} + +#ifndef IN_DESIGNER +ES_MACRO_SORT(RastEdgesSort, RastEdge, { result = _left->yf > _right->yf ? 1 : _left->yf < _right->yf ? -1 : 0; }, void *); +#else +int _RastEdgeCompare(const void *left, const void *right) { + const RastEdge *_left = (const RastEdge *) left; + const RastEdge *_right = (const RastEdge *) right; + return _left->yf > _right->yf ? 1 : _left->yf < _right->yf ? -1 : 0; +} + +void RastEdgesSort(RastEdge *edges, size_t count, void *_unused) { + (void) _unused; + qsort(edges, count, sizeof(RastEdge), _RastEdgeCompare); +} +#endif + +float _RastRepeat(RastRepeatMode mode, float p) { + if (mode == RAST_REPEAT_CLAMP) { + if (p < 0) return 0; + if (p > 1) return 1; + return p; + } else if (mode == RAST_REPEAT_MIRROR) { + p = EsCRTfabsf(EsCRTfmodf(p, 2.0f)); + if (p > 1) return 2 - p; + return p; + } else { + return EsCRTfabsf(EsCRTfmodf(p, 1.0f)); + } +} + +void _RastShapeDestroy(RastShape shape) { + RAST_ARRAY_FREE(shape.edges); +} + +void RastSurfaceFill(RastSurface surface, RastShape shape, RastPaint paint, bool evenOdd) { + if (paint.type == RAST_PAINT_LINEAR_GRADIENT + || paint.type == RAST_PAINT_RADIAL_GRADIENT + || paint.type == RAST_PAINT_ANGULAR_GRADIENT) { + if (!paint.gradient.color) { + _RastShapeDestroy(shape); + return; + } + } + + RAST_ARRAY(RastEdge) active = { 0 }; + int edgePosition = 0; + + if (shape.left < 0) shape.left = 0; + if (shape.right > surface.width) shape.right = surface.width; + if (shape.top < 0) shape.top = 0; + if (shape.bottom > surface.height) shape.bottom = surface.height; + + // Split edges that cross the left side of the shape. + + int initialShapeEdges = RAST_ARRAY_LENGTH(shape.edges); + + for (int i = 0; i < initialShapeEdges; i++) { + RastEdge *a = &shape.edges[i]; + + float y0 = a->yf; + float y1 = a->yt; + float x0 = a->xf; + float x1 = a->xt; + bool flipped = false; + + if (x0 > x1) { + float t = x0; + x0 = x1, x1 = t; + flipped = true; + } + + if (x0 < shape.left && x1 >= shape.left) { + RastEdge e = *a; + + if (flipped) { + y1 += (shape.left - x0) * a->dy; + a->xt = e.xf = e.xt = shape.left; + e.yf = a->yt = y1; + e.dx = 0; + } else { + y0 += (shape.left - x0) * a->dy; + a->xt = e.xf = a->xf = shape.left; + e.yf = a->yt = y0; + a->dx = 0; + } + + RAST_ARRAY_ADD(shape.edges, e); + } + } + + RastEdgesSort(&shape.edges[0], RAST_ARRAY_LENGTH(shape.edges), NULL); + + if (paint.type == RAST_PAINT_CHECKERBOARD && paint.checkboard.size < 1) paint.checkboard.size = 1; + + for (int scanline = shape.top; scanline < shape.bottom; scanline++) { + // Remove edges above this scanline. + + for (int i = 0; i < RAST_ARRAY_LENGTH(active); i++) { + if (active[i].yt < scanline) { + RAST_ARRAY_DELETE_SWAP(active, i); + i--; + } + } + + // Add edges that start within this scanline. + + while (edgePosition < RAST_ARRAY_LENGTH(shape.edges)) { + RastEdge *e = &shape.edges[edgePosition]; + + if (e->yf < scanline + 1.0f) { + RAST_ARRAY_ADD(active, *e); + edgePosition++; + } else { + break; + } + } + + // If there are no active edges, don't process the scanline. + + if (!RAST_ARRAY_LENGTH(active)) { + continue; + } + + // Calculate the signed area covered by each active edge. + + for (int i = 0; i < RAST_ARRAY_LENGTH(active); i++) { + RastEdge *a = &active[i]; + + // Calculate the range of pixels the edge crosses on the scanline. + + float top = scanline, bottom = scanline + 1; + float y0 = (a->yf > top) ? a->yf : top; + float y1 = (a->yt < bottom) ? a->yt : bottom; + float x0 = (y0 - a->yf) * a->dx + a->xf; + float x1 = (y1 - a->yf) * a->dx + a->xf; + float dy = a->dy; + bool flipped = false; + + if (x1 < x0) { + // Convert NE-SW edge to NW-SE. + // Flipping the edge preserves signed area. + + float t = y0; + y0 = top + bottom - y1; + y1 = top + bottom - t; + t = x0, x0 = x1, x1 = t; + dy = -dy; + flipped = true; + } + + if (x1 < shape.left) { + x0 = x1 = shape.left; + } else if (x0 < shape.left) { + y0 += (shape.left - x0) * dy; + x0 = shape.left; + } + + if (x1 >= shape.right) { + y1 += (x1 - shape.right + 1) * dy; + x1 = shape.right - 1; + } + + if (y1 <= y0 || x0 >= shape.right || x1 < shape.left || EsCRTisnanf(x0) || EsCRTisnanf(x1) || EsCRTisnanf(y0) || EsCRTisnanf(y1)) { + continue; + } + + if (EsCRTfloorf(x0) == EsCRTfloorf(x1)) { + // Edge crosses one pixel on this scanline, + // forming a trapezium. + + float right = EsCRTfloorf(x0 + 1); + float p = a->sign * (y1 - y0); + int xs = (int) x0; + surface.area[xs] += p * (right - x0 + right - x1) * 0.5f; + surface.areaFill[xs + 1] += p; + } else { + // Edge crosses multiple pixels on this scanline. + // The first pixel is a triangle. + + float tx = EsCRTfloorf(x0 + 1); + float th = dy * (tx - x0); + int xs = (int) x0, xf = (int) x1; + surface.area[xs] += a->sign * (tx - x0) * th * 0.5f; + + // The middle pixels are trapeziums. + + float pa = th + 0.5f * dy; + for (int j = xs + 1; j < xf; j++, pa += dy) surface.area[j] += a->sign * pa; + + // The final pixel is a removed triangle. + + float p = a->sign * (y1 - y0); + float fx = EsCRTfloorf(x1); + float fy = a->yf + a->dy * (fx - a->xf); + if (flipped) fy = top + bottom - fy; + surface.area[xf] += p - a->sign * 0.5f * (x1 - fx) * (y1 - fy); + surface.areaFill[xf + 1] += p; + } + } + + // Calculate the final coverage of each pixel. + + float cumulativeArea = 0; + uint32_t *destination = (uint32_t *) ((uint8_t *) surface.buffer + scanline * surface.stride + 4 * shape.left); + + float textureDX = paint.gradient.transform[0]; + float texturePX = shape.left * textureDX + (float) scanline * paint.gradient.transform[1] + paint.gradient.transform[2]; + float textureDY = paint.gradient.transform[3]; + float texturePY = shape.left * textureDY + (float) scanline * paint.gradient.transform[4] + paint.gradient.transform[5]; + + if (paint.type == RAST_PAINT_NOISE) { + textureDX = 1; + texturePX = 0; + } + + for (int i = shape.left; i < shape.right; i++) { + cumulativeArea += surface.areaFill[i]; + float a = surface.area[i] + cumulativeArea; + + if (evenOdd) { + a = EsCRTfmodf(AbsoluteFloat(a), 2); + if (a > 1) a = 2 - a; + } else { + if (a < 0) a = -a; + if (a > 1) a = 1; + } + + if (a > 0.0039f) { + if (paint.type == RAST_PAINT_SOLID) { + uint8_t c = (uint8_t) (a * paint.solid.alpha * 255.0f); + if (c) BlendPixel(destination, (c << 24) | paint.solid.color, true); + } else if (paint.type == RAST_PAINT_CHECKERBOARD) { + if (((i - shape.left) / paint.checkboard.size + (scanline - shape.top) / paint.checkboard.size) & 1) { + uint8_t c = (uint8_t) (a * paint.checkboard.alpha2 * 255.0f); + if (c) BlendPixel(destination, (c << 24) | paint.checkboard.color2, true); + } else { + uint8_t c = (uint8_t) (a * paint.checkboard.alpha1 * 255.0f); + if (c) BlendPixel(destination, (c << 24) | paint.checkboard.color1, true); + } + } else if (paint.type == RAST_PAINT_LINEAR_GRADIENT) { + float p = _RastRepeat(paint.gradient.repeatMode, texturePX); + int pi = (int) ((RAST_GRADIENT_COLORS - 1) * p); + EsAssert(pi >= 0 && pi < RAST_GRADIENT_COLORS); // Invalid gradient index. + uint8_t c = (uint8_t) (a * paint.gradient.alpha[pi] * 255.0f); + if (c) BlendPixel(destination, (c << 24) | paint.gradient.color[pi], true); + } else if (paint.type == RAST_PAINT_RADIAL_GRADIENT) { + float p = EsCRTsqrtf(texturePX * texturePX + texturePY * texturePY); + if (p < 0) p = 0; + if (p > 1) p = 1; + int pi = (int) ((RAST_GRADIENT_COLORS - 1) * p); + uint8_t c = (uint8_t) (a * paint.gradient.alpha[pi] * 255.0f); + if (c) BlendPixel(destination, (c << 24) | paint.gradient.color[pi], true); + } else if (paint.type == RAST_PAINT_ANGULAR_GRADIENT) { + float p = EsCRTatan2f(texturePY, texturePX) * 0.159154943091f + 0.5f; + if (p < 0) p = 0; + if (p > 1) p = 1; + int pi = (int) ((RAST_GRADIENT_COLORS - 1) * p); + uint8_t c = (uint8_t) (a * paint.gradient.alpha[pi] * 255.0f); + if (c) BlendPixel(destination, (c << 24) | paint.gradient.color[pi], true); + } else if (paint.type == RAST_PAINT_NOISE) { + union { float f; uint32_t u; } noise = { texturePX + texturePY }; + noise.u += noise.u << 10; + noise.u ^= noise.u >> 6; + noise.u += noise.u << 3; + noise.u ^= noise.u >> 11; + noise.u += noise.u << 15; + noise.u &= 0x7FFFFF; + noise.u |= 0x3F800000; + noise.f /= 2; + noise.f *= paint.noise.maximum - paint.noise.minimum; + noise.f += paint.noise.minimum; + + uint8_t c = (uint8_t) (a * noise.f * 255.0f); + if (c) BlendPixel(destination, (c << 24) | paint.noise.color, true); + } + } + + surface.area[i] = surface.areaFill[i] = 0; + destination++; + texturePX += textureDX; + texturePY += textureDY; + } + + surface.areaFill[shape.right] = 0; + } + + RAST_ARRAY_FREE(active); + _RastShapeDestroy(shape); +} + +void _RastShapeAddEdges(RastShape *shape, RastVertex *vertices, int sign, bool open, int vertexCount) { + if (vertexCount <= 1) return; + + for (int i = 0; i < vertexCount - (open ? 1 : 0); i++) { + RastVertex *from = &vertices[i]; + RastVertex *to = &vertices[(i + 1) % vertexCount]; + if (from->y == to->y) continue; + + int p = RAST_ARRAY_LENGTH(shape->edges); + RAST_ARRAY_INSERT(shape->edges, p, 1); + RastEdge *edge = &shape->edges[p]; + + if (from->y < to->y) { + edge->xf = from->x, edge->yf = from->y; + edge->xt = to->x, edge->yt = to->y; + edge->sign = sign; + } else { + edge->xf = to->x, edge->yf = to->y; + edge->xt = from->x, edge->yt = from->y; + edge->sign = -sign; + } + + edge->dx = (edge->xt - edge->xf) / (edge->yt - edge->yf); + edge->dy = 1.0f / edge->dx; + + if (edge->xf < shape->left) shape->left = edge->xf; + if (edge->xt < shape->left) shape->left = edge->xt; + if (edge->yf < shape->top) shape->top = edge->yf; + if (edge->xf + 1 > shape->right) shape->right = edge->xf + 1; + if (edge->xt + 1 > shape->right) shape->right = edge->xt + 1; + if (edge->yt + 1 > shape->bottom) shape->bottom = edge->yt + 1; + } +} + +void RastPathCloseSegment(RastPath *path) { + if (!RAST_ARRAY_LENGTH_U(path->segments) || RAST_ARRAY_LAST(path->segments).uptoVertex != RAST_ARRAY_LENGTH_U(path->vertices)) { + RastPathSegment segment = {}; + segment.uptoVertex = RAST_ARRAY_LENGTH_U(path->vertices); + RAST_ARRAY_ADD(path->segments, segment); + } +} + +RastShape RastShapeCreateSolid(RastPath *path) { + if (RAST_ARRAY_LENGTH(path->vertices) < 3) return (RastShape) { 0 }; + RastPathCloseSegment(path); + RastShape shape = { .left = INT_MAX, .top = INT_MAX }; + uintptr_t start = 0; + + for (uintptr_t i = 0; i < RAST_ARRAY_LENGTH_U(path->segments); i++) { + _RastShapeAddEdges(&shape, &path->vertices[start], 1, false, path->segments[i].uptoVertex - start); + start = path->segments[i].uptoVertex; + } + + return shape; +} + +void _RastJoinMeter(RAST_ARRAY(RastVertex) *output, RastVertex *from1, RastVertex *to1, RastVertex *from2, RastVertex *to2, RastVertex *point, float miterLimit) { + // TODO For internal contours, this can generate vertices forming anticlockwise regions if the contour width is large enough. + // (You can't see it though because we use a non-zero fill rule.) + + float a = to1->x - from1->x, b = from2->x - to2->x, e = from2->x - from1->x; + float c = to1->y - from1->y, d = from2->y - to2->y, f = from2->y - from1->y; + float j = (d * e - b * f) / (d * a - b * c); + RastVertex v = { from1->x + j * (to1->x - from1->x), from1->y + j * (to1->y - from1->y) }; + + if ((v.x - point->x) * (v.x - point->x) + (v.y - point->y) * (v.y - point->y) <= miterLimit * miterLimit) { + RAST_ARRAY_ADD(*output, v); + } else { + // TODO Move bevel to miter limit. + RAST_ARRAY_ADD(*output, *to1); + RAST_ARRAY_ADD(*output, *from2); + } +} + +void _RastJoinArc(RAST_ARRAY(RastVertex) *output, float fromAngle, float toAngle, int divisions, RastVertex *point, float width) { + for (int j = 0; j < divisions; j++) { + float angle = fromAngle + j * (toAngle - fromAngle) / (divisions - 1); + RastVertex v = { point->x + EsCRTcosf(angle) * width, point->y + EsCRTsinf(angle) * width }; + + if (j == 0 || j == divisions - 1) { + RAST_ARRAY_ADD(*output, v); + continue; + } + + RastVertex l = RAST_ARRAY_LAST(*output); + int dx = v.x - l.x, dy = v.y - l.y; + + if (dx * dx + dy * dy > RAST_ADD_VERTEX_MINIMUM_DISTANCE_SQUARED) { + RAST_ARRAY_ADD(*output, v); + } + } +} + +void _RastJoinRound(RAST_ARRAY(RastVertex) *output, RastVertex *from1, RastVertex *to1, RastVertex *from2, + RastVertex *to2, RastVertex *point, float width, int divisions, bool internal) { + float fromAngle = EsCRTatan2f(to1->y - point->y, to1->x - point->x); + float toAngle = EsCRTatan2f(from2->y - point->y, from2->x - point->x); + + if (toAngle > fromAngle) { + toAngle -= 6.2831853071f; + } + + if (internal == (fromAngle - toAngle < 3.141592653f)) { + _RastJoinMeter(output, from1, to1, from2, to2, point, ES_INFINITY); + return; + } + + if (internal) { + toAngle += 6.2831853071f; + } + + _RastJoinArc(output, fromAngle, toAngle, divisions, point, width); +} + +void _RastShapeCreateContour(RastShape *shape, RastPath *path, RastContourStyle style, bool open) { + RAST_ARRAY(RastVertex) vertices = path->vertices; + size_t vertexCount = RAST_ARRAY_LENGTH(vertices); + + if (vertexCount < 2) { + return; + } + + if (!open) { + RastVertex first = vertices[0], last = RAST_ARRAY_LAST(vertices); + float dx = first.x - last.x, dy = first.y - last.y; + + if (dx * dx + dy * dy < RAST_ADD_VERTEX_MINIMUM_DISTANCE_SQUARED) { + vertexCount--; + } + } + + if (vertexCount <= 1) { + return; + } else if (vertexCount == 2) { + open = true; + } + + RastVertex cap1, cap2, cap3, cap4; + + RAST_ARRAY(RastVertex) path1 = { 0 }; + RAST_ARRAY(RastVertex) path2 = { 0 }; + + for (int internal = 0; internal < 2; internal++) { + float width = internal ? style.internalWidth : style.externalWidth; + RastVertex *capStart = internal ? &cap4 : &cap1; + RastVertex *capEnd = internal ? &cap3 : &cap2; + + for (uintptr_t i = 0; i < vertexCount; i++) { + RastVertex *from = &vertices[(i + 0) % vertexCount], + *to = &vertices[(i + 1) % vertexCount]; + float dx = to->x - from->x, dy = to->y - from->y; + float scale = (internal ? -width : width) / EsCRTsqrtf(dx * dx + dy * dy); + float ox = -dy * scale, oy = dx * scale; + RastVertex cf = { from->x + ox, from->y + oy }; + RastVertex ct = { to->x + ox, to->y + oy }; + RAST_ARRAY_ADD(path1, cf); + RAST_ARRAY_ADD(path1, ct); + } + + if (open) RAST_ARRAY_ADD(path2, (*capStart = path1[0])); + + if (style.joinMode == RAST_LINE_JOIN_MITER) { + for (int i = 0; i < RAST_ARRAY_LENGTH(path1) - (open ? 4 : 0); i += 2) { + RastVertex *p1 = &vertices[(i / 2 + 0) % vertexCount], + *p2 = &vertices[(i / 2 + 1) % vertexCount], + *p3 = &vertices[(i / 2 + 2) % vertexCount]; + float cross = (p2->x - p1->x) * (p3->y - p2->y) - (p2->y - p1->y) * (p3->x - p2->x); + + _RastJoinMeter(&path2, &path1[i], &path1[i + 1], &path1[(i + 2) % RAST_ARRAY_LENGTH(path1)], + &path1[(i + 3) % RAST_ARRAY_LENGTH(path1)], &vertices[(i / 2 + 1) % vertexCount], + (internal ? (cross > 0) : (cross < 0)) ? style.miterLimit : ES_INFINITY); + } + } else if (style.joinMode == RAST_LINE_JOIN_ROUND) { + int divisions = EsCRTceilf(3.14159265358f * 0.5f / EsCRTacosf(width / (width + RAST_ROUND_TOLERANCE))) + 1; + + for (int i = 0; i < RAST_ARRAY_LENGTH(path1) - (open ? 4 : 0); i += 2) { + _RastJoinRound(&path2, &path1[i], &path1[i + 1], &path1[(i + 2) % RAST_ARRAY_LENGTH(path1)], + &path1[(i + 3) % RAST_ARRAY_LENGTH(path1)], &vertices[(i / 2 + 1) % vertexCount], width, divisions, internal); + } + } + + if (open) RAST_ARRAY_ADD(path2, (*capEnd = path1[RAST_ARRAY_LENGTH(path1) - 3])); + + _RastShapeAddEdges(shape, &path2[0], internal ? -1 : 1, open, RAST_ARRAY_LENGTH(path2)); + + RAST_ARRAY_CLEAR(path1); + RAST_ARRAY_CLEAR(path2); + } + + if (open) { + // TODO Cap styles don't work if the contour is not centered (i.e. internalWidth != externalWidth). + + for (int i = 0; i < 2; i++) { + RastVertex c = i ? cap4 : cap2, d = i ? cap1 : cap3; + RastVertex *from = &vertices[(i ? 1 : (vertexCount - 2))]; + RastVertex *to = &vertices[(i ? 0 : (vertexCount - 1))]; + RAST_ARRAY_ADD(path1, c); + + if (style.capMode == RAST_LINE_CAP_SQUARE) { + float dx = to->x - from->x, dy = to->y - from->y; + float scale = 0.5f * (style.internalWidth + style.externalWidth) / EsCRTsqrtf(dx * dx + dy * dy); + RastVertex c0 = { .x = c.x + scale * dx, .y = c.y + scale * dy }; + RastVertex d0 = { .x = d.x + scale * dx, .y = d.y + scale * dy }; + RAST_ARRAY_ADD(path1, c0); + RAST_ARRAY_ADD(path1, d0); + } else if (style.capMode == RAST_LINE_CAP_ROUND) { + float angle = EsCRTatan2f(d.y - to->y, d.x - to->x); + float width = 0.5f * (style.internalWidth + style.externalWidth); + int divisions = EsCRTceilf(3.14159265358f * 0.5f / EsCRTacosf(width / (width + RAST_ROUND_TOLERANCE))) + 1; + _RastJoinArc(&path1, angle + 3.14159265358f, angle, divisions, to, width); + } + + RAST_ARRAY_ADD(path1, d); + _RastShapeAddEdges(shape, &path1[0], 1, true, RAST_ARRAY_LENGTH(path1)); + RAST_ARRAY_CLEAR(path1); + } + } + + RAST_ARRAY_FREE(path1); + RAST_ARRAY_FREE(path2); +} + +RastShape RastShapeCreateContour(RastPath *path, RastContourStyle style, bool open) { + RastShape shape = { .left = INT_MAX, .top = INT_MAX }; + _RastShapeCreateContour(&shape, path, style, open); + if (RAST_ARRAY_LENGTH(shape.edges) == 0) return (RastShape) { 0 }; + return shape; +} + +void _RastPathAddVertex(RastPath *path, RastVertex vertex) { + if (RAST_ARRAY_LENGTH(path->vertices)) { + RastVertex last = RAST_ARRAY_LAST(path->vertices); + float dx = last.x - vertex.x, dy = last.y - vertex.y; + + if (dx * dx + dy * dy < RAST_ADD_VERTEX_MINIMUM_DISTANCE_SQUARED) { + return; + } + } + + RAST_ARRAY_ADD(path->vertices, vertex); +} + +RastShape RastShapeCreateDashed(RastPath *path, RastDash *dashStyles, size_t dashStyleCount, bool open) { + RAST_ARRAY(RastVertex) vertices = path->vertices; + size_t vertexCount = RAST_ARRAY_LENGTH(vertices); + + if (dashStyleCount < 1 || vertexCount < 2) { + return (RastShape) { 0 }; + } + + RastDash *style = dashStyles + 0; + RastVertex from = vertices[0]; + RastVertex *to = &vertices[1]; + RastPath dash = {}; + RastShape shape = { .left = INT_MAX, .top = INT_MAX }; + + if (!open) { + from = RAST_ARRAY_LAST(vertices); + to = &vertices[0]; + } + + while (to != &vertices[vertexCount]) { + float accumulatedLength = 0; + + _RastPathAddVertex(&dash, from); + + while (to != &vertices[vertexCount]) { + float dx = to->x - from.x, dy = to->y - from.y; + float distance = EsCRTsqrtf(dx * dx + dy * dy); + + if (accumulatedLength + distance >= style->length) { + float fraction = (style->length - accumulatedLength) / distance; + RastVertex stop = { from.x + fraction * dx, from.y + fraction * dy }; + _RastPathAddVertex(&dash, stop); + from = stop; + break; + } + + accumulatedLength += distance; + from = *to; + _RastPathAddVertex(&dash, from); + to++; + } + + _RastShapeCreateContour(&shape, &dash, *style->style, true); + + accumulatedLength = 0; + + while (to != &vertices[vertexCount]) { + float dx = to->x - from.x, dy = to->y - from.y; + float distance = EsCRTsqrtf(dx * dx + dy * dy); + + if (accumulatedLength + distance >= style->gap) { + float fraction = (style->gap - accumulatedLength) / distance; + RastVertex stop = { from.x + fraction * dx, from.y + fraction * dy }; + from = stop; + break; + } + + accumulatedLength += distance; + from = *to; + to++; + } + + style++; + + if (style == dashStyles + dashStyleCount) { + style = dashStyles + 0; + } + + RAST_ARRAY_CLEAR(dash.vertices); + } + + return shape; +} + +RastVertex _RastVertexScale(RastVertex vertex, RastVertex scale) { + return (RastVertex) { vertex.x * scale.x, vertex.y * scale.y }; +} + +void _RastFlattenBezierRecursive(RastPath *path, RastVertex v1, RastVertex v2, RastVertex v3, RastVertex v4, int level) { + if (level > 8) return; + + RastVertex v12 = RAST_AVERAGE_VERTICES(v1, v2); + RastVertex v23 = RAST_AVERAGE_VERTICES(v2, v3); + RastVertex v34 = RAST_AVERAGE_VERTICES(v3, v4); + + RastVertex delta = { v4.x - v1.x, v4.y - v1.y }; + float d = AbsoluteFloat((v2.x - v4.x) * delta.y + (v4.y - v2.y) * delta.x) + + AbsoluteFloat((v3.x - v4.x) * delta.y + (v4.y - v3.y) * delta.x); + + if (d * d < RAST_FLATTEN_TOLERANCE * (delta.x * delta.x + delta.y * delta.y)) { + _RastPathAddVertex(path, v4); + return; + } + + RastVertex v123 = RAST_AVERAGE_VERTICES(v12, v23); + RastVertex v234 = RAST_AVERAGE_VERTICES(v23, v34); + RastVertex v1234 = RAST_AVERAGE_VERTICES(v123, v234); + + _RastFlattenBezierRecursive(path, v1, v12, v123, v1234, level + 1); + _RastFlattenBezierRecursive(path, v1234, v234, v34, v4, level + 1); +} + +void RastPathAppendBezier(RastPath *path, const RastVertex *vertices, size_t vertexCount, RastVertex scale) { + if (vertexCount < 4) return; + _RastPathAddVertex(path, _RastVertexScale(vertices[0], scale)); + + for (uintptr_t i = 0; i < vertexCount - 3; i += 3) { + // TODO Scale the control points such that the center of the curve is aligned? + _RastFlattenBezierRecursive(path, _RastVertexScale(vertices[i + 0], scale), _RastVertexScale(vertices[i + 1], scale), + _RastVertexScale(vertices[i + 2], scale), _RastVertexScale(vertices[i + 3], scale), 0); + } +} + +void RastPathAppendLinear(RastPath *path, RastVertex *vertices, size_t vertexCount, RastVertex scale) { + if (!vertexCount) return; + + for (uintptr_t i = 0; i < vertexCount; i++) { + _RastPathAddVertex(path, _RastVertexScale(vertices[i], scale)); + } +} + +void RastPathTranslate(RastPath *path, float x, float y) { + if (!x && !y) return; + + for (uintptr_t i = 0; i < RAST_ARRAY_LENGTH_U(path->vertices); i++) { + path->vertices[i].x += x; + path->vertices[i].y += y; + } +} + +void RastPathTransform(RastPath *path, float *matrix) { + for (uintptr_t i = 0; i < RAST_ARRAY_LENGTH_U(path->vertices); i++) { + float x = path->vertices[i].x, y = path->vertices[i].y; + path->vertices[i].x = matrix[0] * x + matrix[1] * y + matrix[2]; + path->vertices[i].y = matrix[3] * x + matrix[4] * y + matrix[5]; + } +} + +void RastPathDestroy(RastPath *path) { + RAST_ARRAY_FREE(path->segments); + RAST_ARRAY_FREE(path->vertices); +} + +float _RastInterpolateWithGamma(float from, float to, float progress) { + from = from * from; + to = to * to; + return EsCRTsqrtf(from + progress * (to - from)); +} + +float _RastInterpolateSimple(float from, float to, float progress) { + return from + progress * (to - from); +} + +void RastGradientInitialise(RastPaint *paint, RastGradientStop *stops, size_t stopCount, bool useGammaInterpolation) { + if (!stopCount) { + return; + } + + paint->gradient.color = (uint32_t *) EsHeapAllocate(4 * RAST_GRADIENT_COLORS, false); + paint->gradient.alpha = (float *) EsHeapAllocate(sizeof(float) * RAST_GRADIENT_COLORS, false); + + for (uintptr_t stop = 0; stop < stopCount - 1; stop++) { + float fa = ((stops[stop + 0].color >> 24) & 0xFF) / 255.0f; + float fb = ((stops[stop + 0].color >> 16) & 0xFF) / 255.0f; + float fg = ((stops[stop + 0].color >> 8) & 0xFF) / 255.0f; + float fr = ((stops[stop + 0].color >> 0) & 0xFF) / 255.0f; + float ta = ((stops[stop + 1].color >> 24) & 0xFF) / 255.0f; + float tb = ((stops[stop + 1].color >> 16) & 0xFF) / 255.0f; + float tg = ((stops[stop + 1].color >> 8) & 0xFF) / 255.0f; + float tr = ((stops[stop + 1].color >> 0) & 0xFF) / 255.0f; + + int fi = RAST_GRADIENT_COLORS * (stop == 0 ? 0 : stops[stop + 0].position); + int ti = RAST_GRADIENT_COLORS * (stop == stopCount - 2 ? 1 : stops[stop + 1].position); + if (fi < 0) fi = 0; + if (ti > RAST_GRADIENT_COLORS) ti = RAST_GRADIENT_COLORS; + + for (int i = fi; i < ti; i++) { + float p = (float) (i - fi) / (ti - fi); + paint->gradient.alpha[i] = fa + (ta - fa) * p; + + if (useGammaInterpolation) { + paint->gradient.color[i] = (uint32_t) (_RastInterpolateWithGamma(fr, tr, p) * 255.0f) << 0 + | (uint32_t) (_RastInterpolateWithGamma(fg, tg, p) * 255.0f) << 8 + | (uint32_t) (_RastInterpolateWithGamma(fb, tb, p) * 255.0f) << 16; + } else { + paint->gradient.color[i] = (uint32_t) (_RastInterpolateSimple(fr, tr, p) * 255.0f) << 0 + | (uint32_t) (_RastInterpolateSimple(fg, tg, p) * 255.0f) << 8 + | (uint32_t) (_RastInterpolateSimple(fb, tb, p) * 255.0f) << 16; + } + } + } +} + +void RastGradientDestroy(RastPaint *paint) { + if (paint->type == RAST_PAINT_LINEAR_GRADIENT + || paint->type == RAST_PAINT_RADIAL_GRADIENT + || paint->type == RAST_PAINT_ANGULAR_GRADIENT) { + EsHeapFree(paint->gradient.color); + EsHeapFree(paint->gradient.alpha); + } +} + +#ifndef IN_DESIGNER +void EsDrawLine(EsPainter *painter, float *vertices, size_t vertexCount, uint32_t color, float width, uint32_t flags) { + RastSurface surface = {}; + surface.buffer = (uint32_t *) painter->target->bits; + surface.stride = painter->target->stride; + + if (RastSurfaceInitialise(&surface, painter->target->width, painter->target->height, true)) { + RastPath path = {}; + RastPathAppendLinear(&path, (RastVertex *) vertices, vertexCount, { 1, 1 }); + RastContourStyle style = {}; + style.externalWidth = width / 2.0f; + style.internalWidth = width / 2.0f; + style.capMode = (flags & ES_DRAW_LINE_CAP_ROUND) ? RAST_LINE_CAP_ROUND + : (flags & ES_DRAW_LINE_CAP_SQUARE) ? RAST_LINE_CAP_SQUARE + : RAST_LINE_CAP_FLAT; + RastShape shape = RastShapeCreateContour(&path, style, true); + RastPaint paint = {}; + paint.type = RAST_PAINT_SOLID; + paint.solid.color = color & 0xFFFFFF; + paint.solid.alpha = (color >> 24) / 255.0f; + RastSurfaceFill(surface, shape, paint, false); + RastPathDestroy(&path); + } + + RastSurfaceDestroy(&surface); +} +#endif diff --git a/desktop/styles.header b/desktop/styles.header new file mode 100644 index 0000000..edebe24 --- /dev/null +++ b/desktop/styles.header @@ -0,0 +1,113 @@ +define_private ES_STYLE__TEST_STYLE (ES_STYLE_CAST(1385)) +define_private ES_STYLE_ACCESS_KEY_HINT (ES_STYLE_CAST(1221)) +define_private ES_STYLE_ANNOUNCEMENT (ES_STYLE_CAST(1511)) +define_private ES_STYLE_BREADCRUMB_BAR_CRUMB (ES_STYLE_CAST(1223)) +define_private ES_STYLE_BREADCRUMB_BAR_OVERFLOW_ICON (ES_STYLE_CAST(1225)) +define_private ES_STYLE_BREADCRUMB_BAR_PANEL (ES_STYLE_CAST(1227)) +define ES_STYLE_BUTTON_GROUP_CONTAINER (ES_STYLE_CAST(1229)) +define ES_STYLE_BUTTON_GROUP_ITEM (ES_STYLE_CAST(1231)) +define ES_STYLE_BUTTON_GROUP_SEPARATOR (ES_STYLE_CAST(1233)) +define_private ES_STYLE_CANVAS_SHADOW (ES_STYLE_CAST(1451)) +define_private ES_STYLE_CHECKBOX_NORMAL (ES_STYLE_CAST(1235)) +define_private ES_STYLE_CHECKBOX_RADIOBOX (ES_STYLE_CAST(1237)) +define_private ES_STYLE_COLOR_CHOSEN_POINT (ES_STYLE_CAST(1241)) +define_private ES_STYLE_COLOR_CIRCLE (ES_STYLE_CAST(1243)) +define_private ES_STYLE_COLOR_HEX_TEXTBOX (ES_STYLE_CAST(1245)) +define_private ES_STYLE_COLOR_PICKER_MAIN_PANEL (ES_STYLE_CAST(1247)) +define_private ES_STYLE_COLOR_SLIDER (ES_STYLE_CAST(1249)) +define_private ES_STYLE_CONTAINER_WINDOW_ACTIVE (ES_STYLE_CAST(1251)) +define_private ES_STYLE_CONTAINER_WINDOW_INACTIVE (ES_STYLE_CAST(1255)) +define ES_STYLE_DIALOG_BUTTON_AREA (ES_STYLE_CAST(1259)) +define ES_STYLE_DIALOG_CONTENT (ES_STYLE_CAST(1261)) +define ES_STYLE_DIALOG_HEADING (ES_STYLE_CAST(1263)) +define ES_STYLE_ICON_DISPLAY (ES_STYLE_CAST(1265)) +define ES_STYLE_ICON_DISPLAY_SMALL (ES_STYLE_CAST(1543)) +define ES_STYLE_INSTALLER_ROOT (ES_STYLE_CAST(1267)) +define ES_STYLE_LIST_CHOICE_BORDERED (ES_STYLE_CAST(1429)) +define ES_STYLE_LIST_CHOICE_ITEM (ES_STYLE_CAST(1435)) +define_private ES_STYLE_LIST_COLUMN_HEADER (ES_STYLE_CAST(1269)) +define_private ES_STYLE_LIST_COLUMN_HEADER_ITEM (ES_STYLE_CAST(1271)) +define_private ES_STYLE_LIST_COLUMN_HEADER_ITEM_HAS_MENU (ES_STYLE_CAST(1273)) +define_private ES_STYLE_LIST_COLUMN_HEADER_SPLITTER (ES_STYLE_CAST(1275)) +define_private ES_STYLE_LIST_GROUP_HEADER_CELL (ES_STYLE_CAST(1277)) +define ES_STYLE_LIST_ITEM (ES_STYLE_CAST(1279)) +define ES_STYLE_LIST_ITEM_GROUP_FOOTER (ES_STYLE_CAST(1281)) +define ES_STYLE_LIST_ITEM_GROUP_HEADER (ES_STYLE_CAST(1283)) +define ES_STYLE_LIST_ITEM_TILE (ES_STYLE_CAST(1285)) +define_private ES_STYLE_LIST_PRIMARY_CELL (ES_STYLE_CAST(1287)) +define_private ES_STYLE_LIST_SECONDARY_CELL (ES_STYLE_CAST(1289)) +define_private ES_STYLE_LIST_SELECTION_BOX (ES_STYLE_CAST(1291)) +define ES_STYLE_LIST_VIEW (ES_STYLE_CAST(1293)) +define ES_STYLE_LIST_VIEW_BORDERED (ES_STYLE_CAST(1295)) +define ES_STYLE_LIST_DISPLAY_DEFAULT (ES_STYLE_CAST(1441)) +define_private ES_STYLE_MARKER_DOWN_ARROW (ES_STYLE_CAST(1297)) +define_private ES_STYLE_MARKER_UP_ARROW (ES_STYLE_CAST(1501)) +define_private ES_STYLE_MENU_ITEM_HEADER (ES_STYLE_CAST(1299)) +define_private ES_STYLE_MENU_ITEM_NORMAL (ES_STYLE_CAST(1301)) +define_private ES_STYLE_MENU_SEPARATOR_HORIZONTAL (ES_STYLE_CAST(1303)) +define_private ES_STYLE_MENU_SEPARATOR_VERTICAL (ES_STYLE_CAST(1305)) +define_private ES_STYLE_PANEL_CONTAINER_WINDOW_ROOT (ES_STYLE_CAST(1307)) +define_private ES_STYLE_PANEL_CRASH_INFO (ES_STYLE_CAST(1309)) +define ES_STYLE_PANEL_DIALOG_ROOT (ES_STYLE_CAST(1311)) +define ES_STYLE_PANEL_DOCUMENT (ES_STYLE_CAST(1547)) +define ES_STYLE_PANEL_FILLED (ES_STYLE_CAST(1313)) +define ES_STYLE_PANEL_GROUP_BOX (ES_STYLE_CAST(1315)) +define_private ES_STYLE_PANEL_INSPECTOR_WINDOW_CONTAINER (ES_STYLE_CAST(1317)) +define_private ES_STYLE_PANEL_INSPECTOR_WINDOW_ROOT (ES_STYLE_CAST(1319)) +define_private ES_STYLE_PANEL_MENU_COLUMN (ES_STYLE_CAST(1321)) +define_private ES_STYLE_PANEL_MENU_CONTAINER (ES_STYLE_CAST(1323)) +define_private ES_STYLE_PANEL_MENU_ROOT (ES_STYLE_CAST(1325)) +define_private ES_STYLE_PANEL_MODAL_OVERLAY (ES_STYLE_CAST(1327)) +define_private ES_STYLE_PANEL_NORMAL_WINDOW_ROOT (ES_STYLE_CAST(1329)) +define ES_STYLE_PANEL_POPUP (ES_STYLE_CAST(1331)) +define ES_STYLE_PANEL_SHEET (ES_STYLE_CAST(1333)) +define_private ES_STYLE_PANEL_SHUTDOWN_OVERLAY (ES_STYLE_CAST(1335)) +define ES_STYLE_PANEL_STATUS_BAR (ES_STYLE_CAST(1489)) +define ES_STYLE_PANEL_TOOLBAR (ES_STYLE_CAST(1337)) +define ES_STYLE_PANEL_TOOLBAR_ROOT (ES_STYLE_CAST(1339)) +define ES_STYLE_PANEL_WINDOW_BACKGROUND (ES_STYLE_CAST(1341)) +define ES_STYLE_PANEL_WINDOW_DIVIDER (ES_STYLE_CAST(1343)) +define ES_STYLE_PANEL_WINDOW_WITH_STATUS_BAR_CONTENT (ES_STYLE_CAST(1483)) +define ES_STYLE_PUSH_BUTTON_DANGEROUS (ES_STYLE_CAST(1345)) +define_private ES_STYLE_PUSH_BUTTON_NORMAL (ES_STYLE_CAST(1347)) +define_private ES_STYLE_PUSH_BUTTON_NORMAL_COLOR_WELL (ES_STYLE_CAST(1349)) +define_private ES_STYLE_PUSH_BUTTON_SCROLLBAR_DOWN (ES_STYLE_CAST(1351)) +define_private ES_STYLE_PUSH_BUTTON_SCROLLBAR_LEFT (ES_STYLE_CAST(1353)) +define_private ES_STYLE_PUSH_BUTTON_SCROLLBAR_RIGHT (ES_STYLE_CAST(1355)) +define_private ES_STYLE_PUSH_BUTTON_SCROLLBAR_UP (ES_STYLE_CAST(1357)) +define ES_STYLE_PUSH_BUTTON_STATUS_BAR (ES_STYLE_CAST(1495)) +define ES_STYLE_PUSH_BUTTON_TOOLBAR (ES_STYLE_CAST(1359)) +define ES_STYLE_PUSH_BUTTON_TOOLBAR_BIG (ES_STYLE_CAST(1457)) +define ES_STYLE_PUSH_BUTTON_TOOLBAR_MEDIUM (ES_STYLE_CAST(1461)) +define_private ES_STYLE_SCROLLBAR_BAR_HORIZONTAL (ES_STYLE_CAST(1363)) +define_private ES_STYLE_SCROLLBAR_BAR_VERTICAL (ES_STYLE_CAST(1365)) +define_private ES_STYLE_SCROLLBAR_THUMB_HORIZONTAL (ES_STYLE_CAST(1367)) +define_private ES_STYLE_SCROLLBAR_THUMB_VERTICAL (ES_STYLE_CAST(1369)) +define_private ES_STYLE_SCROLLBAR_PAD (ES_STYLE_CAST(1371)) +define ES_STYLE_SEPARATOR_HORIZONTAL (ES_STYLE_CAST(1373)) +define_private ES_STYLE_SPLIT_BAR_HORIZONTAL (ES_STYLE_CAST(1375)) +define_private ES_STYLE_SPLIT_BAR_VERTICAL (ES_STYLE_CAST(1377)) +define_private ES_STYLE_TASK_BAR_BAR (ES_STYLE_CAST(1379)) +define_private ES_STYLE_TASK_BAR_BUTTON (ES_STYLE_CAST(1381)) +define_private ES_STYLE_TASK_BAR_EXTRA (ES_STYLE_CAST(1507)) +define_private ES_STYLE_TASK_BAR_NEW_WINDOW (ES_STYLE_CAST(1383)) +define ES_STYLE_TEXT_HEADING0 (ES_STYLE_CAST(1387)) +define ES_STYLE_TEXT_HEADING2 (ES_STYLE_CAST(1389)) +define_private ES_STYLE_TEXT_HEADING3 (ES_STYLE_CAST(1423)) +define ES_STYLE_TEXT_LABEL (ES_STYLE_CAST(1391)) +define ES_STYLE_TEXT_LABEL_INVERTED (ES_STYLE_CAST(1393)) +define ES_STYLE_TEXT_LABEL_SECONDARY (ES_STYLE_CAST(1395)) +define ES_STYLE_TEXT_PARAGRAPH (ES_STYLE_CAST(1397)) +define ES_STYLE_TEXT_TOOLBAR (ES_STYLE_CAST(1553)) +define ES_STYLE_TEXTBOX_BORDERED_MULTILINE (ES_STYLE_CAST(1399)) +define ES_STYLE_TEXTBOX_BORDERED_SINGLE (ES_STYLE_CAST(1401)) +define ES_STYLE_TEXTBOX_BORDERED_SINGLE_COMPACT (ES_STYLE_CAST(1403)) +define_private ES_STYLE_TEXTBOX_INLINE (ES_STYLE_CAST(1477)) +define_private ES_STYLE_TEXTBOX_MARGIN (ES_STYLE_CAST(1415)) +define ES_STYLE_TEXTBOX_NO_BORDER (ES_STYLE_CAST(1405)) +define ES_STYLE_TEXTBOX_TRANSPARENT (ES_STYLE_CAST(1445)) +define_private ES_STYLE_WINDOW_TAB_ACTIVE (ES_STYLE_CAST(1407)) +define_private ES_STYLE_WINDOW_TAB_CLOSE_BUTTON (ES_STYLE_CAST(1469)) +define_private ES_STYLE_WINDOW_TAB_INACTIVE (ES_STYLE_CAST(1409)) +define_private ES_STYLE_WINDOW_TAB_BAND (ES_STYLE_CAST(1411)) +define_private ES_STYLE_WINDOW_TAB_BAND_NEW (ES_STYLE_CAST(1361)) diff --git a/desktop/syscall.cpp b/desktop/syscall.cpp new file mode 100644 index 0000000..f5f4eb1 --- /dev/null +++ b/desktop/syscall.cpp @@ -0,0 +1,658 @@ +ThreadLocalStorage *GetThreadLocalStorage() { + return (ThreadLocalStorage *) ProcessorTLSRead(tlsStorageOffset); +} + +double EsTimeStampMs() { + if (!api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND]) { + return 0; + } else { + return (double) EsTimeStamp() / api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] / 1000; + } +} + +void *EsMemoryReserve(size_t size, EsMemoryProtection protection, uint32_t flags) { + intptr_t result = EsSyscall(ES_SYSCALL_MEMORY_ALLOCATE, size, flags, protection, 0); + + if (result >= 0) { + return (void *) result; + } else { + return nullptr; + } +} + +void EsMemoryUnreserve(void *address, size_t size) { + EsSyscall(ES_SYSCALL_MEMORY_FREE, (uintptr_t) address, size, 0, 0); +} + +bool EsMemoryCommit(void *pointer, size_t bytes) { + EsAssert(((uintptr_t) pointer & (ES_PAGE_SIZE - 1)) == 0 && (bytes & (ES_PAGE_SIZE - 1)) == 0); // Misaligned pointer/bytes in EsMemoryCommit. + return ES_SUCCESS == (intptr_t) EsSyscall(ES_SYSCALL_MEMORY_COMMIT, (uintptr_t) pointer >> ES_PAGE_BITS, bytes >> ES_PAGE_BITS, 0, 0); +} + +void EsMemoryFaultRange(const void *pointer, size_t bytes, uint32_t flags) { + EsSyscall(ES_SYSCALL_MEMORY_FAULT_RANGE, (uintptr_t) pointer, bytes, flags, 0); +} + +bool EsMemoryDecommit(void *pointer, size_t bytes) { + EsAssert(((uintptr_t) pointer & (ES_PAGE_SIZE - 1)) == 0 && (bytes & (ES_PAGE_SIZE - 1)) == 0); // Misaligned pointer/bytes in EsMemoryDecommit. + return ES_SUCCESS == (intptr_t) EsSyscall(ES_SYSCALL_MEMORY_COMMIT, (uintptr_t) pointer >> ES_PAGE_BITS, bytes >> ES_PAGE_BITS, 1, 0); +} + +EsError EsProcessCreate(EsProcessCreationArguments *arguments, EsProcessInformation *information) { + EsProcessInformation _information; + if (!information) information = &_information; + + EsError error = EsSyscall(ES_SYSCALL_PROCESS_CREATE, (uintptr_t) arguments, 0, (uintptr_t) information, 0); + + if (error == ES_SUCCESS && information == &_information) { + EsHandleClose(information->handle); + EsHandleClose(information->mainThread.handle); + } + + return error; +} + +EsError EsMessagePost(EsElement *target, EsMessage *message) { + EsMutexAcquire(&api.postBoxMutex); + + _EsMessageWithObject m = { target, *message }; + bool success = api.postBox.Add(m); + + if (api.postBox.Length() == 1 && success) { + EsMessage m; + m.type = ES_MSG_WAKEUP; + success = ES_SUCCESS == (EsError) EsSyscall(ES_SYSCALL_MESSAGE_POST, (uintptr_t) &m, 0, ES_CURRENT_PROCESS, 0); + } + + EsMutexRelease(&api.postBoxMutex); + + return success ? ES_SUCCESS : ES_ERROR_INSUFFICIENT_RESOURCES; +} + +EsError EsMessagePostRemote(EsHandle process, EsMessage *message) { + return EsSyscall(ES_SYSCALL_MESSAGE_POST, (uintptr_t) message, 0, process, 0); +} + +EsHandle EsEventCreate(bool autoReset) { + return EsSyscall(ES_SYSCALL_EVENT_CREATE, autoReset, 0, 0, 0); +} + +void EsEventSet(EsHandle handle) { + EsSyscall(ES_SYSCALL_EVENT_SET, handle, 0, 0, 0); +} + +void EsEventReset(EsHandle handle) { + EsSyscall(ES_SYSCALL_EVENT_RESET, handle, 0, 0, 0); +} + +EsError EsHandleClose(EsHandle handle) { + return EsSyscall(ES_SYSCALL_HANDLE_CLOSE, handle, 0, 0, 0); +} + +void EsThreadTerminate(EsHandle thread) { + EsSyscall(ES_SYSCALL_THREAD_TERMINATE, thread, 0, 0, 0); +} + +void EsProcessTerminate(EsHandle process, int status) { + EsSyscall(ES_SYSCALL_PROCESS_TERMINATE, process, status, 0, 0); +} + +void EsProcessTerminateCurrent() { + EsSyscall(ES_SYSCALL_PROCESS_TERMINATE, ES_CURRENT_PROCESS, 0, 0, 0); +} + +int EsProcessGetExitStatus(EsHandle process) { + return EsSyscall(ES_SYSCALL_PROCESS_GET_STATUS, process, 0, 0, 0); +} + +void ThreadInitialise(); + +void ThreadEntry(EsGeneric argument, EsThreadEntryFunction entryFunction) { + ThreadInitialise(); + entryFunction(argument); + EsThreadTerminate(ES_CURRENT_THREAD); +} + +EsError EsThreadCreate(EsThreadEntryFunction entryFunction, EsThreadInformation *information, EsGeneric argument) { + EsThreadInformation discard = {}; + + if (!information) { + information = &discard; + } + + EsError error = EsSyscall(ES_SYSCALL_THREAD_CREATE, (uintptr_t) ThreadEntry, (uintptr_t) entryFunction, (uintptr_t) information, argument.u); + + if (error == ES_SUCCESS && information == &discard) { + EsHandleClose(information->handle); + } + + return error; +} + +EsError EsFileWriteAll(const char *filePath, ptrdiff_t filePathLength, const void *data, size_t sizes) { + return EsFileWriteAllGather(filePath, filePathLength, &data, &sizes, 1); +} + +EsError EsFileWriteAllGather(const char *filePath, ptrdiff_t filePathLength, const void **data, size_t *sizes, size_t gatherCount) { + if (filePathLength == -1) { + filePathLength = EsCStringLength(filePath); + } + + EsFileInformation information = EsFileOpen((char *) filePath, filePathLength, ES_FILE_WRITE_EXCLUSIVE | ES_NODE_CREATE_DIRECTORIES); + + if (ES_SUCCESS != information.error) { + return information.error; + } + + EsError error = EsFileWriteAllGatherFromHandle(information.handle, data, sizes, gatherCount); + EsHandleClose(information.handle); + return error; +} + +EsError EsFileWriteAllFromHandle(EsHandle handle, const void *data, size_t sizes) { + return EsFileWriteAllGatherFromHandle(handle, &data, &sizes, 1); +} + +EsError EsFileWriteAllGatherFromHandle(EsHandle handle, const void **data, size_t *sizes, size_t gatherCount) { + size_t fileSize = 0; + + for (uintptr_t i = 0; i < gatherCount; i++) { + fileSize += sizes[i]; + } + + EsError error = EsFileResize(handle, fileSize); + if (ES_CHECK_ERROR(error)) return error; + + size_t offset = 0; + + for (uintptr_t i = 0; i < gatherCount; i++) { + error = EsFileWriteSync(handle, offset, sizes[i], data[i]); + if (ES_CHECK_ERROR(error)) return error; + offset += sizes[i]; + } + + error = EsFileControl(handle, ES_FILE_CONTROL_NOTIFY_MONITORS | ES_FILE_CONTROL_FLUSH); + return error; +} + +void *EsFileReadAllFromHandle(EsHandle handle, size_t *fileSize, EsError *error) { + if (error) *error = ES_SUCCESS; + EsFileOffset size = EsFileGetSize(handle); + if (fileSize) *fileSize = size; + +#ifdef KERNEL + void *buffer = EsHeapAllocate(size + 1, false, K_PAGED); +#else + void *buffer = EsHeapAllocate(size + 1, false); +#endif + + if (!buffer) { + if (error) *error = ES_ERROR_INSUFFICIENT_RESOURCES; + return nullptr; + } + + ((char *) buffer)[size] = 0; + + uintptr_t result = EsFileReadSync(handle, 0, size, buffer); + + if (size != result) { +#ifdef KERNEL + EsHeapFree(buffer, size + 1, K_PAGED); +#else + EsHeapFree(buffer); +#endif + buffer = nullptr; + if (error) *error = (EsError) result; + } + + return buffer; +} + +void *EsFileReadAll(const char *filePath, ptrdiff_t filePathLength, size_t *fileSize, EsError *error) { + if (error) *error = ES_SUCCESS; + EsFileInformation information = EsFileOpen((char *) filePath, filePathLength, ES_FILE_READ | ES_NODE_FAIL_IF_NOT_FOUND); + + if (ES_SUCCESS != information.error) { + if (error) *error = information.error; + return nullptr; + } + + void *buffer = EsFileReadAllFromHandle(information.handle, fileSize); + EsHandleClose(information.handle); + return buffer; +} + +EsHandle EsMemoryOpen(size_t size, const char *name, ptrdiff_t nameLength, unsigned flags) { + if (nameLength == -1) nameLength = EsCStringLength(name); + return EsSyscall(ES_SYSCALL_MEMORY_OPEN, size, (uintptr_t) name, nameLength, flags); +} + +EsHandle EsMemoryShare(EsHandle sharedMemoryRegion, EsHandle targetProcess, bool readOnly) { + return EsSyscall(ES_SYSCALL_MEMORY_SHARE, sharedMemoryRegion, targetProcess, readOnly, 0); +} + +void *EsObjectMap(EsHandle sharedMemoryRegion, uintptr_t offset, size_t size, unsigned flags) { + intptr_t result = EsSyscall(ES_SYSCALL_MEMORY_MAP_OBJECT, sharedMemoryRegion, offset, size, flags); + + if (result >= 0) { + return (void *) result; + } else { + return nullptr; + } +} + +EsFileInformation EsFileOpen(const char *path, ptrdiff_t pathLength, uint32_t flags) { + if (pathLength == -1) { + pathLength = EsCStringLength(path); + } + + _EsNodeInformation node; + EsError result = NodeOpen(path, pathLength, flags, &node); + + if (result == ES_SUCCESS && node.type == ES_NODE_DIRECTORY) { + result = ES_ERROR_INCORRECT_NODE_TYPE; + EsHandleClose(node.handle); + } + + EsFileInformation information = {}; + + if (result == ES_SUCCESS) { + information.handle = node.handle; + information.size = node.fileSize; + } + + information.error = result; + return information; +} + +size_t EsFileReadSync(EsHandle handle, EsFileOffset offset, size_t size, void *buffer) { + intptr_t result = EsSyscall(ES_SYSCALL_FILE_READ_SYNC, handle, offset, size, (uintptr_t) buffer); + return result; +} + +size_t EsFileWriteSync(EsHandle handle, EsFileOffset offset, size_t size, const void *buffer) { + intptr_t result = EsSyscall(ES_SYSCALL_FILE_WRITE_SYNC, handle, offset, size, (uintptr_t) buffer); + return result; +} + +EsFileOffset EsFileGetSize(EsHandle handle) { + return EsSyscall(ES_SYSCALL_FILE_GET_SIZE, handle, 0, 0, 0); +} + +EsError EsFileResize(EsHandle handle, EsFileOffset newSize) { + return EsSyscall(ES_SYSCALL_FILE_RESIZE, handle, newSize, 0, 0); +} + +void *EsFileStoreReadAll(EsFileStore *file, size_t *fileSize) { + if (file->error != ES_SUCCESS) return nullptr; + + if (file->type == FILE_STORE_HANDLE) { + return EsFileReadAllFromHandle(file->handle, fileSize, &file->error); + } else if (file->type == FILE_STORE_PATH) { + return EsFileReadAll(file->path, file->pathBytes, fileSize, &file->error); + } else { + EsAssert(false); + return nullptr; + } +} + +bool EsFileStoreWriteAll(EsFileStore *file, const void *data, size_t dataBytes) { + if (file->error == ES_SUCCESS) { + if (file->type == FILE_STORE_HANDLE) { + file->error = EsFileWriteAllFromHandle(file->handle, data, dataBytes); + } else if (file->type == FILE_STORE_PATH) { + file->error = EsFileWriteAll(file->path, file->pathBytes, data, dataBytes); + } else { + EsAssert(false); + } + } + + return file->error == ES_SUCCESS; +} + +EsFileOffsetDifference EsFileStoreGetSize(EsFileStore *file) { + if (file->type == FILE_STORE_HANDLE) { + return EsFileGetSize(file->handle); + } else if (file->type == FILE_STORE_PATH) { + EsDirectoryChild information; + + if (EsPathQueryInformation(file->path, file->pathBytes, &information)) { + return file->pathBytes; + } else { + return -1; + } + } else { + EsAssert(false); + return 0; + } +} + +void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flags) { + if (file->type == FILE_STORE_HANDLE) { + EsFileOffsetDifference size = EsFileStoreGetSize(file); + if (size == -1) return nullptr; + *fileSize = size; + return EsObjectMap(file->handle, 0, size, flags); + } else if (file->type == FILE_STORE_PATH) { + return EsFileMap(file->path, file->pathBytes, fileSize, flags); + } else { + EsAssert(false); + return nullptr; + } +} + +uintptr_t EsWait(EsHandle *handles, size_t count, uintptr_t timeoutMs) { + return EsSyscall(ES_SYSCALL_WAIT, (uintptr_t) handles, count, timeoutMs, 0); +} + +void EsProcessPause(EsHandle process, bool resume) { + EsSyscall(ES_SYSCALL_PROCESS_PAUSE, process, resume, 0, 0); +} + +uint64_t EsThreadGetID(EsHandle thread) { + if (thread == ES_CURRENT_THREAD) { + return GetThreadLocalStorage()->id; + } else { + return EsSyscall(ES_SYSCALL_THREAD_GET_ID, thread, 0, 0, 0); + } +} + +uintptr_t EsProcessGetID(EsHandle process) { + return EsSyscall(ES_SYSCALL_THREAD_GET_ID, process, 0, 0, 0); +} + +ptrdiff_t EsDirectoryEnumerateChildrenFromHandle(EsHandle directory, EsDirectoryChild *buffer, size_t size) { + if (!size) return 0; + return EsSyscall(ES_SYSCALL_DIRECTORY_ENUMERATE, directory, (uintptr_t) buffer, size, 0); +} + +#ifndef KERNEL +ptrdiff_t EsDirectoryEnumerateChildren(const char *path, ptrdiff_t pathBytes, EsDirectoryChild **buffer) { + *buffer = nullptr; + if (pathBytes == -1) pathBytes = EsCStringLength(path); + + _EsNodeInformation node; + EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_NODE_DIRECTORY, &node); + if (error != ES_SUCCESS) return error; + + if (node.directoryChildren == ES_DIRECTORY_CHILDREN_UNKNOWN) { + node.directoryChildren = 4194304 / sizeof(EsDirectoryChild); // TODO Grow the buffer until all entries fit. + } + + *buffer = (EsDirectoryChild *) EsHeapAllocate(sizeof(EsDirectoryChild) * node.directoryChildren, true); + + ptrdiff_t result = EsDirectoryEnumerateChildrenFromHandle(node.handle, *buffer, node.directoryChildren); + if (ES_CHECK_ERROR(result)) { EsHeapFree(*buffer); *buffer = nullptr; } + + EsHandleClose(node.handle); + return result; +} +#endif + +void EsBatch(EsBatchCall *calls, size_t count) { +#if 0 + for (uintptr_t i = 0; i < count; i++) { + EsBatchCall *call = calls + i; + // ... modify system call for version changes ... + } +#endif + + EsSyscall(ES_SYSCALL_BATCH, (uintptr_t) calls, count, 0, 0); +} + +EsError EsPathDelete(const char *path, ptrdiff_t pathBytes) { + _EsNodeInformation node; + if (pathBytes == -1) pathBytes = EsCStringLength(path); + EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_FILE_WRITE_EXCLUSIVE, &node); + if (ES_CHECK_ERROR(error)) return error; + error = EsSyscall(ES_SYSCALL_NODE_DELETE, node.handle, 0, 0, 0); + EsHandleClose(node.handle); + return error; +} + +void *EsFileMap(const char *path, ptrdiff_t pathBytes, size_t *fileSize, uint32_t flags) { + EsFileInformation information = EsFileOpen(path, pathBytes, + ES_NODE_FAIL_IF_NOT_FOUND | ((flags & ES_MAP_OBJECT_READ_WRITE) ? ES_FILE_WRITE_EXCLUSIVE : ES_FILE_READ)); + + if (ES_CHECK_ERROR(information.error)) { + return nullptr; + } + + void *base = EsObjectMap(information.handle, 0, information.size, flags); + EsHandleClose(information.handle); + if (fileSize) *fileSize = information.size; + return base; +} + +EsError EsPathMove(const char *oldPath, ptrdiff_t oldPathBytes, const char *newPath, ptrdiff_t newPathBytes) { + if (oldPathBytes == -1) oldPathBytes = EsCStringLength(oldPath); + if (newPathBytes == -1) newPathBytes = EsCStringLength(newPath); + + _EsNodeInformation node = {}; + _EsNodeInformation directory = {}; + EsError error; + + error = NodeOpen(oldPath, oldPathBytes, ES_NODE_FAIL_IF_NOT_FOUND, &node); + if (error != ES_SUCCESS) return error; + + uintptr_t s = 0; + for (intptr_t i = 0; i < newPathBytes; i++) if (newPath[i] == '/') s = i + 1; + error = NodeOpen(newPath, s, ES_NODE_DIRECTORY | ES_NODE_FAIL_IF_NOT_FOUND, &directory); + if (error != ES_SUCCESS) { EsHandleClose(node.handle); return error; } + + error = EsSyscall(ES_SYSCALL_NODE_MOVE, node.handle, directory.handle, (uintptr_t) newPath + s, newPathBytes - s); + EsHandleClose(node.handle); + EsHandleClose(directory.handle); + return error; +} + +bool EsPathExists(const char *path, ptrdiff_t pathBytes, EsNodeType *type) { + if (pathBytes == -1) pathBytes = EsCStringLength(path); + _EsNodeInformation node = {}; + EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND, &node); + if (error != ES_SUCCESS) return false; + EsHandleClose(node.handle); + if (type) *type = node.type; + return true; +} + +bool EsPathQueryInformation(const char *path, ptrdiff_t pathBytes, EsDirectoryChild *information) { + if (pathBytes == -1) pathBytes = EsCStringLength(path); + _EsNodeInformation node = {}; + EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND, &node); + if (error != ES_SUCCESS) return false; + EsHandleClose(node.handle); + information->type = node.type; + information->fileSize = node.fileSize; + information->directoryChildren = node.directoryChildren; + return true; +} + +EsError EsPathCreate(const char *path, ptrdiff_t pathBytes, EsNodeType type, bool createLeadingDirectories) { + if (pathBytes == -1) pathBytes = EsCStringLength(path); + _EsNodeInformation node = {}; + EsError error = NodeOpen(path, pathBytes, + ES_NODE_FAIL_IF_FOUND | type | (createLeadingDirectories ? ES_NODE_CREATE_DIRECTORIES : 0), + &node); + if (error != ES_SUCCESS) return error; + EsHandleClose(node.handle); + return ES_SUCCESS; +} + +EsError EsFileControl(EsHandle file, uint32_t flags) { + return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, flags, 0, 0); +} + +void EsConstantBufferRead(EsHandle buffer, void *output) { + EsSyscall(ES_SYSCALL_CONSTANT_BUFFER_READ, buffer, (uintptr_t) output, 0, 0); +} + +void EsProcessGetState(EsHandle process, EsProcessState *state) { + EsSyscall(ES_SYSCALL_PROCESS_GET_STATE, process, (uintptr_t) state, 0, 0); +} + +void EsSchedulerYield() { + EsSyscall(ES_SYSCALL_YIELD_SCHEDULER, 0, 0, 0, 0); +} + +void EsSleep(uint64_t milliseconds) { + EsSyscall(ES_SYSCALL_SLEEP, milliseconds >> 32, milliseconds & 0xFFFFFFFF, 0, 0); +} + +EsHandle EsTakeSystemSnapshot(int type, size_t *bufferSize) { + return EsSyscall(ES_SYSCALL_SYSTEM_TAKE_SNAPSHOT, type, (uintptr_t) bufferSize, 0, 0); +} + +EsHandle EsProcessOpen(uint64_t pid) { + // TODO This won't work correctly if arguments to system call are 32-bit. + return EsSyscall(ES_SYSCALL_PROCESS_OPEN, pid, 0, 0, 0); +} + +#ifndef KERNEL +EsHandle EsConstantBufferShare(EsHandle constantBuffer, EsHandle targetProcess) { + return EsSyscall(ES_SYSCALL_CONSTANT_BUFFER_SHARE, constantBuffer, targetProcess, 0, 0); +} + +EsHandle EsConstantBufferCreate(const void *data, size_t dataBytes, EsHandle targetProcess) { + return EsSyscall(ES_SYSCALL_CONSTANT_BUFFER_CREATE, (uintptr_t) data, targetProcess, dataBytes, 0); +} + +size_t EsConstantBufferGetSize(EsHandle buffer) { + return EsSyscall(ES_SYSCALL_CONSTANT_BUFFER_READ, buffer, 0, 0, 0); +} +#endif + +EsError EsAddressResolve(const char *domain, ptrdiff_t domainBytes, uint32_t flags, EsAddress *address) { + return EsSyscall(ES_SYSCALL_DOMAIN_NAME_RESOLVE, (uintptr_t) domain, domainBytes, (uintptr_t) address, flags); +} + +EsError EsConnectionOpen(EsConnection *connection, uint32_t flags) { + connection->error = ES_SUCCESS; + connection->open = false; + + EsError error = EsSyscall(ES_SYSCALL_CONNECTION_OPEN, (uintptr_t) connection, flags, 0, 0); + + if (error == ES_SUCCESS && (flags & ES_CONNECTION_OPEN_WAIT)) { + while (!connection->open && connection->error == ES_SUCCESS) { + EsConnectionPoll(connection); + } + + return connection->error; + } else { + return error; + } +} + +void EsConnectionPoll(EsConnection *connection) { + EsSyscall(ES_SYSCALL_CONNECTION_POLL, (uintptr_t) connection, 0, 0, connection->handle); +} + +void EsConnectionNotify(EsConnection *connection) { + EsSyscall(ES_SYSCALL_CONNECTION_NOTIFY, 0, connection->sendWritePointer, connection->receiveReadPointer, connection->handle); +} + +void EsConnectionClose(EsConnection *connection) { + EsObjectUnmap(connection->sendBuffer); + EsHandleClose(connection->handle); +} + +EsError EsConnectionWriteSync(EsConnection *connection, const void *_data, size_t dataBytes) { + const uint8_t *data = (const uint8_t *) _data; + + while (dataBytes) { + EsConnectionPoll(connection); + + if (connection->error != ES_SUCCESS) { + return connection->error; + } + + size_t space = connection->sendWritePointer >= connection->sendReadPointer + ? connection->sendBufferBytes - connection->sendWritePointer + : connection->sendReadPointer - connection->sendWritePointer - 1; + + if (!space) { + continue; + } + + size_t bytesToWrite = space > dataBytes ? dataBytes : space; + EsMemoryCopy(connection->sendBuffer + connection->sendWritePointer, data, bytesToWrite); + data += bytesToWrite, dataBytes -= bytesToWrite; + connection->sendWritePointer = (connection->sendWritePointer + bytesToWrite) % connection->sendBufferBytes; + EsConnectionNotify(connection); + } + + return ES_SUCCESS; +} + +EsError EsConnectionRead(EsConnection *connection, void *_buffer, size_t bufferBytes, size_t *bytesRead) { + uint8_t *buffer = (uint8_t *) _buffer; + *bytesRead = 0; + + EsConnectionPoll(connection); + + if (connection->error != ES_SUCCESS) { + return connection->error; + } + + while (bufferBytes && connection->receiveReadPointer != connection->receiveWritePointer) { + size_t bytesAvailable = connection->receiveReadPointer > connection->receiveWritePointer + ? connection->receiveBufferBytes - connection->receiveReadPointer + : connection->receiveWritePointer - connection->receiveReadPointer; + size_t bytesToRead = bufferBytes > bytesAvailable ? bytesAvailable : bufferBytes; + EsMemoryCopy(buffer, connection->receiveBuffer + connection->receiveReadPointer, bytesToRead); + connection->receiveReadPointer = (connection->receiveReadPointer + bytesToRead) % connection->receiveBufferBytes; + buffer += bytesToRead, bufferBytes -= bytesToRead; + *bytesRead += bytesToRead; + EsConnectionNotify(connection); + } + + return ES_SUCCESS; +} + +void EsEventForward(EsHandle event, EsHandle eventSink, EsGeneric data) { + EsSyscall(ES_SYSCALL_EVENT_FORWARD, event, eventSink, data.u, 0); +} + +EsHandle EsEventSinkCreate(bool ignoreDuplicates) { + return EsSyscall(ES_SYSCALL_EVENT_SINK_CREATE, ignoreDuplicates, 0, 0, 0); +} + +EsError EsEventSinkPop(EsHandle eventSink, EsGeneric *data) { + EsGeneric unused; if (!data) data = &unused; + return EsSyscall(ES_SYSCALL_EVENT_SINK_POP, eventSink, (uintptr_t) data, 0, 0); +} + +EsError EsEventSinkPush(EsHandle eventSink, EsGeneric data) { + return EsSyscall(ES_SYSCALL_EVENT_SINK_PUSH, eventSink, data.u, 0, 0); +} + +size_t EsGameControllerStatePoll(EsGameControllerState *buffer) { + return EsSyscall(ES_SYSCALL_GAME_CONTROLLER_STATE_POLL, (uintptr_t) buffer, 0, 0, 0); +} + +#define CLIPBOARD_FORMAT_TEXT (1) + +EsError EsClipboardAddText(EsClipboard clipboard, const char *text, ptrdiff_t textBytes) { + EsMessageMutexCheck(); + + if (textBytes == -1) { + textBytes = EsCStringLength(text); + } + + return EsSyscall(ES_SYSCALL_CLIPBOARD_ADD, clipboard, CLIPBOARD_FORMAT_TEXT, (uintptr_t) text, textBytes); +} + +bool EsClipboardHasText(EsClipboard clipboard) { + return EsSyscall(ES_SYSCALL_CLIPBOARD_HAS, clipboard, CLIPBOARD_FORMAT_TEXT, 0, 0); +} + +char *EsClipboardReadText(EsClipboard clipboard, size_t *bytes) { + *bytes = 0; + EsHandle handle = EsSyscall(ES_SYSCALL_CLIPBOARD_READ, clipboard, CLIPBOARD_FORMAT_TEXT, 0, (uintptr_t) bytes); + if (handle == ES_INVALID_HANDLE) return nullptr; + char *buffer = (char *) EsHeapAllocate(*bytes, false); + if (!buffer) return nullptr; + EsConstantBufferRead(handle, buffer); + EsHandleClose(handle); + return buffer; +} diff --git a/desktop/text.cpp b/desktop/text.cpp new file mode 100644 index 0000000..51345ab --- /dev/null +++ b/desktop/text.cpp @@ -0,0 +1,4984 @@ +#if defined(TEXT_RENDERER) + +// TODO Fallback VGA font. +// TODO If the font size is sufficiently large disable subpixel anti-aliasing. +// TODO Variable font support. + +#ifdef USE_HARFBUZZ +#include +#include +#define HB_SHAPE(plan, features, featureCount) hb_shape(plan->font.hb, plan->buffer, features, featureCount) +#endif + +#ifdef USE_FREETYPE +#include +#include FT_FREETYPE_H +#include +#endif + +#define FREETYPE_UNIT_SCALE (64) + +#define FALLBACK_SCRIPT_LANGUAGE ("en") +#define FALLBACK_SCRIPT (0x4C61746E) // "Latn" + +struct Font { +#ifdef USE_FREETYPE + FT_Face ft; +#else + float scale; + const BasicFontHeader *header; +#endif + +#ifdef USE_HARFBUZZ + hb_font_t *hb; +#endif +}; + +struct GlyphCacheKey { + uint32_t glyphIndex; + uint16_t size; + uint16_t fractionalPosition; + Font font; +}; + +struct GlyphCacheEntry { + uint8_t *data; + size_t dataBytes; + int width, height, xoff, yoff; + int type; + + LinkedItem itemLRU; + GlyphCacheKey key; +}; + +struct FontSubstitutionKey { + EsFontFamily family; + uint16_t _unused0; + uint32_t script; +}; + +struct FontDatabaseEntry : EsFontInformation { + EsFileStore *files[18]; + char *scripts; + size_t scriptsBytes; +}; + +struct { + // Database. + HashStore substitutions; + Array database; + uintptr_t sans, serif, monospaced, fallback; + char *sansName, *serifName, *monospacedName, *fallbackName; + + // Rendering. +#ifdef USE_FREETYPE + FT_Library freetypeLibrary; +#endif + + // Caching. + HashStore loaded; // TODO How many fonts to keep loaded? Reference counting? +#define GLYPH_CACHE_MAX_SIZE (4194304) + HashStore glyphCache; + LinkedList glyphCacheLRU; + size_t glyphCacheBytes; +} fontManagement; + +struct { + EsBuffer pack; + const uint8_t *standardPack; + size_t standardPackSize; + char *buffer; + size_t bufferPosition, bufferAllocated; +} iconManagement; + +Font FontGet(EsFont key); + +// --------------------------------- Glyph cache. + +void RegisterGlyphCacheEntry(GlyphCacheKey key, GlyphCacheEntry *entry) { + entry->itemLRU.thisItem = entry; + entry->key = key; + *fontManagement.glyphCache.Put(&key) = entry; + fontManagement.glyphCacheLRU.InsertStart(&entry->itemLRU); + + fontManagement.glyphCacheBytes += entry->dataBytes; + + while (fontManagement.glyphCacheBytes > GLYPH_CACHE_MAX_SIZE) { + GlyphCacheEntry *leastRecentlyUsedGlyph = fontManagement.glyphCacheLRU.lastItem->thisItem; + fontManagement.glyphCacheLRU.Remove(&leastRecentlyUsedGlyph->itemLRU); + fontManagement.glyphCache.Delete(&leastRecentlyUsedGlyph->key); + EsAssert(fontManagement.glyphCacheBytes >= entry->dataBytes); // Negative glyph cache bytes. + fontManagement.glyphCacheBytes -= entry->dataBytes; + EsHeapFree(leastRecentlyUsedGlyph->data); + EsHeapFree(leastRecentlyUsedGlyph); + } +} + +GlyphCacheEntry *LookupGlyphCacheEntry(GlyphCacheKey key) { + GlyphCacheEntry *entry = fontManagement.glyphCache.Get1(&key); + + if (!entry) { + return (GlyphCacheEntry *) EsHeapAllocate(sizeof(GlyphCacheEntry), true); + } else { + fontManagement.glyphCacheLRU.Remove(&entry->itemLRU); + fontManagement.glyphCacheLRU.InsertStart(&entry->itemLRU); + return entry; + } +} + +// --------------------------------- Font renderer. + +bool FontLoad(Font *font, const void *data, size_t dataBytes) { +#ifdef USE_FREETYPE + if (!fontManagement.freetypeLibrary) { + FT_Init_FreeType(&fontManagement.freetypeLibrary); + } + + if (FT_New_Memory_Face(fontManagement.freetypeLibrary, (uint8_t *) data, dataBytes, 0, &font->ft)) { + return false; + } +#else + if (dataBytes < sizeof(BasicFontHeader)) { + return false; + } + + const BasicFontHeader *header = (const BasicFontHeader *) data; + + if (header->signature != BASIC_FONT_SIGNATURE + || (dataBytes < sizeof(BasicFontHeader) + + header->glyphCount * sizeof(BasicFontGlyph) + + header->kerningEntries * sizeof(BasicFontKerningEntry))) { + return false; + } + + const BasicFontGlyph *glyphs = (const BasicFontGlyph *) (header + 1); + + for (uintptr_t i = 0; i < header->glyphCount; i++) { + if (dataBytes <= glyphs[i].offsetToPoints + || dataBytes < glyphs[i].offsetToPoints + glyphs[i].pointCount * 24) { + return false; + } + } + + font->header = header; +#endif + +#ifdef USE_HARFBUZZ + font->hb = hb_ft_font_create(font->ft, nullptr); +#endif + + return true; +} + +void FontSetSize(Font *font, uint32_t size) { +#ifdef USE_FREETYPE + FT_Set_Char_Size(font->ft, 0, size * FREETYPE_UNIT_SCALE, 100, 100); +#else + font->scale = 1.75f * (float) size / (font->header->ascender - font->header->descender); +#endif + +#ifdef USE_HARFBUZZ + hb_ft_font_changed(font->hb); +#endif +} + +uint32_t FontCodepointToGlyphIndex(Font *font, uint32_t codepoint) { +#ifdef USE_FREETYPE + return FT_Get_Char_Index(font->ft, codepoint); +#else + const BasicFontGlyph *glyphs = (const BasicFontGlyph *) (font->header + 1); + + for (uintptr_t i = 0; i < font->header->glyphCount; i++) { + if (glyphs[i].codepoint == codepoint) { + return i; + } + } + + return 0; +#endif +} + +void FontGetGlyphMetrics(Font *font, uint32_t glyphIndex, uint32_t *xAdvance, uint32_t *yAdvance, uint32_t *xOffset, uint32_t *yOffset) { +#ifdef USE_FREETYPE + FT_Load_Glyph(font->ft, glyphIndex, 0); + *xAdvance = font->ft->glyph->advance.x; + *yAdvance = font->ft->glyph->advance.y; + // *xOffset = font->ft->glyph->bitmap_left; + // *yOffset = font->ft->glyph->bitmap_top; + *xOffset = *yOffset = 0; +#else + const BasicFontGlyph *glyph = ((const BasicFontGlyph *) (font->header + 1)) + glyphIndex; + *xOffset = *yOffset = *yAdvance = 0; + *xAdvance = glyph->xAdvance * font->scale * FREETYPE_UNIT_SCALE; +#endif +} + +int32_t FontGetKerning(Font *font, uint32_t previous, uint32_t next) { +#ifdef USE_FREETYPE + FT_Vector kerning = {}; + if (previous) FT_Get_Kerning(font->ft, previous, next, 0, &kerning); + return kerning.x; +#else + const BasicFontKerningEntry *entries = (const BasicFontKerningEntry *) (((const BasicFontGlyph *) (font->header + 1)) + font->header->glyphCount); + + uintptr_t currentIndex = 0; + bool startFound = false; + ES_MACRO_SEARCH(font->header->kerningEntries, result = previous - entries[index].leftGlyphIndex;, currentIndex, startFound); + int32_t xAdvance = 0; + + if (startFound) { + if (entries[currentIndex].rightGlyphIndex == next) { + xAdvance = entries[currentIndex].xAdvance; + } else if (entries[currentIndex].rightGlyphIndex < next) { + while (currentIndex != font->header->kerningEntries && entries[currentIndex].leftGlyphIndex == previous) { + if (entries[currentIndex].rightGlyphIndex == next) { + xAdvance = entries[currentIndex].xAdvance; + break; + } else { + currentIndex++; + } + } + } else { + while (entries[currentIndex].leftGlyphIndex == previous) { + if (entries[currentIndex].rightGlyphIndex == next) { + xAdvance = entries[currentIndex].xAdvance; + break; + } else if (!currentIndex) { + break; + } else { + currentIndex--; + } + } + } + } + + return xAdvance * FREETYPE_UNIT_SCALE * font->scale; +#endif +} + +int32_t FontGetAscent(Font *font) { +#ifdef USE_FREETYPE + return font->ft->size->metrics.ascender; +#else + return font->header->ascender * font->scale * FREETYPE_UNIT_SCALE; +#endif +} + +int32_t FontGetDescent(Font *font) { +#ifdef USE_FREETYPE + return font->ft->size->metrics.descender; +#else + return font->header->descender * font->scale * FREETYPE_UNIT_SCALE; +#endif +} + +int32_t FontGetEmWidth(Font *font) { +#ifdef USE_FREETYPE + return font->ft->size->metrics.x_ppem; +#else + return font->header->ascender * font->scale; // TODO. +#endif +} + +int EsTextGetLineHeight(const EsTextStyle *textStyle) { + EsMessageMutexCheck(); + Font font = FontGet(textStyle->font); + FontSetSize(&font, textStyle->size); + return (FontGetAscent(&font) - FontGetDescent(&font) + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE; +} + +bool FontRenderGlyph(bool mono, GlyphCacheKey key, GlyphCacheEntry *entry) { +#ifdef USE_FREETYPE + FT_Load_Glyph(key.font.ft, key.glyphIndex, FT_LOAD_DEFAULT); + FT_Outline_Translate(&key.font.ft->glyph->outline, key.fractionalPosition, 0); + + int width; + int height; + int xoff; + int yoff; + uint8_t *output; + + if (mono) { + FT_Render_Glyph(key.font.ft->glyph, FT_RENDER_MODE_MONO); + + FT_Bitmap *bitmap = &key.font.ft->glyph->bitmap; + width = bitmap->width; + height = bitmap->rows; + xoff = key.font.ft->glyph->bitmap_left; + yoff = -key.font.ft->glyph->bitmap_top; + + entry->dataBytes = 1 + (width * height + 7) / 8; + output = (uint8_t *) EsHeapAllocate(entry->dataBytes, true); + + if (!output) { + return false; + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + uintptr_t s = bitmap->pitch * 8 * y + x; + uintptr_t d = width * y + x; + + if (bitmap->buffer[s / 8] & (1 << (7 - (s & 7)))) { + output[d / 8] |= (1 << (d & 7)); + } + } + } + } else { + FT_Render_Glyph(key.font.ft->glyph, FT_RENDER_MODE_LCD); + + FT_Bitmap *bitmap = &key.font.ft->glyph->bitmap; + width = bitmap->width / 3; + height = bitmap->rows; + xoff = key.font.ft->glyph->bitmap_left; + yoff = -key.font.ft->glyph->bitmap_top; + + entry->dataBytes = 1 /*stupid hack for whitespace*/ + width * height * 4; + output = (uint8_t *) EsHeapAllocate(entry->dataBytes, false); + + if (!output) { + return false; + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int32_t r = (int32_t) ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 0]; + int32_t g = (int32_t) ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 1]; + int32_t b = (int32_t) ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 2]; + + // Reduce how noticible the colour fringes are. + // TODO Make this adjustable? + int32_t average = (r + g + b) / 3; + r -= (r - average) / 3; + g -= (g - average) / 3; + b -= (b - average) / 3; + + output[(x + y * width) * 4 + 0] = (uint8_t) r; + output[(x + y * width) * 4 + 1] = (uint8_t) g; + output[(x + y * width) * 4 + 2] = (uint8_t) b; + output[(x + y * width) * 4 + 3] = 0xFF; + + // EsPrint("\tPixel %d, %d: red %X, green %X, blue %X\n", x, y, r, g, b); + } + } + } + + if (output) { + entry->data = output; + entry->width = width; + entry->height = height; + entry->xoff = xoff; + entry->yoff = yoff; + return true; + } + + return false; +#else + EsAssert(!mono); + + const BasicFontGlyph *glyph = ((const BasicFontGlyph *) (key.font.header + 1)) + key.glyphIndex; + uint32_t width = glyph->width * key.font.scale + 2; + uint32_t height = glyph->height * key.font.scale + 2; + + if (width > 4096 || height > 4096) { + return false; + } + + RastSurface surface = {}; + RastPath path = {}; + RastPaint paint = {}; + paint.type = RAST_PAINT_SOLID; + paint.solid.alpha = 1.0f; + + float vertexScale = key.font.scale * (key.font.header->ascender - key.font.header->descender) * 0.01f; + + entry->data = (uint8_t *) EsHeapAllocate(width * height * 4, true); + + if (!entry->data) { + return false; + } + + if (glyph->pointCount) { + float *points = (float *) ((const uint8_t *) key.font.header + glyph->offsetToPoints); + + for (uintptr_t i = 0, j = 0; i < glyph->pointCount * 3; i += 3) { + if ((int) i == glyph->pointCount * 3 - 3 || points[i * 2 + 2] == -1e6) { + RastPathAppendBezier(&path, (RastVertex *) points + j, i - j + 1, { vertexScale, vertexScale }); + RastPathCloseSegment(&path); + j = i + 3; + } + } + + RastPathTranslate(&path, (float) key.fractionalPosition / FREETYPE_UNIT_SCALE - glyph->xOffset * key.font.scale, -glyph->yOffset * key.font.scale); + RastShape shape = RastShapeCreateSolid(&path); + + if (RastSurfaceInitialise(&surface, width, height, false)) { + RastSurfaceFill(surface, shape, paint, false); + RastPathDestroy(&path); + + uint32_t *in = surface.buffer; + uint8_t *out = entry->data; + + for (uintptr_t i = 0; i < height; i++) { + for (uintptr_t j = 0; j < width; j++) { + int32_t a = in[(height - i - 1) * width + j] >> 24; + *out++ = (uint8_t) a; + *out++ = (uint8_t) a; + *out++ = (uint8_t) a; + *out++ = 0xFF; + } + } + } + + RastSurfaceDestroy(&surface); + } + + entry->width = width; + entry->height = height; + entry->xoff = glyph->xOffset * key.font.scale + 0.25f; + entry->yoff = -glyph->yOffset * key.font.scale - height + 0.25f; + + return true; +#endif +} + +// --------------------------------- Font management. + +void FontInitialise() { + if (fontManagement.database.Length()) { + return; + } + + fontManagement.sansName = EsSystemConfigurationReadString(EsLiteral("ui"), EsLiteral("font_sans")); + fontManagement.serifName = EsSystemConfigurationReadString(EsLiteral("ui"), EsLiteral("font_serif")); + fontManagement.monospacedName = EsSystemConfigurationReadString(EsLiteral("ui"), EsLiteral("font_mono")); + fontManagement.fallbackName = EsSystemConfigurationReadString(EsLiteral("ui"), EsLiteral("font_fallback")); + + FontDatabaseEntry nullFont = {}; + fontManagement.database.Add(nullFont); + + for (uintptr_t i = 0; i < api.systemConfigurationGroups.Length(); i++) { + EsSystemConfigurationGroup *g = &api.systemConfigurationGroups[i]; + + if (0 == EsStringCompareRaw(g->sectionClass, g->sectionClassBytes, EsLiteral("font"))) { + if (0 == EsStringCompareRaw(g->section, g->sectionBytes, EsLiteral(fontManagement.sansName))) { + fontManagement.sans = fontManagement.database.Length(); + } + + if (0 == EsStringCompareRaw(g->section, g->sectionBytes, EsLiteral(fontManagement.serifName))) { + fontManagement.serif = fontManagement.database.Length(); + } + + if (0 == EsStringCompareRaw(g->section, g->sectionBytes, EsLiteral(fontManagement.monospacedName))) { + fontManagement.monospaced = fontManagement.database.Length(); + } + + if (0 == EsStringCompareRaw(g->section, g->sectionBytes, EsLiteral(fontManagement.fallbackName))) { + fontManagement.fallback = fontManagement.database.Length(); + } + + FontDatabaseEntry entry = {}; + + entry.nameBytes = MinimumInteger(g->sectionBytes, sizeof(entry.name)); + EsMemoryCopy(entry.name, g->section, entry.nameBytes); + entry.id = fontManagement.database.Length(); + + for (uintptr_t i = 0; i < g->itemCount; i++) { + EsSystemConfigurationItem *item = g->items + i; + + if (0 == EsStringCompareRaw(item->key, item->keyBytes, EsLiteral("category"))) { + entry.categoryBytes = MinimumInteger(item->valueBytes, sizeof(entry.category)); + EsMemoryCopy(entry.category, item->value, entry.categoryBytes); + } else if (0 == EsStringCompareRaw(item->key, item->keyBytes, EsLiteral("scripts"))) { + entry.scripts = item->value; + entry.scriptsBytes = item->valueBytes; + } else if ((item->keyBytes == 2 && item->key[0] == '.' && EsCRTisdigit(item->key[1])) + || (item->keyBytes == 3 && item->key[0] == '.' && EsCRTisdigit(item->key[1]) && item->key[2] == 'i') ) { + int weight = item->key[1] - '0'; + bool italic = item->keyBytes == 3; + + if (italic) { + entry.availableWeightsItalic |= 1 << weight; + } else { + entry.availableWeightsNormal |= 1 << weight; + } + + size_t fileIndex = weight - 1 + italic * 9; + entry.files[fileIndex] = FileStoreCreateFromPath(item->value, item->valueBytes); + } + } + + fontManagement.database.Add(entry); + } + } +} + +EsFontFamily FontGetStandardFamily(EsFontFamily family) { + FontInitialise(); + + if (family == 0 || family == ES_FONT_SANS) { + return fontManagement.sans ?: fontManagement.fallback; + } else if (family == ES_FONT_SERIF) { + return fontManagement.serif ?: fontManagement.fallback; + } else if (family == ES_FONT_MONOSPACED) { + return fontManagement.monospaced ?: fontManagement.fallback; + } else { + return family; + } +} + +bool EsFontDatabaseLookupByID(EsFontFamily id, EsFontInformation *information) { + FontInitialise(); + EsMemoryZero(information, sizeof(EsFontInformation)); + + id = FontGetStandardFamily(id); + + if (id >= fontManagement.database.Length()) { + return false; + } + + EsMemoryCopy(information, &fontManagement.database[id], sizeof(EsFontInformation)); + + return true; +} + +EsFontFamily EsFontDatabaseInsertFile(const EsFontInformation *information, EsFileStore *store) { + FontInitialise(); + + EsAssert(store->handles); + store->handles++; + + FontDatabaseEntry *entry = nullptr; + + if (information->nameBytes) { + for (uintptr_t i = 1; i < fontManagement.database.Length(); i++) { + FontDatabaseEntry *entry = &fontManagement.database[i]; + EsAssert(entry->id == i); + + if (0 == EsStringCompareRaw(information->name, information->nameBytes, + fontManagement.database[i].name, fontManagement.database[i].nameBytes)) { + if ((information->availableWeightsItalic & entry->availableWeightsItalic) + || (information->availableWeightsNormal & entry->availableWeightsNormal)) { + // The variant is already in the database. + return entry->id; + } + + goto addFileToFamily; + } + } + } + + { + // The family is not yet in the database; add it. + FontDatabaseEntry e = {}; + EsMemoryCopy(&e, information, sizeof(EsFontInformation)); + e.id = fontManagement.database.Length(); + fontManagement.database.Add(e); + entry = &fontManagement.database.Last(); + } + + addFileToFamily:; + + entry->availableWeightsNormal |= information->availableWeightsNormal; + entry->availableWeightsItalic |= information->availableWeightsItalic; + + for (uintptr_t i = 0; i < 18; i++) { + if ((i < 9 && (information->availableWeightsNormal & (1 << i))) + || (i >= 9 && (information->availableWeightsItalic & (1 << i)))) { + store->handles++; + entry->files[i] = store; + return entry->id; + } + } + + EsAssert(false); + return 0; +} + +void EsFontDatabaseEnumerate(EsFontEnumerationCallbackFunction callback, EsGeneric context) { + FontInitialise(); + + for (uintptr_t i = 1; i < fontManagement.database.Length(); i++) { + EsFontInformation information; + EsFontDatabaseLookupByID(i, &information); + callback(&information, context); + } +} + +bool FontSupportsScript(FontDatabaseEntry *entry, uint32_t _script, bool first) { + if (!entry->scriptsBytes) { + return first; + } + + char script[4]; + script[0] = (char) (_script >> 24); + script[1] = (char) (_script >> 16); + script[2] = (char) (_script >> 8); + script[3] = (char) (_script >> 0); + + for (uintptr_t i = 0; i <= entry->scriptsBytes - 4; i += 5) { + if (script[0] == entry->scripts[i + 0] + && script[1] == entry->scripts[i + 1] + && script[2] == entry->scripts[i + 2] + && script[3] == entry->scripts[i + 3]) { + return true; + } + } + + return false; +} + +EsFontFamily FontApplySubstitution(EsTextPlanProperties *properties, EsFontFamily family, uint32_t script) { + FontInitialise(); + + if (properties->flags & ES_TEXT_PLAN_NO_FONT_SUBSTITUTION) { + return family; + } + + FontSubstitutionKey key = {}; + key.family = FontGetStandardFamily(family); + key.script = script; + EsFontFamily result = fontManagement.substitutions.Get1(&key); + if (result) return result; + + EsAssert(key.family < fontManagement.database.Length()); + FontDatabaseEntry *entry = &fontManagement.database[key.family]; + + if (FontSupportsScript(entry, script, true)) { + *fontManagement.substitutions.Put(&key) = key.family; + return key.family; + } + + EsFontFamily firstMatch = (EsFontFamily) -1; + + for (uintptr_t i = 1; i < fontManagement.database.Length(); i++) { + if (&fontManagement.database[i] == entry) continue; + if (!FontSupportsScript(&fontManagement.database[i], script, false)) continue; + + if (firstMatch == (EsFontFamily) -1) { + firstMatch = i; + } + + if (0 == EsStringCompareRaw(fontManagement.database[i].category, fontManagement.database[i].categoryBytes, + entry->category, entry->categoryBytes)) { + *fontManagement.substitutions.Put(&key) = i; + return i; + } + } + + if (firstMatch != (EsFontFamily) -1) { + *fontManagement.substitutions.Put(&key) = firstMatch; + return firstMatch; + } else { + // No installed font supports the script. + *fontManagement.substitutions.Put(&key) = key.family; + return result; + } +} + +Font FontGet(EsFont key) { + FontInitialise(); + + if (key.weight == 0) { + key.weight = ES_FONT_REGULAR; + } + + key.family = FontGetStandardFamily(key.family); + + Font *_font = fontManagement.loaded.Get(&key); + if (_font) return *_font; + + EsFileStore *file = nullptr; + int matchDistance = 1000; + + EsAssert(key.family < fontManagement.database.Length()); + FontDatabaseEntry *entry = &fontManagement.database[key.family]; + + for (uintptr_t i = 0; i < 18; i++) { + if (entry->files[i]) { + int weight = (i % 9) + 1; + bool italic = i >= 9; + int distance = ((italic != key.italic) ? 10 : 0) + AbsoluteInteger(weight - key.weight); + + if (distance < matchDistance) { + matchDistance = distance; + file = entry->files[i]; + } + } + } + + if (!file) { + EsPrint("Could not load font (f%d/w%d/i%d).\n", key.family, key.weight, key.italic); + return {}; + } + + // EsPrint("Loading font from '%z' (f%d/w%d/i%d).\n", file, key.family, key.weight, key.italic); + + size_t size; + void *data = EsFileStoreMap(file, &size, ES_MAP_OBJECT_READ_ONLY); + + if (!data) { + EsPrint("Could not load font (f%d/w%d/i%d).\n", key.family, key.weight, key.italic); + return {}; + } + + Font font = {}; + + if (!FontLoad(&font, data, size)) { + EsPrint("Could not load font (f%d/w%d/i%d).\n", key.family, key.weight, key.italic); + return {}; + } + + *fontManagement.loaded.Put(&key) = font; + return font; +} + +// --------------------------------- Blitting rendered glyphs. + +inline static void DrawStringPixel(int oX, int oY, void *bitmap, size_t stride, uint32_t textColor, + uint32_t selectionColor, int32_t backgroundColor, uint32_t pixel, bool selected, bool fullAlpha) { + uint32_t *destination = (uint32_t *) ((uint8_t *) bitmap + (oX) * 4 + (oY) * stride); + uint8_t alpha = (textColor & 0xFF000000) >> 24; + + if (pixel == 0xFFFFFF && alpha == 0xFF) { + *destination = 0xFF000000 | textColor; + } else if (pixel && fullAlpha) { + uint32_t original; + + if (selected) { + original = selectionColor; + } else if (backgroundColor < 0) { + original = *destination; + } else { + original = backgroundColor; + } + + uint32_t ga = (((pixel & 0x0000FF00) >> 8) * alpha) >> 8; + uint32_t alphaD2 = (255 - ga) * ((original & 0xFF000000) >> 24); + uint32_t alphaOut = ga + (alphaD2 >> 8); + + if (alphaOut) { + uint32_t m2 = alphaD2 / alphaOut; + uint32_t m1 = (ga << 8) / alphaOut; + if (m2 == 0x100) m2--; + if (m1 == 0x100) m1--; + + uint32_t r2 = m2 * ((original & 0x000000FF) >> 0); + uint32_t g2 = m2 * ((original & 0x0000FF00) >> 8); + uint32_t b2 = m2 * ((original & 0x00FF0000) >> 16); + uint32_t r1 = m1 * ((textColor & 0x000000FF) >> 0); + uint32_t g1 = m1 * ((textColor & 0x0000FF00) >> 8); + uint32_t b1 = m1 * ((textColor & 0x00FF0000) >> 16); + + uint32_t result = + (0x00FF0000 & ((b1 + b2) << 8)) + | (0x0000FF00 & ((g1 + g2) << 0)) + | (0x000000FF & ((r1 + r2) >> 8)) + | (alphaOut << 24); + + *destination = result; + } + } else if (pixel) { + uint32_t original; + + if (selected) { + original = selectionColor; + } else if (backgroundColor < 0) { + original = *destination; + } else { + original = backgroundColor; + } + + uint32_t ra = (((pixel & 0x000000FF) >> 0) * alpha) >> 8; + uint32_t ga = (((pixel & 0x0000FF00) >> 8) * alpha) >> 8; + uint32_t ba = (((pixel & 0x00FF0000) >> 16) * alpha) >> 8; + uint32_t r2 = (255 - ra) * ((original & 0x000000FF) >> 0); + uint32_t g2 = (255 - ga) * ((original & 0x0000FF00) >> 8); + uint32_t b2 = (255 - ba) * ((original & 0x00FF0000) >> 16); + uint32_t r1 = ra * ((textColor & 0x000000FF) >> 0); + uint32_t g1 = ga * ((textColor & 0x0000FF00) >> 8); + uint32_t b1 = ba * ((textColor & 0x00FF0000) >> 16); + + uint32_t result = 0xFF000000 | (0x00FF0000 & ((b1 + b2) << 8)) + | (0x0000FF00 & ((g1 + g2) << 0)) + | (0x000000FF & ((r1 + r2) >> 8)); + + *destination = result; + } +} + +void DrawSingleCharacter(int width, int height, int xoff, int yoff, + EsPoint outputPosition, EsRectangle region, EsPaintTarget *target, + int blur, int type, bool selected, uint8_t *output, + uint32_t color, uint32_t selectionColor, int32_t backgroundColor, bool fullAlpha) { + // TODO Rewrite. + + if (type != CHARACTER_SUBPIXEL) { + blur = 0; + } + + uint8_t alpha = color >> 24; + + int xOut = outputPosition.x + xoff; + int yOut = outputPosition.y + yoff; + int xFrom = xOut, xTo = xOut + width; + int yFrom = yOut, yTo = yOut + height; + + if (blur) { + xFrom -= blur; + yFrom -= blur; + xTo += blur; + yTo += blur; + } + + if (xFrom < region.l) xFrom = region.l; else if (xFrom >= region.r) xFrom = region.r; + if (xFrom < 0) xFrom = 0; else if (xFrom >= (int) target->width) xFrom = target->width; + if (xTo < region.l) xTo = region.l; else if (xTo >= region.r) xTo = region.r; + if (xTo < 0) xTo = 0; else if (xTo >= (int) target->width) xTo = target->width; + + if (yFrom < region.t) yFrom = region.t; else if (yFrom >= region.b) yFrom = region.b; + if (yFrom < 0) yFrom = 0; else if (yFrom >= (int) target->height) yFrom = target->height; + if (yTo < region.t) yTo = region.t; else if (yTo >= region.b) yTo = region.b; + if (yTo < 0) yTo = 0; else if (yTo >= (int) target->height) yTo = target->height; + + float blurExponentDenominator = -1.0f / (2.0f * (blur / 3.0f) * (blur / 3.0f)); + + for (int oY = yFrom; oY < yTo; oY++) { + int y = oY - yOut; + + for (int oX = xFrom; oX < xTo; oX++) { + int x = oX - xOut; + + if (blur) { + float c = 0, d = 0; + + for (int i = y - blur; i <= y + blur; i++) { + for (int j = x - blur; j <= x + blur; j++) { + float weight = EsCRTexpf(blurExponentDenominator * ((i - y) * (i - y) + (j - x) * (j - x))); + d += weight; + + if (i >= 0 && j >= 0 && i < height && j < width) { + uint32_t pixel = *((uint32_t *) (output + (j * 4 + i * width * 4))); + c += (pixel & 0xFF00) * weight; + } + } + } + + uint32_t a = c / (d * 256.0f); + DrawStringPixel(oX, oY, target->bits, target->stride, color, selectionColor, backgroundColor, + a | (a << 8) | (a << 16), selected, fullAlpha); + } else if (type == CHARACTER_MONO) { + uintptr_t n = y * width + x; + + if (output[n / 8] & (1 << (n & 7))) { + uint32_t *destination = (uint32_t *) ((uint8_t *) target->bits + oX * 4 + oY * target->stride); + *destination = 0xFF000000 | color; + } + } else if (type == CHARACTER_IMAGE || type == CHARACTER_RECOLOR) { + uint32_t pixel = *((uint32_t *) (output + (x * 4 + y * width * 4))); + uint32_t *destination = (uint32_t *) ((uint8_t *) target->bits + (oX) * 4 + (oY) * target->stride); + + if (type == CHARACTER_RECOLOR) { + pixel = (pixel & 0xFF000000) | (color & 0x00FFFFFF); + } + + if ((pixel >> 24) == 0xFF && alpha == 0xFF) { + *destination = pixel; + } else if (pixel && fullAlpha) { + uint32_t original = *destination; + uint32_t alphaSource = ((pixel >> 24) * alpha) >> 8; + uint32_t alphaDestination = ((original & 0xFF000000) >> 24) * (255 - alphaSource); + uint32_t alphaOut = alphaSource + (alphaDestination >> 8); + + if (alphaOut) { + uint32_t m2 = alphaDestination / alphaOut; + uint32_t m1 = (alphaSource << 8) / alphaOut; + if (m2 == 0x100) m2--; + if (m1 == 0x100) m1--; + uint32_t r2 = m2 * ((original & 0x000000FF) >> 0); + uint32_t g2 = m2 * ((original & 0x0000FF00) >> 8); + uint32_t b2 = m2 * ((original & 0x00FF0000) >> 16); + uint32_t r1 = m1 * ((pixel & 0x000000FF) >> 0); + uint32_t g1 = m1 * ((pixel & 0x0000FF00) >> 8); + uint32_t b1 = m1 * ((pixel & 0x00FF0000) >> 16); + uint32_t result = (alphaOut << 24) | (0x00FF0000 & ((b1 + b2) << 8)) + | (0x0000FF00 & ((g1 + g2) << 0)) + | (0x000000FF & ((r1 + r2) >> 8)); + *destination = result; + } + } else if (pixel) { + uint32_t original = *destination; + uint32_t a = ((pixel >> 24) * alpha) >> 8; + uint32_t r2 = (255 - a) * ((original & 0x000000FF) >> 0); + uint32_t g2 = (255 - a) * ((original & 0x0000FF00) >> 8); + uint32_t b2 = (255 - a) * ((original & 0x00FF0000) >> 16); + uint32_t r1 = a * ((pixel & 0x000000FF) >> 0); + uint32_t g1 = a * ((pixel & 0x0000FF00) >> 8); + uint32_t b1 = a * ((pixel & 0x00FF0000) >> 16); + uint32_t result = 0xFF000000 + | (0x00FF0000 & ((b1 + b2) << 8)) + | (0x0000FF00 & ((g1 + g2) << 0)) + | (0x000000FF & ((r1 + r2) >> 8)); + *destination = result; + } + } else if (type == CHARACTER_SUBPIXEL) { + uint32_t pixel = *((uint32_t *) (output + (x * 4 + y * width * 4))); + DrawStringPixel(oX, oY, target->bits, target->stride, color, selectionColor, backgroundColor, pixel, selected, fullAlpha); + } + } + } +} + +// --------------------------------- Icons. + +#define ICON_PACK_PAINT_SOLID (1) +#define ICON_PACK_PAINT_LINEAR_GRADIENT (2) +#define ICON_PACK_PAINT_RADIAL_GRADIENT (3) + +struct IconPackGradientStop { + uint32_t color; + float offset; +}; + +struct IconPackGradient { + float transform[6]; + uint8_t repeatMode, stopCount; + float fx, fy; + IconPackGradientStop stops[1]; +}; + +struct IconPackPaint { + uint8_t type; + + union { + uint32_t color; + IconPackGradient *gradient; + }; +}; + +struct IconPackPath { + IconPackPath *next; + float *points; + int pointCount; + bool closed; +}; + +struct IconPackShape { + IconPackShape *next; + IconPackPath *paths; + IconPackPaint fill, stroke; + bool evenOddRule; + float opacity; + float strokeWidth, strokeDashOffset, strokeDashArray[8], miterLimit; + uint8_t strokeLineJoin, strokeLineCap, strokeDashCount; +}; + +struct IconPackImage { + IconPackShape *shapes; + float width, height; +}; + +void *IconBufferAllocate(size_t size) { + // Must allocate adjacent to the previous allocation. + void *memory = iconManagement.buffer + iconManagement.bufferPosition; + iconManagement.bufferPosition += size; + EsAssert(iconManagement.bufferAllocated > iconManagement.bufferPosition); // Icon required more space than is available in iconBuffer. + EsMemoryZero(memory, size); + return memory; +} + +void IconPackReadPaint(IconPackPaint *paint) { + paint->type = EsBufferReadByte(&iconManagement.pack); + + if (paint->type == ICON_PACK_PAINT_SOLID) { + paint->color = EsBufferReadInt(&iconManagement.pack); + } else if (paint->type == ICON_PACK_PAINT_LINEAR_GRADIENT || paint->type == ICON_PACK_PAINT_RADIAL_GRADIENT) { + paint->gradient = (IconPackGradient *) IconBufferAllocate(sizeof(IconPackGradient)); + for (int i = 0; i < 6; i++) paint->gradient->transform[i] = EsBufferReadFloat(&iconManagement.pack); + paint->gradient->repeatMode = EsBufferReadByte(&iconManagement.pack); + paint->gradient->fx = EsBufferReadFloat(&iconManagement.pack); + paint->gradient->fy = EsBufferReadFloat(&iconManagement.pack); + paint->gradient->stopCount = EsBufferReadInt(&iconManagement.pack); + IconBufferAllocate(8 * paint->gradient->stopCount); + + for (int i = 0; i < paint->gradient->stopCount; i++) { + paint->gradient->stops[i].color = EsBufferReadInt(&iconManagement.pack); + paint->gradient->stops[i].offset = EsBufferReadFloat(&iconManagement.pack); + } + } +} + +void IconPackReadPaint(IconPackPath **link) { + if (EsBufferReadByte(&iconManagement.pack) != 0x34) return; + next:; + + IconPackPath *path = *link = (IconPackPath *) IconBufferAllocate(sizeof(IconPackPath)); + + path->pointCount = EsBufferReadInt(&iconManagement.pack); + path->closed = EsBufferReadByte(&iconManagement.pack); + path->points = (float *) IconBufferAllocate(sizeof(float) * 2 * path->pointCount); + link = &path->next; + + for (int i = 0; i < path->pointCount; i++) { + path->points[i * 2 + 0] = EsBufferReadFloat(&iconManagement.pack); + path->points[i * 2 + 1] = EsBufferReadFloat(&iconManagement.pack); + } + + if (EsBufferReadByte(&iconManagement.pack)) goto next; +} + +void IconPackReadShape(IconPackShape **link) { + if (EsBufferReadByte(&iconManagement.pack) != 0x12) return; + next:; + + IconPackShape *shape = *link = (IconPackShape *) IconBufferAllocate(sizeof(IconPackShape)); + + shape->opacity = EsBufferReadFloat(&iconManagement.pack); + shape->strokeWidth = EsBufferReadFloat(&iconManagement.pack); + shape->strokeDashOffset = EsBufferReadFloat(&iconManagement.pack); + for (int i = 0; i < 8; i++) shape->strokeDashArray[i] = EsBufferReadFloat(&iconManagement.pack); + shape->strokeDashCount = EsBufferReadByte(&iconManagement.pack); + shape->strokeLineJoin = EsBufferReadByte(&iconManagement.pack); + shape->strokeLineCap = EsBufferReadByte(&iconManagement.pack); + shape->miterLimit = EsBufferReadFloat(&iconManagement.pack); + shape->evenOddRule = EsBufferReadByte(&iconManagement.pack); + + IconPackReadPaint(&shape->fill); + IconPackReadPaint(&shape->stroke); + IconPackReadPaint(&shape->paths); + link = &shape->next; + + if (EsBufferReadByte(&iconManagement.pack)) goto next; +} + +IconPackImage *IconPackReadImage(uint32_t id, uint32_t size, int *type) { + iconManagement.bufferPosition = 0; + iconManagement.pack.position = 0; + + uint32_t count = EsBufferReadInt(&iconManagement.pack); + if (id >= count) return nullptr; + iconManagement.pack.position = (id + 1) * 4; + uint32_t start = iconManagement.pack.position = EsBufferReadInt(&iconManagement.pack); + *type = (EsBufferReadInt(&iconManagement.pack) == 1) ? CHARACTER_RECOLOR : CHARACTER_IMAGE; + iconManagement.pack.position = start; + + bool rtl = api.systemConstants[ES_SYSTEM_CONSTANT_RIGHT_TO_LEFT]; + bool found = false; + uint32_t variant = 0; + + while (true) { + variant = EsBufferReadInt(&iconManagement.pack); + if (!variant) break; + if ((variant == size || variant == 1) && !rtl) { found = true; break; } + iconManagement.pack.position = EsBufferReadInt(&iconManagement.pack); + } + + if (!found) { + iconManagement.pack.position = start; + + while (true) { + variant = EsBufferReadInt(&iconManagement.pack); + if (!variant) break; + if ((variant & 0x7FFF) > size && !rtl) { found = true; break; } + iconManagement.pack.position = EsBufferReadInt(&iconManagement.pack); + } + } + + if (!found && rtl) { + iconManagement.pack.position = start; + + while (true) { + variant = EsBufferReadInt(&iconManagement.pack); + if (!variant) break; + if ((variant == (size | 0x8000)) || variant == 0x8001) { found = true; break; } + iconManagement.pack.position = EsBufferReadInt(&iconManagement.pack); + } + } + + if (!found && rtl) { + iconManagement.pack.position = start; + + while (true) { + variant = EsBufferReadInt(&iconManagement.pack); + if (!variant) break; + if ((variant & 0x7FFF) > size && (variant & 0x8000)) { found = true; break; } + iconManagement.pack.position = EsBufferReadInt(&iconManagement.pack); + } + } + + // skipSizeSearch:; + + if (!found) { + iconManagement.pack.position = start; + EsBufferReadInt(&iconManagement.pack); + } + + EsBufferReadInt(&iconManagement.pack); + + IconPackImage *image = (IconPackImage *) IconBufferAllocate(sizeof(IconPackImage)); + image->width = EsBufferReadFloat(&iconManagement.pack); + image->height = EsBufferReadFloat(&iconManagement.pack); + IconPackReadShape(&image->shapes); + return image; +} + +void DrawIcon(int width, int height, uint8_t *destination, IconPackImage *icon, int stride, float translateX, float translateY, float scaleX, float scaleY) { + if (width <= 0 || height <= 0) return; + + RastVertex scale2 = { scaleX, scaleY }; + + RastSurface surface = {}; + + surface.buffer = (uint32_t *) destination; + surface.stride = stride; + + if (!RastSurfaceInitialise(&surface, width, height, true)) { + RastSurfaceDestroy(&surface); + return; + } + + // TODO strokeDashOffset, strokeDashArray, strokeDashCount. + + IconPackShape *shape = icon->shapes; + int shapeIndex = 0; + + while (shape) { + RastPaint paintFill = {}, paintStroke = {}; + + RastContourStyle contour = {}; + contour.internalWidth = shape->strokeWidth * scaleX * 0.5f; + contour.externalWidth = shape->strokeWidth * scaleX * 0.5f; + contour.joinMode = (RastLineJoinMode) shape->strokeLineJoin; + contour.capMode = (RastLineCapMode) shape->strokeLineCap; + contour.miterLimit = scaleX * shape->strokeWidth * shape->miterLimit; + + if (shape->opacity == 0) { + goto nextShape; + } + + for (uintptr_t i = 0; i < 2; i++) { + IconPackPaint *p1 = i ? &shape->stroke : &shape->fill; + RastPaint *p2 = i ? &paintStroke : &paintFill; + + if (p1->type == ICON_PACK_PAINT_SOLID) { + p2->type = RAST_PAINT_SOLID; + uint32_t color = p1->color; + color = (color & 0xFF00FF00) | ((color & 0xFF) << 16) | ((color & 0xFF0000) >> 16); + p2->solid.color = 0xFFFFFF & color; + p2->solid.alpha = (float) ((0xFF000000 & color) >> 24) / 255.0f * shape->opacity; + } else if (p1->type == ICON_PACK_PAINT_LINEAR_GRADIENT || p1->type == ICON_PACK_PAINT_RADIAL_GRADIENT) { + IconPackGradient *gradient = p1->gradient; + p2->type = p1->type == ICON_PACK_PAINT_RADIAL_GRADIENT ? RAST_PAINT_RADIAL_GRADIENT : RAST_PAINT_LINEAR_GRADIENT; + + if (p1->type == ICON_PACK_PAINT_RADIAL_GRADIENT) { + p2->gradient.transform[0] = gradient->transform[0] / scale2.x; + p2->gradient.transform[1] = gradient->transform[2] / scale2.y; + p2->gradient.transform[2] = gradient->transform[4] - (p2->gradient.transform[0] * translateX + p2->gradient.transform[1] * translateY); + p2->gradient.transform[3] = gradient->transform[1] / scale2.x; + p2->gradient.transform[4] = gradient->transform[3] / scale2.y; + p2->gradient.transform[5] = gradient->transform[5] - (p2->gradient.transform[3] * translateX + p2->gradient.transform[4] * translateY); + } else { + p2->gradient.transform[0] = gradient->transform[1] / scale2.x; + p2->gradient.transform[1] = gradient->transform[3] / scale2.y; + p2->gradient.transform[2] = gradient->transform[5] - (p2->gradient.transform[0] * translateX + p2->gradient.transform[1] * translateY); + } + + RastGradientStop stops[16]; + size_t stopCount = gradient->stopCount; + if (stopCount > 16) stopCount = 16; + + for (uintptr_t i = 0; i < stopCount; i++) { + uint32_t color = gradient->stops[i].color; + color = (color & 0xFF00FF00) | ((color & 0xFF) << 16) | ((color & 0xFF0000) >> 16); + stops[i].color = (0xFFFFFF & color) + | ((uint32_t) ((float) ((0xFF000000 & color) >> 24) * shape->opacity) << 24); + stops[i].position = gradient->stops[i].offset; + } + + RastGradientInitialise(p2, stops, stopCount, false); + p2->gradient.repeatMode = (RastRepeatMode) gradient->repeatMode; + } + } + + if (paintFill.type) { + RastPath p = {}; + IconPackPath *path = shape->paths; + + while (path) { + RastPathAppendBezier(&p, (RastVertex *) path->points, path->pointCount, scale2); + if (path->closed || path->next) RastPathCloseSegment(&p); + path = path->next; + } + + RastPathTranslate(&p, translateX, translateY); + RastShape s = RastShapeCreateSolid(&p); + RastSurfaceFill(surface, s, paintFill, shape->evenOddRule); + + RastPathDestroy(&p); + } + + if (shape->strokeWidth && paintStroke.type) { + IconPackPath *path = shape->paths; + + int pathCount = 0; + + while (path) { + RastPath p = {}; + RastPathAppendBezier(&p, (RastVertex *) path->points, path->pointCount, scale2); + RastPathTranslate(&p, translateX, translateY); + RastShape s = RastShapeCreateContour(&p, contour, !path->closed); + RastSurfaceFill(surface, s, paintStroke, false); + path = path->next; + RastPathDestroy(&p); + pathCount++; + } + } + + nextShape:; + + RastGradientDestroy(&paintFill); + RastGradientDestroy(&paintStroke); + + shapeIndex++; + shape = shape->next; + } + + RastSurfaceDestroy(&surface); +} + +bool EsDrawStandardIcon(EsPainter *painter, uint32_t id, int size, EsRectangle region, uint32_t color) { + if (!id) return false; + id--; + + if (!iconManagement.standardPack) { + size_t pathBytes; + char *path = EsSystemConfigurationReadString(EsLiteral("ui"), EsLiteral("icon_pack"), &pathBytes); + iconManagement.standardPack = (uint8_t *) EsFileMap(path, pathBytes, &iconManagement.standardPackSize, ES_MAP_OBJECT_READ_ONLY); + EsHeapFree(path); + } + + { + // Center the icon. + + if (region.r - region.l > size) { + int d = region.r - region.l - size; + region.l += d / 2, region.r -= d / 2; + } + + if (region.b - region.t > size) { + int d = region.b - region.t - size; + region.t += d / 2, region.b -= d / 2; + } + } + + int left = region.l, top = region.t; + EsRectangleClip(region, painter->clip, ®ion); + + GlyphCacheKey key = {}; + key.glyphIndex = id; + key.size = size; + + GlyphCacheEntry *cacheEntry = LookupGlyphCacheEntry(key); + + if (!cacheEntry->data) { + iconManagement.buffer = (char *) EsHeapAllocate((iconManagement.bufferAllocated = 131072), false); + if (!iconManagement.buffer) return false; + iconManagement.pack = { .in = iconManagement.standardPack, .bytes = iconManagement.standardPackSize }; + cacheEntry->width = size, cacheEntry->height = size; + cacheEntry->dataBytes = size * size * 4; + cacheEntry->data = (uint8_t *) EsHeapAllocate(cacheEntry->dataBytes, true); + RegisterGlyphCacheEntry(key, cacheEntry); + IconPackImage *image = IconPackReadImage(id, size, &cacheEntry->type); + DrawIcon(size, size, cacheEntry->data, image, size * 4, 0, 0, (float) size / image->width, (float) size / image->height); + EsHeapFree(iconManagement.buffer); + } + + DrawSingleCharacter(cacheEntry->width, cacheEntry->height, 0, 0, + ES_POINT(left, top), region, painter->target, + 0, cacheEntry->type, false, cacheEntry->data, + color, 0, 0, painter->target->fullAlpha); + + return true; +} + +void EsDrawVectorFile(EsPainter *painter, EsRectangle bounds, const void *data, size_t dataBytes) { + iconManagement.bufferPosition = 0; + iconManagement.buffer = (char *) EsHeapAllocate((iconManagement.bufferAllocated = 131072), false); + iconManagement.pack = { .in = (const uint8_t *) data, .bytes = dataBytes }; + + IconPackImage *image = (IconPackImage *) IconBufferAllocate(sizeof(IconPackImage)); + image->width = EsBufferReadFloat(&iconManagement.pack); + image->height = EsBufferReadFloat(&iconManagement.pack); + IconPackReadShape(&image->shapes); + + EsRectangle destination = EsRectangleIntersection(bounds, painter->clip); + EsPaintTarget *target = painter->target; + DrawIcon(Width(destination), Height(destination), (uint8_t *) target->bits + destination.l * 4 + destination.t * target->stride, image, target->stride, + bounds.l - destination.l, bounds.t - destination.t, (float) Width(bounds) / image->width, (float) Height(bounds) / image->height); + + EsHeapFree(iconManagement.buffer); +} + +// --------------------------------- Basic shaping engine. + +#ifndef USE_HARFBUZZ + +#define HB_SCRIPT_COMMON (1) +#define HB_SCRIPT_INHERITED (1) + +#define HB_SHAPE(plan, features, featureCount) hb_shape(plan->font, plan->buffer, features, featureCount) + +struct hb_segment_properties_t { + uint32_t script; +}; + +struct hb_glyph_info_t { + uint32_t cluster; + uint32_t codepoint; +}; + +struct hb_glyph_position_t { + uint32_t x_advance; + uint32_t y_advance; + uint32_t x_offset; + uint32_t y_offset; +}; + +struct hb_feature_t { +}; + +struct hb_buffer_t { + const char *text; + size_t textBytes; + uintptr_t shapeOffset; + size_t shapeBytes; + + Array glyphInfos; + Array glyphPositions; +}; + +void hb_buffer_clear_contents(hb_buffer_t *buffer) { + buffer->glyphInfos.Free(); + buffer->glyphPositions.Free(); +} + +void hb_buffer_set_segment_properties(hb_buffer_t *, hb_segment_properties_t *) { +} + +void hb_buffer_add_utf8(hb_buffer_t *buffer, const char *text, size_t textBytes, uintptr_t shapeOffset, size_t shapeBytes) { + buffer->text = text; + buffer->textBytes = textBytes; + buffer->shapeOffset = shapeOffset; + buffer->shapeBytes = shapeBytes; +} + +hb_glyph_info_t *hb_buffer_get_glyph_infos(hb_buffer_t *buffer, uint32_t *glyphCount) { + *glyphCount = buffer->glyphInfos.Length(); + return buffer->glyphInfos.array; +} + +hb_glyph_position_t *hb_buffer_get_glyph_positions(hb_buffer_t *buffer, uint32_t *glyphCount) { + *glyphCount = buffer->glyphPositions.Length(); + return buffer->glyphPositions.array; +} + +uint32_t hb_unicode_script(struct hb_unicode_funcs_t *, uint32_t) { + return FALLBACK_SCRIPT; +} + +struct hb_unicode_funcs_t *hb_unicode_funcs_get_default() { + return nullptr; +} + +hb_buffer_t *hb_buffer_create() { + return (hb_buffer_t *) EsHeapAllocate(sizeof(hb_buffer_t), true); +} + +void hb_buffer_destroy(hb_buffer_t *buffer) { + hb_buffer_clear_contents(buffer); + EsHeapFree(buffer); +} + +void hb_shape(Font font, hb_buffer_t *buffer, const hb_feature_t *, uint32_t) { + // TODO Cache glyph metrics. + + const char *text = buffer->text + buffer->shapeOffset; + uint32_t previous = 0; + + while (true) { + hb_glyph_info_t info = {}; + hb_glyph_position_t position = {}; + info.cluster = text - buffer->text; + uint32_t codepoint = utf8_value(text, buffer->text + buffer->shapeOffset + buffer->shapeBytes - text, nullptr); + if (!codepoint) break; + text = utf8_advance(text); + info.codepoint = FontCodepointToGlyphIndex(&font, codepoint); + FontGetGlyphMetrics(&font, info.codepoint, &position.x_advance, &position.y_advance, &position.x_offset, &position.y_offset); + position.x_advance += FontGetKerning(&font, previous, info.codepoint); + previous = info.codepoint; + buffer->glyphInfos.Add(info); + buffer->glyphPositions.Add(position); + } +} + +#endif + +// --------------------------------- Text shaping. + +enum TextStyleDifference { + TEXT_STYLE_NEW_FONT, // A new font is selected. + TEXT_STYLE_NEW_SHAPE, // Shaping parameters have changed. + TEXT_STYLE_NEW_RENDER, // Render-only properties have changed. + TEXT_STYLE_IDENTICAL, // The styles are the same. +}; + +struct TextPiece { + // Shaped glyphs, on the same line, and with constant style and script. + int32_t ascent, descent, width; + const EsTextStyle *style; + uintptr_t glyphOffset; + size_t glyphCount; + uintptr_t start, end; + bool isTabPiece; +}; + +struct TextLine { + int32_t ascent, descent, width; + bool hasEllipsis; + uintptr_t ellipsisPieceIndex; + uintptr_t pieceOffset; + size_t pieceCount; +}; + +struct TextRun { + EsTextStyle style; + uint32_t offset; + uint32_t script; +}; + +struct EsTextPlan { + hb_buffer_t *buffer; + hb_segment_properties_t segmentProperties; + + const char *string; + + Array textRuns; + uintptr_t textRunPosition; + + const EsTextStyle *currentTextStyle; + Font font; + + BreakState breaker; + + Array glyphInfos; + Array glyphPositions; + + Array pieces; + Array lines; + + int32_t totalHeight, totalWidth; + + bool singleUse; + + EsTextPlanProperties properties; +}; + +TextStyleDifference CompareTextStyles(const EsTextStyle *style1, const EsTextStyle *style2) { + if (!style1) return TEXT_STYLE_NEW_FONT; + if (style1->font.family != style2->font.family) return TEXT_STYLE_NEW_FONT; + if (style1->font.weight != style2->font.weight) return TEXT_STYLE_NEW_FONT; + if (style1->font.italic != style2->font.italic) return TEXT_STYLE_NEW_FONT; + if (style1->size != style2->size) return TEXT_STYLE_NEW_FONT; + if (style1->baselineOffset != style2->baselineOffset) return TEXT_STYLE_NEW_SHAPE; + if (style1->tracking != style2->tracking) return TEXT_STYLE_NEW_SHAPE; + if (style1->figures != style2->figures) return TEXT_STYLE_NEW_SHAPE; + if (style1->alternateDirection != style2->alternateDirection) return TEXT_STYLE_NEW_SHAPE; + if (style1->color != style2->color) return TEXT_STYLE_NEW_RENDER; + if (style1->blur != style2->blur) return TEXT_STYLE_NEW_RENDER; + if (style1->decorations != style2->decorations) return TEXT_STYLE_NEW_RENDER; + if (style1->decorationsColor != style2->decorationsColor) return TEXT_STYLE_NEW_RENDER; + return TEXT_STYLE_IDENTICAL; +} + +ptrdiff_t TextGetCharacterAtPoint(const EsTextStyle *textStyle, const char *string, size_t stringBytes, int *_pointX, uint32_t flags) { + // TODO Better integration with the EsTextPlan API. + + EsTextPlanProperties properties = {}; + EsTextRun textRuns[2] = {}; + textRuns[0].style = *textStyle; + textRuns[1].offset = stringBytes; + EsTextPlan *plan = EsTextPlanCreate(&properties, {}, string, textRuns, 1); + if (!plan) return 0; + + EsAssert(plan->lines.Length() == 1); + bool useMiddle = flags & ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE; + int pointX = *_pointX; + pointX *= FREETYPE_UNIT_SCALE; + int currentX = 0, priorMiddle = 0; + ptrdiff_t result = -1; + + for (uintptr_t j = 0; j < plan->lines[0].pieceCount; j++) { + TextPiece *piece = &plan->pieces[plan->lines[0].pieceOffset + j]; + hb_glyph_info_t *glyphs = &plan->glyphInfos[piece->glyphOffset]; + hb_glyph_position_t *glyphPositions = &plan->glyphPositions[piece->glyphOffset]; + + for (uintptr_t i = 0; i < piece->glyphCount; i++) { + int left = useMiddle ? priorMiddle : currentX; + int right = currentX + glyphPositions[i].x_advance / (useMiddle ? 2 : 1); + + priorMiddle = right; + + if (pointX >= left && pointX < right) { + result = glyphs[i].cluster; + goto done; + } + + currentX += glyphPositions[i].x_advance; + } + } + + done:; + *_pointX = currentX / FREETYPE_UNIT_SCALE; + EsTextPlanDestroy(plan); + return result; +} + +int TextGetPartialStringWidth(const EsTextStyle *textStyle, const char *fullString, size_t fullStringBytes, size_t measureBytes) { + // TODO Better integration with the EsTextPlan API. + + EsTextPlanProperties properties = {}; + EsTextRun textRuns[3] = {}; + textRuns[0].style = *textStyle; + textRuns[1].style = *textStyle; + textRuns[1].offset = measureBytes; + textRuns[2].offset = fullStringBytes; + EsTextPlan *plan = EsTextPlanCreate(&properties, {}, fullString, textRuns, 2); + if (!plan) return 0; + + int width = 0; + EsAssert(plan->lines.Length() == 1); + + for (uintptr_t i = 0; i < plan->lines[0].pieceCount; i++) { + TextPiece *piece = &plan->pieces[plan->lines[0].pieceOffset + i]; + + if (piece->start < measureBytes) { + width += piece->width; + } + } + + EsTextPlanDestroy(plan); + return width / FREETYPE_UNIT_SCALE; +} + +int TextGetStringWidth(const EsTextStyle *textStyle, const char *string, size_t stringBytes) { + return TextGetPartialStringWidth(textStyle, string, stringBytes, stringBytes); +} + +void TextTrimSpaces(EsTextPlan *plan) { + if (~plan->properties.flags & ES_TEXT_PLAN_TRIM_SPACES) { + return; + } + + for (uintptr_t i = 0; i < plan->lines.Length(); i++) { + TextLine *line = &plan->lines[i]; + + if (!line->pieceCount) { + continue; + } + + TextPiece *firstPiece = &plan->pieces[line->pieceOffset]; + TextPiece *lastPiece = &plan->pieces[line->pieceOffset + line->pieceCount - 1]; + + while (firstPiece->glyphCount && firstPiece->start != firstPiece->end + && plan->glyphInfos[firstPiece->glyphOffset].cluster == firstPiece->start + && plan->string[firstPiece->start] == ' ') { + line->width -= plan->glyphPositions[firstPiece->glyphOffset].x_advance; + firstPiece->width -= plan->glyphPositions[firstPiece->glyphOffset].x_advance; + firstPiece->glyphOffset++; + firstPiece->glyphCount--; + firstPiece->start++; + } + + while (lastPiece->glyphCount && lastPiece->start != lastPiece->end + && plan->glyphInfos[lastPiece->glyphOffset + lastPiece->glyphCount - 1].cluster == lastPiece->end - 1 + && plan->string[lastPiece->end - 1] == ' ') { + line->width -= plan->glyphPositions[lastPiece->glyphOffset + lastPiece->glyphCount - 1].x_advance; + lastPiece->width -= plan->glyphPositions[lastPiece->glyphOffset + lastPiece->glyphCount - 1].x_advance; + lastPiece->glyphCount--; + lastPiece->end--; + } + } +} + +void TextPlaceEmergencyBreaks(EsTextPlan *plan, int32_t maximumLineWidth) { + if ((plan->properties.flags & ES_TEXT_PLAN_CLIP_UNBREAKABLE_LINES) || maximumLineWidth == -1) { + return; + } + + repeat:; + TextLine *line = &plan->lines.Last(); + if (line->width <= maximumLineWidth) return; + EsAssert(line->pieceCount >= 1); + + int32_t x = 0, x0 = 0; + uintptr_t j, piece; + + for (piece = 0; piece < line->pieceCount; piece++) { + TextPiece *p = &plan->pieces[line->pieceOffset + piece]; + x0 = x; + + for (j = 0; j < p->glyphCount; j++) { + int32_t width = plan->glyphPositions[p->glyphOffset + j].x_advance; + + if (x + width > maximumLineWidth && (j || piece)) { + goto foundBreakPoint; + } + + x += width; + } + } + + return; // One glyph on the line; we can't do anything. + foundBreakPoint:; + + // Split the line. + + TextPiece *piece0 = &plan->pieces[line->pieceOffset + piece]; + TextPiece piece1 = *piece0; + piece1.width = piece0->width - (x - x0); + piece1.glyphOffset += j; + piece1.glyphCount = piece0->glyphCount - j; + piece1.start = plan->glyphInfos[piece0->glyphOffset + j].cluster; + piece0->end = piece1.start; + piece0->width = x - x0; + piece0->glyphCount = j; + plan->pieces.Insert(piece1, line->pieceOffset + piece + 1); + + TextLine *line0 = line; + TextLine line1 = *line; + line1.width -= x; + line0->width = x; + line1.pieceOffset += piece + 1; + line1.pieceCount = line0->pieceCount - piece; + line0->pieceCount = piece + 1; + plan->lines.Add(line1); + + goto repeat; +} + +void TextAddEllipsis(EsTextPlan *plan, int32_t maximumLineWidth, bool needFinalEllipsis, int32_t boundsWidth) { + if (!boundsWidth || (~plan->properties.flags & ES_TEXT_ELLIPSIS)) { + return; + } + + bool needEllipsis = false; + + if (maximumLineWidth == -1) { + for (uintptr_t i = 0; i < plan->lines.Length(); i++) { + if (plan->lines[i].width > boundsWidth * FREETYPE_UNIT_SCALE) { + maximumLineWidth = boundsWidth * FREETYPE_UNIT_SCALE; + needEllipsis = true; + } + } + } else { + // Word-wrapping was enabled so lines won't exceed the boundary width. + } + + if (!needEllipsis && !needFinalEllipsis) { + return; + } + + uint8_t ellipsisUTF8[3] = { 0xE2, 0x80, 0xA6 }; + + // Shape and measure the ellipsis character. + + hb_buffer_clear_contents(plan->buffer); + hb_buffer_set_segment_properties(plan->buffer, &plan->segmentProperties); + hb_buffer_add_utf8(plan->buffer, (const char *) ellipsisUTF8, sizeof(ellipsisUTF8), 0, sizeof(ellipsisUTF8)); + HB_SHAPE(plan, nullptr, 0); + + int32_t ellipsisWidth = 0; + + uint32_t glyphCount, glyphCount2; + hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(plan->buffer, &glyphCount); + hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions(plan->buffer, &glyphCount2); + EsAssert(glyphCount == glyphCount2); + + for (uintptr_t i = 0; i < glyphCount; i++) { + ellipsisWidth += glyphPositions[i].x_advance; + } + + for (uintptr_t i = needEllipsis ? 0 : plan->lines.Length() - 1; i < plan->lines.Length(); i++) { + TextLine *line = &plan->lines[i]; + + if (i == plan->lines.Length() - 1 && needFinalEllipsis) { + // The maximum number of lines was exceeded, and this is the last permitted line, so add an ellipsis. + } else if (line->width > boundsWidth * FREETYPE_UNIT_SCALE) { + // This line exceeds the width boundary (and hence word-wrapping was disabled), so add an ellipsis. + } else { + continue; + } + + // Make space for the ellipsis. + + int32_t spaceNeeded = ellipsisWidth - (maximumLineWidth - line->width); + + while (line->pieceCount && spaceNeeded > 0) { + TextPiece *piece = &plan->pieces[line->pieceOffset + line->pieceCount - 1]; + + if (piece->isTabPiece) { + spaceNeeded -= piece->width; + line->pieceCount--; + } else if (piece->start == piece->end || !piece->glyphCount) { + line->pieceCount--; + } else { + piece->end = plan->glyphInfos[piece->glyphOffset + piece->glyphCount - 1].cluster; + int32_t width = plan->glyphPositions[piece->glyphOffset + piece->glyphCount - 1].x_advance; + spaceNeeded -= width, line->width -= width, piece->width -= width; + piece->glyphCount--; + + while (piece->glyphCount) { + if (plan->glyphInfos[piece->glyphOffset + piece->glyphCount - 1].cluster == piece->end) { + // TODO Test this branch! + int32_t width = plan->glyphPositions[piece->glyphOffset + piece->glyphCount - 1].x_advance; + spaceNeeded -= width, line->width -= width, piece->width -= width; + piece->glyphCount--; + } else { + break; + } + } + } + } + + // Add the ellipsis. + + TextPiece piece = {}; + piece.style = plan->currentTextStyle; + piece.glyphOffset = plan->glyphInfos.Length(); + piece.glyphCount = glyphCount; + piece.ascent = FontGetAscent (&plan->font) + plan->currentTextStyle->baselineOffset, + piece.descent = -FontGetDescent(&plan->font) - plan->currentTextStyle->baselineOffset; + + for (uintptr_t i = 0; i < glyphCount; i++) { + plan->glyphInfos.Add(glyphInfos[i]); + plan->glyphPositions.Add(glyphPositions[i]); + int32_t width = glyphPositions[i].x_advance; + piece.width += width, line->width += width; + } + + line->hasEllipsis = true; + line->ellipsisPieceIndex = plan->pieces.Length(); + plan->pieces.Add(piece); + } +} + +void TextItemizeByScript(EsTextPlan *plan, const EsTextRun *runs, size_t runCount) { + hb_unicode_funcs_t *unicodeFunctions = hb_unicode_funcs_get_default(); + uint32_t lastAssignedScript = FALLBACK_SCRIPT; + + for (uintptr_t i = 0; i < runCount; i++) { + uintptr_t offset = runs[i].offset; + + for (uintptr_t j = offset; j < runs[i + 1].offset;) { + uint32_t codepoint = utf8_value(plan->string + j); + uint32_t script; + + if (codepoint == '\t') { + // Tab characters should go in their own section. + script = '\t'; + } else { + script = hb_unicode_script(unicodeFunctions, codepoint); + } + + if (script == HB_SCRIPT_COMMON || script == HB_SCRIPT_INHERITED) { + // TODO If this is a closing character, restore the last assigned script before the most recent opening character. + script = lastAssignedScript == '\t' ? FALLBACK_SCRIPT : lastAssignedScript; + } + + if (lastAssignedScript != script && j != runs[i].offset) { + TextRun run = {}; + run.style = runs[i].style; + run.offset = offset; + run.script = lastAssignedScript; + run.style.font.family = FontApplySubstitution(&plan->properties, run.style.font.family, run.script); + plan->textRuns.Add(run); + offset = j; + } + + lastAssignedScript = script; + j = utf8_advance(plan->string + j) - plan->string; + } + + TextRun run = {}; + run.style = runs[i].style; + run.offset = offset; + run.script = lastAssignedScript; + run.style.font.family = FontApplySubstitution(&plan->properties, run.style.font.family, run.script); + plan->textRuns.Add(run); + } + + TextRun run = {}; + run.offset = runs[runCount].offset; + plan->textRuns.Add(run); +} + +void TextUpdateFont(EsTextPlan *plan, const EsTextStyle *style) { + if (TEXT_STYLE_NEW_FONT == CompareTextStyles(plan->currentTextStyle, style)) { + plan->font = FontGet(style->font); + FontSetSize(&plan->font, style->size); + } + + plan->currentTextStyle = style; +} + +int32_t TextExpandTabs(EsTextPlan *plan, uintptr_t pieceOffset, int32_t width) { + int32_t addedWidth = 0; + + for (uintptr_t i = pieceOffset; i < plan->pieces.Length(); i++) { + TextPiece *piece = &plan->pieces[i]; + + if (piece->isTabPiece) { + TextUpdateFont(plan, piece->style); + int32_t emWidth = FontGetEmWidth(&plan->font) * FREETYPE_UNIT_SCALE; + int32_t tabWidth = emWidth * 4; // TODO Make spaces-per-tab customizable. + int32_t firstWidth = emWidth + tabWidth - (width + emWidth) % tabWidth; + piece->width = firstWidth + tabWidth * (piece->end - piece->start - 1); + addedWidth += piece->width; + piece->glyphOffset = plan->glyphInfos.Length(); + piece->glyphCount = piece->end - piece->start; + piece->ascent = FontGetAscent(&plan->font); + piece->descent = -FontGetDescent(&plan->font); + + for (uintptr_t i = 0; i < piece->glyphCount; i++) { + hb_glyph_info_t info = {}; + info.cluster = piece->start + i; + info.codepoint = 0xFFFFFFFF; + hb_glyph_position_t position = {}; + position.x_advance = i ? tabWidth : firstWidth; + plan->glyphInfos.Add(info); + plan->glyphPositions.Add(position); + } + } + + width += piece->width; + } + + return addedWidth; +} + +int32_t TextBuildTextPieces(EsTextPlan *plan, uintptr_t sectionStart, uintptr_t sectionEnd) { + // Find the first run that contains the section. + + for (; plan->textRunPosition < plan->textRuns.Length() - 1; plan->textRunPosition++) { + if (plan->textRuns[plan->textRunPosition].offset <= sectionStart && plan->textRuns[plan->textRunPosition + 1].offset > sectionStart) { + break; + } + } + + EsAssert(plan->textRunPosition != plan->textRuns.Length() - 1); + + // Iterate through each run in the section. + + int32_t width = 0; + + while (plan->textRunPosition != plan->textRuns.Length() - 1) { + TextRun *run = &plan->textRuns[plan->textRunPosition]; + + uintptr_t start = sectionStart > run[0].offset ? sectionStart : run[0].offset; + uintptr_t end = sectionEnd < run[1].offset ? sectionEnd : run[1].offset; + + if (end <= start) { + break; + } + + // Update the font to match the run. + + TextUpdateFont(plan, &run->style); + + // Don't shape newline characters. + + while (start < end && plan->string[start] == '\n') start++; + while (end - 1 > start && plan->string[end - 1] == '\n') end--; + + if (end == start) { + plan->textRunPosition++; + continue; + } + + EsAssert(end > start); + + // Handle tab characters specially. + + if (plan->string[start] == '\t') { + TextPiece _piece = {}; + plan->pieces.Add(_piece); + TextPiece *piece = &plan->pieces.Last(); + piece->style = plan->currentTextStyle; + piece->glyphOffset = 0; + piece->glyphCount = 0; + piece->start = start; + piece->end = end; + piece->isTabPiece = true; + plan->textRunPosition++; + continue; + } + + // Shape the run. + + hb_feature_t features[4] = {}; + size_t featureCount = 0; + +#ifdef USE_HARFBUZZ + if (plan->currentTextStyle->figures == ES_TEXT_FIGURE_OLD) hb_feature_from_string("onum", -1, features + (featureCount++)); + if (plan->currentTextStyle->figures == ES_TEXT_FIGURE_TABULAR) hb_feature_from_string("tnum", -1, features + (featureCount++)); + plan->segmentProperties.script = (hb_script_t) run->script; +#endif + + hb_buffer_clear_contents(plan->buffer); + hb_buffer_set_segment_properties(plan->buffer, &plan->segmentProperties); + hb_buffer_add_utf8(plan->buffer, plan->string, plan->breaker.bytes, start, end - start); + + HB_SHAPE(plan, features, featureCount); + + uint32_t glyphCount, glyphCount2; + hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(plan->buffer, &glyphCount); + hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions(plan->buffer, &glyphCount2); + EsAssert(glyphCount == glyphCount2); + + // Create the text piece. + + TextPiece _piece = {}; + plan->pieces.Add(_piece); + TextPiece *piece = &plan->pieces.Last(); + piece->style = plan->currentTextStyle; + piece->glyphOffset = plan->glyphInfos.Length(); + piece->glyphCount = glyphCount; + piece->ascent = FontGetAscent (&plan->font) + plan->currentTextStyle->baselineOffset; + piece->descent = -FontGetDescent(&plan->font) - plan->currentTextStyle->baselineOffset; + piece->start = start; + piece->end = end; + + for (uintptr_t i = 0; i < glyphCount; i++) { + plan->glyphInfos.Add(glyphInfos[i]); + plan->glyphPositions.Add(glyphPositions[i]); + + piece->width += glyphPositions[i].x_advance; + + if (i == glyphCount - 1 || glyphInfos[i].cluster != glyphInfos[i + 1].cluster) { + piece->width += plan->currentTextStyle->tracking * FREETYPE_UNIT_SCALE; + } + + // EsPrint("\t%d\n", glyphInfos[i].codepoint); + } + + width += piece->width; + + // Go to the next run. + + plan->textRunPosition++; + } + + plan->textRunPosition--; + + return width; +} + +EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *formatRuns, size_t formatRunCount) { + // TODO Bidirectional text (UAX9). + // TODO Vertical text layout (UAX50). + // TODO Supporting arbitrary OpenType features. + // TODO Reshaping lines once word wrapping is applied. + + // EsPrint("EsTextPlanCreate... width %d\n", Width(bounds) * FREETYPE_UNIT_SCALE); + + EsMessageMutexCheck(); + + EsTextPlan plan = {}; + + // Initialise the line breaker. + + plan.breaker.string = string; + plan.breaker.bytes = formatRuns[formatRunCount].offset; + EsAssert(plan.breaker.bytes < 0x80000000); + + if (!plan.breaker.bytes) { + return nullptr; // Empty input. + } + + // Initialise the plan. + + plan.string = string; + plan.singleUse = properties->flags & ES_TEXT_PLAN_SINGLE_USE; + plan.properties = *properties; + + TextLine blankLine = {}; + plan.lines.Add(blankLine); + + // Setup the HarfBuzz buffer. + + plan.buffer = hb_buffer_create(); +#ifdef USE_HARFBUZZ + hb_buffer_set_cluster_level(plan.buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); + + plan.segmentProperties.direction = (properties->flags & ES_TEXT_PLAN_RTL) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR; + plan.segmentProperties.script = (hb_script_t) FALLBACK_SCRIPT; + plan.segmentProperties.language = hb_language_from_string(properties->cLanguage ?: FALLBACK_SCRIPT_LANGUAGE, -1); +#endif + + // Subdivide the runs by character script. + + TextItemizeByScript(&plan, formatRuns, formatRunCount); + + // Layout the paragraph. + + int32_t maximumLineWidth = Width(bounds) && (properties->flags & ES_TEXT_WRAP) ? Width(bounds) * FREETYPE_UNIT_SCALE : -1; + Break previousBreak = {}; + bool needEllipsis = false; + + while (previousBreak.position != plan.breaker.bytes) { + // Find the next break opportunity. + + Break nextBreak = plan.breaker.Next(); + + while (!plan.breaker.error && !nextBreak.forced && (~properties->flags & ES_TEXT_WRAP)) { + nextBreak = plan.breaker.Next(); + } + + if (plan.breaker.error) { + break; + } + + // Build the text pieces for this section. + + uintptr_t pieceOffset = plan.pieces.Length(); + int32_t width = TextBuildTextPieces(&plan, previousBreak.position, nextBreak.position); + width += TextExpandTabs(&plan, pieceOffset, plan.lines.Last().width); + + // Should we start a new line? + + if (previousBreak.forced || (maximumLineWidth != -1 && plan.lines.Last().width + width > maximumLineWidth)) { + if (properties->maxLines == (int32_t) plan.lines.Length()) { + needEllipsis = true; + break; + } + + plan.lines.Add(blankLine); + plan.lines.Last().pieceOffset = pieceOffset; + } + +#if 0 + EsPrint("\tadded section '%s' to line %d (%d pieces) at x=%d\n", + nextBreak.position - previousBreak.position, string + previousBreak.position, + ArrayLength(plan.lines) - 1, ArrayLength(plan.pieces) - pieceOffset, + plan.lines.Last().width); +#endif + + // Add the pieces to the line. + + TextLine *line = &plan.lines.Last(); + TextExpandTabs(&plan, pieceOffset, line->width); + + for (uintptr_t i = pieceOffset; i < plan.pieces.Length(); i++) { + line->width += plan.pieces[i].width; + line->pieceCount++; + } + + TextPlaceEmergencyBreaks(&plan, maximumLineWidth); + + // Go to the next section. + + previousBreak = nextBreak; + } + + // Calculate the ascent/descent of each line. + + for (uintptr_t i = 0; i < plan.lines.Length(); i++) { + TextLine *line = &plan.lines[i]; + + if (!line->pieceCount && i) { + // If the line doesn't have any pieces, it must be from a double newline. + // Inherit the ascent/descent of the previous line. + + line->ascent = line[-1].ascent; + line->descent = line[-1].descent; + } + + for (uintptr_t i = line->pieceOffset; i < line->pieceOffset + line->pieceCount; i++) { + if (line->ascent < plan.pieces[i].ascent) line->ascent = plan.pieces[i].ascent; + if (line->descent < plan.pieces[i].descent) line->descent = plan.pieces[i].descent; + } + } + + // Trim leading and trailing spaces. + + TextTrimSpaces(&plan); + + // Add a terminating ellipsis. + + TextAddEllipsis(&plan, maximumLineWidth, needEllipsis, Width(bounds)); + + // Calculate the total width and height. + + for (uintptr_t i = 0; i < plan.lines.Length(); i++) { + plan.totalHeight += plan.lines[i].ascent + plan.lines[i].descent; + + if (plan.lines[i].width > plan.totalWidth) { + plan.totalWidth = plan.lines[i].width; + } + } + + // Destroy the HarfBuzz buffer. + + hb_buffer_destroy(plan.buffer); + plan.buffer = nullptr; + + // Return the plan. + + EsTextPlan *copy = (EsTextPlan *) EsHeapAllocate(sizeof(EsTextPlan), true); + *copy = plan; + return copy; +} + +void EsTextPlanDestroy(EsTextPlan *plan) { + EsMessageMutexCheck(); + EsAssert(!plan->singleUse); + plan->glyphInfos.Free(); + plan->glyphPositions.Free(); + plan->pieces.Free(); + plan->lines.Free(); + plan->textRuns.Free(); + EsHeapFree(plan); +} + +void EsTextPlanReplaceStyleRenderProperties(EsTextPlan *plan, EsTextStyle *style) { + for (uintptr_t i = 0; i < plan->textRuns.Length() - 1; i++) { + plan->textRuns[i].style.color = style->color; + plan->textRuns[i].style.blur = style->blur; + plan->textRuns[i].style.decorations = style->decorations; + plan->textRuns[i].style.decorationsColor = style->decorationsColor; + } +} + +int EsTextPlanGetWidth(EsTextPlan *plan) { + return (plan->totalWidth + FREETYPE_UNIT_SCALE - 1) / FREETYPE_UNIT_SCALE; +} + +int EsTextPlanGetHeight(EsTextPlan *plan) { + return (plan->totalHeight + FREETYPE_UNIT_SCALE - 1) / FREETYPE_UNIT_SCALE; +} + +size_t EsTextPlanGetLineCount(EsTextPlan *plan) { + return plan->lines.Length(); +} + +EsTextStyle TextPlanGetPrimaryStyle(EsTextPlan *plan) { + return plan->textRuns[0].style; +} + +void DrawTextPiece(EsPainter *painter, EsTextPlan *plan, TextPiece *piece, TextLine *line, + int32_t cursorX, int32_t cursorY, + EsTextSelection *selection, uintptr_t caret, int32_t selectionBackgroundBottom) { + if (cursorX / FREETYPE_UNIT_SCALE > painter->clip.r + || (cursorX + piece->width) / FREETYPE_UNIT_SCALE < painter->clip.l + || cursorY > painter->clip.b + || (cursorY + (piece->ascent + piece->descent) / FREETYPE_UNIT_SCALE) < painter->clip.t) { + return; + } + +#if 0 + EsPrint("\tdrawing piece; '%s' on line %d glyphOffset %d and glyphCount %d at %i, %i with caret %d\n", + piece->end - piece->start, plan->string + piece->start, + line - plan->lines, piece->glyphOffset, piece->glyphCount, + cursorX / FREETYPE_UNIT_SCALE, cursorY, caret); +#endif + + // Prevent issues with negative numbers getting rounded differently... + int32_t cursorXIntegerOffset = -(0x40000000 / FREETYPE_UNIT_SCALE); + cursorX += 0x40000000; + int32_t cursorXStart = cursorX; + + hb_glyph_info_t *glyphs = &plan->glyphInfos[piece->glyphOffset]; + hb_glyph_position_t *glyphPositions = &plan->glyphPositions[piece->glyphOffset]; + + // Update the font to match the piece. + + TextUpdateFont(plan, piece->style); + + // Draw the selection background. + + if (selection->caret0 != selection->caret1 && !selection->hideCaret) { + int sCursorX = cursorX, selectionStartX = -1, selectionEndX = -1; + + for (uintptr_t i = 0; i < piece->glyphCount; i++) { + if (selectionStartX == -1 && glyphs[i].cluster >= selection->caret0) { + selectionStartX = sCursorX; + } + + if (selectionEndX == -1 && glyphs[i].cluster >= selection->caret1) { + selectionEndX = sCursorX; + } + + sCursorX += glyphPositions[i].x_advance; + + if (i == piece->glyphCount - 1 || glyphs[i].cluster != glyphs[i + 1].cluster) { + sCursorX += plan->currentTextStyle->tracking; + } + } + + if (selectionStartX == -1 && selection->caret0 >= 0) { + selectionStartX = sCursorX; + } + + if (selectionEndX == -1) { + selectionEndX = sCursorX; + } + + EsRectangle s; + s.l = (selectionStartX + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE + cursorXIntegerOffset; + s.t = cursorY; + s.r = (selectionEndX + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE + cursorXIntegerOffset; + s.b = selectionBackgroundBottom; + EsDrawBlock(painter, s, selection->background); + } + + // Draw each glyph in the piece. + + int32_t caretX = -1, caretY = cursorY; + + for (uintptr_t i = 0; i < piece->glyphCount; i++) { + uint32_t codepoint = glyphs[i].codepoint; + + int positionX = (glyphPositions[i].x_offset + cursorX) / FREETYPE_UNIT_SCALE + cursorXIntegerOffset, + positionY = ((glyphPositions[i].y_offset + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE + cursorY); + uint32_t color = plan->currentTextStyle->color; + + GlyphCacheKey key = {}; + key.glyphIndex = codepoint; + key.size = plan->currentTextStyle->size; + key.font = plan->font; + GlyphCacheEntry *entry = nullptr; + + if (codepoint == 0xFFFFFFFF) { + goto nextCharacter; + } + + if (key.size > 25) { + key.fractionalPosition = 0; + } else if (key.size > 15) { + key.fractionalPosition = ((glyphPositions[i].x_offset + cursorX) & 0x3F) & 0x20; + } else { + key.fractionalPosition = ((glyphPositions[i].x_offset + cursorX) & 0x3F) & 0x30; + } + + entry = LookupGlyphCacheEntry(key); + + if (!entry->data) { + if (!FontRenderGlyph(api.systemConstants[ES_SYSTEM_CONSTANT_NO_FANCY_GRAPHICS], key, entry)) { + EsHeapFree(entry); + goto nextCharacter; + } else { + RegisterGlyphCacheEntry(key, entry); + } + } + + if (selection->caret0 != selection->caret1 && !selection->hideCaret + && glyphs[i].cluster >= selection->caret0 && glyphs[i].cluster < selection->caret1 + && selection->foreground) { + color = selection->foreground; + } + + // EsPrint("\t%c at %i.%i\n", plan->string[glyphs[i].cluster], positionX, (glyphPositions[i].x_offset + cursorX) & 0x3F); + + DrawSingleCharacter(entry->width, entry->height, entry->xoff, entry->yoff, + ES_POINT(positionX, positionY + line->ascent / FREETYPE_UNIT_SCALE), + painter->clip, painter->target, + plan->currentTextStyle->blur, + api.systemConstants[ES_SYSTEM_CONSTANT_NO_FANCY_GRAPHICS] ? CHARACTER_MONO : CHARACTER_SUBPIXEL, + false, entry->data, + color, 0, -1, painter->target->fullAlpha); + + nextCharacter:; + + if (caretX == -1 && glyphs[i].cluster >= caret) { + caretX = (cursorX + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE; + } + + cursorX += glyphPositions[i].x_advance; + cursorY += (glyphPositions[i].y_advance + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE; + + if (i == piece->glyphCount - 1 || glyphs[i].cluster != glyphs[i + 1].cluster) { + cursorX += plan->currentTextStyle->tracking * FREETYPE_UNIT_SCALE; + } + } + + if (caretX == -1) { + caretX = (cursorX + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE; + } + + // Draw the caret. + + if (!selection->hideCaret && caret >= piece->start + && (caret < piece->end || (caret == piece->end && piece == &plan->pieces[line->pieceOffset + line->pieceCount - 1]))) { + caretX += cursorXIntegerOffset; + + if (selection->snapCaretToInsets && selection->caret0 == selection->caret1) { + EsRectangle insets = EsPainterBoundsInset(painter); + // EsPrint("%d, %d, %d\n", caretX + bounds.l, insets.l, insets.r); + + if (caretX >= insets.l - 1 && caretX <= insets.l + 1) { + caretX = insets.l; + } else if (caretX >= insets.r - 2 && caretX <= insets.r) { + caretX = insets.r - 1; + } + } + + int caretWidth = theming.scale; // TODO Make this a system constant. + EsDrawInvert(painter, ES_RECT_4(caretX, caretX + caretWidth, caretY, selectionBackgroundBottom)); + } + + // Draw decorations. + + { + int32_t thickness = piece->style->size / 15 + 1; + uint32_t color = piece->style->decorationsColor ?: piece->style->color; + + EsRectangle bounds; + bounds.l = cursorXStart / FREETYPE_UNIT_SCALE + cursorXIntegerOffset; + bounds.r = cursorX / FREETYPE_UNIT_SCALE + cursorXIntegerOffset; + + if (piece->style->decorations & ES_TEXT_DECORATION_STRIKE_THROUGH) { + int32_t center = cursorY + (line->ascent + line->descent) / FREETYPE_UNIT_SCALE / 2; + bounds.t = center - thickness / 2 + 1; + bounds.b = center + (thickness + 1) / 2 + 1; + EsDrawBlock(painter, bounds, color); + } + + if (piece->style->decorations & ES_TEXT_DECORATION_UNDERLINE) { + int32_t baseline = cursorY + line->ascent / FREETYPE_UNIT_SCALE; + bounds.t = baseline + thickness; + bounds.b = baseline + thickness * 2; + EsDrawBlock(painter, bounds, color); + } + } +} + +void EsDrawText(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsRectangle *_clip, EsTextSelection *_selection) { + EsMessageMutexCheck(); + + if (!plan) return; + + // EsPrint("EsDrawText... '%s' in %R\n", plan->textRuns[plan->textRunCount].offset, plan->string, bounds); + + // TODO Underlined text. + // TODO Inline images and icons. + + // Work out the selection we should display. + + EsTextSelection selection = {}; + if (_selection) selection = *_selection; + uintptr_t caret = selection.caret1; + + if (selection.caret0 > selection.caret1) { + int swap = selection.caret1; + selection.caret1 = selection.caret0; + selection.caret0 = swap; + } else if (!_selection) { + selection.hideCaret = true; + } + + // Calculate the area we're drawing into. + + int32_t maximumLineWidth = Width(bounds), maximumHeight = Height(bounds); + EsRectangle oldClip = painter->clip; + if (_clip) EsRectangleClip(*_clip, painter->clip, &painter->clip); + int32_t cursorY = (plan->properties.flags & ES_TEXT_V_CENTER) ? (maximumHeight - EsTextPlanGetHeight(plan)) / 2 + : (plan->properties.flags & ES_TEXT_V_BOTTOM) ? maximumHeight - EsTextPlanGetHeight(plan) : 0; + + // Iterate through each line. + + for (uintptr_t i = 0; i < plan->lines.Length(); i++) { + TextLine *line = &plan->lines[i]; + + int32_t cursorX = (plan->properties.flags & ES_TEXT_H_CENTER) ? ((maximumLineWidth * FREETYPE_UNIT_SCALE - line->width) / 2) + : (plan->properties.flags & ES_TEXT_H_RIGHT) ? (maximumLineWidth * FREETYPE_UNIT_SCALE - line->width) : 0; + + int32_t selectionBackgroundBottom; + + if (plan->lines.Length() == 1 && (plan->properties.flags & ES_TEXT_V_CENTER)) { + // If this is a single, centered line, make sure that the selection background bottom edge + // is the same distance from the destination bounds as it is for the top edge. + selectionBackgroundBottom = bounds.b - cursorY; + } else { + selectionBackgroundBottom = cursorY + bounds.t + (line->ascent + line->descent + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE; + } + + // Draw each text piece on the line. + + for (uintptr_t j = 0; j < line->pieceCount; j++) { + TextPiece *piece = &plan->pieces[line->pieceOffset + j]; + DrawTextPiece(painter, plan, piece, line, cursorX + bounds.l * FREETYPE_UNIT_SCALE, cursorY + bounds.t, &selection, caret, selectionBackgroundBottom); + cursorX += piece->width; + } + + if (line->hasEllipsis) { + TextPiece *piece = &plan->pieces[line->ellipsisPieceIndex]; + DrawTextPiece(painter, plan, piece, line, cursorX + bounds.l * FREETYPE_UNIT_SCALE, cursorY + bounds.t, &selection, caret, selectionBackgroundBottom); + cursorX += piece->width; + } + + cursorY += (line->ascent + line->descent + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE; + } + + // Destroy the plan if it is single use. + + if (plan->singleUse) { + plan->singleUse = false; + EsTextPlanDestroy(plan); + } + + painter->clip = oldClip; +} + +#elif defined(TEXT_ELEMENTS) + +// --------------------------------- Markup parsing. + +void EsRichTextParse(const char *inString, ptrdiff_t inStringBytes, + char **outString, EsTextRun **outTextRuns, size_t *outTextRunCount, + EsTextStyle *baseStyle) { + if (inStringBytes == -1) { + inStringBytes = EsCStringLength(inString); + } + + // Step 1: Count the number of runs, and the number of bytes in the actual string. + + size_t textRunCount = 1; + size_t stringBytes = 0; + + for (ptrdiff_t i = 0; i < inStringBytes; i++) { + if (inString[i] == '\a') { + for (; i < inStringBytes; i++) { + if (inString[i] == ']') { + break; + } + } + + textRunCount++; + } else { + stringBytes++; + } + } + + // Step 2: Allocate the string and text runs array. + + char *string = (char *) EsHeapAllocate(stringBytes, false); + EsTextRun *textRuns = (EsTextRun *) EsHeapAllocate((textRunCount + 1) * sizeof(EsTextRun), false); + + textRuns[0].style = *baseStyle; + textRuns[0].offset = 0; + textRuns[textRunCount].offset = stringBytes; + + // Step 3: Copy the information. + + uintptr_t textRunIndex = 1; + uintptr_t stringIndex = 0; + + for (ptrdiff_t i = 0; i < inStringBytes; i++) { + if (inString[i] == '\a') { + EsTextRun *textRun = textRuns + textRunIndex; + textRun->offset = stringIndex; + textRun->style = *baseStyle; + + for (; i < inStringBytes; i++) { + char c = inString[i]; + + if (c == ']') { + break; + } else if (c == 'w' /* weight */) { + i++; if (i >= inStringBytes || inString[i] == ']') goto parsedFormat; + textRun->style.font.weight = inString[i] - '0'; + } else if (c == 'i' /* italic */) { + textRun->style.font.italic = true; + } else if (c == 's' /* size */) { + textRun->style.size = 0; + + while (true) { + i++; if (i >= inStringBytes || inString[i] == ']') goto parsedFormat; + if (inString[i] < '0' || inString[i] > '9') { i--; break; } + textRun->style.size *= 10; + textRun->style.size += inString[i] - '0'; + } + } else if (c == 'm' /* monospaced */) { + textRun->style.font.family = ES_FONT_MONOSPACED; + } else if (c == '-' /* strike-through */) { + textRun->style.decorations |= ES_TEXT_DECORATION_STRIKE_THROUGH; + } else if (c == '_' /* underline */) { + textRun->style.decorations |= ES_TEXT_DECORATION_UNDERLINE; + } else if (c == '2' /* secondary color */) { + textRun->style.color = GetConstantNumber("textSecondary"); + } + } + + parsedFormat:; + textRunIndex++; + } else { + string[stringIndex++] = inString[i]; + } + } + + EsAssert(textRunIndex == textRunCount && stringIndex == stringBytes); + + // Step 4: Return the parsed information. + + *outString = string; + *outTextRuns = textRuns; + *outTextRunCount = textRunCount; +} + +const char *const keywords_a[] = { "auto", nullptr }; +const char *const keywords_b[] = { "bool", "break", nullptr }; +const char *const keywords_c[] = { "case", "char", "const", "continue", nullptr }; +const char *const keywords_d[] = { "default", "do", "double", nullptr }; +const char *const keywords_e[] = { "else", "enum", "extern", nullptr }; +const char *const keywords_f[] = { "float", "for", nullptr }; +const char *const keywords_g[] = { "goto", nullptr }; +const char *const keywords_h[] = { nullptr }; +const char *const keywords_i[] = { "if", "inline", "int", "int16_t", "int32_t", "int64_t", "int8_t", "intptr_t", nullptr }; +const char *const keywords_j[] = { nullptr }; +const char *const keywords_k[] = { nullptr }; +const char *const keywords_l[] = { "long", nullptr }; +const char *const keywords_m[] = { nullptr }; +const char *const keywords_n[] = { nullptr }; +const char *const keywords_o[] = { nullptr }; +const char *const keywords_p[] = { nullptr }; +const char *const keywords_q[] = { nullptr }; +const char *const keywords_r[] = { "register", "restrict", "return", nullptr }; +const char *const keywords_s[] = { "short", "signed", "sizeof", "static", "struct", "switch", nullptr }; +const char *const keywords_t[] = { "typedef", nullptr }; +const char *const keywords_u[] = { "uint16_t", "uint32_t", "uint64_t", "uint8_t", "uintptr_t", "union", "unsigned", nullptr }; +const char *const keywords_v[] = { "void", "volatile", nullptr }; +const char *const keywords_w[] = { "while", nullptr }; +const char *const keywords_x[] = { nullptr }; +const char *const keywords_y[] = { nullptr }; +const char *const keywords_z[] = { nullptr }; + +const char *const *const keywords[] = { + keywords_a, keywords_b, keywords_c, keywords_d, + keywords_e, keywords_f, keywords_g, keywords_h, + keywords_i, keywords_j, keywords_k, keywords_l, + keywords_m, keywords_n, keywords_o, keywords_p, + keywords_q, keywords_r, keywords_s, keywords_t, + keywords_u, keywords_v, keywords_w, keywords_x, + keywords_y, keywords_z, +}; + +bool CharIsAlphaOrDigitOrUnderscore(char c) { + return EsCRTisalpha(c) || EsCRTisdigit(c) || c == '_'; +} + +Array TextApplySyntaxHighlighting(const EsTextStyle *baseStyle, int language, uint32_t *colors, Array runs, const char *string, size_t bytes) { + // TODO Make these colors customizable! + // TODO Highlight keywords. + + int lexState = 0; + bool inComment = false, inIdentifier = false, inChar = false, startedString = false; + bool seenEquals = false; + uint32_t last = 0; + + for (uintptr_t index = 0; index < bytes; index++) { + char c = index >= bytes ? 0 : string[index]; + char c1 = index >= bytes - 1 ? 0 : string[index + 1]; + last <<= 8; + last |= c; + + if (c == '\n') { + lexState = 0; + inComment = false, inIdentifier = false, inChar = false, startedString = false; + seenEquals = false; + last = 0; + } + + if (language == ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C) { + if (lexState == 4) { + lexState = 0; + } else if (lexState == 1) { + if ((last & 0xFF0000) == ('*' << 16) && (last & 0xFF00) == ('/' << 8) && inComment) { + lexState = 0, inComment = false; + } + } else if (lexState == 3 || lexState == 6) { + if (!CharIsAlphaOrDigitOrUnderscore(c)) { + lexState = 0; + } + } else if (lexState == 2) { + if (!startedString) { + if (!inChar && ((last >> 8) & 0xFF) == '"' && ((last >> 16) & 0xFF) != '\\') { + lexState = 0; + } else if (inChar && ((last >> 8) & 0xFF) == '\'' && ((last >> 16) & 0xFF) != '\\') { + lexState = 0; + } + } + + startedString = false; + } + + if (lexState == 0) { + if (c == '#') { + lexState = 5; + } else if (c == '/' && c1 == '/') { + lexState = 1; + } else if (c == '/' && c1 == '*') { + lexState = 1, inComment = true; + } else if (c == '"') { + lexState = 2; + inChar = false; + startedString = true; + } else if (c == '\'') { + lexState = 2; + inChar = true; + startedString = true; + } else if (EsCRTisdigit(c) && !inIdentifier) { + lexState = 3; + } else if (!CharIsAlphaOrDigitOrUnderscore(c)) { + lexState = 4; + inIdentifier = false; + } else { + inIdentifier = true; + + if (c >= 'a' && c <= 'z' && (!index || !CharIsAlphaOrDigitOrUnderscore(string[index - 1]))) { + const char *const *k = keywords[c - 'a']; + + for (int i = 0; k[i]; i++) { + int j = 0; + + for (; k[i][j]; j++) { + if (index + j >= bytes || string[index + j] != k[i][j]) { + goto next; + } + } + + if (index + j == bytes || !CharIsAlphaOrDigitOrUnderscore(string[index + j])) { + lexState = 6; + } + + next:; + } + } + } + } + } else if (language == ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI) { + if (c == ';' && !index) { + lexState = 1; + } else if (c == '[' && !index) { + lexState = 6; + } else if ((c == ' ' || c == ']') && lexState == 5) { + lexState = 6; + } else if (c == '=' && !seenEquals) { + seenEquals = true; + lexState = 4; + } else if (c == '@' && lexState == 6) { + lexState = 5; + } else if (seenEquals && lexState == 4 && EsCRTisdigit(c)) { + lexState = 3; + } else if (seenEquals && lexState == 4) { + lexState = 2; + } + } + + if (!runs.Length() || runs.Last().style.color != colors[lexState + 1]) { + EsTextRun run = {}; + run.offset = index; + run.style = *baseStyle; + run.style.color = colors[lexState + 1]; + runs.Add(run); + } + } + + EsTextRun run = {}; + run.offset = bytes; + runs.Add(run); + + return runs; +} + +// --------------------------------- Textboxes. + +// TODO Caret blinking. +// TODO Wrapped lines. +// TODO Unicode grapheme/word boundaries. +// TODO Selecting lines with the margin. + +struct DocumentLine { + char *GetBuffer(EsTextbox *textbox); + + int32_t lengthBytes, + lengthWidth, + height, + yPosition, + offset; +}; + +struct TextboxVisibleLine { + int32_t yPosition; +}; + +struct TextboxCaret { + int32_t byte, // Relative to the start of the line. + line; +}; + +struct EsTextbox : EsElement { + ScrollPane scroll; + + char *data; // Call TextboxSetActiveLine(textbox, -1) to access this. + uintptr_t dataAllocated; + int32_t dataBytes; + + bool editing; + char *editStartContent; + int32_t editStartContentBytes; + + EsUICallbackFunction overlayCallback; + EsGeneric overlayData; + + char *activeLine; + uintptr_t activeLineAllocated; + int32_t activeLineIndex, activeLineStart, activeLineOldBytes, activeLineBytes; + + int32_t longestLine, longestLineWidth; // To set the horizontal scrollbar's size. + + TextboxCaret carets[2]; // carets[1] is the actual caret; carets[0] is the selection anchor. + TextboxCaret wordSelectionAnchor, wordSelectionAnchor2; + + Array lines; + Array visibleLines; + int32_t firstVisibleLine; + + int verticalMotionHorizontalDepth; + int oldHorizontalScroll; + + EsUndoManager *undo; + EsUndoManager localUndo; + + EsElement *margin; + + EsRectangle borders, insets; + EsTextStyle textStyle; + + uint32_t syntaxHighlightingLanguage; + uint32_t syntaxHighlightingColors[8]; + + bool inRightClickDrag; + + // For smart context menus: + bool colorUppercase; +}; + +#define MOVE_CARET_SINGLE (2) +#define MOVE_CARET_WORD (3) +#define MOVE_CARET_LINE (4) +#define MOVE_CARET_VERTICAL (5) +#define MOVE_CARET_ALL (6) + +#define MOVE_CARET_BACKWARDS (false) +#define MOVE_CARET_FORWARDS (true) + +void TextboxBufferResize(void **array, uintptr_t *allocated, uintptr_t needed, uintptr_t itemSize) { + if (*allocated >= needed) { + return; + } + + uintptr_t oldAllocated = *allocated; + void *oldArray = *array; + + uintptr_t newAllocated = oldAllocated * 2; + if (newAllocated < needed) newAllocated = needed + 16; + void *newArray = EsHeapAllocate(newAllocated * itemSize, false); + + EsMemoryCopy(newArray, oldArray, oldAllocated * itemSize); + EsHeapFree(oldArray); + + *allocated = newAllocated; + *array = newArray; +} + +bool IsScancodeNonTypeable(unsigned scancode) { + switch (scancode) { + case ES_SCANCODE_CAPS_LOCK: + case ES_SCANCODE_SCROLL_LOCK: + case ES_SCANCODE_NUM_LOCK: + case ES_SCANCODE_LEFT_SHIFT: + case ES_SCANCODE_LEFT_CTRL: + case ES_SCANCODE_LEFT_ALT: + case ES_SCANCODE_LEFT_FLAG: + case ES_SCANCODE_RIGHT_SHIFT: + case ES_SCANCODE_RIGHT_CTRL: + case ES_SCANCODE_RIGHT_ALT: + case ES_SCANCODE_PAUSE: + case ES_SCANCODE_CONTEXT_MENU: + case ES_SCANCODE_PRINT_SCREEN: + case ES_SCANCODE_F1: + case ES_SCANCODE_F2: + case ES_SCANCODE_F3: + case ES_SCANCODE_F4: + case ES_SCANCODE_F5: + case ES_SCANCODE_F6: + case ES_SCANCODE_F7: + case ES_SCANCODE_F8: + case ES_SCANCODE_F9: + case ES_SCANCODE_F10: + case ES_SCANCODE_F11: + case ES_SCANCODE_F12: + case ES_SCANCODE_ACPI_POWER: + case ES_SCANCODE_ACPI_SLEEP: + case ES_SCANCODE_ACPI_WAKE: + case ES_SCANCODE_MM_NEXT: + case ES_SCANCODE_MM_PREVIOUS: + case ES_SCANCODE_MM_STOP: + case ES_SCANCODE_MM_PAUSE: + case ES_SCANCODE_MM_MUTE: + case ES_SCANCODE_MM_QUIETER: + case ES_SCANCODE_MM_LOUDER: + case ES_SCANCODE_MM_SELECT: + case ES_SCANCODE_MM_EMAIL: + case ES_SCANCODE_MM_CALC: + case ES_SCANCODE_MM_FILES: + case ES_SCANCODE_WWW_SEARCH: + case ES_SCANCODE_WWW_HOME: + case ES_SCANCODE_WWW_BACK: + case ES_SCANCODE_WWW_FORWARD: + case ES_SCANCODE_WWW_STOP: + case ES_SCANCODE_WWW_REFRESH: + case ES_SCANCODE_WWW_STARRED: + return true; + + default: + return false; + } +} + +void ConvertScancodeToCharacter(unsigned scancode, int *_ic, int *_isc, bool enableTabs, bool enableNewline) { + int ic = -1, isc = -1; + + switch (scancode) { + case ES_SCANCODE_A: ic = 'a'; isc = 'A'; break; + case ES_SCANCODE_B: ic = 'b'; isc = 'B'; break; + case ES_SCANCODE_C: ic = 'c'; isc = 'C'; break; + case ES_SCANCODE_D: ic = 'd'; isc = 'D'; break; + case ES_SCANCODE_E: ic = 'e'; isc = 'E'; break; + case ES_SCANCODE_F: ic = 'f'; isc = 'F'; break; + case ES_SCANCODE_G: ic = 'g'; isc = 'G'; break; + case ES_SCANCODE_H: ic = 'h'; isc = 'H'; break; + case ES_SCANCODE_I: ic = 'i'; isc = 'I'; break; + case ES_SCANCODE_J: ic = 'j'; isc = 'J'; break; + case ES_SCANCODE_K: ic = 'k'; isc = 'K'; break; + case ES_SCANCODE_L: ic = 'l'; isc = 'L'; break; + case ES_SCANCODE_M: ic = 'm'; isc = 'M'; break; + case ES_SCANCODE_N: ic = 'n'; isc = 'N'; break; + case ES_SCANCODE_O: ic = 'o'; isc = 'O'; break; + case ES_SCANCODE_P: ic = 'p'; isc = 'P'; break; + case ES_SCANCODE_Q: ic = 'q'; isc = 'Q'; break; + case ES_SCANCODE_R: ic = 'r'; isc = 'R'; break; + case ES_SCANCODE_S: ic = 's'; isc = 'S'; break; + case ES_SCANCODE_T: ic = 't'; isc = 'T'; break; + case ES_SCANCODE_U: ic = 'u'; isc = 'U'; break; + case ES_SCANCODE_V: ic = 'v'; isc = 'V'; break; + case ES_SCANCODE_W: ic = 'w'; isc = 'W'; break; + case ES_SCANCODE_X: ic = 'x'; isc = 'X'; break; + case ES_SCANCODE_Y: ic = 'y'; isc = 'Y'; break; + case ES_SCANCODE_Z: ic = 'z'; isc = 'Z'; break; + case ES_SCANCODE_0: ic = '0'; isc = ')'; break; + case ES_SCANCODE_1: ic = '1'; isc = '!'; break; + case ES_SCANCODE_2: ic = '2'; isc = '@'; break; + case ES_SCANCODE_3: ic = '3'; isc = '#'; break; + case ES_SCANCODE_4: ic = '4'; isc = '$'; break; + case ES_SCANCODE_5: ic = '5'; isc = '%'; break; + case ES_SCANCODE_6: ic = '6'; isc = '^'; break; + case ES_SCANCODE_7: ic = '7'; isc = '&'; break; + case ES_SCANCODE_8: ic = '8'; isc = '*'; break; + case ES_SCANCODE_9: ic = '9'; isc = '('; break; + case ES_SCANCODE_SLASH: ic = '/'; isc = '?'; break; + case ES_SCANCODE_PUNCTUATION_1: ic = '\\'; isc = '|'; break; + case ES_SCANCODE_LEFT_BRACE: ic = '['; isc = '{'; break; + case ES_SCANCODE_RIGHT_BRACE: ic = ']'; isc = '}'; break; + case ES_SCANCODE_EQUALS: ic = '='; isc = '+'; break; + case ES_SCANCODE_PUNCTUATION_5: ic = '`'; isc = '~'; break; + case ES_SCANCODE_HYPHEN: ic = '-'; isc = '_'; break; + case ES_SCANCODE_PUNCTUATION_3: ic = ';'; isc = ':'; break; + case ES_SCANCODE_PUNCTUATION_4: ic = '\''; isc = '"'; break; + case ES_SCANCODE_COMMA: ic = ','; isc = '<'; break; + case ES_SCANCODE_PERIOD: ic = '.'; isc = '>'; break; + case ES_SCANCODE_SPACE: ic = ' '; isc = ' '; break; + case ES_SCANCODE_ENTER: if (enableNewline) { ic = '\n'; isc = '\n'; } break; + case ES_SCANCODE_TAB: if (enableTabs) { ic = '\t'; isc = '\t'; } break; + } + + *_ic = ic, *_isc = isc; +} + +size_t EsMessageGetInputText(EsMessage *message, char *buffer) { + int ic, isc; + ConvertScancodeToCharacter(message->keyboard.scancode, &ic, &isc, true, true); + + if (message->keyboard.modifiers & ES_MODIFIER_SHIFT) ic = isc; + if (ic == -1) return 0; + + return utf8_encode(ic, buffer); +} + +enum CharacterType { + CHARACTER_INVALID, + CHARACTER_IDENTIFIER, // A-Z, a-z, 0-9, _, >= 0x7F + CHARACTER_WHITESPACE, // space, tab, newline + CHARACTER_OTHER, +}; + +static CharacterType GetCharacterType(int character) { + if ((character >= '0' && character <= '9') + || (character >= 'a' && character <= 'z') + || (character >= 'A' && character <= 'Z') + || (character == '_') + || (character >= 0x80)) { + return CHARACTER_IDENTIFIER; + } + + if (character == '\n' || character == '\t' || character == ' ') { + return CHARACTER_WHITESPACE; + } + + return CHARACTER_OTHER; +} + +int TextboxCompareCarets(const TextboxCaret *left, const TextboxCaret *right) { + if (left->line < right->line) return -1; + if (left->line > right->line) return 1; + if (left->byte < right->byte) return -1; + if (left->byte > right->byte) return 1; + return 0; +} + +void TextboxSetActiveLine(EsTextbox *textbox, int lineIndex) { + if (textbox->activeLineIndex == lineIndex) { + return; + } + + if (lineIndex == -1) { + int32_t lineBytesDelta = textbox->activeLineBytes - textbox->activeLineOldBytes; + + // Step 1: Resize the data buffer to fit the new contents of the line. + + TextboxBufferResize((void **) &textbox->data, &textbox->dataAllocated, textbox->dataBytes + lineBytesDelta, 1); + + // Step 2: Move everything after the old end of the active line to its new position. + + EsMemoryMove(textbox->data + textbox->activeLineStart + textbox->activeLineOldBytes, + textbox->data + textbox->dataBytes, + lineBytesDelta, + false); + textbox->dataBytes += lineBytesDelta; + + // Step 3: Copy the active line back into the data buffer. + + EsMemoryCopy(textbox->data + textbox->activeLineStart, + textbox->activeLine, + textbox->activeLineBytes); + + // Step 4: Update the line byte offsets. + + for (uintptr_t i = textbox->activeLineIndex + 1; i < textbox->lines.Length(); i++) { + textbox->lines[i].offset += lineBytesDelta; + } + } else { + TextboxSetActiveLine(textbox, -1); + + DocumentLine *line = &textbox->lines[lineIndex]; + + TextboxBufferResize((void **) &textbox->activeLine, &textbox->activeLineAllocated, (textbox->activeLineBytes = line->lengthBytes), 1); + EsMemoryCopy(textbox->activeLine, textbox->data + line->offset, textbox->activeLineBytes); + + textbox->activeLineStart = line->offset; + textbox->activeLineOldBytes = textbox->activeLineBytes; + } + + textbox->activeLineIndex = lineIndex; +} + +void EsTextboxStartEdit(EsTextbox *textbox) { + textbox->state &= ~UI_STATE_LOST_STRONG_FOCUS; + + if ((textbox->flags & ES_TEXTBOX_EDIT_BASED) && !textbox->editing) { + EsMessage m = { ES_MSG_TEXTBOX_EDIT_START }; + + if (0 == EsMessageSend(textbox, &m)) { + EsTextboxSelectAll(textbox); + } + + if (textbox->state & UI_STATE_DESTROYING) { + return; + } + + textbox->editing = true; // Update this after sending the message so overlays can receive it. + TextboxSetActiveLine(textbox, -1); + textbox->editStartContent = (char *) EsHeapAllocate(textbox->dataBytes, false); + textbox->editStartContentBytes = textbox->dataBytes; + EsMemoryCopy(textbox->editStartContent, textbox->data, textbox->editStartContentBytes); + textbox->Repaint(true); + } +} + +void TextboxEndEdit(EsTextbox *textbox, bool reject) { + if ((textbox->flags & ES_TEXTBOX_EDIT_BASED) && textbox->editing) { + textbox->editing = false; + EsMessage m = { ES_MSG_TEXTBOX_EDIT_END }; + m.endEdit.rejected = reject; + + if (reject || ES_REJECTED == EsMessageSend(textbox, &m)) { + EsTextboxSelectAll(textbox); + EsTextboxInsert(textbox, textbox->editStartContent, textbox->editStartContentBytes); + TextboxSetActiveLine(textbox, -1); + if (reject) EsMessageSend(textbox, &m); + } + + if (textbox->state & UI_STATE_DESTROYING) { + return; + } + + EsTextboxSetSelection(textbox, 0, 0, 0, 0); + EsHeapFree(textbox->editStartContent); + textbox->editStartContent = nullptr; + textbox->scroll.SetX(0); + textbox->Repaint(true); + } +} + +void TextboxUpdateCommands(EsTextbox *textbox, bool caretsMovedOnly) { + if (~textbox->state & UI_STATE_FOCUSED) { + return; + } + + EsCommand *command; + + bool selectionEmpty = !TextboxCompareCarets(textbox->carets + 0, textbox->carets + 1) && textbox->editing; + + command = EsCommandByID(textbox->instance, ES_COMMAND_DELETE); + command->data = textbox; + EsCommandSetDisabled(command, selectionEmpty); + + EsCommandSetCallback(command, [] (EsInstance *, EsElement *, EsCommand *command) { + EsTextbox *textbox = (EsTextbox *) command->data.p; + EsTextboxInsert(textbox, "", 0, true); + }); + + command = EsCommandByID(textbox->instance, ES_COMMAND_COPY); + command->data = textbox; + EsCommandSetDisabled(command, selectionEmpty); + + EsCommandSetCallback(command, [] (EsInstance *, EsElement *, EsCommand *command) { + EsTextbox *textbox = (EsTextbox *) command->data.p; + size_t textBytes; + char *text = EsTextboxGetContents(textbox, &textBytes, textbox->editing ? ES_TEXTBOX_GET_CONTENTS_SELECTED_ONLY : ES_FLAGS_DEFAULT); + EsError error = EsClipboardAddText(ES_CLIPBOARD_PRIMARY, text, textBytes); + EsHeapFree(text); + + EsRectangle bounds = EsElementGetWindowBounds(textbox); + int32_t x = (bounds.l + bounds.r) / 2; + int32_t y = (bounds.t + bounds.b) / 2; // TODO Position this in the middle of the selection. + + if (error == ES_SUCCESS) { + EsAnnouncementShow(textbox->window, ES_FLAGS_DEFAULT, x, y, INTERFACE_STRING(CommonAnnouncementTextCopied)); + } else if (error == ES_ERROR_INSUFFICIENT_RESOURCES) { + EsAnnouncementShow(textbox->window, ES_FLAGS_DEFAULT, x, y, INTERFACE_STRING(CommonAnnouncementCopyErrorResources)); + } else { + EsAnnouncementShow(textbox->window, ES_FLAGS_DEFAULT, x, y, INTERFACE_STRING(CommonAnnouncementCopyErrorOther)); + } + }); + + command = EsCommandByID(textbox->instance, ES_COMMAND_CUT); + command->data = textbox; + EsCommandSetDisabled(command, selectionEmpty); + + EsCommandSetCallback(command, [] (EsInstance *, EsElement *, EsCommand *command) { + EsTextbox *textbox = (EsTextbox *) command->data.p; + size_t textBytes; + char *text = EsTextboxGetContents(textbox, &textBytes, textbox->editing ? ES_TEXTBOX_GET_CONTENTS_SELECTED_ONLY : ES_FLAGS_DEFAULT); + EsClipboardAddText(ES_CLIPBOARD_PRIMARY, text, textBytes); + EsHeapFree(text); + EsTextboxStartEdit(textbox); + EsTextboxInsert(textbox, "", 0, true); + }); + + if (!caretsMovedOnly) { + EsInstanceSetActiveUndoManager(textbox->instance, textbox->undo); + + command = EsCommandByID(textbox->instance, ES_COMMAND_SELECT_ALL); + command->data = textbox; + EsCommandSetDisabled(command, !(textbox->lines.Length() > 1 || textbox->lines[0].lengthBytes)); + + EsCommandSetCallback(command, [] (EsInstance *, EsElement *, EsCommand *command) { + EsTextboxSelectAll((EsTextbox *) command->data.p); + }); + + command = EsCommandByID(textbox->instance, ES_COMMAND_PASTE); + command->data = textbox; + EsCommandSetDisabled(command, !EsClipboardHasText(ES_CLIPBOARD_PRIMARY)); + + EsCommandSetCallback(command, [] (EsInstance *, EsElement *, EsCommand *command) { + EsTextbox *textbox = (EsTextbox *) command->data.p; + + size_t textBytes = 0; + char *text = EsClipboardReadText(ES_CLIPBOARD_PRIMARY, &textBytes); + EsTextboxInsert(textbox, text, textBytes, true); + EsTextboxEnsureCaretVisible(textbox); + }); + } +} + +char *DocumentLine::GetBuffer(EsTextbox *textbox) { + if (textbox->activeLineIndex == this - textbox->lines.array) { + return textbox->activeLine; + } else { + return textbox->data + offset; + } +} + +void TextboxFindLongestLine(EsTextbox *textbox) { + if (textbox->longestLine == -1) { + textbox->longestLine = 0; + textbox->longestLineWidth = textbox->lines[0].lengthWidth; + + for (uintptr_t i = 1; i < textbox->lines.Length(); i++) { + int32_t width = textbox->lines[i].lengthWidth; + + if (width > textbox->longestLineWidth) { + textbox->longestLine = i, textbox->longestLineWidth = width; + } + } + } +} + +TextboxVisibleLine *TextboxGetVisibleLine(EsTextbox *textbox, int32_t documentLineIndex) { + return textbox->firstVisibleLine > documentLineIndex + || textbox->firstVisibleLine + (int32_t) textbox->visibleLines.Length() <= documentLineIndex + ? nullptr : &textbox->visibleLines[documentLineIndex - textbox->firstVisibleLine]; +} + +void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) { + TextboxCaret caret = textbox->carets[1]; + EsRectangle bounds = textbox->GetBounds(); + + { + DocumentLine *line = &textbox->lines[caret.line]; + int caretY = line->yPosition + textbox->insets.t; + + int scrollY = textbox->scroll.position[1]; + int viewportHeight = bounds.b; + caretY -= scrollY; + + if (viewportHeight > 0) { + if (verticallyCenter) { + scrollY += caretY - viewportHeight / 2; + } else { + if (caretY < textbox->insets.t) { + scrollY += caretY - textbox->insets.t; + } else if (caretY + line->height > viewportHeight - textbox->insets.b) { + scrollY += caretY + line->height - viewportHeight + textbox->insets.b; + } + } + + textbox->scroll.SetY(scrollY); + } + } + + TextboxVisibleLine *visibleLine = TextboxGetVisibleLine(textbox, caret.line); + + if (visibleLine) { + DocumentLine *line = &textbox->lines[caret.line]; + int scrollX = textbox->scroll.position[0]; + int viewportWidth = bounds.r; + int caretX = TextGetPartialStringWidth(&textbox->textStyle, + line->GetBuffer(textbox), line->lengthBytes, caret.byte) - scrollX + textbox->insets.l; + + if (caretX < textbox->insets.l) { + scrollX += caretX - textbox->insets.l; + } else if (caretX + 1 > viewportWidth - textbox->insets.r) { + scrollX += caretX + 1 - viewportWidth + textbox->insets.r; + } + + textbox->scroll.SetX(scrollX); + } +} + +bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int moveType, bool strongWhitespace = false) { + TextboxCaret old = *caret; + EsDefer(TextboxUpdateCommands(textbox, true)); + + if (moveType == MOVE_CARET_LINE) { + caret->byte = right ? textbox->lines[caret->line].lengthBytes : 0; + } else if (moveType == MOVE_CARET_ALL) { + caret->line = right ? textbox->lines.Length() - 1 : 0; + caret->byte = right ? textbox->lines[caret->line].lengthBytes : 0; + } else if (moveType == MOVE_CARET_VERTICAL) { + if ((right && caret->line + 1 == (int32_t) textbox->lines.Length()) || (!right && !caret->line)) { + return false; + } + + if (textbox->verticalMotionHorizontalDepth == -1) { + textbox->verticalMotionHorizontalDepth = TextGetPartialStringWidth(&textbox->textStyle, + textbox->lines[caret->line].GetBuffer(textbox), textbox->lines[caret->line].lengthBytes, caret->byte); + } + + if (right) caret->line++; else caret->line--; + caret->byte = 0; + + DocumentLine *line = &textbox->lines[caret->line]; + int pointX = textbox->verticalMotionHorizontalDepth ? textbox->verticalMotionHorizontalDepth - 1 : 0; + ptrdiff_t result = TextGetCharacterAtPoint(&textbox->textStyle, + line->GetBuffer(textbox), line->lengthBytes, &pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE); + caret->byte = result == -1 ? line->lengthBytes : result; + } else { + CharacterType type = CHARACTER_INVALID; + char *currentLineBuffer = textbox->lines[caret->line].GetBuffer(textbox); + if (moveType == MOVE_CARET_WORD && right) goto checkCharacterType; + + while (true) { + if (!right) { + if (caret->byte || caret->line) { + if (caret->byte) { + caret->byte = utf8_retreat(currentLineBuffer + caret->byte) - currentLineBuffer; + } else { + caret->byte = textbox->lines[--caret->line].lengthBytes; + currentLineBuffer = textbox->lines[caret->line].GetBuffer(textbox); + } + } else { + break; // We cannot move any further left. + } + } else { + if (caret->line < (int32_t) textbox->lines.Length() - 1 || caret->byte < textbox->lines[caret->line].lengthBytes) { + if (caret->byte < textbox->lines[caret->line].lengthBytes) { + caret->byte = utf8_advance(currentLineBuffer + caret->byte) - currentLineBuffer; + } else { + caret->line++; + caret->byte = 0; + currentLineBuffer = textbox->lines[caret->line].GetBuffer(textbox); + } + } else { + break; // We cannot move any further right. + } + } + + if (moveType == MOVE_CARET_SINGLE) { + break; + } + + checkCharacterType:; + + int character; + + if (caret->byte == textbox->lines[caret->line].lengthBytes) { + character = '\n'; + } else { + character = utf8_value(currentLineBuffer + caret->byte); + } + + CharacterType newType = GetCharacterType(character); + + if (type == CHARACTER_INVALID) { + if (newType != CHARACTER_WHITESPACE || strongWhitespace) { + type = newType; + } + } else { + if (newType != type) { + if (!right) { + // We've gone too far. + TextboxMoveCaret(textbox, caret, true, MOVE_CARET_SINGLE); + } + + break; + } + } + } + } + + return caret->line != old.line; +} + +void EsTextboxMoveCaretRelative(EsTextbox *textbox, uint32_t flags) { + if (~flags & ES_TEXTBOX_MOVE_CARET_SECOND_ONLY) { + TextboxMoveCaret(textbox, &textbox->carets[0], ~flags & ES_TEXTBOX_MOVE_CARET_BACKWARDS, + flags & 0xFF, flags & ES_TEXTBOX_MOVE_CARET_STRONG_WHITESPACE); + } + + if (~flags & ES_TEXTBOX_MOVE_CARET_FIRST_ONLY) { + TextboxMoveCaret(textbox, &textbox->carets[1], ~flags & ES_TEXTBOX_MOVE_CARET_BACKWARDS, + flags & 0xFF, flags & ES_TEXTBOX_MOVE_CARET_STRONG_WHITESPACE); + } +} + +void TextboxRepaintLine(EsTextbox *textbox, int line) { + if (line == -1 || (~textbox->flags & ES_TEXTBOX_MULTILINE)) { + textbox->Repaint(true); + } else { + EsRectangle borders = textbox->borders; + int topInset = textbox->insets.t; + + TextboxVisibleLine *visibleLine = TextboxGetVisibleLine(textbox, line); + + if (visibleLine) { + EsRectangle bounds = textbox->GetBounds(); + EsRectangle lineBounds = ES_RECT_4(bounds.l + borders.l, bounds.r - borders.r, + visibleLine->yPosition + topInset - 1 - textbox->scroll.position[1], + visibleLine->yPosition + topInset + textbox->lines[line].height - textbox->scroll.position[1]); + // EsPrint("textbox bounds %R; line bounds %R\n", bounds); + textbox->Repaint(false, lineBounds); + } + } +} + +void TextboxSetHorizontalScroll(EsTextbox *textbox, int scroll) { + textbox->Repaint(true); + textbox->oldHorizontalScroll = scroll; +} + +void TextboxRefreshVisibleLines(EsTextbox *textbox, bool repaint = true) { + if (textbox->visibleLines.Length()) { + textbox->visibleLines.SetLength(0); + } + + int scrollX = textbox->scroll.position[0], scrollY = textbox->scroll.position[1]; + EsRectangle bounds = textbox->GetBounds(); + + int32_t low = 0, high = textbox->lines.Length() - 1, target = scrollY - textbox->insets.t; + + while (low != high) { + int32_t middle = (low + high) / 2; + int32_t position = textbox->lines[middle].yPosition; + + if (position < target && low != middle) low = middle; + else if (position > target && high != middle) high = middle; + else break; + } + + textbox->firstVisibleLine = (low + high) / 2; + if (textbox->firstVisibleLine) textbox->firstVisibleLine--; + + for (int32_t i = textbox->firstVisibleLine; i < (int32_t) textbox->lines.Length(); i++) { + TextboxVisibleLine line = {}; + line.yPosition = textbox->lines[i].yPosition; + textbox->visibleLines.Add(line); + + if (line.yPosition - scrollY > bounds.b) { + break; + } + } + + bool refreshXLimit = false; + + for (uintptr_t i = 0; i < textbox->visibleLines.Length(); i++) { + DocumentLine *line = &textbox->lines[textbox->firstVisibleLine + i]; + + if (line->lengthWidth != -1) { + continue; + } + + line->lengthWidth = TextGetStringWidth(&textbox->textStyle, + line->GetBuffer(textbox), line->lengthBytes); + + if (textbox->longestLine != -1 && line->lengthWidth > textbox->longestLineWidth) { + textbox->longestLine = textbox->firstVisibleLine + i; + textbox->longestLineWidth = line->lengthWidth; + refreshXLimit = true; + } + } + + if (refreshXLimit) { + textbox->scroll.Refresh(); + EsElementRelayout(textbox); + } + + textbox->scroll.SetX(scrollX); + if (repaint) textbox->Repaint(true); +} + +void TextboxLineCountChangeCleanup(EsTextbox *textbox, int32_t offsetDelta, int32_t startLine) { + for (int32_t i = startLine; i < (int32_t) textbox->lines.Length(); i++) { + DocumentLine *line = &textbox->lines[i], *previous = &textbox->lines[i - 1]; + line->yPosition = previous->yPosition + previous->height; + line->offset += offsetDelta; + } + + TextboxRefreshVisibleLines(textbox); +} + +void EsTextboxMoveCaret(EsTextbox *textbox, int32_t line, int32_t byte) { + EsMessageMutexCheck(); + + textbox->carets[0].line = line; + textbox->carets[0].byte = byte; + textbox->carets[1].line = line; + textbox->carets[1].byte = byte; + textbox->Repaint(true); + TextboxUpdateCommands(textbox, true); +} + +void EsTextboxGetSelection(EsTextbox *textbox, int32_t *fromLine, int32_t *fromByte, int32_t *toLine, int32_t *toByte) { + EsMessageMutexCheck(); + + *fromLine = textbox->carets[0].line; + *fromByte = textbox->carets[0].byte; + *toLine = textbox->carets[1].line; + *toByte = textbox->carets[1].byte; +} + +void EsTextboxSetSelection(EsTextbox *textbox, int32_t fromLine, int32_t fromByte, int32_t toLine, int32_t toByte) { + EsMessageMutexCheck(); + + if (fromByte == -1) fromByte = textbox->lines[fromLine].lengthBytes; + if (toByte == -1) toByte = textbox->lines[toLine].lengthBytes; + if (fromByte < 0 || toByte < 0 || fromByte > textbox->lines[fromLine].lengthBytes || toByte > textbox->lines[toLine].lengthBytes) return; + textbox->carets[0].line = fromLine; + textbox->carets[0].byte = fromByte; + textbox->carets[1].line = toLine; + textbox->carets[1].byte = toByte; + textbox->Repaint(true); + TextboxUpdateCommands(textbox, true); + EsTextboxEnsureCaretVisible(textbox); +} + +void EsTextboxSelectAll(EsTextbox *textbox) { + EsMessageMutexCheck(); + + TextboxMoveCaret(textbox, &textbox->carets[0], false, MOVE_CARET_ALL); + TextboxMoveCaret(textbox, &textbox->carets[1], true, MOVE_CARET_ALL); + EsTextboxEnsureCaretVisible(textbox); + textbox->Repaint(true); +} + +void EsTextboxClear(EsTextbox *textbox, bool sendUpdatedMessage) { + EsMessageMutexCheck(); + + EsTextboxSelectAll(textbox); + EsTextboxInsert(textbox, "", 0, sendUpdatedMessage); +} + +size_t EsTextboxGetLineLength(EsTextbox *textbox, uintptr_t line) { + EsMessageMutexCheck(); + + return textbox->lines[line].lengthBytes; +} + +struct TextboxUndoItemHeader { + EsTextbox *textbox; + TextboxCaret caretsBefore[2]; + size_t insertBytes; + double timeStampMs; + // Followed by insert string. +}; + +void TextboxUndoItemCallback(const void *item, EsUndoManager *manager, EsMessage *message) { + if (message->type == ES_MSG_UNDO_INVOKE) { + TextboxUndoItemHeader *header = (TextboxUndoItemHeader *) item; + EsTextbox *textbox = header->textbox; + EsAssert(textbox->undo == manager); + TextboxRepaintLine(textbox, textbox->carets[0].line); + TextboxRepaintLine(textbox, textbox->carets[0].line); + textbox->carets[0] = header->caretsBefore[0]; + textbox->carets[1] = header->caretsBefore[1]; + EsTextboxInsert(textbox, (const char *) (header + 1), header->insertBytes, true); + } else if (message->type == ES_MSG_UNDO_CANCEL) { + // Nothing to do. + } +} + +void EsTextboxInsert(EsTextbox *textbox, const char *string, ptrdiff_t stringBytes, bool sendUpdatedMessage) { + EsMessageMutexCheck(); + + // EsPerformanceTimerPush(); + // double measureLineTime = 0; + + if (stringBytes == -1) { + stringBytes = EsCStringLength(string); + } + + TextboxUndoItemHeader *undoItem = nullptr; + size_t undoItemBytes = 0; + + textbox->wordSelectionAnchor = textbox->carets[0]; + textbox->wordSelectionAnchor2 = textbox->carets[1]; + + textbox->verticalMotionHorizontalDepth = -1; + + // ::: Delete the selected text. + + // Step 1: Get the range of text we're deleting. + + TextboxCaret deleteFrom, deleteTo; + int comparison = TextboxCompareCarets(textbox->carets + 0, textbox->carets + 1); + + if (comparison < 0) deleteFrom = textbox->carets[0], deleteTo = textbox->carets[1]; + else if (comparison > 0) deleteFrom = textbox->carets[1], deleteTo = textbox->carets[0]; + + if (comparison) { + textbox->carets[0] = textbox->carets[1] = deleteFrom; + + // Step 2: Calculate the number of bytes we are deleting. + + int32_t deltaBytes; + + if (deleteFrom.line == deleteTo.line) { + deltaBytes = deleteFrom.byte - deleteTo.byte; + } else { + TextboxSetActiveLine(textbox, -1); + + deltaBytes = deleteFrom.byte - deleteTo.byte; + + for (int32_t i = deleteFrom.line; i < deleteTo.line; i++) { + deltaBytes -= textbox->lines[i].lengthBytes; + } + } + + if (textbox->undo) { + // Step 3: Allocate space for an undo item. + + undoItemBytes = sizeof(TextboxUndoItemHeader) - deltaBytes + deleteTo.line - deleteFrom.line; + undoItem = (TextboxUndoItemHeader *) EsHeapAllocate(undoItemBytes, false); + EsMemoryZero(undoItem, sizeof(TextboxUndoItemHeader)); + undoItem->insertBytes = undoItemBytes - sizeof(TextboxUndoItemHeader); + } + + if (deleteFrom.line == deleteTo.line) { + EsAssert(deltaBytes < 0); // Expected deleteTo > deleteFrom. + DocumentLine *line = &textbox->lines[deleteFrom.line]; + TextboxSetActiveLine(textbox, deleteFrom.line); + + // Step 4: Update the width of the line and repaint it. + + line->lengthWidth = TextGetStringWidth(&textbox->textStyle, textbox->activeLine, textbox->activeLineBytes); + TextboxRepaintLine(textbox, deleteFrom.line); + + // Step 5: Update the active line buffer. + + if (undoItem) EsMemoryCopy(undoItem + 1, textbox->activeLine + deleteFrom.byte, -deltaBytes); + EsMemoryMove(textbox->activeLine + deleteTo.byte, textbox->activeLine + line->lengthBytes, deltaBytes, false); + textbox->activeLineBytes += deltaBytes; + line->lengthBytes += deltaBytes; + + // Step 6: Update the longest line. + + if (textbox->longestLine == deleteFrom.line && line->lengthWidth < textbox->longestLineWidth) { + textbox->longestLine = -1; + } + } else { + if (undoItem) { + // Step 4: Copy into the undo item. + + char *position = (char *) (undoItem + 1); + + for (int32_t i = deleteFrom.line; i <= deleteTo.line; i++) { + char *from = textbox->data + textbox->lines[i].offset; + char *to = textbox->data + textbox->lines[i].offset + textbox->lines[i].lengthBytes; + if (i == deleteFrom.line) from += deleteFrom.byte; + if (i == deleteTo.line) to += deleteTo.byte - textbox->lines[i].lengthBytes; + EsMemoryCopy(position, from, to - from); + position += to - from; + if (i != deleteTo.line) *position++ = '\n'; + } + } + + // Step 5: Remove the text from the buffer. + + EsMemoryMove(textbox->data + deleteTo.byte + textbox->lines[deleteTo.line].offset, textbox->data + textbox->dataBytes, deltaBytes, false); + textbox->dataBytes += deltaBytes; + + // Step 6: Merged the joined lines. + + DocumentLine *firstLine = &textbox->lines[deleteFrom.line]; + firstLine->lengthBytes = textbox->lines[deleteTo.line].lengthBytes - deleteTo.byte + deleteFrom.byte; + firstLine->lengthWidth = TextGetStringWidth(&textbox->textStyle, textbox->data + firstLine->offset, firstLine->lengthBytes); + + // Step 7: Remove the deleted lines and update the textbox. + + textbox->lines.DeleteMany(deleteFrom.line + 1, deleteTo.line - deleteFrom.line); + textbox->longestLine = -1; + TextboxLineCountChangeCleanup(textbox, deltaBytes, deleteFrom.line + 1); + } + } else { + if (textbox->undo) { + undoItemBytes = sizeof(TextboxUndoItemHeader); + undoItem = (TextboxUndoItemHeader *) EsHeapAllocate(undoItemBytes, false); + EsMemoryZero(undoItem, sizeof(TextboxUndoItemHeader)); + } + } + + if (undoItem) { + undoItem->caretsBefore[0] = undoItem->caretsBefore[1] = textbox->carets[0]; + } + + // ::: Insert the new text. + + if (!stringBytes) goto done; + + { + TextboxCaret insertionPoint = textbox->carets[0]; + + DocumentLine *line = &textbox->lines[insertionPoint.line]; + int32_t lineByteOffset = line->offset, + offsetIntoLine = insertionPoint.byte, + byteOffset = offsetIntoLine + lineByteOffset; + + // Step 1: Count the number of newlines in the input string. + + uintptr_t position = 0, + newlines = 0, + carriageReturns = 0; + + while (position < (size_t) stringBytes) { + int length; + UTF8_LENGTH_CHAR(string + position, length); + if (length == 0) length = 1; + + if (position + length > (size_t) stringBytes) { + break; + } else if (string[position] == '\n') { + newlines++; + } else if (string[position] == '\r' && position != (size_t) stringBytes - 1 && string[position + 1] == '\n') { + carriageReturns++; + } + + position += length; + } + + size_t bytesToInsert = stringBytes - newlines - carriageReturns; + + if (!newlines || (~textbox->flags & ES_TEXTBOX_MULTILINE)) { + // Step 2: Update the active line buffer. + + TextboxSetActiveLine(textbox, insertionPoint.line); + TextboxBufferResize((void **) &textbox->activeLine, &textbox->activeLineAllocated, (textbox->activeLineBytes += bytesToInsert), 1); + EsMemoryMove(textbox->activeLine + offsetIntoLine, textbox->activeLine + line->lengthBytes, bytesToInsert, false); + + const char *dataToInsert = string; + size_t added = 0; + + for (uintptr_t i = 0; i < newlines + 1; i++) { + const char *end = (const char *) EsCRTmemchr(dataToInsert, '\n', stringBytes - (dataToInsert - string)) ?: string + stringBytes; + bool carriageReturn = end != string && end[-1] == '\r'; + if (carriageReturn) end--; + EsMemoryCopy(textbox->activeLine + offsetIntoLine + added, dataToInsert, end - dataToInsert); + added += end - dataToInsert; + dataToInsert = end + (carriageReturn ? 2 : 1); + } + + EsAssert(added == bytesToInsert); // Added incorrect number of bytes in EsTextboxInsert. + + line->lengthBytes += bytesToInsert; + + // Step 3: Update the carets, line width, and repaint it. + + textbox->carets[0].byte += bytesToInsert; + textbox->carets[1].byte += bytesToInsert; + line->lengthWidth = TextGetStringWidth(&textbox->textStyle, textbox->activeLine, line->lengthBytes); + TextboxRepaintLine(textbox, insertionPoint.line); + + // Step 4: Update the longest line. + + if (textbox->longestLine != -1 && line->lengthWidth > textbox->longestLineWidth) { + textbox->longestLine = insertionPoint.line; + textbox->longestLineWidth = line->lengthWidth; + } + } else { + // Step 2: Make room in the buffer for the contents of the string. + + TextboxSetActiveLine(textbox, -1); + TextboxBufferResize((void **) &textbox->data, &textbox->dataAllocated, textbox->dataBytes + bytesToInsert, 1); + EsMemoryMove(textbox->data + byteOffset, textbox->data + textbox->dataBytes, bytesToInsert, false); + textbox->dataBytes += bytesToInsert; + + // Step 3: Truncate the insertion line. + + int32_t truncation = line->lengthBytes - insertionPoint.byte; + line->lengthBytes = insertionPoint.byte; + + // Step 4: Add the new lines. + + textbox->lines.InsertMany(insertionPoint.line + 1, newlines); + const char *dataToInsert = string; + uintptr_t insertedBytes = 0; + + for (uintptr_t i = 0; i < newlines + 1; i++) { + DocumentLine *line = &textbox->lines[insertionPoint.line + i], *previous = line - 1; + + // Step 4a: Initialise the line. + + if (i) { + EsMemoryZero(line, sizeof(*line)); + line->height = EsTextGetLineHeight(&textbox->textStyle); + line->yPosition = previous->yPosition + previous->height; + line->offset = lineByteOffset + insertedBytes; + } + + // Step 4b: Copy the string data into the line. + + const char *end = (const char *) EsCRTmemchr(dataToInsert, '\n', stringBytes - (dataToInsert - string)) ?: string + stringBytes; + bool carriageReturn = end != string && end[-1] == '\r'; + if (carriageReturn) end--; + EsMemoryCopy(textbox->data + line->offset + line->lengthBytes, dataToInsert, end - dataToInsert); + line->lengthBytes += end - dataToInsert; + insertedBytes += line->lengthBytes; + dataToInsert = end + (carriageReturn ? 2 : 1); + + if (i == newlines) { + line->lengthBytes += truncation; + } + + // Step 4c: Update the line's width. + + // EsPerformanceTimerPush(); +#if 0 + line->lengthWidth = EsTextGetPartialStringWidth(&textbox->textStyle, textbox->data + line->offset, line->lengthBytes, 0, line->lengthBytes); +#else + line->lengthWidth = -1; +#endif + // double time = EsPerformanceTimerPop(); + // measureLineTime += time; + // EsPrint("Measured the length of line %d in %Fms.\n", insertionPoint.line + i, time * 1000); + } + + // Step 5: Update the carets. + + textbox->carets[0].line = insertionPoint.line + newlines; + textbox->carets[1].line = insertionPoint.line + newlines; + textbox->carets[0].byte = textbox->lines[insertionPoint.line + newlines].lengthBytes - truncation; + textbox->carets[1].byte = textbox->lines[insertionPoint.line + newlines].lengthBytes - truncation; + + // Step 6: Update the textbox. + + textbox->longestLine = -1; + TextboxLineCountChangeCleanup(textbox, bytesToInsert, insertionPoint.line + 1 + newlines); + } + + if (undoItem) undoItem->caretsBefore[1] = textbox->carets[0]; + } + + done:; + + if (sendUpdatedMessage) { + EsMessage m = { ES_MSG_TEXTBOX_UPDATED }; + EsMessageSend(textbox, &m); + } else if (textbox->overlayCallback) { + EsMessage m = { ES_MSG_TEXTBOX_UPDATED }; + textbox->overlayCallback(textbox, &m); + } + + if (textbox->state & UI_STATE_DESTROYING) { + return; + } + + TextboxFindLongestLine(textbox); + InspectorNotifyElementContentChanged(textbox); + + if (undoItem && (undoItem->insertBytes || TextboxCompareCarets(undoItem->caretsBefore + 0, undoItem->caretsBefore + 1))) { + undoItem->timeStampMs = EsTimeStampMs(); + + EsUndoCallback previousCallback; + const void *previousItem; + + if (!EsUndoInUndo(textbox->undo) + && EsUndoPeek(textbox->undo, &previousCallback, &previousItem) + && previousCallback == TextboxUndoItemCallback) { + TextboxUndoItemHeader *header = (TextboxUndoItemHeader *) previousItem; + +#define TEXTBOX_UNDO_TIMEOUT (500) // TODO Make this configurable. + if (undoItem->timeStampMs - header->timeStampMs < TEXTBOX_UNDO_TIMEOUT) { + if (!undoItem->insertBytes && !header->insertBytes + && undoItem->caretsBefore[0].line == header->caretsBefore[1].line + && undoItem->caretsBefore[0].byte == header->caretsBefore[1].byte) { + // Merge the items. + undoItem->caretsBefore[0] = header->caretsBefore[0]; + EsUndoPop(textbox->undo); + } else { + // Add the new item to the same group as the previous. + EsUndoContinueGroup(textbox->undo); + } + } + } + + undoItem->textbox = textbox; + EsUndoPush(textbox->undo, TextboxUndoItemCallback, undoItem, undoItemBytes); + } + + EsHeapFree(undoItem); + + // double time = EsPerformanceTimerPop(); + // EsPrint("EsTextboxInsert in %Fms (%Fms measuring new lines).\n", time * 1000, measureLineTime * 1000); + + textbox->scroll.Refresh(); + TextboxUpdateCommands(textbox, false); +} + +char *EsTextboxGetContents(EsTextbox *textbox, size_t *_bytes, uint32_t flags) { + EsMessageMutexCheck(); + + TextboxSetActiveLine(textbox, -1); + + bool includeNewline = textbox->flags & ES_TEXTBOX_MULTILINE; + size_t bytes = textbox->dataBytes + (includeNewline ? textbox->lines.Length() : 0); + char *buffer = (char *) EsHeapAllocate(bytes + 1, false); + buffer[bytes] = 0; + + uintptr_t position = 0; + uintptr_t lineFrom = 0, lineTo = textbox->lines.Length() - 1; + + if (flags & ES_TEXTBOX_GET_CONTENTS_SELECTED_ONLY) { + lineFrom = textbox->carets[0].line; + lineTo = textbox->carets[1].line; + + if (lineFrom > lineTo) { + uintptr_t swap = lineFrom; + lineFrom = lineTo, lineTo = swap; + } + } + + for (uintptr_t i = lineFrom; i <= lineTo; i++) { + DocumentLine *line = &textbox->lines[i]; + + uintptr_t offsetFrom = 0; + uintptr_t offsetTo = line->lengthBytes; + + if (flags & ES_TEXTBOX_GET_CONTENTS_SELECTED_ONLY) { + if (i == lineFrom) { + offsetFrom = TextboxCompareCarets(textbox->carets + 0, textbox->carets + 1) < 0 ? textbox->carets[0].byte : textbox->carets[1].byte; + } + + if (i == lineTo) { + offsetTo = TextboxCompareCarets(textbox->carets + 0, textbox->carets + 1) > 0 ? textbox->carets[0].byte : textbox->carets[1].byte; + } + } + + EsMemoryCopy(buffer + position, line->GetBuffer(textbox) + offsetFrom, offsetTo - offsetFrom); + position += offsetTo - offsetFrom; + + if (includeNewline && i != lineTo) { + buffer[position++] = '\n'; + } + } + + buffer[position] = 0; + EsAssert(position <= bytes); + if (_bytes) *_bytes = position; + return (char *) EsHeapReallocate(buffer, position + 1, false); +} + +double EsTextboxGetContentsAsDouble(EsTextbox *textbox, uint32_t flags) { + size_t bytes; + char *text = EsTextboxGetContents(textbox, &bytes, flags); + double result = EsDoubleParse(text, bytes, nullptr); + EsHeapFree(text); + return result; +} + +bool EsTextboxFind(EsTextbox *textbox, const char *needle, intptr_t _needleBytes, int32_t *_line, int32_t *_byte, uint32_t flags) { + EsMessageMutexCheck(); + + if (_needleBytes == 0) { + return false; + } + + uintptr_t needleBytes = _needleBytes == -1 ? EsCStringLength(needle) : _needleBytes; + uint32_t lineIndex = *_line, byteIndex = *_byte; + bool firstLoop = true; + + while (true) { + DocumentLine *line = &textbox->lines[lineIndex]; + const char *buffer = line->GetBuffer(textbox); + size_t bufferBytes = line->lengthBytes; + EsAssert(byteIndex <= bufferBytes); // Invalid find byte offset. + + // TODO Case-insensitive search. + + if (flags & ES_TEXTBOX_FIND_BACKWARDS) { + if (bufferBytes >= needleBytes) { + for (uintptr_t i = byteIndex; i >= needleBytes; i--) { + for (uintptr_t j = 0; j < needleBytes; j++) { + if (buffer[i - needleBytes + j] != needle[j]) { + goto previousPosition; + } + } + + *_line = lineIndex; + *_byte = i - needleBytes; + return true; + + previousPosition:; + } + } + + if ((int32_t) lineIndex <= *_line && !firstLoop) { + return false; + } + + if (lineIndex == 0) { + firstLoop = false; + lineIndex = textbox->lines.Length() - 1; + } else { + lineIndex--; + } + + byteIndex = textbox->lines[lineIndex].lengthBytes; + } else { + if (bufferBytes >= needleBytes) { + for (uintptr_t i = byteIndex; i <= bufferBytes - needleBytes; i++) { + for (uintptr_t j = 0; j < needleBytes; j++) { + if (buffer[i + j] != needle[j]) { + goto nextPosition; + } + } + + *_line = lineIndex; + *_byte = i; + return true; + + nextPosition:; + } + } + + lineIndex++; + + if ((int32_t) lineIndex > *_line && !firstLoop) { + return false; + } + + if (lineIndex == textbox->lines.Length()) { + firstLoop = false; + lineIndex = 0; + } + + byteIndex = 0; + } + } + + return false; +} + +bool TextboxFindCaret(EsTextbox *textbox, int positionX, int positionY, bool secondCaret, int clickChainCount) { + int startLine0 = textbox->carets[0].line, startLine1 = textbox->carets[1].line; + EsRectangle bounds = textbox->GetBounds(); + + if (positionX < 0) { + positionX = 0; + } else if (positionX >= bounds.r) { + positionX = bounds.r - 1; + } + + if (positionY < 0) { + positionY = 0; + } else if (positionY >= bounds.b) { + positionY = bounds.b - 1; + } + + if (clickChainCount >= 4) { + textbox->carets[0].line = 0; + textbox->carets[0].byte = 0; + textbox->carets[1].line = textbox->lines.Length() - 1; + textbox->carets[1].byte = textbox->lines[textbox->lines.Length() - 1].lengthBytes; + } else { + for (uintptr_t i = 0; i < textbox->visibleLines.Length(); i++) { + TextboxVisibleLine *visibleLine = &textbox->visibleLines[i]; + DocumentLine *line = &textbox->lines[textbox->firstVisibleLine + i]; + + EsRectangle lineBounds = ES_RECT_4(textbox->insets.l, bounds.r, + textbox->insets.t + visibleLine->yPosition, + textbox->insets.t + visibleLine->yPosition + line->height); + lineBounds.l -= textbox->scroll.position[0]; + lineBounds.t -= textbox->scroll.position[1]; + lineBounds.b -= textbox->scroll.position[1]; + + if (!((positionY >= lineBounds.t || i + textbox->firstVisibleLine == 0) && (positionY < lineBounds.b + || i + textbox->firstVisibleLine == textbox->lines.Length() - 1))) { + continue; + } + + if (!line->lengthBytes) { + textbox->carets[1].byte = 0; + } else { + DocumentLine *line = &textbox->lines[i + textbox->firstVisibleLine]; + int pointX = positionX + textbox->scroll.position[0] - textbox->insets.l; + if (pointX < 0) pointX = 0; + ptrdiff_t result = TextGetCharacterAtPoint(&textbox->textStyle, + line->GetBuffer(textbox), line->lengthBytes, + &pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE); + textbox->carets[1].byte = result == -1 ? line->lengthBytes : result; + } + + textbox->carets[1].line = i + textbox->firstVisibleLine; + + break; + } + + if (!secondCaret) { + textbox->carets[0] = textbox->carets[1]; + + if (clickChainCount == 2) { + TextboxMoveCaret(textbox, textbox->carets + 0, MOVE_CARET_BACKWARDS, MOVE_CARET_WORD, true); + TextboxMoveCaret(textbox, textbox->carets + 1, MOVE_CARET_FORWARDS, MOVE_CARET_WORD, true); + textbox->wordSelectionAnchor = textbox->carets[0]; + textbox->wordSelectionAnchor2 = textbox->carets[1]; + } else if (clickChainCount == 3) { + TextboxMoveCaret(textbox, textbox->carets + 0, MOVE_CARET_BACKWARDS, MOVE_CARET_LINE, true); + TextboxMoveCaret(textbox, textbox->carets + 1, MOVE_CARET_FORWARDS, MOVE_CARET_LINE, true); + textbox->wordSelectionAnchor = textbox->carets[0]; + textbox->wordSelectionAnchor2 = textbox->carets[1]; + } + } else { + if (clickChainCount == 2) { + if (TextboxCompareCarets(textbox->carets + 1, textbox->carets + 0) < 0) { + TextboxMoveCaret(textbox, textbox->carets + 1, MOVE_CARET_BACKWARDS, MOVE_CARET_WORD); + textbox->carets[0] = textbox->wordSelectionAnchor2; + } else { + TextboxMoveCaret(textbox, textbox->carets + 1, MOVE_CARET_FORWARDS, MOVE_CARET_WORD); + textbox->carets[0] = textbox->wordSelectionAnchor; + } + } else if (clickChainCount == 3) { + if (TextboxCompareCarets(textbox->carets + 1, textbox->carets + 0) < 0) { + TextboxMoveCaret(textbox, textbox->carets + 1, MOVE_CARET_BACKWARDS, MOVE_CARET_LINE); + textbox->carets[0] = textbox->wordSelectionAnchor2; + } else { + TextboxMoveCaret(textbox, textbox->carets + 1, MOVE_CARET_FORWARDS, MOVE_CARET_LINE); + textbox->carets[0] = textbox->wordSelectionAnchor; + } + } + } + } + + TextboxUpdateCommands(textbox, true); + return textbox->carets[0].line != startLine0 || textbox->carets[1].line != startLine1; +} + +void TextboxMoveCaretToCursor(EsTextbox *textbox, int x, int y, bool doNotMoveIfNoSelection) { + int oldCompare = TextboxCompareCarets(textbox->carets + 0, textbox->carets + 1); + bool hasSelection = oldCompare != 0; + TextboxCaret old[2] = { textbox->carets[0], textbox->carets[1] }; + bool lineChanged = TextboxFindCaret(textbox, x, y, gui.clickChainCount == 1, gui.clickChainCount); + + if (doNotMoveIfNoSelection && TextboxCompareCarets(&old[0], &old[1]) != 0) { + textbox->carets[0] = old[0]; + textbox->carets[1] = old[1]; + } else if (gui.clickChainCount == 1 && !EsKeyboardIsShiftHeld()) { + textbox->carets[0] = textbox->carets[1]; + } + + TextboxUpdateCommands(textbox, true); + textbox->verticalMotionHorizontalDepth = -1; + TextboxRepaintLine(textbox, lineChanged || hasSelection ? -1 : textbox->carets[0].line); + EsTextboxEnsureCaretVisible(textbox); +} + +int ProcessTextboxMarginMessage(EsElement *element, EsMessage *message) { + EsTextbox *textbox = (EsTextbox *) element->parent; + + if (message->type == ES_MSG_PAINT) { + EsPainter *painter = message->painter; + + for (int32_t i = 0; i < (int32_t) textbox->visibleLines.Length(); i++) { + TextboxVisibleLine *visibleLine = &textbox->visibleLines[i]; + DocumentLine *line = &textbox->lines[i + textbox->firstVisibleLine]; + + EsRectangle bounds; + bounds.l = painter->offsetX + element->currentStyle->insets.l; + bounds.r = painter->offsetX + painter->width - element->currentStyle->insets.r; + bounds.t = painter->offsetY + textbox->insets.t + visibleLine->yPosition - textbox->scroll.position[1]; + bounds.b = bounds.t + line->height; + + char label[64]; + EsTextRun textRun[2] = {}; + element->currentStyle->GetTextStyle(&textRun[0].style); + textRun[0].style.figures = ES_TEXT_FIGURE_TABULAR; + textRun[1].offset = EsStringFormat(label, sizeof(label), "%d", i + textbox->firstVisibleLine + 1); + EsTextPlanProperties properties = {}; + properties.flags = ES_TEXT_V_CENTER | ES_TEXT_H_RIGHT | ES_TEXT_ELLIPSIS | ES_TEXT_PLAN_SINGLE_USE; + EsDrawText(painter, EsTextPlanCreate(&properties, bounds, label, textRun, 1), bounds, nullptr, nullptr); + } + } + + return 0; +} + +int ProcessTextboxMessage(EsElement *element, EsMessage *message) { + EsTextbox *textbox = (EsTextbox *) element; + + if (!textbox->editing && textbox->overlayCallback) { + int response = textbox->overlayCallback(element, message); + if (response != 0 && message->type != ES_MSG_DESTROY) return response; + } + + textbox->scroll.ReceivedMessage(message); + + int response = ES_HANDLED; + + if (message->type == ES_MSG_PAINT) { + EsPainter *painter = message->painter; + + EsTextSelection selectionProperties = {}; + selectionProperties.hideCaret = (~textbox->state & UI_STATE_FOCUSED) || (textbox->flags & ES_ELEMENT_DISABLED) || !textbox->editing; + selectionProperties.snapCaretToInsets = true; + selectionProperties.background = textbox->currentStyle->metrics->selectedBackground; + selectionProperties.foreground = textbox->currentStyle->metrics->selectedText; + + EsRectangle clip; + EsRectangleClip(painter->clip, ES_RECT_4(painter->offsetX + textbox->borders.l, + painter->offsetX + painter->width - textbox->borders.r, + painter->offsetY + textbox->borders.t, + painter->offsetY + painter->height - textbox->borders.b), &clip); + + Array textRuns = {}; + + for (int32_t i = 0; i < (int32_t) textbox->visibleLines.Length(); i++) { + TextboxVisibleLine *visibleLine = &textbox->visibleLines[i]; + DocumentLine *line = &textbox->lines[i + textbox->firstVisibleLine]; + + EsRectangle lineBounds = ES_RECT_4(painter->offsetX + textbox->insets.l, + painter->offsetX + painter->width, + painter->offsetY + textbox->insets.t + visibleLine->yPosition, + painter->offsetY + textbox->insets.t + visibleLine->yPosition + line->height); + lineBounds.l -= textbox->scroll.position[0]; + lineBounds.t -= textbox->scroll.position[1]; + lineBounds.b -= textbox->scroll.position[1]; + + if (~textbox->flags & ES_TEXTBOX_MULTILINE) { + lineBounds.b = painter->offsetY + painter->height - textbox->insets.b; + } + + int32_t caret0 = textbox->carets[0].byte, caret1 = textbox->carets[1].byte; + if (textbox->carets[0].line < i + textbox->firstVisibleLine) caret0 = -2; + if (textbox->carets[0].line > i + textbox->firstVisibleLine) caret0 = line->lengthBytes + 2; + if (textbox->carets[1].line < i + textbox->firstVisibleLine) caret1 = -2; + if (textbox->carets[1].line > i + textbox->firstVisibleLine) caret1 = line->lengthBytes + 2; + + if (textbox->carets[1].line == i + textbox->firstVisibleLine && textbox->syntaxHighlightingLanguage) { + EsRectangle line = ES_RECT_4(painter->offsetX, painter->offsetX + painter->width, lineBounds.t, lineBounds.b); + EsDrawBlock(painter, line, textbox->syntaxHighlightingColors[0]); + } + + if (textbox->syntaxHighlightingLanguage && line->lengthBytes) { + if (textRuns.Length()) textRuns.SetLength(0); + textRuns = TextApplySyntaxHighlighting(&textbox->textStyle, textbox->syntaxHighlightingLanguage, + textbox->syntaxHighlightingColors, textRuns, line->GetBuffer(textbox), line->lengthBytes); + } else { + textRuns.SetLength(2); + textRuns[0].style = textbox->textStyle; + textRuns[0].offset = 0; + textRuns[1].offset = line->lengthBytes; + } + + EsTextPlanProperties properties = {}; + properties.flags = ES_TEXT_V_CENTER | ES_TEXT_H_LEFT | ES_TEXT_PLAN_SINGLE_USE; + selectionProperties.caret0 = caret0; + selectionProperties.caret1 = caret1; + EsTextPlan *plan; + + if (textRuns[1].offset) { + plan = EsTextPlanCreate(&properties, lineBounds, line->GetBuffer(textbox), textRuns.array, textRuns.Length() - 1); + } else { + textRuns[1].offset = 1; // Make sure that the caret and selection is draw correctly, even on empty lines. + plan = EsTextPlanCreate(&properties, lineBounds, " ", textRuns.array, textRuns.Length() - 1); + } + + if (plan) { + EsDrawText(painter, plan, lineBounds, &clip, &selectionProperties); + } + } + + textRuns.Free(); + } else if (message->type == ES_MSG_LAYOUT) { + EsRectangle bounds = textbox->GetBounds(); + + if (textbox->margin) { + int marginWidth = textbox->margin->currentStyle->preferredWidth; + textbox->margin->InternalMove(marginWidth, Height(bounds), bounds.l, bounds.t); + } + + TextboxRefreshVisibleLines(textbox); + + if (textbox->editing && (~textbox->flags & ES_TEXTBOX_MULTILINE)) { + EsTextboxEnsureCaretVisible(textbox); + } + } else if (message->type == ES_MSG_DESTROY) { + textbox->visibleLines.Free(); + textbox->lines.Free(); + UndoManagerDestroy(&textbox->localUndo); + EsHeapFree(textbox->activeLine); + EsHeapFree(textbox->data); + EsHeapFree(textbox->editStartContent); + } else if (message->type == ES_MSG_KEY_TYPED && !IsScancodeNonTypeable(message->keyboard.scancode)) { + bool verticalMotion = false; + bool ctrl = message->keyboard.modifiers & ES_MODIFIER_CTRL; + + if (message->keyboard.scancode == ES_SCANCODE_LEFT_ARROW || message->keyboard.scancode == ES_SCANCODE_RIGHT_ARROW + || message->keyboard.scancode == ES_SCANCODE_HOME || message->keyboard.scancode == ES_SCANCODE_END + || message->keyboard.scancode == ES_SCANCODE_UP_ARROW || message->keyboard.scancode == ES_SCANCODE_DOWN_ARROW) { + bool direction = (message->keyboard.scancode == ES_SCANCODE_LEFT_ARROW || message->keyboard.scancode == ES_SCANCODE_HOME + || message->keyboard.scancode == ES_SCANCODE_UP_ARROW) + ? MOVE_CARET_BACKWARDS : MOVE_CARET_FORWARDS; + int moveType = (message->keyboard.scancode == ES_SCANCODE_HOME || message->keyboard.scancode == ES_SCANCODE_END) + ? (ctrl ? MOVE_CARET_ALL : MOVE_CARET_LINE) + : ((message->keyboard.scancode == ES_SCANCODE_UP_ARROW || message->keyboard.scancode == ES_SCANCODE_DOWN_ARROW) + ? MOVE_CARET_VERTICAL : (ctrl ? MOVE_CARET_WORD : MOVE_CARET_SINGLE)); + if (moveType == MOVE_CARET_VERTICAL) verticalMotion = true; + + int32_t lineFrom = textbox->carets[1].line; + + if (message->keyboard.modifiers & ES_MODIFIER_SHIFT) { + TextboxMoveCaret(textbox, &textbox->carets[1], direction, moveType); + } else { + int caretCompare = TextboxCompareCarets(textbox->carets + 1, textbox->carets + 0); + + if ((caretCompare < 0 && direction == MOVE_CARET_BACKWARDS) || (caretCompare > 0 && direction == MOVE_CARET_FORWARDS)) { + textbox->carets[0] = textbox->carets[1]; + TextboxUpdateCommands(textbox, true); + } else if ((caretCompare > 0 && direction == MOVE_CARET_BACKWARDS) || (caretCompare < 0 && direction == MOVE_CARET_FORWARDS)) { + textbox->carets[1] = textbox->carets[0]; + TextboxUpdateCommands(textbox, true); + } else { + TextboxMoveCaret(textbox, &textbox->carets[1], direction, moveType); + textbox->carets[0] = textbox->carets[1]; + TextboxUpdateCommands(textbox, true); + } + } + + int32_t lineTo = textbox->carets[1].line; + if (lineFrom > lineTo) { int32_t t = lineTo; lineTo = lineFrom; lineFrom = t; } + for (int32_t i = lineFrom; i <= lineTo; i++) TextboxRepaintLine(textbox, i); + } else if (message->keyboard.scancode == ES_SCANCODE_PAGE_UP || message->keyboard.scancode == ES_SCANCODE_PAGE_DOWN) { + for (uintptr_t i = 0; i < 10; i++) { + TextboxMoveCaret(textbox, textbox->carets + 1, + message->keyboard.scancode == ES_SCANCODE_PAGE_UP ? MOVE_CARET_BACKWARDS : MOVE_CARET_FORWARDS, + MOVE_CARET_VERTICAL); + } + + if (~message->keyboard.modifiers & ES_MODIFIER_SHIFT) { + textbox->carets[0] = textbox->carets[1]; + TextboxUpdateCommands(textbox, true); + } + + textbox->Repaint(true); + verticalMotion = true; + } else if (message->keyboard.scancode == ES_SCANCODE_BACKSPACE || message->keyboard.scancode == ES_SCANCODE_DELETE) { + if (!TextboxCompareCarets(textbox->carets + 0, textbox->carets + 1)) { + TextboxMoveCaret(textbox, textbox->carets + 1, message->keyboard.scancode == ES_SCANCODE_BACKSPACE ? MOVE_CARET_BACKWARDS : MOVE_CARET_FORWARDS, + ctrl ? MOVE_CARET_WORD : MOVE_CARET_SINGLE); + } + + EsTextboxInsert(textbox, EsLiteral("")); + } else if (message->keyboard.scancode == ES_SCANCODE_ENTER && (textbox->flags & ES_TEXTBOX_EDIT_BASED)) { + if (textbox->editing) { + TextboxEndEdit(textbox, false); + } else { + EsTextboxStartEdit(textbox); + } + } else if (message->keyboard.scancode == ES_SCANCODE_ESCAPE && (textbox->flags & ES_TEXTBOX_EDIT_BASED)) { + TextboxEndEdit(textbox, true); + } else if (message->keyboard.scancode == ES_SCANCODE_TAB && (~textbox->flags & ES_TEXTBOX_ALLOW_TABS)) { + response = 0; + } else { + if (!textbox->editing) { + EsTextboxStartEdit(textbox); + } + + int ic, isc; + ConvertScancodeToCharacter(message->keyboard.scancode, &ic, &isc, true, textbox->flags & ES_TEXTBOX_MULTILINE); + + if (ic != -1 && (message->keyboard.modifiers & ~ES_MODIFIER_SHIFT) == 0) { + char buffer[4]; + EsTextboxInsert(textbox, buffer, utf8_encode((message->keyboard.modifiers & ES_MODIFIER_SHIFT) ? isc : ic, buffer)); + + if (buffer[0] == '\n' && textbox->carets[0].line) { + // Copy the indentation from the previous line. + + DocumentLine *previousLine = &textbox->lines[textbox->carets[0].line - 1]; + const char *buffer = previousLine->GetBuffer(textbox); + int32_t i = 0; + + for (; i < previousLine->lengthBytes; i++) { + if (buffer[i] != '\t') { + break; + } + } + + EsTextboxInsert(textbox, buffer, i); + } + } else { + response = 0; + } + } + + if (!verticalMotion) { + textbox->verticalMotionHorizontalDepth = -1; + } + + if (response != 0 && (~textbox->state & UI_STATE_DESTROYING)) { + TextboxFindLongestLine(textbox); + textbox->scroll.Refresh(); + EsTextboxEnsureCaretVisible(textbox); + textbox->window->ensureVisible = textbox; + } + } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN || message->type == ES_MSG_MOUSE_RIGHT_DOWN) { + TextboxMoveCaretToCursor(textbox, message->mouseDown.positionX, message->mouseDown.positionY, message->type == ES_MSG_MOUSE_RIGHT_DOWN); + } else if (message->type == ES_MSG_MOUSE_LEFT_CLICK) { + EsTextboxStartEdit(textbox); + } else if (message->type == ES_MSG_FOCUSED_START || message->type == ES_MSG_PRIMARY_CLIPBOARD_UPDATED) { + TextboxUpdateCommands(textbox, false); + EsInstanceSetActiveUndoManager(textbox->instance, textbox->undo); + textbox->Repaint(true); + } else if (message->type == ES_MSG_FOCUSED_END) { + EsCommandSetCallback(EsCommandByID(textbox->instance, ES_COMMAND_SELECT_ALL), nullptr); + EsCommandSetCallback(EsCommandByID(textbox->instance, ES_COMMAND_DELETE), nullptr); + EsCommandSetCallback(EsCommandByID(textbox->instance, ES_COMMAND_COPY), nullptr); + EsCommandSetCallback(EsCommandByID(textbox->instance, ES_COMMAND_CUT), nullptr); + EsCommandSetCallback(EsCommandByID(textbox->instance, ES_COMMAND_PASTE), nullptr); + EsInstanceSetActiveUndoManager(textbox->instance, textbox->instance->undoManager); + textbox->Repaint(true); + } else if (message->type == ES_MSG_STRONG_FOCUS_END) { + TextboxEndEdit(textbox, textbox->flags & ES_TEXTBOX_REJECT_EDIT_IF_LOST_FOCUS); + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG || message->type == ES_MSG_MOUSE_RIGHT_DRAG || (message->type == ES_MSG_ANIMATE && textbox->scroll.dragScrolling)) { + int32_t lineFrom = textbox->carets[1].line; + + if (gui.lastClickButton == ES_MSG_MOUSE_RIGHT_DOWN && !textbox->inRightClickDrag) { + TextboxMoveCaretToCursor(textbox, message->mouseDragged.originalPositionX, message->mouseDragged.originalPositionY, false); + textbox->inRightClickDrag = true; + } + + EsPoint position = EsMouseGetPosition(textbox); + TextboxFindCaret(textbox, position.x, position.y, true, gui.clickChainCount); + + int32_t lineTo = textbox->carets[1].line; + if (lineFrom > lineTo) { int32_t t = lineTo; lineTo = lineFrom; lineFrom = t; } + for (int32_t i = lineFrom; i <= lineTo; i++) TextboxRepaintLine(textbox, i); + } else if (message->type == ES_MSG_GET_CURSOR) { + if (!textbox->editing || (textbox->flags & ES_ELEMENT_DISABLED)) { + message->cursorStyle = ES_CURSOR_NORMAL; + } else { + return 0; + } + } else if (message->type == ES_MSG_MOUSE_RIGHT_UP) { + textbox->inRightClickDrag = false; + EsMenu *menu = EsMenuCreate(textbox, ES_MENU_AT_CURSOR); + + // TODO User customisation of menus. + + if (textbox->editing) { + EsMenuAddCommand(menu, 0, INTERFACE_STRING(CommonUndo), EsCommandByID(textbox->instance, ES_COMMAND_UNDO)); + EsMenuAddSeparator(menu); + } + + EsMenuAddCommand(menu, 0, INTERFACE_STRING(CommonClipboardCut), EsCommandByID(textbox->instance, ES_COMMAND_CUT)); + EsMenuAddCommand(menu, 0, INTERFACE_STRING(CommonClipboardCopy), EsCommandByID(textbox->instance, ES_COMMAND_COPY)); + EsMenuAddCommand(menu, 0, INTERFACE_STRING(CommonClipboardPaste), EsCommandByID(textbox->instance, ES_COMMAND_PASTE)); + + if (textbox->editing) { + EsMenuAddSeparator(menu); + EsMenuAddCommand(menu, 0, INTERFACE_STRING(CommonSelectionSelectAll), EsCommandByID(textbox->instance, ES_COMMAND_SELECT_ALL)); + EsMenuAddCommand(menu, 0, INTERFACE_STRING(CommonSelectionDelete), EsCommandByID(textbox->instance, ES_COMMAND_DELETE)); + + // Add the smart context menu, if necessary. + + if ((~textbox->flags & ES_TEXTBOX_NO_SMART_CONTEXT_MENUS) && textbox->carets[0].line == textbox->carets[1].line) { + int32_t selectionFrom = textbox->carets[0].byte, selectionTo = textbox->carets[1].byte; + + if (selectionTo < selectionFrom) { + int32_t temporary = selectionFrom; + selectionFrom = selectionTo; + selectionTo = temporary; + } + + if (selectionTo - selectionFrom == 7) { + char buffer[7]; + EsMemoryCopy(buffer, textbox->lines[textbox->carets[0].line].GetBuffer(textbox) + selectionFrom, 7); + + if (buffer[0] == '#' && EsCRTisxdigit(buffer[1]) && EsCRTisxdigit(buffer[2]) && EsCRTisxdigit(buffer[3]) + && EsCRTisxdigit(buffer[4]) && EsCRTisxdigit(buffer[5]) && EsCRTisxdigit(buffer[6])) { + // It's a color hex-code! + // TODO Versions with alpha. + EsMenuNextColumn(menu); + ColorPickerCreate(menu, { textbox }, EsColorParse(buffer, 7), false); + + textbox->colorUppercase = true; + + for (uintptr_t i = 1; i <= 6; i++) { + if (buffer[i] >= 'a' && buffer[i] <= 'f') { + textbox->colorUppercase = false; + break; + } + } + } + } + } + } + + EsMenuShow(menu); + } else if (message->type == ES_MSG_COLOR_CHANGED) { + EsAssert(~textbox->flags & ES_TEXTBOX_NO_SMART_CONTEXT_MENUS); // Textbox sent color changed message, but it cannot have smart context menus? + uint32_t color = message->colorChanged.newColor; + + if (message->colorChanged.pickerClosed) { + int32_t selectionFrom = textbox->carets[0].byte, selectionTo = textbox->carets[1].byte; + + if (textbox->carets[0].line == textbox->carets[1].line && AbsoluteInteger(selectionFrom - selectionTo) == 7) { + char buffer[7]; + const char *hexChars = textbox->colorUppercase ? "0123456789ABCDEF" : "0123456789abcedf"; + size_t length = EsStringFormat(buffer, 7, "#%c%c%c%c%c%c", + hexChars[(color >> 20) & 0xF], hexChars[(color >> 16) & 0xF], hexChars[(color >> 12) & 0xF], + hexChars[(color >> 8) & 0xF], hexChars[(color >> 4) & 0xF], hexChars[(color >> 0) & 0xF]); + EsTextboxInsert(textbox, buffer, length, true); + EsTextboxSetSelection(textbox, textbox->carets[1].line, textbox->carets[1].byte - 7, + textbox->carets[1].line, textbox->carets[1].byte); + } + } + } else if (message->type == ES_MSG_GET_WIDTH) { + message->measure.width = textbox->longestLineWidth + textbox->insets.l + textbox->insets.r; + } else if (message->type == ES_MSG_GET_HEIGHT) { + DocumentLine *lastLine = &textbox->lines.Last(); + message->measure.height = lastLine->yPosition + lastLine->height + textbox->insets.t + textbox->insets.b; + } else if (message->type == ES_MSG_SCROLL_X) { + TextboxSetHorizontalScroll(textbox, message->scrollbarMoved.scroll); + } else if (message->type == ES_MSG_SCROLL_Y) { + TextboxRefreshVisibleLines(textbox, false); + EsElementRepaintForScroll(textbox, message); + } else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) { + DocumentLine *firstLine = &textbox->lines.First(); + EsBufferFormat(message->getContent.buffer, "'%s'", firstLine->lengthBytes, firstLine->GetBuffer(textbox)); + } else { + response = 0; + } + + return response; +} + +EsTextbox *EsTextboxCreate(EsElement *parent, uint64_t flags, const EsStyle *style) { + EsTextbox *textbox = (EsTextbox *) EsHeapAllocate(sizeof(EsTextbox), true); + + if (!style) { + if (flags & ES_TEXTBOX_MULTILINE) { + style = ES_STYLE_TEXTBOX_BORDERED_MULTILINE; + } else { + style = ES_STYLE_TEXTBOX_BORDERED_SINGLE; + } + } + + textbox->Initialise(parent, ES_ELEMENT_FOCUSABLE | flags, ProcessTextboxMessage, style); + textbox->cName = "textbox"; + + textbox->scroll.Setup(textbox, + (flags & ES_TEXTBOX_MULTILINE) ? SCROLL_MODE_AUTO : SCROLL_MODE_HIDDEN, + (flags & ES_TEXTBOX_MULTILINE) ? SCROLL_MODE_AUTO : SCROLL_MODE_NONE, + SCROLL_X_DRAG | SCROLL_Y_DRAG); + + textbox->undo = &textbox->localUndo; + textbox->undo->instance = textbox->instance; + + // TODO Automatically update these when the theme changes. + textbox->borders = textbox->currentStyle->borders; + textbox->insets = textbox->currentStyle->insets; + textbox->currentStyle->GetTextStyle(&textbox->textStyle); + + DocumentLine firstLine = {}; + firstLine.height = EsTextGetLineHeight(&textbox->textStyle); + textbox->lines.Add(firstLine); + + TextboxVisibleLine firstVisibleLine = {}; + textbox->visibleLines.Add(firstVisibleLine); + + textbox->activeLineIndex = textbox->verticalMotionHorizontalDepth = textbox->longestLine = -1; + + if (~flags & ES_TEXTBOX_EDIT_BASED) { + textbox->editing = true; + } + + if (textbox->flags & ES_TEXTBOX_MARGIN) { + textbox->margin = EsCustomElementCreate(textbox, ES_CELL_FILL, ES_STYLE_TEXTBOX_MARGIN); + textbox->margin->cName = "margin"; + textbox->margin->messageUser = ProcessTextboxMarginMessage; + + int marginWidth = textbox->margin->currentStyle->preferredWidth; + textbox->borders.l += marginWidth; + textbox->insets.l += marginWidth + textbox->margin->currentStyle->gapMajor; + } + + return textbox; +} + +void EsTextboxUseNumberOverlay(EsTextbox *textbox, bool defaultBehaviour) { + EsMessageMutexCheck(); + + EsAssert(textbox->flags & ES_TEXTBOX_EDIT_BASED); // Using textbox overlay without edit based mode. + EsAssert(~textbox->flags & ES_TEXTBOX_MULTILINE); // Using number overlay with multiline mode. + + textbox->overlayData = defaultBehaviour; + + textbox->overlayCallback = [] (EsElement *element, EsMessage *message) { + EsTextbox *textbox = (EsTextbox *) element; + bool defaultBehaviour = textbox->overlayData.u; + + if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + if (!gui.draggingStarted) { + EsMessage m = { ES_MSG_TEXTBOX_NUMBER_DRAG_START }; + EsMessageSend(textbox, &m); + } + + TextboxFindCaret(textbox, message->mouseDragged.originalPositionX, message->mouseDragged.originalPositionY, false, 1); + + EsMessage m = { ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA }; + m.numberDragDelta.delta = message->mouseDragged.originalPositionY - message->mouseDragged.newPositionY; + m.numberDragDelta.fast = EsKeyboardIsShiftHeld(); + m.numberDragDelta.hoverCharacter = textbox->carets[1].byte; + EsMessageSend(textbox, &m); + + EsMouseSetPosition(textbox->window, gui.lastClickX, gui.lastClickY); + } else if (message->type == ES_MSG_KEY_TYPED && message->keyboard.scancode == ES_SCANCODE_UP_ARROW) { + EsMessage m = { ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA }; + m.numberDragDelta.delta = 1; + m.numberDragDelta.fast = EsKeyboardIsShiftHeld(); + m.numberDragDelta.hoverCharacter = 0; + EsMessageSend(textbox, &m); + } else if (message->type == ES_MSG_KEY_TYPED && message->keyboard.scancode == ES_SCANCODE_DOWN_ARROW) { + EsMessage m = { ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA }; + m.numberDragDelta.delta = -1; + m.numberDragDelta.fast = EsKeyboardIsShiftHeld(); + m.numberDragDelta.hoverCharacter = 0; + EsMessageSend(textbox, &m); + } else if (message->type == ES_MSG_MOUSE_LEFT_UP) { + if (gui.draggingStarted) { + EsMessage m = { ES_MSG_TEXTBOX_NUMBER_DRAG_END }; + EsMessageSend(textbox, &m); + } + } else if (message->type == ES_MSG_GET_CURSOR) { + if (gui.draggingStarted) { + message->cursorStyle = ES_CURSOR_BLANK; + } else if (~textbox->flags & ES_ELEMENT_DISABLED) { + message->cursorStyle = ES_CURSOR_RESIZE_VERTICAL; + } else { + message->cursorStyle = ES_CURSOR_NORMAL; + } + } else if (message->type == ES_MSG_TEXTBOX_EDIT_END && defaultBehaviour) { + double oldValue = EsDoubleParse(textbox->editStartContent, textbox->editStartContentBytes, nullptr); + + char *expression = EsTextboxGetContents(textbox); + EsCalculationValue value = EsCalculateFromUserExpression(expression); + EsHeapFree(expression); + + if (value.error) { + return ES_REJECTED; + } else { + EsMessage m = { ES_MSG_TEXTBOX_NUMBER_UPDATED }; + m.numberUpdated.delta = value.number - oldValue; + m.numberUpdated.newValue = value.number; + EsMessageSend(textbox, &m); + + char result[64]; + size_t resultBytes = EsStringFormat(result, sizeof(result), "%F", (double) m.numberUpdated.newValue); + EsTextboxSelectAll(textbox); + EsTextboxInsert(textbox, result, resultBytes); + } + } else if (message->type == ES_MSG_TEXTBOX_NUMBER_DRAG_DELTA && defaultBehaviour) { + TextboxSetActiveLine(textbox, -1); + double oldValue = EsDoubleParse(textbox->data, textbox->lines[0].lengthBytes, nullptr); + double newValue = oldValue + message->numberDragDelta.delta * (message->numberDragDelta.fast ? 10 : 1); + + EsMessage m = { ES_MSG_TEXTBOX_NUMBER_UPDATED }; + m.numberUpdated.delta = newValue - oldValue; + m.numberUpdated.newValue = newValue; + EsMessageSend(textbox, &m); + + char result[64]; + size_t resultBytes = EsStringFormat(result, sizeof(result), "%F", m.numberUpdated.newValue); + EsTextboxSelectAll(textbox); + EsTextboxInsert(textbox, result, resultBytes); + } else { + return 0; + } + + return ES_HANDLED; + }; +} + +void TextboxBreadcrumbOverlayRecreate(EsTextbox *textbox) { + if (textbox->overlayData.p) { + // Remove the old breadcrumb panel. + ((EsElement *) textbox->overlayData.p)->Destroy(); + } + + EsPanel *panel = EsPanelCreate(textbox, ES_PANEL_HORIZONTAL | ES_CELL_FILL | ES_ELEMENT_NO_HOVER, ES_STYLE_BREADCRUMB_BAR_PANEL); + textbox->overlayData = panel; + + uint8_t _buffer[256]; + EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; + EsMessage m = { ES_MSG_TEXTBOX_GET_BREADCRUMB }; + m.getBreadcrumb.buffer = &buffer; + + while (true) { + buffer.position = 0; + int response = EsMessageSend(textbox, &m); + EsAssert(response != 0); // Must handle ES_MSG_TEXTBOX_GET_BREADCRUMB message for breadcrumb overlay. + if (response == ES_REJECTED) break; + + EsButton *crumb = EsButtonCreate(panel, ES_BUTTON_NOT_FOCUSABLE | ES_BUTTON_COMPACT | ES_CELL_V_FILL, + ES_STYLE_BREADCRUMB_BAR_CRUMB, (char *) buffer.out, buffer.position); + crumb->userData = m.getBreadcrumb.index; + + crumb->messageUser = [] (EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_MOUSE_LEFT_CLICK) { + EsMessage m = { ES_MSG_TEXTBOX_ACTIVATE_BREADCRUMB }; + m.activateBreadcrumb = element->userData.u; + EsMessageSend(element->parent->parent, &m); + } else { + return 0; + } + + return ES_HANDLED; + }; + + m.getBreadcrumb.index++; + } +} + +void EsTextboxUseBreadcrumbOverlay(EsTextbox *textbox) { + EsMessageMutexCheck(); + + EsAssert(textbox->flags & ES_TEXTBOX_EDIT_BASED); // Using textbox overlay without edit based mode. + + // Use this to store the panel containing the breadcrumb buttons. + textbox->overlayData = nullptr; + + textbox->overlayCallback = [] (EsElement *element, EsMessage *message) { + EsTextbox *textbox = (EsTextbox *) element; + + if (message->type == ES_MSG_TEXTBOX_UPDATED) { + TextboxBreadcrumbOverlayRecreate(textbox); + } else if (message->type == ES_MSG_TEXTBOX_EDIT_START) { + ((EsElement *) textbox->overlayData.p)->Destroy(); + textbox->overlayData.p = nullptr; + } else if (message->type == ES_MSG_TEXTBOX_EDIT_END) { + TextboxBreadcrumbOverlayRecreate(textbox); + } else if (message->type == ES_MSG_LAYOUT) { + EsRectangle bounds = textbox->GetBounds(); + ((EsElement *) textbox->overlayData.p)->InternalMove(bounds.r, bounds.b, 0, 0); + } else if (message->type == ES_MSG_PAINT) { + return ES_HANDLED; + } + + return 0; + }; + + TextboxBreadcrumbOverlayRecreate(textbox); +} + +void EsTextboxSetUndoManager(EsTextbox *textbox, EsUndoManager *undoManager) { + EsMessageMutexCheck(); + EsAssert(~textbox->state & UI_STATE_FOCUSED); // Can't change undo manager if the textbox is focused. + EsAssert(textbox->undo == &textbox->localUndo); // This can only be set once. + textbox->undo = undoManager; +} + +void EsTextboxSetTextStyle(EsTextbox *textbox, const EsTextStyle *textStyle) { + if (0 == EsMemoryCompare(textStyle, &textbox->textStyle, sizeof(EsTextStyle))) { + return; + } + + EsMemoryCopy(&textbox->textStyle, textStyle, sizeof(EsTextStyle)); + int lineHeight = EsTextGetLineHeight(&textbox->textStyle); + + for (int32_t i = 0; i < (int32_t) textbox->lines.Length(); i++) { + DocumentLine *line = &textbox->lines[i]; + DocumentLine *previous = i ? (&textbox->lines[i - 1]) : nullptr; + line->height = lineHeight; + line->yPosition = previous ? (previous->yPosition + previous->height) : 0; + line->lengthWidth = -1; + textbox->longestLine = -1; + } + + TextboxRefreshVisibleLines(textbox); + TextboxFindLongestLine(textbox); + textbox->scroll.Refresh(); + EsElementRepaint(textbox); +} + +void EsTextboxGetTextStyle(EsTextbox *textbox, EsTextStyle *textStyle) { + EsMemoryCopy(textStyle, &textbox->textStyle, sizeof(EsTextStyle)); +} + +void EsTextboxSetupSyntaxHighlighting(EsTextbox *textbox, uint32_t language, uint32_t *customColors, size_t customColorCount) { + textbox->syntaxHighlightingLanguage = language; + + // TODO Load these from the theme file. + textbox->syntaxHighlightingColors[0] = 0x04000000; // Highlighted line. + textbox->syntaxHighlightingColors[1] = 0xFF000000; // Default. + textbox->syntaxHighlightingColors[2] = 0xFFA11F20; // Comment. + textbox->syntaxHighlightingColors[3] = 0xFF037E01; // String. + textbox->syntaxHighlightingColors[4] = 0xFF213EF1; // Number. + textbox->syntaxHighlightingColors[5] = 0xFF7F0480; // Operator. + textbox->syntaxHighlightingColors[6] = 0xFF545D70; // Preprocessor. + textbox->syntaxHighlightingColors[7] = 0xFF17546D; // Keyword. + + if (customColorCount > sizeof(textbox->syntaxHighlightingColors) / sizeof(uint32_t)) { + customColorCount = sizeof(textbox->syntaxHighlightingColors) / sizeof(uint32_t); + } + + EsMemoryCopy(textbox->syntaxHighlightingColors, customColors, customColorCount * sizeof(uint32_t)); + + textbox->Repaint(true); +} + +// --------------------------------- Text displays. + +// TODO Inline images and icons. +// TODO Links. +// TODO Inline backgrounds. + +void TextDisplayFreeRuns(EsTextDisplay *display) { + if (display->usingSyntaxHighlighting) { + Array textRuns = { display->textRuns }; + textRuns.Free(); + } else { + EsHeapFree(display->textRuns); + } +} + +int ProcessTextDisplayMessage(EsElement *element, EsMessage *message) { + EsTextDisplay *display = (EsTextDisplay *) element; + + if (message->type == ES_MSG_PAINT) { + EsRectangle textBounds = EsPainterBoundsInset(message->painter); + + if (!display->plan || display->planWidth != textBounds.r - textBounds.l || display->planHeight != textBounds.b - textBounds.t) { + if (display->plan) EsTextPlanDestroy(display->plan); + display->properties.flags = display->currentStyle->textAlign; + if (~display->flags & ES_TEXT_DISPLAY_PREFORMATTED) display->properties.flags |= ES_TEXT_PLAN_TRIM_SPACES; + if (display->flags & ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION) display->properties.flags |= ES_TEXT_PLAN_NO_FONT_SUBSTITUTION; + display->plan = EsTextPlanCreate(&display->properties, textBounds, display->contents, display->textRuns, display->textRunCount); + display->planWidth = textBounds.r - textBounds.l; + display->planHeight = textBounds.b - textBounds.t; + } + + if (display->plan) { + EsDrawTextLayers(message->painter, display->plan, EsPainterBoundsInset(message->painter)); + } + } else if (message->type == ES_MSG_GET_WIDTH || message->type == ES_MSG_GET_HEIGHT) { + if (!display->measurementCache.Get(message, &display->state)) { + if (display->plan) EsTextPlanDestroy(display->plan); + display->properties.flags = display->currentStyle->textAlign | ((display->flags & ES_TEXT_DISPLAY_PREFORMATTED) ? 0 : ES_TEXT_PLAN_TRIM_SPACES); + EsRectangle insets = EsElementGetInsets(element); + display->planWidth = message->type == ES_MSG_GET_HEIGHT && message->measure.width + ? (message->measure.width - insets.l - insets.r) : 0; + display->planHeight = 0; + display->plan = EsTextPlanCreate(&display->properties, + ES_RECT_4(0, display->planWidth, 0, 0), + display->contents, display->textRuns, display->textRunCount); + + if (!display->plan) { + message->measure.width = message->measure.height = 0; + } else { + if (message->type == ES_MSG_GET_WIDTH) { + message->measure.width = EsTextPlanGetWidth(display->plan) + insets.l + insets.r; + } else { + message->measure.height = EsTextPlanGetHeight(display->plan) + insets.t + insets.b; + } + } + + display->measurementCache.Store(message); + } + } else if (message->type == ES_MSG_DESTROY) { + if (display->plan) { + EsTextPlanDestroy(display->plan); + } + + TextDisplayFreeRuns(display); + EsHeapFree(display->contents); + } else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) { + EsBufferFormat(message->getContent.buffer, "'%s'", display->textRuns[display->textRunCount].offset, display->contents); + } else { + return 0; + } + + return ES_HANDLED; +} + +void EsTextDisplaySetStyledContents(EsTextDisplay *display, const char *string, EsTextRun *runs, size_t runCount) { + TextDisplayFreeRuns(display); + + display->textRuns = (EsTextRun *) EsHeapAllocate(sizeof(EsTextRun) * (runCount + 1), true); + display->textRunCount = runCount; + HeapDuplicate((void **) &display->contents, string, runs[runCount].offset); + EsMemoryCopy(display->textRuns, runs, sizeof(EsTextRun) * (runCount + 1)); + + display->usingSyntaxHighlighting = false; + EsElementUpdateContentSize(display); + InspectorNotifyElementContentChanged(display); +} + +void EsTextDisplaySetContents(EsTextDisplay *display, const char *string, ptrdiff_t stringBytes) { + if (stringBytes == -1) stringBytes = EsCStringLength(string); + + TextDisplayFreeRuns(display); + + if (display->flags & ES_TEXT_DISPLAY_RICH_TEXT) { + EsHeapFree(display->contents); + EsTextStyle baseStyle = {}; + display->currentStyle->GetTextStyle(&baseStyle); + EsRichTextParse(string, stringBytes, &display->contents, &display->textRuns, &display->textRunCount, &baseStyle); + } else { + HeapDuplicate((void **) &display->contents, string, stringBytes); + display->textRuns = (EsTextRun *) EsHeapAllocate(sizeof(EsTextRun) * 2, true); + display->currentStyle->GetTextStyle(&display->textRuns[0].style); + display->textRuns[1].offset = stringBytes; + display->textRunCount = 1; + } + + display->usingSyntaxHighlighting = false; + EsElementUpdateContentSize(display); + InspectorNotifyElementContentChanged(display); +} + +EsTextDisplay *EsTextDisplayCreate(EsElement *parent, uint64_t flags, const EsStyle *style, const char *label, ptrdiff_t labelBytes) { + EsTextDisplay *display = (EsTextDisplay *) EsHeapAllocate(sizeof(EsTextDisplay), true); + display->Initialise(parent, flags, ProcessTextDisplayMessage, style ?: UIGetDefaultStyleVariant(ES_STYLE_TEXT_LABEL, parent)); + display->cName = "text display"; + if (labelBytes == -1) labelBytes = EsCStringLength(label); + EsTextDisplaySetContents(display, label, labelBytes); + return display; +} + +void EsTextDisplaySetupSyntaxHighlighting(EsTextDisplay *display, uint32_t language, uint32_t *customColors, size_t customColorCount) { + // Copied from EsTextboxSetupSyntaxHighlighting. + uint32_t colors[8]; + colors[0] = 0x04000000; // Highlighted line. + colors[1] = 0xFF000000; // Default. + colors[2] = 0xFFA11F20; // Comment. + colors[3] = 0xFF037E01; // String. + colors[4] = 0xFF213EF1; // Number. + colors[5] = 0xFF7F0480; // Operator. + colors[6] = 0xFF545D70; // Preprocessor. + colors[7] = 0xFF17546D; // Keyword. + + if (customColorCount > sizeof(colors) / sizeof(uint32_t)) customColorCount = sizeof(colors) / sizeof(uint32_t); + EsMemoryCopy(colors, customColors, customColorCount * sizeof(uint32_t)); + + EsTextStyle textStyle = {}; + display->currentStyle->GetTextStyle(&textStyle); + + EsTextRun *newRuns = TextApplySyntaxHighlighting(&textStyle, language, colors, {}, + display->contents, display->textRuns[display->textRunCount].offset).array; + TextDisplayFreeRuns(display); + display->textRuns = newRuns; + display->textRunCount = ArrayLength(display->textRuns) - 1; + display->usingSyntaxHighlighting = true; + display->Repaint(true); +} + +// --------------------------------- List displays. + +struct EsListDisplay : EsElement { + uintptr_t itemCount, startIndex; + EsListDisplay *previous; +}; + +int ProcessListDisplayMessage(EsElement *element, EsMessage *message) { + EsListDisplay *display = (EsListDisplay *) element; + + if (message->type == ES_MSG_GET_HEIGHT) { + int32_t height = 0; + int32_t margin = element->currentStyle->insets.l + element->currentStyle->insets.r + element->currentStyle->gapMinor; + uintptr_t itemCount = 0; + + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + EsElement *child = element->GetChild(i); + if (child->flags & ES_ELEMENT_NON_CLIENT) continue; + height += child->GetHeight(message->measure.width - margin); + itemCount++; + } + + if (itemCount) { + height += (itemCount - 1) * element->currentStyle->gapMajor; + } + + message->measure.height = height + element->currentStyle->insets.t + element->currentStyle->insets.b; + } else if (message->type == ES_MSG_LAYOUT) { + int32_t position = element->currentStyle->insets.t; + int32_t margin = element->currentStyle->insets.l + element->currentStyle->gapMinor; + int32_t width = element->width - margin - element->currentStyle->insets.r; + + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + EsElement *child = element->GetChild(i); + if (child->flags & ES_ELEMENT_NON_CLIENT) continue; + int height = child->GetHeight(width); + EsElementMove(child, margin, position, width, height); + position += height + element->currentStyle->gapMajor; + } + } else if (message->type == ES_MSG_PAINT) { + char buffer[64]; + EsTextPlanProperties properties = {}; + properties.flags = ES_TEXT_H_RIGHT | ES_TEXT_V_TOP | ES_TEXT_PLAN_SINGLE_USE; + EsTextRun textRun[2] = {}; + + EsRectangle bounds = EsPainterBoundsClient(message->painter); + bounds.r = bounds.l + element->currentStyle->insets.l; + + uintptr_t counter = display->previous ? display->previous->itemCount : display->startIndex; + uint8_t markerType = element->flags & ES_LIST_DISPLAY_MARKER_TYPE_MASK; + + EsMessage m = {}; + m.type = ES_MSG_LIST_DISPLAY_GET_MARKER; + EsBuffer buffer2 = { .out = (uint8_t *) buffer, .bytes = sizeof(buffer) }; + m.getContent.buffer = &buffer2; + + for (uintptr_t i = 0; i < element->GetChildCount(); i++) { + EsElement *child = element->GetChild(i); + if (child->flags & ES_ELEMENT_NON_CLIENT) continue; + + if (markerType == ES_LIST_DISPLAY_BULLETED) { + EsMemoryCopy(buffer, "\xE2\x80\xA2", (textRun[1].offset = 3)); + } else if (markerType == ES_LIST_DISPLAY_NUMBERED) { + textRun[1].offset = EsStringFormat(buffer, sizeof(buffer), "%d.", counter + 1); + } else if (markerType == ES_LIST_DISPLAY_LOWER_ALPHA) { + textRun[1].offset = EsStringFormat(buffer, sizeof(buffer), "(%c)", counter + 'a'); + } else if (markerType == ES_LIST_DISPLAY_CUSTOM_MARKER) { + m.getContent.index = counter; + EsMessageSend(element, &m); + textRun[1].offset = buffer2.position; + } else { + EsAssert(false); + } + + child->currentStyle->GetTextStyle(&textRun[0].style); + textRun[0].style.figures = ES_TEXT_FIGURE_TABULAR; + bounds.t += child->offsetY; + bounds.b = bounds.t + child->height; + EsTextPlan *plan = EsTextPlanCreate(&properties, bounds, buffer, textRun, 1); + EsDrawText(message->painter, plan, bounds); + bounds.t -= child->offsetY; + counter++; + } + } else if (message->type == ES_MSG_ADD_CHILD) { + display->itemCount++; + } else if (message->type == ES_MSG_REMOVE_CHILD) { + display->itemCount--; + } + + return 0; +} + +EsListDisplay *EsListDisplayCreate(EsElement *parent, uint64_t flags, const EsStyle *style) { + EsListDisplay *display = (EsListDisplay *) EsHeapAllocate(sizeof(EsListDisplay), true); + display->Initialise(parent, flags, ProcessListDisplayMessage, style ?: ES_STYLE_LIST_DISPLAY_DEFAULT); + display->cName = "list display"; + return display; +} + +void EsListDisplaySetCounterContinuation(EsListDisplay *display, EsListDisplay *previous) { + display->previous = previous; + EsElementRepaint(display); +} + +void EsListDisplaySetCounterStart(EsListDisplay *display, uintptr_t index) { + display->startIndex = index; + display->previous = nullptr; + EsElementRepaint(display); +} + +#endif diff --git a/desktop/theme.cpp b/desktop/theme.cpp new file mode 100644 index 0000000..3d67507 --- /dev/null +++ b/desktop/theme.cpp @@ -0,0 +1,2209 @@ +#define THEME_LAYER_BOX (1) +#define THEME_LAYER_TEXT (2) +#define THEME_LAYER_METRICS (3) +#define THEME_LAYER_PATH (4) + +#define THEME_PAINT_SOLID (1) +#define THEME_PAINT_LINEAR_GRADIENT (2) +#define THEME_PAINT_CUSTOM (3) +#define THEME_PAINT_OVERWRITE (4) +#define THEME_PAINT_RADIAL_GRADIENT (5) + +#define THEME_LAYER_MODE_BACKGROUND (0) +#define THEME_LAYER_MODE_SHADOW (1) +#define THEME_LAYER_MODE_CONTENT (2) +#define THEME_LAYER_MODE_OVERLAY (3) + +#define THEME_FONT_FAMILY_SANS (0) +#define THEME_FONT_FAMILY_SERIF (1) +#define THEME_FONT_FAMILY_MONO (2) + +#define THEME_OVERRIDE_I8 (1) +#define THEME_OVERRIDE_I16 (2) +#define THEME_OVERRIDE_F32 (3) +#define THEME_OVERRIDE_COLOR (4) + +#define THEME_PRIMARY_STATE_ANY (0) +#define THEME_PRIMARY_STATE_IDLE (1) +#define THEME_PRIMARY_STATE_HOVERED (2) +#define THEME_PRIMARY_STATE_PRESSED (3) +#define THEME_PRIMARY_STATE_DISABLED (4) +#define THEME_PRIMARY_STATE_MASK (0x000F) + +#define THEME_STATE_FOCUSED (1 << 15) +#define THEME_STATE_CHECKED (1 << 14) +#define THEME_STATE_INDETERMINATE (1 << 13) +#define THEME_STATE_DEFAULT_BUTTON (1 << 12) +#define THEME_STATE_SELECTED (1 << 11) +#define THEME_STATE_FOCUSED_ITEM (1 << 10) +#define THEME_STATE_LIST_FOCUSED (1 << 9) +#define THEME_STATE_BEFORE_ENTER (1 << 8) +#define THEME_STATE_AFTER_EXIT (1 << 7) + +#define THEME_STATE_CHECK(sequenceHeaderState, requestedState) \ + (((sequenceHeaderState & THEME_PRIMARY_STATE_MASK) == (requestedState & THEME_PRIMARY_STATE_MASK) \ + || ((sequenceHeaderState & THEME_PRIMARY_STATE_MASK) == THEME_PRIMARY_STATE_ANY)) \ + && !((sequenceHeaderState & ~THEME_PRIMARY_STATE_MASK) & ~(requestedState & ~THEME_PRIMARY_STATE_MASK))) \ + +#define THEME_LAYER_BOX_IS_BLURRED (1 << 0) +#define THEME_LAYER_BOX_AUTO_CORNERS (1 << 1) +#define THEME_LAYER_BOX_AUTO_BORDERS (1 << 2) +#define THEME_LAYER_BOX_SHADOW_HIDING (1 << 3) +#define THEME_LAYER_BOX_SHADOW_CUT (1 << 4) + +#define THEME_LAYER_PATH_FILL_EVEN_ODD (1 << 0) +#define THEME_LAYER_PATH_CLOSED (1 << 1) + +#define THEME_PATH_FILL_SOLID (1 << 4) +#define THEME_PATH_FILL_CONTOUR (2 << 4) +#define THEME_PATH_FILL_DASHED (3 << 4) + +#define THEME_HEADER_SIGNATURE (0x96BC555A) + +#define THEME_CHILD_TYPE_ONLY (0) +#define THEME_CHILD_TYPE_FIRST (1) +#define THEME_CHILD_TYPE_LAST (2) +#define THEME_CHILD_TYPE_NONE (3) +#define THEME_CHILD_TYPE_HORIZONTAL (1 << 4) + +typedef enum ThemeCursor { + THEME_CURSOR_NORMAL, + THEME_CURSOR_TEXT, + THEME_CURSOR_RESIZE_VERTICAL, + THEME_CURSOR_RESIZE_HORIZONTAL, + THEME_CURSOR_RESIZE_DIAGONAL_1, + THEME_CURSOR_RESIZE_DIAGONAL_2, + THEME_CURSOR_SPLIT_VERTICAL, + THEME_CURSOR_SPLIT_HORIZONTAL, + THEME_CURSOR_HAND_HOVER, + THEME_CURSOR_HAND_DRAG, + THEME_CURSOR_HAND_POINT, + THEME_CURSOR_SCROLL_UP_LEFT, + THEME_CURSOR_SCROLL_UP, + THEME_CURSOR_SCROLL_UP_RIGHT, + THEME_CURSOR_SCROLL_LEFT, + THEME_CURSOR_SCROLL_CENTER, + THEME_CURSOR_SCROLL_RIGHT, + THEME_CURSOR_SCROLL_DOWN_LEFT, + THEME_CURSOR_SCROLL_DOWN, + THEME_CURSOR_SCROLL_DOWN_RIGHT, + THEME_CURSOR_SELECT_LINES, + THEME_CURSOR_DROP_TEXT, + THEME_CURSOR_CROSS_HAIR_PICK, + THEME_CURSOR_CROSS_HAIR_RESIZE, + THEME_CURSOR_MOVE_HOVER, + THEME_CURSOR_MOVE_DRAG, + THEME_CURSOR_ROTATE_HOVER, + THEME_CURSOR_ROTATE_DRAG, + THEME_CURSOR_BLANK, +} ThemeCursor; + +typedef struct ThemePaintSolid { + uint32_t color; +} ThemePaintSolid; + +typedef struct ThemeGradientStop { + uint32_t color; + int8_t position; +} ThemeGradientStop; + +typedef struct ThemePaintLinearGradient { + float transform[3]; + uint8_t stopCount; + int8_t useGammaInterpolation : 1, useDithering : 1, useSystemHue : 1; + uint8_t repeatMode; + uint8_t _unused0; + // Followed by gradient stops. +} ThemePaintLinearGradient; + +typedef struct ThemePaintRadialGradient { + float transform[6]; + uint8_t stopCount; + int8_t useGammaInterpolation : 1, useDithering : 1; + uint8_t repeatMode; + uint8_t _unused0; + // Followed by gradient stops. +} ThemePaintRadialGradient; + +typedef struct ThemePaintCustom { +#ifndef IN_DESIGNER + EsFragmentShaderCallbackFunction callback; +#endif +} ThemePaintCustom; + +typedef struct ThemeLayerBox { + Rectangle8 borders; + Corners8 corners; + int8_t flags, mainPaintType, borderPaintType; + uint8_t _unused0; + uint32_t _unused1; // Align to 8 bytes for ThemePaintCustom. + // Followed by main paint data, then border paint data. +} ThemeLayerBox; + +typedef struct ThemeLayerText { + uint32_t color; + uint16_t _unused0; + int8_t blur; + uint8_t _unused1; +} ThemeLayerText; + +typedef struct ThemeLayerIcon { + int8_t align; + uint8_t _unused0; + uint16_t alpha; + Rectangle16 image; +} ThemeLayerIcon; + +typedef struct ThemeLayerImage { + uint16_t alpha; + uint16_t _unused0; + Rectangle16 image, contentRegion; +} ThemeLayerImage; + +typedef struct ThemeLayerPathFillContour { + float miterLimit; + uint8_t internalWidth, externalWidth; + uint8_t mode; +} ThemeLayerPathFillContour; + +typedef struct ThemeLayerPathFillDash { + ThemeLayerPathFillContour contour; + uint8_t length, gap; +} ThemeLayerPathFillDash; + +typedef struct ThemeLayerPathFill { + uint8_t paintAndFillType; + uint8_t dashCount; + uint16_t _unused0; + // Followed by paint data, then fill type specific data. +} ThemeLayerPathFill; + +typedef struct ThemeLayerPath { + uint8_t flags, fillCount; + uint16_t alpha, pointCount, _unused0; + // Followed by points (2*3 floats per point), then fills. +} ThemeLayerPath; + +typedef struct ThemeLayer { + uint32_t sequenceDataOffset; + Rectangle8 offset; // (dpx) + Rectangle8 position; // (percent) + int8_t mode, type; + uint16_t dataByteCount; + // Followed by type-specific data. +} ThemeLayer; + +typedef struct ThemeMetrics { + Rectangle16 insets, clipInsets; + Rectangle16 globalOffset; + uint8_t clipEnabled, cursor, entranceTransition, exitTransition; + uint16_t entranceDuration, exitDuration, fontFamily; + int16_t preferredWidth, preferredHeight; + int16_t minimumWidth, minimumHeight; + int16_t maximumWidth, maximumHeight; + int16_t gapMajor, gapMinor, gapWrap; + uint32_t textColor, selectedBackground, selectedText, iconColor; + int8_t textAlign, textSize, fontWeight, iconSize; + bool isItalic, ellipsis, layoutVertical; +} ThemeMetrics; + +typedef union ThemeVariant { + int8_t i8; + int16_t i16; + uint32_t u32; + float f32; +} ThemeVariant; + +typedef struct ThemeOverride { + uint16_t offset; + uint8_t type, layer; + ThemeVariant data; +} ThemeOverride; + +typedef struct ThemeSequenceHeader { + uint16_t state; // Low 4 bits are the primary state. + uint16_t overrideCount; + uint16_t duration; + uint8_t isLastSequence; + uint8_t _unused; + // Followed by overrides. +} ThemeSequenceHeader; + +typedef struct ThemeStyle { + uint32_t layerListOffset; // A list of uint32_t, giving offsets to ThemeLayer. First is the metrics layer. + uint16_t id; + uint8_t layerCount; + uint8_t _unused1; + Rectangle8 paintOutsets, opaqueInsets, approximateBorders; +} ThemeStyle; + +typedef struct ThemeConstant { + uint64_t hash; + uint32_t valueOffset; + uint32_t valueByteCount; + bool scale; +} ThemeConstant; + +typedef struct ThemeHeader { + uint32_t signature; + uint32_t styleCount, constantCount; + uint32_t bitmapBytes; + // Followed by array of ThemeStyles and then an array of ThemeConstants. + // The bitmap is at the end of the theme file. +} ThemeHeader; + +typedef struct BasicFontKerningEntry { + uint16_t leftGlyphIndex, rightGlyphIndex; + int16_t xAdvance; +} BasicFontKerningEntry; + +typedef struct BasicFontGlyph { + uint32_t codepoint; + int16_t xAdvance, xOffset, yOffset; + uint16_t width, height; + uint16_t pointCount; + uint32_t offsetToPoints; // Cubic bezier points. Contains 3*pointCount-2 of (x,y) float pairs. +} BasicFontGlyph; + +typedef struct BasicFontHeader { +#define BASIC_FONT_SIGNATURE (0x83259919) + uint32_t signature; + int32_t ascender, descender; + uint16_t glyphCount; + uint16_t kerningEntries; + // Followed by array of BasicFontGlyph. + // Followed by array of BasicFontKerningEntry. +} BasicFontHeader; + +////////////////////////////////////////// + +#define THEME_RECT_WIDTH(_r) ((_r).r - (_r).l) +#define THEME_RECT_HEIGHT(_r) ((_r).b - (_r).t) +#define THEME_RECT_4(x, y, z, w) ((EsRectangle) { (x), (y), (z), (w) }) +#define THEME_RECT_VALID(_r) (THEME_RECT_WIDTH(_r) > 0 && THEME_RECT_HEIGHT(_r) > 0) + +EsRectangle ThemeRectangleIntersection(EsRectangle a, EsRectangle b) { + if (a.l < b.l) a.l = b.l; + if (a.t < b.t) a.t = b.t; + if (a.r > b.r) a.r = b.r; + if (a.b > b.b) a.b = b.b; + return a; +} + +typedef struct ThemePaintData { + int8_t type; + + union { + const ThemePaintSolid *solid; + const ThemePaintLinearGradient *linearGradient; + const ThemePaintCustom *custom; + }; +} ThemePaintData; + +typedef struct GradientCache { +#define GRADIENT_CACHE_COUNT (256) + uint32_t colors[GRADIENT_CACHE_COUNT]; +#if 0 + uint32_t ditherColors[GRADIENT_CACHE_COUNT]; + uint32_t ditherThresholds[GRADIENT_CACHE_COUNT]; +#endif +#define GRADIENT_COORD_BASE (16) + int start, dx, dy; + int ox, oy; + bool opaque, dithered; + void *context; +} GradientCache; + +static const float gaussLookup[] = { + 1.000000, 0.999862, 0.999450, 0.998764, 0.997805, 0.996572, 0.995068, 0.993293, + 0.991249, 0.988937, 0.986360, 0.983520, 0.980418, 0.977058, 0.973442, 0.969573, + 0.965454, 0.961089, 0.956480, 0.951633, 0.946549, 0.941235, 0.935693, 0.929928, + 0.923946, 0.917749, 0.911344, 0.904735, 0.897927, 0.890926, 0.883736, 0.876364, + 0.868815, 0.861094, 0.853207, 0.845160, 0.836960, 0.828611, 0.820121, 0.811494, + 0.802738, 0.793858, 0.784861, 0.775752, 0.766539, 0.757227, 0.747823, 0.738333, + 0.728763, 0.719119, 0.709409, 0.699637, 0.689810, 0.679935, 0.670017, 0.660062, + 0.650077, 0.640067, 0.630038, 0.619995, 0.609946, 0.599894, 0.589846, 0.579807, + 0.569782, 0.559777, 0.549797, 0.539846, 0.529930, 0.520053, 0.510220, 0.500435, + 0.490704, 0.481029, 0.471416, 0.461867, 0.452388, 0.442982, 0.433653, 0.424403, + 0.415236, 0.406156, 0.397166, 0.388267, 0.379464, 0.370759, 0.362153, 0.353651, + 0.345253, 0.336962, 0.328780, 0.320708, 0.312749, 0.304903, 0.297173, 0.289559, + 0.282062, 0.274685, 0.267426, 0.260289, 0.253272, 0.246376, 0.239602, 0.232951, + 0.226422, 0.220016, 0.213732, 0.207571, 0.201532, 0.195614, 0.189819, 0.184144, + 0.178591, 0.173157, 0.167842, 0.162646, 0.157567, 0.152605, 0.147759, 0.143027, + 0.138409, 0.133903, 0.129508, 0.125223, 0.121047, 0.116978, 0.113014, 0.109155, + 0.105399, 0.101744, 0.098188, 0.094731, 0.091371, 0.088106, 0.084933, 0.081853, + 0.078863, 0.075961, 0.073146, 0.070415, 0.067769, 0.065203, 0.062718, 0.060310, + 0.057980, 0.055723, 0.053541, 0.051429, 0.049387, 0.047413, 0.045506, 0.043663, + 0.041883, 0.040165, 0.038507, 0.036907, 0.035364, 0.033876, 0.032442, 0.031060, + 0.029729, 0.028447, 0.027212, 0.026025, 0.024882, 0.023782, 0.022726, 0.021710, + 0.020734, 0.019796, 0.018895, 0.018031, 0.017201, 0.016405, 0.015642, 0.014910, + 0.014208, 0.013536, 0.012892, 0.012275, 0.011684, 0.011119, 0.010578, 0.010061, + 0.009567, 0.009094, 0.008642, 0.008211, 0.007798, 0.007405, 0.007029, 0.006671, + 0.006329, 0.006003, 0.005692, 0.005396, 0.005114, 0.004845, 0.004590, 0.004346, + 0.004114, 0.003894, 0.003684, 0.003485, 0.003295, 0.003115, 0.002944, 0.002782, + 0.002628, 0.002482, 0.002343, 0.002211, 0.002086, 0.001968, 0.001856, 0.001750, + 0.001649, 0.001554, 0.001464, 0.001378, 0.001298, 0.001221, 0.001149, 0.001081, + 0.001017, 0.000956, 0.000899, 0.000844, 0.000793, 0.000745, 0.000699, 0.000656, + 0.000616, 0.000578, 0.000542, 0.000508, 0.000476, 0.000446, 0.000418, 0.000391, + 0.000366, 0.000343, 0.000321, 0.000300, 0.000281, 0.000263, 0.000245, 0.000229, + 0.000214, 0.000200, 0.000187, 0.000174, 0.000163, 0.000152, 0.000141, 0.000000, +}; + +#ifndef IN_DESIGNER +struct UIStyleKey { + uintptr_t part; + float scale; + uint16_t stateFlags; + uint16_t _unused1; +}; + +struct { + EsBuffer system; + const ThemeHeader *header; + EsPaintTarget cursors; + float scale; + HashStore loadedStyles; + float systemHue; +} theming; +#endif + +__attribute__((optimize("-O2"))) +void ThemeFillRectangle(EsPainter *painter, EsRectangle bounds, ThemePaintData paint, GradientCache *gradient) { + uint32_t *bits = (uint32_t *) painter->target->bits; + int width = painter->target->width; + bounds = ThemeRectangleIntersection(bounds, painter->clip); + if (!THEME_RECT_VALID(bounds)) return; + + if (paint.type == THEME_PAINT_SOLID) { +#ifndef IN_DESIGNER + _DrawBlock(painter->target->stride, bits, bounds, paint.solid->color, painter->target->fullAlpha); +#else + uint32_t color = paint.solid->color; + + if ((color & 0xFF000000) == 0) { + } else if ((color & 0xFF000000) == 0xFF000000) { + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l; + uint32_t *b = bits + x + y * width; + do { *b = color; x++, b++; } while (x < bounds.r); + } + } else { + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l; + uint32_t *b = bits + x + y * width; + do { BlendPixel(b, color, painter->target->fullAlpha); x++, b++; } while (x < bounds.r); + } + } +#endif + } else if (paint.type == THEME_PAINT_LINEAR_GRADIENT) { +#if 0 + if (gradient->dithered) { + uint32_t random = 0; + + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l, p = (y - gradient->oy) * gradient->dy + (bounds.l - gradient->ox) * gradient->dx + gradient->start; + uint32_t *b = bits + bounds.l + y * width; + + do { + random = (random * 1103515245) + 12345; + uintptr_t index = ClampInteger(0, GRADIENT_CACHE_COUNT - 1, p >> GRADIENT_COORD_BASE); + + if (random > gradient->ditherThresholds[index]) { + *b = gradient->ditherColors[index]; + } else { + *b = gradient->colors[index]; + } + + x++, b++, p += gradient->dx; + } while (x < bounds.r); + } + } else +#endif + if (gradient->opaque) { + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l, p = (y - gradient->oy) * gradient->dy + (bounds.l - gradient->ox) * gradient->dx + gradient->start; + uint32_t *b = bits + bounds.l + y * width; + + do { + *b = gradient->colors[ClampInteger(0, GRADIENT_CACHE_COUNT - 1, p >> GRADIENT_COORD_BASE)]; + x++, b++, p += gradient->dx; + } while (x < bounds.r); + } + } else { + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l, p = (y - gradient->oy) * gradient->dy + (bounds.l - gradient->ox) * gradient->dx + gradient->start; + uint32_t *b = bits + bounds.l + y * width; + + do { + BlendPixel(b, gradient->colors[ClampInteger(0, GRADIENT_CACHE_COUNT - 1, p >> GRADIENT_COORD_BASE)], painter->target->fullAlpha); + x++, b++, p += gradient->dx; + } while (x < bounds.r); + } + } +#ifndef IN_DESIGNER + } else if (paint.type == THEME_PAINT_CUSTOM) { + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l; + uint32_t *b = bits + bounds.l + y * width; + + do { + BlendPixel(b, paint.custom->callback(x, y, (EsStyledBox *) gradient->context), painter->target->fullAlpha); + x++, b++; + } while (x < bounds.r); + } +#endif + } else if (paint.type == THEME_PAINT_OVERWRITE) { + uint32_t color = paint.solid->color; + + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l; + uint32_t *b = bits + x + y * width; + do { *b = color; x++, b++; } while (x < bounds.r); + } + } +} + +#ifndef IN_DESIGNER +__attribute__((optimize("-O2"))) +#endif +void ThemeFillCorner(EsPainter *painter, EsRectangle bounds, int cx, int cy, + int border, int corner, ThemePaintData mainPaint, ThemePaintData borderPaint, + GradientCache *mainGradient, GradientCache *borderGradient) { + uint32_t *bits = (uint32_t *) painter->target->bits; + int width = painter->target->width; + + int oldLeft = bounds.l, oldTop = bounds.t; + bounds = ThemeRectangleIntersection(bounds, painter->clip); + if (!THEME_RECT_VALID(bounds)) return; + cx += oldLeft - bounds.l, cy += oldTop - bounds.t; + +#define STYLE_CORNER_OVERSAMPLING (3) + border <<= STYLE_CORNER_OVERSAMPLING; + corner <<= STYLE_CORNER_OVERSAMPLING; + cx <<= STYLE_CORNER_OVERSAMPLING; + cy <<= STYLE_CORNER_OVERSAMPLING; + + int mainRadius2 = corner > border ? corner - border : 0; + int borderRadius2 = corner * corner; + mainRadius2 *= mainRadius2; + + int oversampledWidth = THEME_RECT_WIDTH(bounds) << STYLE_CORNER_OVERSAMPLING; + int oversampledHeight = THEME_RECT_HEIGHT(bounds) << STYLE_CORNER_OVERSAMPLING; + + uint32_t *b0 = bits + bounds.t * width; + + for (int j = 0; j < oversampledHeight; j += (1 << STYLE_CORNER_OVERSAMPLING), b0 += width) { + int i = 0; + uint32_t *b = b0 + bounds.l; + + do { + int mainCount = 0, borderCount = 0, outsideCount = 0; + + for (int x = 0; x < (1 << STYLE_CORNER_OVERSAMPLING); x++) { + for (int y = 0; y < (1 << STYLE_CORNER_OVERSAMPLING); y++) { + int dx = i + x - cx, dy = j + y - cy; + int radius2 = dx * dx + dy * dy; + if (radius2 <= mainRadius2) mainCount++; + else if (radius2 <= borderRadius2) borderCount++; + else outsideCount++; + } + } + + uint32_t mainColor, borderColor; + + if (mainPaint.type == THEME_PAINT_SOLID || mainPaint.type == THEME_PAINT_OVERWRITE) { + mainColor = mainPaint.solid->color; + } else if (mainPaint.type == THEME_PAINT_LINEAR_GRADIENT) { + mainColor = mainGradient->colors[ClampInteger(0, GRADIENT_CACHE_COUNT - 1, + (((j >> STYLE_CORNER_OVERSAMPLING) - mainGradient->oy + bounds.t) * mainGradient->dy + + ((i >> STYLE_CORNER_OVERSAMPLING) - mainGradient->ox + bounds.l) * mainGradient->dx + mainGradient->start) + >> GRADIENT_COORD_BASE)]; +#ifndef IN_DESIGNER + } else if (mainPaint.type == THEME_PAINT_CUSTOM) { + mainColor = mainPaint.custom->callback((i >> STYLE_CORNER_OVERSAMPLING) - mainGradient->ox + bounds.l, + (j >> STYLE_CORNER_OVERSAMPLING) - mainGradient->oy + bounds.t, (EsStyledBox *) mainGradient->context); +#endif + } else { + mainColor = 0; + } + + if (borderPaint.type == THEME_PAINT_SOLID || borderPaint.type == THEME_PAINT_OVERWRITE) { + borderColor = borderPaint.solid->color; + } else if (borderPaint.type == THEME_PAINT_LINEAR_GRADIENT) { + borderColor = borderGradient->colors[ClampInteger(0, GRADIENT_CACHE_COUNT - 1, + (((j >> STYLE_CORNER_OVERSAMPLING) - borderGradient->oy + bounds.t) * borderGradient->dy + + ((i >> STYLE_CORNER_OVERSAMPLING) - borderGradient->ox + bounds.l) * borderGradient->dx + borderGradient->start) + >> GRADIENT_COORD_BASE)]; + } else { + borderColor = 0; + } + + uint32_t mainAlpha = mainColor >> 24; + uint32_t borderAlpha = borderColor >> 24; + + if (outsideCount == (1 << (2 * STYLE_CORNER_OVERSAMPLING))) { + } else if (outsideCount || ((borderColor & 0xFF000000) != 0xFF000000) || (mainColor & 0xFF000000) != 0xFF000000) { + BlendPixel(b, (mainColor & 0x00FFFFFF) | (((mainAlpha * mainCount) << (24 - STYLE_CORNER_OVERSAMPLING * 2)) & 0xFF000000), + painter->target->fullAlpha); + BlendPixel(b, (borderColor & 0x00FFFFFF) | (((borderAlpha * borderCount) << (24 - STYLE_CORNER_OVERSAMPLING * 2)) & 0xFF000000), + painter->target->fullAlpha); + } else if (mainCount == (1 << (2 * STYLE_CORNER_OVERSAMPLING))) { + BlendPixel(b, mainColor, painter->target->fullAlpha); + } else if (borderCount == (1 << (2 * STYLE_CORNER_OVERSAMPLING))) { + BlendPixel(b, borderColor, painter->target->fullAlpha); + } else { + uint32_t blend = mainColor; + BlendPixel(&blend, (borderColor & 0x00FFFFFF) | (((borderAlpha * borderCount) << (24 - STYLE_CORNER_OVERSAMPLING * 2)) & 0xFF000000), true); + BlendPixel(b, blend, painter->target->fullAlpha); + } + + i += (1 << STYLE_CORNER_OVERSAMPLING), b++; + } while (i < oversampledWidth); + } +} + +#ifndef IN_DESIGNER +__attribute__((optimize("-O2"))) +#endif +void ThemeFillBlurCutCorner(EsPainter *painter, EsRectangle bounds, int cx, int cy, int border, int corner, GradientCache *gradient, ThemePaintData mainPaint) { + uint32_t *bits = (uint32_t *) painter->target->bits; + int width = painter->target->width; + cx += bounds.l, cy += bounds.t; + bounds = ThemeRectangleIntersection(bounds, painter->clip); + + int dp = (GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE) / border; + float mainRadius = corner > border ? corner - border : 0; + + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l; + uint32_t *b = bits + x + y * width; + + do { + int dx = x - cx, dy = y - cy; + float radius = EsCRTsqrtf(dx * dx + dy * dy) - mainRadius; + uint32_t color1 = 0, color2 = 0, color; + + if (radius < 1) { + if (mainPaint.type == THEME_PAINT_SOLID) { + color1 = mainPaint.solid->color; + } + } + + if (radius >= 0) { + color2 = gradient->colors[ClampInteger(0, GRADIENT_CACHE_COUNT - 1, + (int) (radius * dp) >> GRADIENT_COORD_BASE)]; + } + + if (radius < 0) { + color = color1; + } else if (radius < 1) { + int p = (uint32_t) (radius * 0x100); + int c10 = (color1 >> 24) & 0xFF, c11 = (color1 >> 16) & 0xFF, c12 = (color1 >> 8) & 0xFF, c13 = (color1 >> 0) & 0xFF; + int c20 = (color2 >> 24) & 0xFF, c21 = (color2 >> 16) & 0xFF, c22 = (color2 >> 8) & 0xFF, c23 = (color2 >> 0) & 0xFF; + int c30 = (c10 << 8) + p * (c20 - c10), c31 = (c11 << 8) + p * (c21 - c11), c32 = (c12 << 8) + p * (c22 - c12), c33 = (c13 << 8) + p * (c23 - c13); + color = ((c30 & 0xFF00) << 16) | ((c31 & 0xFF00) << 8) | ((c32 & 0xFF00) << 0) | ((c33 & 0xFF00) >> 8); + } else { + color = color2; + } + + BlendPixel(b, color, painter->target->fullAlpha); + + x++, b++; + } while (x < bounds.r); + } +} + +#ifndef IN_DESIGNER +__attribute__((optimize("-O2"))) +#endif +void ThemeFillBlurCorner(EsPainter *painter, EsRectangle bounds, int cx, int cy, int border, int corner, GradientCache *gradient) { + uint32_t *bits = (uint32_t *) painter->target->bits; + int width = painter->target->width; + cx += bounds.l, cy += bounds.t; + bounds = ThemeRectangleIntersection(bounds, painter->clip); + + int dp = (GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE) / border; + int mainRadius = corner > border ? corner - border : 0; + + for (int y = bounds.t; y < bounds.b; y++) { + int x = bounds.l; + uint32_t *b = bits + x + y * width; + + do { + int dx = x - cx, dy = y - cy; + int radius2 = dx * dx + dy * dy; + int p = (EsCRTsqrtf(radius2) - mainRadius) * dp; + BlendPixel(b, gradient->colors[ClampInteger(0, GRADIENT_CACHE_COUNT - 1, p >> GRADIENT_COORD_BASE)], painter->target->fullAlpha); + x++, b++; + } while (x < bounds.r); + } +} + +__attribute__((optimize("-O2"))) +void GradientCacheSetup(GradientCache *cache, const ThemePaintLinearGradient *gradient, int width, int height, EsBuffer *data) { + width--, height--; + + cache->dx = gradient->transform[0] / width * (GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE); + cache->dy = gradient->transform[1] / height * (GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE); + cache->start = gradient->transform[2] * (GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE); + + cache->opaque = true; + cache->dithered = gradient->useDithering; + + if (!gradient->stopCount) { + return; + } + + const ThemeGradientStop *stop0 = (ThemeGradientStop *) EsBufferRead(data, sizeof(ThemeGradientStop)); + + for (uintptr_t stop = 0; stop < (uintptr_t) (gradient->stopCount - 1); stop++) { + const ThemeGradientStop *stop1 = (ThemeGradientStop *) EsBufferRead(data, sizeof(ThemeGradientStop)); + + if (!stop1) { + return; + } + + uint32_t color0 = stop0->color; + uint32_t color1 = stop1->color; + +#ifndef IN_DESIGNER + if (gradient->useSystemHue) { + float h, h2, s, v; + EsColorConvertToHSV(color0, &h, &s, &v); + color0 = (color0 & 0xFF000000) | EsColorConvertToRGB(theming.systemHue, s, v); + EsColorConvertToHSV(color1, &h2, &s, &v); + color1 = (color1 & 0xFF000000) | EsColorConvertToRGB(theming.systemHue + (h2 - h), s, v); + } +#endif + + float fa = ((color0 >> 24) & 0xFF) / 255.0f; + float fb = ((color0 >> 16) & 0xFF) / 255.0f; + float fg = ((color0 >> 8) & 0xFF) / 255.0f; + float fr = ((color0 >> 0) & 0xFF) / 255.0f; + float ta = ((color1 >> 24) & 0xFF) / 255.0f; + float tb = ((color1 >> 16) & 0xFF) / 255.0f; + float tg = ((color1 >> 8) & 0xFF) / 255.0f; + float tr = ((color1 >> 0) & 0xFF) / 255.0f; + + if (fa && !ta) { tr = fr, tg = fg, tb = fb; } + if (ta && !fa) { fr = tr, fg = tg, fb = tb; } + + int fi = GRADIENT_CACHE_COUNT * (stop == 0 ? 0 : stop0->position / 100.0); + int ti = GRADIENT_CACHE_COUNT * (stop == (uintptr_t) (gradient->stopCount - 2) ? 1 : stop1->position / 100.0); + if (fi < 0) fi = 0; + if (ti > GRADIENT_CACHE_COUNT) ti = GRADIENT_CACHE_COUNT; + + for (int i = fi; i < ti; i++) { + float p = (float) (i - fi) / (ti - fi - 1); + + if (p < 0) p = 0; + if (p > 1) p = 1; + + if (gradient->useGammaInterpolation) { + cache->colors[i] = (uint32_t) (GammaInterpolate(fr, tr, p) * 255.0f) << 0 + | (uint32_t) (GammaInterpolate(fg, tg, p) * 255.0f) << 8 + | (uint32_t) (GammaInterpolate(fb, tb, p) * 255.0f) << 16 + | (uint32_t) ((fa + (ta - fa) * p) * 255.0f) << 24; + } else { + cache->colors[i] = (uint32_t) (LinearInterpolate(fr, tr, p) * 255.0f) << 0 + | (uint32_t) (LinearInterpolate(fg, tg, p) * 255.0f) << 8 + | (uint32_t) (LinearInterpolate(fb, tb, p) * 255.0f) << 16 + | (uint32_t) ((fa + (ta - fa) * p) * 255.0f) << 24; + } + + if ((cache->colors[i] & 0xFF000000) != 0xFF000000) { + cache->opaque = false; + } + } + + stop0 = stop1; + } + +#if 0 + if (gradient->useDithering) { + for (uintptr_t i = 0; i < GRADIENT_CACHE_COUNT; i++) { + uint32_t mainColor = cache->colors[i]; + uint32_t ditherColor = mainColor; + int forwardSteps = 0, totalSteps = 0; + + for (uintptr_t j = i + 1; j < GRADIENT_CACHE_COUNT; j++) { + forwardSteps++; + + if (cache->colors[j] != mainColor) { + ditherColor = cache->colors[j]; + break; + } + } + + totalSteps = forwardSteps; + + for (intptr_t j = i - 1; j >= 0; j--) { + totalSteps++; + + if (cache->colors[j] != mainColor) { + break; + } + } + + if (!totalSteps) { + totalSteps = 1; + } + + cache->ditherColors[i] = ditherColor; + cache->ditherThresholds[i] = (uint32_t) ((float) forwardSteps / totalSteps * 65535.0f) << 16; + } + } +#endif +} + +void ThemeDrawBox(EsPainter *painter, EsRectangle rect, EsBuffer *data, float scale, + const ThemeLayer *layer, EsRectangle opaqueRegion, int childType) { + int width = THEME_RECT_WIDTH(rect), height = THEME_RECT_HEIGHT(rect); + if (width <= 0 || height <= 0) return; + + const ThemeLayerBox *box = (const ThemeLayerBox *) EsBufferRead(data, sizeof(ThemeLayerBox)); + if (!box) return; + + if ((box->flags & THEME_LAYER_BOX_SHADOW_HIDING) && layer->offset.l == 0 && layer->offset.r == 0 && layer->offset.t == 0 && layer->offset.b == 0) { + return; + } + + bool isBlurred = box->flags & THEME_LAYER_BOX_IS_BLURRED; + +#if 0 + if (scale == 1 && isBlurred) { + width--, rect.r--; + height--, rect.b--; + } +#endif + + ThemePaintData mainPaint, borderPaint; + GradientCache mainGradient, borderGradient; + + mainPaint.type = box->mainPaintType; + borderPaint.type = box->borderPaintType; + + if (mainPaint.type == 0) { + } else if (mainPaint.type == THEME_PAINT_SOLID || mainPaint.type == THEME_PAINT_OVERWRITE) { + mainPaint.solid = (const ThemePaintSolid *) EsBufferRead(data, sizeof(ThemePaintSolid)); + } else if (mainPaint.type == THEME_PAINT_LINEAR_GRADIENT) { + mainPaint.linearGradient = (const ThemePaintLinearGradient *) EsBufferRead(data, sizeof(ThemePaintLinearGradient)); + GradientCacheSetup(&mainGradient, mainPaint.linearGradient, width, height, data); + mainGradient.ox = rect.l; + mainGradient.oy = rect.t; + } else if (mainPaint.type == THEME_PAINT_CUSTOM && data->context) { + mainPaint.custom = (const ThemePaintCustom *) EsBufferRead(data, sizeof(ThemePaintCustom)); + mainGradient.ox = rect.l; + mainGradient.oy = rect.t; + mainGradient.context = data->context; + } else { + data->error = true; + } + + if (borderPaint.type == 0) { + } else if (borderPaint.type == THEME_PAINT_SOLID || borderPaint.type == THEME_PAINT_OVERWRITE) { + borderPaint.solid = (ThemePaintSolid *) EsBufferRead(data, sizeof(ThemePaintSolid)); + } else if (borderPaint.type == THEME_PAINT_LINEAR_GRADIENT) { + borderPaint.linearGradient = (ThemePaintLinearGradient *) EsBufferRead(data, sizeof(ThemePaintLinearGradient)); + if (!data->error) GradientCacheSetup(&borderGradient, borderPaint.linearGradient, width, height, data); + borderGradient.ox = rect.l; + borderGradient.oy = rect.t; + } else { + data->error = true; + } + + if (data->error) { + return; + } + + if (mainPaint.type == 0 && borderPaint.type == 0) { + return; + } + + if (isBlurred && borderPaint.type == THEME_PAINT_SOLID) { + float alpha = borderPaint.solid->color >> 24; + uint32_t color = borderPaint.solid->color & 0xFFFFFF; + borderGradient.start = 0; + borderGradient.opaque = false; + borderGradient.dithered = false; + + for (uintptr_t i = 0; i < GRADIENT_CACHE_COUNT; i++) { + borderGradient.colors[i] = color | (uint32_t) (alpha * gaussLookup[i]) << 24; + } + + if (~box->flags & THEME_LAYER_BOX_SHADOW_CUT) { + mainPaint.type = THEME_PAINT_SOLID; + mainPaint.solid = borderPaint.solid; + } + + borderPaint.type = THEME_PAINT_LINEAR_GRADIENT; + borderPaint.linearGradient = NULL; + } + + Corners32 corners = { (int) (box->corners.tl * scale + 0.5f), (int) (box->corners.tr * scale + 0.5f), + (int) (box->corners.bl * scale + 0.5f), (int) (box->corners.br * scale + 0.5f) }; + + if (box->flags & THEME_LAYER_BOX_AUTO_CORNERS) { + bool horizontal = childType & THEME_CHILD_TYPE_HORIZONTAL; + int c = childType & ~THEME_CHILD_TYPE_HORIZONTAL; + + if (c == THEME_CHILD_TYPE_FIRST) { + if (horizontal) corners.tr = corners.br = 0; else corners.bl = corners.br = 0; + } else if (c == THEME_CHILD_TYPE_LAST) { + if (horizontal) corners.tl = corners.bl = 0; else corners.tl = corners.tr = 0; + } else if (c != THEME_CHILD_TYPE_ONLY) { + corners.tl = corners.tr = corners.bl = corners.br = 0; + } + } + + if (isBlurred) { + corners.bl = corners.tr = corners.br = corners.tl; + } + + if (corners.tl + corners.tr > width) { float p = (float) corners.tl / (corners.tl + corners.tr); corners.tl = p * width; corners.tr = (1 - p) * width; } + if (corners.bl + corners.br > width) { float p = (float) corners.bl / (corners.bl + corners.br); corners.bl = p * width; corners.br = (1 - p) * width; } + if (corners.tl + corners.bl > height) { float p = (float) corners.tl / (corners.tl + corners.bl); corners.tl = p * height; corners.bl = (1 - p) * height; } + if (corners.tr + corners.br > height) { float p = (float) corners.tr / (corners.tr + corners.br); corners.tr = p * height; corners.br = (1 - p) * height; } + + Rectangle32 borders = { (int) (box->borders.l * scale), (int) (box->borders.r * scale), + (int) (box->borders.t * scale), (int) (box->borders.b * scale) }; + + if (box->flags & THEME_LAYER_BOX_AUTO_BORDERS) { + bool horizontal = childType & THEME_CHILD_TYPE_HORIZONTAL; + int c = childType & ~THEME_CHILD_TYPE_HORIZONTAL; + + if (c == THEME_CHILD_TYPE_FIRST) { + if (horizontal) borders.r = 0; else borders.b = 0; + } else if (c == THEME_CHILD_TYPE_LAST) { + if (horizontal) borders.l = 0; else borders.t = 0; + } else if (c != THEME_CHILD_TYPE_ONLY) { + if (horizontal) borders.l = borders.r = 0; else borders.t = borders.b = 0; + } + } + + if (isBlurred) { + borders.r = borders.t = borders.b = borders.l; + } + + if (borders.l + borders.r > width) { float p = (float) borders.l / (borders.l + borders.r); borders.l = p * width; borders.r = (1 - p) * width; } + if (borders.t + borders.b > height) { float p = (float) borders.t / (borders.t + borders.b); borders.t = p * height; borders.b = (1 - p) * height; } + + if (isBlurred && !borders.l) { + return; + } + + Corners32 cornerBorders = { MaximumInteger(borders.l, borders.t), MaximumInteger(borders.t, borders.r), + MaximumInteger(borders.l, borders.b), MaximumInteger(borders.b, borders.r) }; + + if (isBlurred) { + borderGradient.dx = -(GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE) / borders.l; + borderGradient.ox = rect.l + borders.l; + borderGradient.dy = borderGradient.oy = 0; + } + + ThemeFillRectangle(painter, THEME_RECT_4(rect.l, rect.l + borders.l, rect.t + MaximumInteger(borders.t, corners.tl), + rect.b - MaximumInteger(borders.b, corners.bl)), borderPaint, &borderGradient); + + if (isBlurred) { + borderGradient.dx = (GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE) / borders.r; + borderGradient.ox = rect.r - borders.r - 1; + } + + ThemeFillRectangle(painter, THEME_RECT_4(rect.r - borders.r, rect.r, rect.t + MaximumInteger(borders.t, corners.tr), + rect.b - MaximumInteger(borders.b, corners.br)), borderPaint, &borderGradient); + + if (isBlurred) { + borderGradient.dy = -(GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE) / borders.t; + borderGradient.oy = rect.t + borders.t; + borderGradient.dx = borderGradient.ox = 0; + } + + ThemeFillRectangle(painter, THEME_RECT_4(rect.l + corners.tl, rect.r - corners.tr, rect.t, rect.t + borders.t), borderPaint, &borderGradient); + + if (isBlurred) { + borderGradient.dy = (GRADIENT_CACHE_COUNT << GRADIENT_COORD_BASE) / borders.b; + borderGradient.oy = rect.b - borders.b - 1; + } + + ThemeFillRectangle(painter, THEME_RECT_4(rect.l + corners.bl, rect.r - corners.br, rect.b - borders.b, rect.b), borderPaint, &borderGradient); + + ThemeFillRectangle(painter, THEME_RECT_4(rect.l + corners.tl, rect.r - corners.tr, + rect.t + borders.t, rect.t + MaximumInteger(MinimumInteger(corners.tl, corners.tr), borders.t)), mainPaint, &mainGradient); + ThemeFillRectangle(painter, THEME_RECT_4(rect.l + (corners.tl > corners.tr ? corners.tl : borders.l), + rect.r - (corners.tl > corners.tr ? borders.r : corners.tr), + rect.t + MaximumInteger(MinimumInteger(corners.tl, corners.tr), borders.t), + rect.t + MaximumInteger3(corners.tl, corners.tr, borders.t)), mainPaint, &mainGradient); + + EsRectangle mainBlock = THEME_RECT_4(rect.l + borders.l, rect.r - borders.r, + rect.t + MaximumInteger3(corners.tl, corners.tr, borders.t), + rect.b - MaximumInteger3(corners.bl, corners.br, borders.b)); + + if ((box->flags & THEME_LAYER_BOX_SHADOW_HIDING) && THEME_RECT_VALID(opaqueRegion)) { + EsRectangle neededBorders = THEME_RECT_4(MaximumInteger(opaqueRegion.l - mainBlock.l, 0), MaximumInteger(mainBlock.r - opaqueRegion.r, 0), + MaximumInteger(opaqueRegion.t - mainBlock.t, 0), MaximumInteger(mainBlock.b - opaqueRegion.b, 0)); + ThemeFillRectangle(painter, THEME_RECT_4(mainBlock.l, mainBlock.r, mainBlock.t, mainBlock.t + neededBorders.t), mainPaint, &mainGradient); + ThemeFillRectangle(painter, THEME_RECT_4(mainBlock.l, mainBlock.l + neededBorders.l, + mainBlock.t + neededBorders.t, mainBlock.b - neededBorders.b), mainPaint, &mainGradient); + ThemeFillRectangle(painter, THEME_RECT_4(mainBlock.r - neededBorders.r, mainBlock.r, + mainBlock.t + neededBorders.t, mainBlock.b - neededBorders.b), mainPaint, &mainGradient); + ThemeFillRectangle(painter, THEME_RECT_4(mainBlock.l, mainBlock.r, mainBlock.b - neededBorders.b, mainBlock.b), mainPaint, &mainGradient); + } else { + ThemeFillRectangle(painter, mainBlock, mainPaint, &mainGradient); + } + + ThemeFillRectangle(painter, THEME_RECT_4(rect.l + (corners.bl > corners.br ? corners.bl : borders.l), + rect.r - (corners.bl > corners.br ? borders.r : corners.br), + rect.b - MaximumInteger3(corners.bl, corners.br, borders.b), + rect.b - MaximumInteger(MinimumInteger(corners.bl, corners.br), borders.b)), mainPaint, &mainGradient); + ThemeFillRectangle(painter, THEME_RECT_4(rect.l + corners.bl, rect.r - corners.br, + rect.b - MaximumInteger(MinimumInteger(corners.bl, corners.br), borders.b), + rect.b - borders.b), mainPaint, &mainGradient); + + if (cornerBorders.tl >= corners.tl) { + ThemeFillRectangle(painter, THEME_RECT_4(rect.l, rect.l + corners.tl, rect.t + corners.tl, rect.t + cornerBorders.tl), borderPaint, &borderGradient); + } + + if (cornerBorders.tr >= corners.tr) { + ThemeFillRectangle(painter, THEME_RECT_4(rect.r - corners.tr, rect.r, rect.t + corners.tr, rect.t + cornerBorders.tr), borderPaint, &borderGradient); + } + + if (cornerBorders.bl >= corners.bl) { + ThemeFillRectangle(painter, THEME_RECT_4(rect.l, rect.l + corners.bl, rect.b - cornerBorders.bl, rect.b - corners.bl), borderPaint, &borderGradient); + } + + if (cornerBorders.br >= corners.br) { + ThemeFillRectangle(painter, THEME_RECT_4(rect.r - corners.br, rect.r, rect.b - cornerBorders.br, rect.b - corners.br), borderPaint, &borderGradient); + } + + if (box->flags & THEME_LAYER_BOX_SHADOW_CUT) { + ThemeFillBlurCutCorner(painter, THEME_RECT_4(rect.l, rect.l + corners.tl, rect.t, rect.t + corners.tl), + corners.tl, corners.tl, borders.l, corners.tl, &borderGradient, mainPaint); + ThemeFillBlurCutCorner(painter, THEME_RECT_4(rect.r - corners.tr, rect.r, rect.t, rect.t + corners.tr), + -1, corners.tr, borders.l, corners.tr, &borderGradient, mainPaint); + ThemeFillBlurCutCorner(painter, THEME_RECT_4(rect.l, rect.l + corners.bl, rect.b - corners.bl, rect.b), + corners.bl, -1, borders.l, corners.bl, &borderGradient, mainPaint); + ThemeFillBlurCutCorner(painter, THEME_RECT_4(rect.r - corners.br, rect.r, rect.b - corners.br, rect.b), + -1, -1, borders.l, corners.br, &borderGradient, mainPaint); + } else if (isBlurred) { + ThemeFillBlurCorner(painter, THEME_RECT_4(rect.l, rect.l + corners.tl, rect.t, rect.t + corners.tl), + corners.tl, corners.tl, borders.l, corners.tl, &borderGradient); + ThemeFillBlurCorner(painter, THEME_RECT_4(rect.r - corners.tr, rect.r, rect.t, rect.t + corners.tr), + -1, corners.tr, borders.l, corners.tr, &borderGradient); + ThemeFillBlurCorner(painter, THEME_RECT_4(rect.l, rect.l + corners.bl, rect.b - corners.bl, rect.b), + corners.bl, -1, borders.l, corners.bl, &borderGradient); + ThemeFillBlurCorner(painter, THEME_RECT_4(rect.r - corners.br, rect.r, rect.b - corners.br, rect.b), + -1, -1, borders.l, corners.br, &borderGradient); + } else { + ThemeFillCorner(painter, THEME_RECT_4(rect.l, rect.l + corners.tl, rect.t, rect.t + corners.tl), + corners.tl, corners.tl, cornerBorders.tl, corners.tl, mainPaint, borderPaint, &mainGradient, &borderGradient); + ThemeFillCorner(painter, THEME_RECT_4(rect.r - corners.tr, rect.r, rect.t, rect.t + corners.tr), + 0, corners.tr, cornerBorders.tr, corners.tr, mainPaint, borderPaint, &mainGradient, &borderGradient); + ThemeFillCorner(painter, THEME_RECT_4(rect.l, rect.l + corners.bl, rect.b - corners.bl, rect.b), + corners.bl, 0, cornerBorders.bl, corners.bl, mainPaint, borderPaint, &mainGradient, &borderGradient); + ThemeFillCorner(painter, THEME_RECT_4(rect.r - corners.br, rect.r, rect.b - corners.br, rect.b), + 0, 0, cornerBorders.br, corners.br, mainPaint, borderPaint, &mainGradient, &borderGradient); + } +} + +void ThemeDrawPath(EsPainter *painter, EsRectangle rect, EsBuffer *data, float scale) { + int width = THEME_RECT_WIDTH(rect), height = THEME_RECT_HEIGHT(rect); + if (width <= 0 || height <= 0) return; + + const ThemeLayerPath *layer = (const ThemeLayerPath *) EsBufferRead(data, sizeof(ThemeLayerPath)); + if (!layer) return; + if (!layer->pointCount) return; + if (!layer->alpha) return; + const float *points = (const float *) EsBufferRead(data, layer->pointCount * 6 * sizeof(float)); + if (!points) return; + + EsRectangle bounds; + EsRectangleClip(rect, painter->clip, &bounds); + + if (!THEME_RECT_VALID(bounds)) { + return; + } + + RastVertex scale2 = { width / 100.0f, height / 100.0f }; + + RastPath path = {}; + + for (uintptr_t i = 0, j = 0; i < layer->pointCount * 3; i += 3) { + if ((int) i == layer->pointCount * 3 - 3 || points[i * 2 + 2] == -1e6) { + RastPathAppendBezier(&path, (RastVertex *) points + j, i - j + 1, scale2); + RastPathCloseSegment(&path); + j = i + 3; + } + } + + RastPathTranslate(&path, rect.l - painter->clip.l, rect.t - painter->clip.t); + + RastSurface surface = {}; + + float xOffset = rect.l - painter->clip.l; + float yOffset = rect.t - painter->clip.t; + + if (!RastSurfaceInitialise(&surface, THEME_RECT_WIDTH(painter->clip), THEME_RECT_HEIGHT(painter->clip), false)) { + goto error; + } + + for (uintptr_t i = 0; i < layer->fillCount; i++) { + const ThemeLayerPathFill *fill = (const ThemeLayerPathFill *) EsBufferRead(data, sizeof(ThemeLayerPathFill)); + if (!fill) return; + + RastPaint paint = {}; + RastShape shape = {}; + + if ((fill->paintAndFillType & 0x0F) == THEME_PAINT_SOLID) { + const ThemePaintSolid *p = (const ThemePaintSolid *) EsBufferRead(data, sizeof(ThemePaintSolid)); + if (!p) return; + paint.type = RAST_PAINT_SOLID; + paint.solid.color = p->color & 0xFFFFFF; + paint.solid.alpha = (p->color >> 24) / 255.0f; + } else if ((fill->paintAndFillType & 0x0F) == THEME_PAINT_LINEAR_GRADIENT) { + RastGradientStop stops[16]; + size_t stopCount = 0; + + const ThemePaintLinearGradient *p = (const ThemePaintLinearGradient *) EsBufferRead(data, sizeof(ThemePaintLinearGradient)); + if (!p) return; + + for (uintptr_t i = 0; i < p->stopCount && i < 16; i++, stopCount++) { + const ThemeGradientStop *stop = (const ThemeGradientStop *) EsBufferRead(data, sizeof(ThemeGradientStop)); + if (!stop) return; + stops[i].color = stop->color; + stops[i].position = stop->position / 100.0f; + } + + paint.type = RAST_PAINT_LINEAR_GRADIENT; + paint.gradient.repeatMode = (RastRepeatMode) p->repeatMode; + paint.gradient.transform[0] = p->transform[0] / THEME_RECT_WIDTH(rect); + paint.gradient.transform[1] = p->transform[1] / THEME_RECT_HEIGHT(rect); + paint.gradient.transform[2] = p->transform[2] - (paint.gradient.transform[0] * xOffset + paint.gradient.transform[1] * yOffset); + + RastGradientInitialise(&paint, stops, stopCount, p->useGammaInterpolation); + } else if ((fill->paintAndFillType & 0x0F) == THEME_PAINT_RADIAL_GRADIENT) { + RastGradientStop stops[16]; + size_t stopCount = 0; + + const ThemePaintRadialGradient *p = (const ThemePaintRadialGradient *) EsBufferRead(data, sizeof(ThemePaintRadialGradient)); + if (!p) return; + + for (uintptr_t i = 0; i < p->stopCount && i < 16; i++, stopCount++) { + const ThemeGradientStop *stop = (const ThemeGradientStop *) EsBufferRead(data, sizeof(ThemeGradientStop)); + if (!stop) return; + stops[i].color = stop->color; + stops[i].position = stop->position / 100.0f; + } + + paint.type = RAST_PAINT_RADIAL_GRADIENT; + paint.gradient.repeatMode = (RastRepeatMode) p->repeatMode; + paint.gradient.transform[0] = p->transform[0] / THEME_RECT_WIDTH(rect); + paint.gradient.transform[1] = p->transform[1] / THEME_RECT_HEIGHT(rect); + paint.gradient.transform[2] = p->transform[2] - (paint.gradient.transform[0] * xOffset + paint.gradient.transform[1] * yOffset); + paint.gradient.transform[3] = p->transform[3] / THEME_RECT_WIDTH(rect); + paint.gradient.transform[4] = p->transform[4] / THEME_RECT_HEIGHT(rect); + paint.gradient.transform[5] = p->transform[5] - (paint.gradient.transform[3] * xOffset + paint.gradient.transform[4] * yOffset); + + RastGradientInitialise(&paint, stops, stopCount, p->useGammaInterpolation); + } else { + // TODO Checkboards, angular gradients and noise. + } + + if ((fill->paintAndFillType & 0xF0) == THEME_PATH_FILL_SOLID) { + shape = RastShapeCreateSolid(&path); + } else if ((fill->paintAndFillType & 0xF0) == THEME_PATH_FILL_CONTOUR) { + const ThemeLayerPathFillContour *contour = (const ThemeLayerPathFillContour *) EsBufferRead(data, sizeof(ThemeLayerPathFillContour)); + if (!contour) return; + RastContourStyle style = {}; + style.internalWidth = contour->internalWidth * scale; + style.externalWidth = contour->externalWidth * scale; + style.joinMode = (RastLineJoinMode) ((contour->mode >> 0) & 3); + style.capMode = (RastLineCapMode) ((contour->mode >> 2) & 3); + style.miterLimit = contour->miterLimit * scale; + + if (contour->mode & 0x80) { + style.internalWidth = EsCRTfloorf(style.internalWidth); + style.externalWidth = EsCRTfloorf(style.externalWidth); + } + + shape = RastShapeCreateContour(&path, style, ~layer->flags & THEME_LAYER_PATH_CLOSED); + } else if ((fill->paintAndFillType & 0xF0) == THEME_PATH_FILL_DASHED) { + RastDash dashes[16]; + RastContourStyle styles[16]; + size_t styleCount = 0; + + for (uintptr_t i = 0; i < fill->dashCount && i < 16; i++, styleCount++) { + const ThemeLayerPathFillDash *dash = (const ThemeLayerPathFillDash *) EsBufferRead(data, sizeof(ThemeLayerPathFillDash)); + if (!dash) return; + dashes[i].gap = dash->gap * scale; + dashes[i].length = dash->length * scale; + dashes[i].style = styles + i; + styles[i].internalWidth = dash->contour.internalWidth * scale; + styles[i].externalWidth = dash->contour.externalWidth * scale; + styles[i].joinMode = (RastLineJoinMode) ((dash->contour.mode >> 0) & 3); + styles[i].capMode = (RastLineCapMode) ((dash->contour.mode >> 2) & 3); + styles[i].miterLimit = dash->contour.miterLimit * scale; + + if (dash->contour.mode & 0x80) { + styles[i].internalWidth = EsCRTfloorf(styles[i].internalWidth); + styles[i].externalWidth = EsCRTfloorf(styles[i].externalWidth); + } + } + + shape = RastShapeCreateDashed(&path, dashes, styleCount, ~layer->flags & THEME_LAYER_PATH_CLOSED); + } + + RastSurfaceFill(surface, shape, paint, layer->flags & THEME_LAYER_PATH_FILL_EVEN_ODD); + + RastGradientDestroy(&paint); + } + + // TODO Use drawn bounding box. + + for (int32_t j = painter->clip.t; j < painter->clip.b; j++) { + uint32_t *source = surface.buffer + (j - painter->clip.t) * surface.stride / 4; + uint32_t *destination = (uint32_t *) painter->target->bits + j * painter->target->stride / 4 + painter->clip.l; + + for (int32_t i = painter->clip.l; i < painter->clip.r; i++) { + uint32_t s = *source; + + if (layer->alpha != 0xFF) { + uint32_t alpha = s >> 24; + + if (alpha) { + alpha *= layer->alpha; + alpha >>= 8; + s = (s & 0xFFFFFF) | (alpha << 24); + BlendPixel(destination, s, painter->target->fullAlpha); + } + } else { + BlendPixel(destination, s, painter->target->fullAlpha); + } + + destination++, source++; + } + } + + error:; + RastSurfaceDestroy(&surface); + RastPathDestroy(&path); +} + +#ifdef IN_DESIGNER + +void ThemeDrawLayer(EsPainter *painter, EsRectangle _bounds, EsBuffer *data, float scale, EsRectangle opaqueRegion) { + const ThemeLayer *layer = (const ThemeLayer *) EsBufferRead(data, sizeof(ThemeLayer)); + + if (!layer) { + return; + } + + EsRectangle bounds; + bounds.l = _bounds.l + (int) (scale * layer->offset.l) + THEME_RECT_WIDTH(_bounds) * layer->position.l / 100; + bounds.r = _bounds.l + (int) (scale * layer->offset.r) + THEME_RECT_WIDTH(_bounds) * layer->position.r / 100; + bounds.t = _bounds.t + (int) (scale * layer->offset.t) + THEME_RECT_HEIGHT(_bounds) * layer->position.t / 100; + bounds.b = _bounds.t + (int) (scale * layer->offset.b) + THEME_RECT_HEIGHT(_bounds) * layer->position.b / 100; + + if (THEME_RECT_WIDTH(bounds) <= 0 || THEME_RECT_HEIGHT(bounds) <= 0) { + if (layer->dataByteCount) { + EsBufferRead(data, layer->dataByteCount - sizeof(ThemeLayer)); + } + } else { + if (layer->type == THEME_LAYER_BOX) { + ThemeDrawBox(painter, bounds, data, scale, layer, opaqueRegion, 0); + } else if (layer->type == THEME_LAYER_PATH) { + ThemeDrawPath(painter, bounds, data, scale); + } else if (layer->type == THEME_LAYER_METRICS) { + EsBufferRead(data, sizeof(ThemeMetrics)); + } + } +} + +#endif + +////////////////////////////////////////// + +#ifndef IN_DESIGNER + +typedef struct ThemeAnimatingProperty { + uint16_t offset; // Offset into the theme data. + uint8_t type : 4, beforeEnter : 1, _unused1 : 3; // Interpolation type. + uint8_t _unused0; + uint16_t duration, elapsed; // Milliseconds. + ThemeVariant from; // Value to interpolate from. +} ThemeAnimatingProperty; + +typedef struct ThemeAnimation { + Array properties; +} ThemeAnimation; + +struct UIStyle { + intptr_t referenceCount; + + uint32_t observedStyleStateMask; + bool IsStateChangeObserved(uint16_t state1, uint16_t state2); + + // General information. + + uint8_t textSize, textAlign; + uint32_t textColor; + EsFont font; + + EsRectangle insets, borders; + uint16_t preferredWidth, preferredHeight; + int16_t gapMajor, gapMinor, gapWrap; + + EsRectangle paintOutsets, opaqueInsets; + + float scale; + + EsThemeAppearance *appearance; // An optional, custom appearance provided by the application. + + // Data. + + uint16_t layerDataByteCount; + const ThemeStyle *style; + ThemeMetrics *metrics; // Points to correct position in layer data. + // Followed by overrides, then layer data. + // The overrides store the base value, and the layer data contains the overriden values. + + // Loaded styles management. + + void CloseReference(); + + // Painting. + + void PaintText(EsPainter *painter, EsElement *element, EsRectangle rectangle, const char *text, size_t textBytes, + uint32_t iconID, uint32_t flags, EsTextSelection *selectionProperties = nullptr); + void PaintLayers(EsPainter *painter, EsRectangle rectangle, int childType, int whichLayers); + void PaintTextLayers(EsPainter *painter, EsTextPlan *plan, EsRectangle textBounds, EsTextSelection *selectionProperties); + + // Misc. + + bool IsRegionCompletelyOpaque(EsRectangle region, int width, int height); + + inline void GetTextStyle(EsTextStyle *style); + + inline int GetLineHeight() { + EsTextStyle style; + GetTextStyle(&style); + return EsTextGetLineHeight(&style); + } + + inline int MeasureTextWidth(const char *text, size_t textBytes) { + EsTextStyle style; + GetTextStyle(&style); + return TextGetStringWidth(&style, text, textBytes); + } +}; + +const void *GetConstant(const char *cKey, size_t *byteCount, bool *scale) { + EsBuffer data = theming.system; + const ThemeHeader *header = (const ThemeHeader *) EsBufferRead(&data, sizeof(ThemeHeader)); + EsBufferRead(&data, sizeof(ThemeStyle) * header->styleCount); + + uint64_t hash = CalculateCRC64(EsLiteral(cKey)); + + for (uintptr_t i = 0; i < header->constantCount; i++) { + const ThemeConstant *constant = (const ThemeConstant *) EsBufferRead(&data, sizeof(ThemeConstant)); + + if (!constant) { + EsPrint("Broken theme constants list.\n"); + break; + } + + if (constant->hash == hash) { + data.position = constant->valueOffset; + const void *value = EsBufferRead(&data, (constant->valueByteCount + 3) & ~3); + + if (!value) { + EsPrint("Broken theme constant value.\n"); + return 0; + } + + *byteCount = constant->valueByteCount; + *scale = constant->scale; + return value; + } + } + + EsPrint("Could not find theme constant with key \"%z\".\n", cKey); + return nullptr; +} + +int GetConstantNumber(const char *cKey) { + size_t byteCount; + bool scale = false; + const void *value = GetConstant(cKey, &byteCount, &scale); + int integer = value ? EsIntegerParse((const char *) value, byteCount) : 0; + if (scale) integer *= theming.scale; + return integer; +} + +EsRectangle GetConstantRectangle(const char *cKey) { + size_t byteCount; + bool scale = false; + char *value = (char *) GetConstant(cKey, &byteCount, &scale); + if (!value) return {}; + EsRectangle rectangle; + rectangle.l = EsCRTstrtol(value, &value, 10); + if (*value == ',') value++; + rectangle.r = EsCRTstrtol(value, &value, 10); + if (*value == ',') value++; + rectangle.t = EsCRTstrtol(value, &value, 10); + if (*value == ',') value++; + rectangle.b = EsCRTstrtol(value, &value, 10); + + if (scale) { + rectangle.l *= theming.scale; + rectangle.r *= theming.scale; + rectangle.t *= theming.scale; + rectangle.b *= theming.scale; + } + + return rectangle; +} + +const char *GetConstantString(const char *cKey) { + size_t byteCount; + bool scale; + const char *value = (const char *) GetConstant(cKey, &byteCount, &scale); + return !value || !byteCount || value[byteCount - 1] ? nullptr : value; +} + +bool ThemeLoadData(void *buffer, size_t byteCount) { + EsBuffer data = {}; + data.in = (const uint8_t *) buffer; + data.bytes = byteCount; + + const ThemeHeader *header = (const ThemeHeader *) EsBufferRead(&data, sizeof(ThemeHeader)); + + if (!header || header->signature != THEME_HEADER_SIGNATURE + || !header->styleCount || !EsBufferRead(&data, sizeof(ThemeStyle)) + || byteCount < header->bitmapBytes) { + return false; + } + + theming.system.in = (const uint8_t *) buffer; + theming.system.bytes = byteCount; + theming.header = header; + return true; +} + +void ThemeStyleCopyInlineMetrics(UIStyle *style) { + style->textSize = style->metrics->textSize; + style->textColor = style->metrics->textColor; + style->font.family = style->metrics->fontFamily; + style->font.weight = style->metrics->fontWeight; + style->font.italic = style->metrics->isItalic; + style->preferredWidth = style->metrics->preferredWidth; + style->preferredHeight = style->metrics->preferredHeight; + style->gapMajor = style->metrics->gapMajor; + style->gapMinor = style->metrics->gapMinor; + style->gapWrap = style->metrics->gapWrap; + style->insets.l = style->metrics->insets.l; + style->insets.r = style->metrics->insets.r; + style->insets.t = style->metrics->insets.t; + style->insets.b = style->metrics->insets.b; + style->textAlign = style->metrics->textAlign; +} + +bool ThemeAnimationComplete(ThemeAnimation *animation) { + return !animation->properties.Length(); +} + +bool ThemeAnimationStep(ThemeAnimation *animation, int delta) { + bool repaint = false; + + for (uintptr_t i = 0; i < animation->properties.Length(); i++) { + ThemeAnimatingProperty *property = &animation->properties[i]; + + repaint = true; + property->elapsed += delta; + + if (property->duration < property->elapsed) { + animation->properties.Delete(i); + i--; + } + } + + return repaint; +} + +void ThemeAnimationDestroy(ThemeAnimation *animation) { + animation->properties.Free(); +} + +ThemeVariant ThemeAnimatingPropertyInterpolate(ThemeAnimatingProperty *property, UIStyle *destination, uint8_t *layerData) { + uint32_t dataOffset = property->offset; + EsAssert(dataOffset <= destination->layerDataByteCount - sizeof(ThemeVariant)); + float position = (float) property->elapsed / property->duration; + position = SmoothAnimationTime(position); + + if (property->type == THEME_OVERRIDE_I8) { + int8_t to = *(int8_t *) (layerData + dataOffset); + return (ThemeVariant) { .i8 = (int8_t ) LinearInterpolate(property->from.i8, to, position) }; + } else if (property->type == THEME_OVERRIDE_I16) { + int16_t to = *(int16_t *) (layerData + dataOffset); + return (ThemeVariant) { .i16 = (int16_t) LinearInterpolate(property->from.i16, to, position) }; + } else if (property->type == THEME_OVERRIDE_F32) { + float to = *(float *) (layerData + dataOffset); + return (ThemeVariant) { .f32 = (float) LinearInterpolate(property->from.f32, to, position) }; + } else if (property->type == THEME_OVERRIDE_COLOR) { + uint32_t from = property->from.u32; + uint32_t to = *(uint32_t *) (layerData + dataOffset); + + float fa = ((from >> 24) & 0xFF) / 255.0f; + float fb = ((from >> 16) & 0xFF) / 255.0f; + float fg = ((from >> 8) & 0xFF) / 255.0f; + float fr = ((from >> 0) & 0xFF) / 255.0f; + float ta = ((to >> 24) & 0xFF) / 255.0f; + float tb = ((to >> 16) & 0xFF) / 255.0f; + float tg = ((to >> 8) & 0xFF) / 255.0f; + float tr = ((to >> 0) & 0xFF) / 255.0f; + + if (fa && !ta) { tr = fr, tg = fg, tb = fb; } + if (ta && !fa) { fr = tr, fg = tg, fb = tb; } + + return (ThemeVariant) { .u32 = (uint32_t) (LinearInterpolate(fr, tr, position) * 255.0f) << 0 + | (uint32_t) (LinearInterpolate(fg, tg, position) * 255.0f) << 8 + | (uint32_t) (LinearInterpolate(fb, tb, position) * 255.0f) << 16 + | (uint32_t) ((fa + (ta - fa) * position) * 255.0f) << 24 }; + } else { + EsAssert(false); + return {}; + } +} + +UIStyle *ThemeStyleInterpolate(UIStyle *source, ThemeAnimation *animation) { + size_t byteCount = sizeof(UIStyle) + source->layerDataByteCount; + UIStyle *destination = (UIStyle *) EsHeapAllocate(byteCount, false); + EsMemoryCopy(destination, source, byteCount); + uint8_t *layerData = (uint8_t *) (destination + 1); + destination->metrics = (ThemeMetrics *) (layerData + sizeof(ThemeLayer)); + + for (uintptr_t i = 0; i < animation->properties.Length(); i++) { + ThemeAnimatingProperty *property = &animation->properties[i]; + ThemeVariant result = ThemeAnimatingPropertyInterpolate(property, destination, layerData); + + if (property->type == THEME_OVERRIDE_I8) { + *(int8_t *) (layerData + property->offset) = result.i8; + } else if (property->type == THEME_OVERRIDE_I16) { + *(int16_t *) (layerData + property->offset) = result.i16; + } else if (property->type == THEME_OVERRIDE_F32) { + *(float *) (layerData + property->offset) = result.f32; + } else if (property->type == THEME_OVERRIDE_COLOR) { + *(uint32_t *) (layerData + property->offset) = result.u32; + } + } + + ThemeStyleCopyInlineMetrics(destination); + return destination; +} + +void _ThemeAnimationBuildAddProperties(ThemeAnimation *animation, UIStyle *style, uint16_t stateFlags) { + const uint32_t *layerList = (const uint32_t *) (theming.system.in + style->style->layerListOffset); + // (Layer list was validated during ThemeStyleInitialise.) + uintptr_t layerCumulativeDataOffset = 0; + uint8_t *oldLayerData = (uint8_t *) (style + 1); + + for (uintptr_t i = 0; i < style->style->layerCount; i++) { + const ThemeLayer *layer = (const ThemeLayer *) (theming.system.in + layerList[i]); + + EsBuffer layerData = theming.system; + layerData.position = layer->sequenceDataOffset; + + while (layerData.position) { + const ThemeSequenceHeader *sequenceHeader = (const ThemeSequenceHeader *) EsBufferRead(&layerData, sizeof(ThemeSequenceHeader)); + + if (THEME_STATE_CHECK(sequenceHeader->state, stateFlags) && sequenceHeader->duration) { + for (uintptr_t j = 0; j < sequenceHeader->overrideCount; j++) { + const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); + uintptr_t key = themeOverride->offset + layerCumulativeDataOffset; + EsAssert(key <= (uintptr_t) style->layerDataByteCount - sizeof(ThemeVariant)); + + uintptr_t point; + bool alreadyInList; + + // Find where the property is/should be in the animation list. + + ES_MACRO_SEARCH(animation->properties.Length(), { + uintptr_t item = animation->properties[index].offset; + result = key < item ? -1 : key > item ? 1 : 0; + }, point, alreadyInList); + + bool beforeEnter = (sequenceHeader->state & THEME_STATE_BEFORE_ENTER) != 0; + + if (alreadyInList) { + // Update the duration, if the property is already in the list. + // Prioritise before enter sequence durations. + + if (!animation->properties[point].beforeEnter || beforeEnter) { + animation->properties[point].duration = sequenceHeader->duration * ANIMATION_TIME_SCALE; + animation->properties[point].beforeEnter = beforeEnter; + } + } else { + // Add the property to the list. + + if (point < animation->properties.Length()) EsAssert(key < animation->properties[point].offset); + if (point > 0) EsAssert(key > animation->properties[point - 1].offset); + + ThemeAnimatingProperty property = {}; + property.offset = key; + property.type = themeOverride->type; + property.duration = sequenceHeader->duration * ANIMATION_TIME_SCALE; + property.beforeEnter = beforeEnter; + + if (themeOverride->type == THEME_OVERRIDE_I8) { + EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 1); + property.from.i8 = *(int8_t *) (oldLayerData + key); + } else if (themeOverride->type == THEME_OVERRIDE_I16) { + EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 2); + property.from.i16 = *(int16_t *) (oldLayerData + key); + } else if (themeOverride->type == THEME_OVERRIDE_F32) { + EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 4); + property.from.f32 = *(float *) (oldLayerData + key); + } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { + EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 4); + property.from.u32 = *(uint32_t *) (oldLayerData + key); + } + + animation->properties.Insert(property, point); + } + } + } else { + EsBufferRead(&layerData, sizeof(ThemeOverride) * sequenceHeader->overrideCount); + } + + if (sequenceHeader->isLastSequence) { + break; + } + } + + layerCumulativeDataOffset += layer->dataByteCount; + } +} + +void ThemeAnimationBuild(ThemeAnimation *animation, UIStyle *oldStyle, uint16_t oldStateFlags, uint16_t newStateFlags) { + // Interpolate all the animating properties using the old style as the target. + + uint8_t *oldLayerData = (uint8_t *) (oldStyle + 1); + + for (uintptr_t i = 0; i < animation->properties.Length(); i++) { + ThemeAnimatingProperty *property = &animation->properties[i]; + property->from = ThemeAnimatingPropertyInterpolate(property, oldStyle, oldLayerData); + property->elapsed = 0; + } + + // Look for the all the sequences that match the old state flags, + // and add properties to return values to base. + + _ThemeAnimationBuildAddProperties(animation, oldStyle, oldStateFlags); + + // Look for the all the sequences that match the new state flags, + // and add properties to interpolate them to the target sequencs. + + _ThemeAnimationBuildAddProperties(animation, oldStyle, newStateFlags); +} + +UIStyle *ThemeStyleInitialise(UIStyleKey key) { + // Find the ThemeStyle entry. + + EsStyle *esStyle = (key.part & 1) || (!key.part) ? nullptr : (EsStyle *) (key.part); + EsThemeMetrics *customMetrics = esStyle ? &esStyle->metrics : nullptr; + uint16_t id = esStyle ? (uint16_t) (uintptr_t) esStyle->inherit : key.part; + if (!id) id = 1; + + EsBuffer data = theming.system; + const ThemeHeader *header = (const ThemeHeader *) EsBufferRead(&data, sizeof(ThemeHeader)); + const ThemeStyle *themeStyle = nullptr; + bool found = false; + + for (uintptr_t i = 0; i < header->styleCount; i++) { + themeStyle = (const ThemeStyle *) EsBufferRead(&data, sizeof(ThemeStyle)); + + if (!themeStyle) { + EsPrint("Broken theme styles list.\n"); + break; + } + + if (themeStyle->id == id) { + found = true; + break; + } + } + + if (!found) { + EsPrint("Could not find theme style with ID %d.\n", id); + data.position = sizeof(ThemeHeader); + themeStyle = (const ThemeStyle *) EsBufferRead(&data, sizeof(ThemeStyle)); + } + + if (!themeStyle->layerCount) { + EsPrint("Style has no layers (must have a metrics layer).\n"); + return nullptr; + } + + // Get information about the layers. + + size_t layerDataByteCount = 0; + data.position = themeStyle->layerListOffset; + + for (uintptr_t i = 0; i < themeStyle->layerCount; i++) { + const uint32_t *offset = (const uint32_t *) EsBufferRead(&data, sizeof(uint32_t)); + + if (!offset) { + EsPrint("Broken style layer list.\n"); + return nullptr; + } + + EsBuffer layerData = data; + layerData.position = *offset; + const ThemeLayer *layer = (const ThemeLayer *) EsBufferRead(&layerData, sizeof(ThemeLayer)); + + if (!layer) { + EsPrint("Broken style layer list.\n"); + return nullptr; + } + + if (layer->dataByteCount < sizeof(ThemeLayer)) { + EsPrint("Broken layer data byte count.\n"); + return nullptr; + } + + layerDataByteCount += layer->dataByteCount; + + if (i == 0) { + if (layer->type != THEME_LAYER_METRICS) { + EsPrint("Style does not have metrics layer.\n"); + return nullptr; + } + + if (layer->dataByteCount != sizeof(ThemeMetrics) + sizeof(ThemeLayer)) { + EsPrint("Broken metrics layer.\n"); + return nullptr; + } + + const ThemeMetrics *metrics = (const ThemeMetrics *) EsBufferRead(&layerData, sizeof(ThemeMetrics)); + + if (!metrics) { + EsPrint("Broken metrics layer.\n"); + return nullptr; + } + } else { + const uint8_t *data = (const uint8_t *) EsBufferRead(&layerData, layer->dataByteCount); + + if (!data) { + EsPrint("Broken layer.\n"); + return nullptr; + } + } + + layerData.position = layer->sequenceDataOffset; + + while (layerData.position) { + const ThemeSequenceHeader *sequenceHeader = (const ThemeSequenceHeader *) EsBufferRead(&layerData, sizeof(ThemeSequenceHeader)); + + if (!sequenceHeader) { + EsPrint("Broken sequence list.\n"); + return nullptr; + } + + if (THEME_STATE_CHECK(sequenceHeader->state, key.stateFlags)) { + for (uintptr_t j = 0; j < sequenceHeader->overrideCount; j++) { + const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); + + if (!themeOverride) { + EsPrint("Broken override list.\n"); + return nullptr; + } + + if (themeOverride->offset >= layer->dataByteCount) { + EsPrint("Broken override list.\n"); + return nullptr; + } + + bool valid; + + if (themeOverride->type == THEME_OVERRIDE_I8) { + valid = themeOverride->offset + 1 <= layer->dataByteCount; + } else if (themeOverride->type == THEME_OVERRIDE_I16) { + valid = themeOverride->offset + 2 <= layer->dataByteCount; + } else if (themeOverride->type == THEME_OVERRIDE_F32) { + valid = themeOverride->offset + 4 <= layer->dataByteCount; + } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { + valid = themeOverride->offset + 4 <= layer->dataByteCount; + } else { + EsPrint("Unsupported override type.\n"); + return nullptr; + } + + if (!valid) { + EsPrint("Broken override list.\n"); + return nullptr; + } + } + } else { + if (!EsBufferRead(&layerData, sizeof(ThemeOverride) * sequenceHeader->overrideCount)) { + EsPrint("Broken sequence list.\n"); + return nullptr; + } + } + + if (sequenceHeader->isLastSequence) { + break; + } + } + } + + if (layerDataByteCount > 0xFFFF) { + EsPrint("Layer data too large.\n"); + return nullptr; + } + + // Allocate the style. + + UIStyle *style = (UIStyle *) EsHeapAllocate(sizeof(UIStyle) + layerDataByteCount, true); + + style->referenceCount = 1; + style->layerDataByteCount = layerDataByteCount; + style->style = themeStyle; + + layerDataByteCount = 0; + data.position = themeStyle->layerListOffset; + uint8_t *baseData = (uint8_t *) (style + 1); + style->metrics = (ThemeMetrics *) (baseData + sizeof(ThemeLayer)); + + // Copy overrides and base layer data into the style, and apply overrides. + + for (uintptr_t i = 0; i < themeStyle->layerCount; i++) { + const uint32_t *offset = (const uint32_t *) EsBufferRead(&data, sizeof(uint32_t)); + EsBuffer layerData = data; + layerData.position = *offset; + const ThemeLayer *layer = (const ThemeLayer *) EsBufferRead(&layerData, sizeof(ThemeLayer)); + layerData.position = *offset; + const uint8_t *data = (const uint8_t *) EsBufferRead(&layerData, layer->dataByteCount); + EsMemoryCopy(baseData + layerDataByteCount, data, layer->dataByteCount); + layerData.position = layer->sequenceDataOffset; + + while (layerData.position) { + const ThemeSequenceHeader *sequenceHeader = (const ThemeSequenceHeader *) EsBufferRead(&layerData, sizeof(ThemeSequenceHeader)); + + style->observedStyleStateMask |= 0x10000 << (sequenceHeader->state & THEME_PRIMARY_STATE_MASK); + style->observedStyleStateMask |= sequenceHeader->state & ~THEME_PRIMARY_STATE_MASK; + + if (THEME_STATE_CHECK(sequenceHeader->state, key.stateFlags)) { + for (uintptr_t j = 0; j < sequenceHeader->overrideCount; j++) { + const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); + + ThemeVariant overrideValue = themeOverride->data; + + if (themeOverride->type == THEME_OVERRIDE_I8) { + *(int8_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.i8; + } else if (themeOverride->type == THEME_OVERRIDE_I16) { + *(int16_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.i16; + } else if (themeOverride->type == THEME_OVERRIDE_F32) { + *(float *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.f32; + } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { + *(uint32_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.u32; + } else { + EsAssert(false); + } + } + } else { + EsBufferRead(&layerData, sizeof(ThemeOverride) * sequenceHeader->overrideCount); + } + + if (sequenceHeader->isLastSequence) { + break; + } + } + + layerDataByteCount += layer->dataByteCount; + } + + // Apply custom metrics and appearance. + + if (customMetrics) { +#define ES_RECTANGLE_TO_RECTANGLE_8(x) { (int8_t) (x).l, (int8_t) (x).r, (int8_t) (x).t, (int8_t) (x).b } + if (customMetrics->mask & ES_THEME_METRICS_INSETS) style->metrics->insets = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->insets); + if (customMetrics->mask & ES_THEME_METRICS_CLIP_INSETS) style->metrics->clipInsets = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->clipInsets); + if (customMetrics->mask & ES_THEME_METRICS_GLOBAL_OFFSET) style->metrics->globalOffset = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->globalOffset); + if (customMetrics->mask & ES_THEME_METRICS_CLIP_ENABLED) style->metrics->clipEnabled = customMetrics->clipEnabled; + if (customMetrics->mask & ES_THEME_METRICS_CURSOR) style->metrics->cursor = customMetrics->cursor; + if (customMetrics->mask & ES_THEME_METRICS_ENTRANCE_TRANSITION) style->metrics->entranceTransition = customMetrics->entranceTransition; + if (customMetrics->mask & ES_THEME_METRICS_EXIT_TRANSITION) style->metrics->exitTransition = customMetrics->exitTransition; + if (customMetrics->mask & ES_THEME_METRICS_ENTRANCE_DURATION) style->metrics->entranceDuration = customMetrics->entranceDuration; + if (customMetrics->mask & ES_THEME_METRICS_EXIT_DURATION) style->metrics->exitDuration = customMetrics->exitDuration; + if (customMetrics->mask & ES_THEME_METRICS_PREFERRED_WIDTH) style->metrics->preferredWidth = customMetrics->preferredWidth; + if (customMetrics->mask & ES_THEME_METRICS_PREFERRED_HEIGHT) style->metrics->preferredHeight = customMetrics->preferredHeight; + if (customMetrics->mask & ES_THEME_METRICS_MINIMUM_WIDTH) style->metrics->minimumWidth = customMetrics->minimumWidth; + if (customMetrics->mask & ES_THEME_METRICS_MINIMUM_HEIGHT) style->metrics->minimumHeight = customMetrics->minimumHeight; + if (customMetrics->mask & ES_THEME_METRICS_MAXIMUM_WIDTH) style->metrics->maximumWidth = customMetrics->maximumWidth; + if (customMetrics->mask & ES_THEME_METRICS_MAXIMUM_HEIGHT) style->metrics->maximumHeight = customMetrics->maximumHeight; + if (customMetrics->mask & ES_THEME_METRICS_GAP_MAJOR) style->metrics->gapMajor = customMetrics->gapMajor; + if (customMetrics->mask & ES_THEME_METRICS_GAP_MINOR) style->metrics->gapMinor = customMetrics->gapMinor; + if (customMetrics->mask & ES_THEME_METRICS_GAP_WRAP) style->metrics->gapWrap = customMetrics->gapWrap; + if (customMetrics->mask & ES_THEME_METRICS_TEXT_COLOR) style->metrics->textColor = customMetrics->textColor; + if (customMetrics->mask & ES_THEME_METRICS_SELECTED_BACKGROUND) style->metrics->selectedBackground = customMetrics->selectedBackground; + if (customMetrics->mask & ES_THEME_METRICS_SELECTED_TEXT) style->metrics->selectedText = customMetrics->selectedText; + if (customMetrics->mask & ES_THEME_METRICS_ICON_COLOR) style->metrics->iconColor = customMetrics->iconColor; + if (customMetrics->mask & ES_THEME_METRICS_TEXT_ALIGN) style->metrics->textAlign = customMetrics->textAlign; + if (customMetrics->mask & ES_THEME_METRICS_TEXT_SIZE) style->metrics->textSize = customMetrics->textSize; + if (customMetrics->mask & ES_THEME_METRICS_FONT_FAMILY) style->metrics->fontFamily = customMetrics->fontFamily; + if (customMetrics->mask & ES_THEME_METRICS_FONT_WEIGHT) style->metrics->fontWeight = customMetrics->fontWeight; + if (customMetrics->mask & ES_THEME_METRICS_ICON_SIZE) style->metrics->iconSize = customMetrics->iconSize; + if (customMetrics->mask & ES_THEME_METRICS_IS_ITALIC) style->metrics->isItalic = customMetrics->isItalic; + if (customMetrics->mask & ES_THEME_METRICS_ELLIPSIS) style->metrics->ellipsis = customMetrics->ellipsis; + if (customMetrics->mask & ES_THEME_METRICS_LAYOUT_VERTICAL) style->metrics->layoutVertical = customMetrics->layoutVertical; + } + + if (esStyle && esStyle->appearance.enabled) { + style->appearance = &esStyle->appearance; + } + + // Apply scaling to the metrics. + + int8_t *scale8[] = { + &style->metrics->textSize, &style->metrics->iconSize, + }; + + for (uintptr_t i = 0; i < sizeof(scale8) / sizeof(scale8[0]); i++) { + *(scale8[i]) = *(scale8[i]) * key.scale; + } + + int16_t *scale16[] = { + &style->metrics->insets.l, &style->metrics->insets.r, &style->metrics->insets.t, &style->metrics->insets.b, + &style->metrics->clipInsets.l, &style->metrics->clipInsets.r, &style->metrics->clipInsets.t, &style->metrics->clipInsets.b, + &style->metrics->globalOffset.l, &style->metrics->globalOffset.r, &style->metrics->globalOffset.t, &style->metrics->globalOffset.b, + &style->metrics->gapMajor, &style->metrics->gapMinor, &style->metrics->gapWrap, + &style->metrics->preferredWidth, &style->metrics->preferredHeight, + &style->metrics->minimumWidth, &style->metrics->minimumHeight, + &style->metrics->maximumWidth, &style->metrics->maximumHeight, + }; + + for (uintptr_t i = 0; i < sizeof(scale16) / sizeof(scale16[0]); i++) { + *(scale16[i]) = *(scale16[i]) * key.scale; + } + + style->scale = key.scale; + + // Copy inline metrics. + + style->borders.l = themeStyle->approximateBorders.l * key.scale; + style->borders.r = themeStyle->approximateBorders.r * key.scale; + style->borders.t = themeStyle->approximateBorders.t * key.scale; + style->borders.b = themeStyle->approximateBorders.b * key.scale; + + style->paintOutsets.l = themeStyle->paintOutsets.l * key.scale; + style->paintOutsets.r = themeStyle->paintOutsets.r * key.scale; + style->paintOutsets.t = themeStyle->paintOutsets.t * key.scale; + style->paintOutsets.b = themeStyle->paintOutsets.b * key.scale; + + if (style->opaqueInsets.l != 0x7F) { + style->opaqueInsets.l = themeStyle->opaqueInsets.l * key.scale; + style->opaqueInsets.r = themeStyle->opaqueInsets.r * key.scale; + style->opaqueInsets.t = themeStyle->opaqueInsets.t * key.scale; + style->opaqueInsets.b = themeStyle->opaqueInsets.b * key.scale; + } + + if (style->appearance) { + if ((style->appearance->backgroundColor & 0xFF000000) == 0xFF000000) { + style->opaqueInsets = ES_RECT_1(0); + } else { + style->opaqueInsets = ES_RECT_1(0x7F); + } + } + + ThemeStyleCopyInlineMetrics(style); + + return style; +} + +UIStyleKey MakeStyleKey(const EsStyle *style, uint16_t stateFlags) { + return { .part = (uintptr_t) style, .stateFlags = stateFlags }; +} + +void FreeUnusedStyles() { + for (uintptr_t i = 0; i < theming.loadedStyles.Count(); i++) { + if (theming.loadedStyles[i]->referenceCount == 0) { + UIStyle *style = theming.loadedStyles[i]; + UIStyleKey key = theming.loadedStyles.KeyAtIndex(i); + theming.loadedStyles.Delete(&key); + EsHeapFree(style); + i--; + } + } +} + +UIStyle *GetStyle(UIStyleKey key, bool keepAround) { + UIStyle **style = theming.loadedStyles.Get(&key); + + if (!style) { + UIStyleKey key2 = key; + key2.scale = theming.scale; // TODO Per-window scaling. + style = theming.loadedStyles.Put(&key); + *style = ThemeStyleInitialise(key2); + EsAssert(style); + } else if ((*style)->referenceCount != -1) { + (*style)->referenceCount++; + } + + if (keepAround || !key.part) { + (*style)->referenceCount = -1; + } + + return *style; +} + +void GetPreferredSizeFromStylePart(const EsStyle *esStyle, int64_t *width, int64_t *height) { + UIStyle *style = GetStyle(MakeStyleKey(esStyle, ES_FLAGS_DEFAULT), true); + if (width) *width = style->preferredWidth; + if (height) *height = style->preferredHeight; + style->CloseReference(); +} + +void UIStyle::CloseReference() { + if (referenceCount == -1) { + return; + } + + referenceCount--; +} + +void UIStyle::PaintTextLayers(EsPainter *painter, EsTextPlan *plan, EsRectangle textBounds, EsTextSelection *selectionProperties) { + EsBuffer data = {}; + data.in = (uint8_t *) (this + 1); + data.bytes = layerDataByteCount; + + EsTextStyle primaryStyle = TextPlanGetPrimaryStyle(plan); + bool restore = false; + + for (uintptr_t i = 0; i < style->layerCount; i++) { + const ThemeLayer *layer = (const ThemeLayer *) EsBufferRead(&data, sizeof(ThemeLayer)); + if (!layer) break; + + if (layer->mode == THEME_LAYER_MODE_CONTENT && layer->type == THEME_LAYER_TEXT) { + EsBuffer data2 = data; + const ThemeLayerText *textLayer = (const ThemeLayerText *) EsBufferRead(&data2, sizeof(ThemeLayerText)); + if (!textLayer) break; + + EsTextStyle textStyle = primaryStyle; + textStyle.color = textLayer->color; + textStyle.blur = textLayer->blur; + EsTextPlanReplaceStyleRenderProperties(plan, &textStyle); + restore = true; + + EsDrawText(painter, plan, Translate(textBounds, layer->offset.l, layer->offset.t)); + } + + EsBufferRead(&data, layer->dataByteCount - sizeof(ThemeLayer)); + } + + if (restore) EsTextPlanReplaceStyleRenderProperties(plan, &primaryStyle); + EsDrawText(painter, plan, textBounds, nullptr, selectionProperties); +} + +void UIStyle::PaintText(EsPainter *painter, EsElement *element, EsRectangle rectangle, + const char *text, size_t textBytes, uint32_t iconID, uint32_t flags, EsTextSelection *selectionProperties) { + EsRectangle bounds = EsRectangleAdd(Translate(EsRectangleAddBorder(rectangle, insets), painter->offsetX, painter->offsetY), RECT16_TO_RECT(metrics->globalOffset)); + EsRectangle textBounds = bounds; + EsRectangle oldClip = painter->clip; + EsRectangleClip(painter->clip, bounds, &painter->clip); + + EsRectangle iconBounds = EsRectangleSplit(&textBounds, metrics->iconSize, metrics->layoutVertical ? 't' : 'l', gapMinor); + EsPainter iconPainter = *painter; + iconPainter.width = Width(iconBounds), iconPainter.height = Height(iconBounds); + iconPainter.offsetX = iconBounds.l, iconPainter.offsetY = iconBounds.t; + EsMessage m = { ES_MSG_PAINT_ICON }; + m.painter = &iconPainter; + + if (element && ES_HANDLED == EsMessageSend(element, &m)) { + // Icon painted by the application. + } else if (iconID) { + EsDrawStandardIcon(painter, iconID, metrics->iconSize, iconBounds, metrics->iconColor); + } else { + // Restore the previous bounds. + textBounds = bounds; + } + + if (flags & (ES_DRAW_CONTENT_MARKER_DOWN_ARROW | ES_DRAW_CONTENT_MARKER_UP_ARROW)) { + EsStyle *part = (flags & ES_DRAW_CONTENT_MARKER_DOWN_ARROW) ? ES_STYLE_MARKER_DOWN_ARROW : ES_STYLE_MARKER_UP_ARROW; + UIStyle *style = GetStyle(MakeStyleKey(part, 0), true); + textBounds.r -= style->preferredWidth + gapMinor; + EsRectangle location = ES_RECT_4PD(bounds.r - style->preferredWidth - painter->offsetX, + bounds.t + Height(bounds) / 2 - style->preferredHeight / 2 - painter->offsetY, + style->preferredWidth, style->preferredHeight); + style->PaintLayers(painter, location, THEME_CHILD_TYPE_ONLY, THEME_LAYER_MODE_BACKGROUND); + } + + if (textBytes == (size_t) -1) { + textBytes = EsCStringLength(text); + } + + if (selectionProperties) { + selectionProperties->foreground = metrics->selectedText; + selectionProperties->background = metrics->selectedBackground; + } + + if (textBytes) { + EsTextPlanProperties properties = {}; + properties.flags = textAlign; + + EsTextRun textRun[2] = {}; + textRun[1].offset = textBytes; + textRun[0].style.font = font; + textRun[0].style.size = textSize; + textRun[0].style.color = textColor; + + if (flags & ES_DRAW_CONTENT_TABULAR) { + textRun[0].style.figures = ES_TEXT_FIGURE_TABULAR; + } + + if (flags & ES_DRAW_CONTENT_RICH_TEXT) { + char *string; + EsTextRun *textRuns; + size_t textRunCount; + EsRichTextParse(text, textBytes, &string, &textRuns, &textRunCount, &textRun[0].style); + EsTextPlan *plan = EsTextPlanCreate(&properties, textBounds, string, textRuns, textRunCount); + EsDrawText(painter, plan, textBounds, nullptr, selectionProperties); + EsTextPlanDestroy(plan); + EsHeapFree(textRuns); + EsHeapFree(string); + } else { + EsTextPlan *plan = EsTextPlanCreate(&properties, textBounds, text, textRun, 1); + PaintTextLayers(painter, plan, textBounds, selectionProperties); + EsTextPlanDestroy(plan); + } + } + + painter->clip = oldClip; +} + +void EsDrawContent(EsPainter *painter, EsElement *element, EsRectangle rectangle, + const char *text, ptrdiff_t textBytes, uint32_t iconID, uint32_t flags, EsTextSelection *selectionProperties) { + if (textBytes == -1) textBytes = EsCStringLength(text); + ((UIStyle *) painter->style)->PaintText(painter, element, rectangle, text, textBytes, iconID, flags, selectionProperties); +} + +void EsDrawTextLayers(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsTextSelection *selectionProperties) { + ((UIStyle *) painter->style)->PaintTextLayers(painter, plan, bounds, selectionProperties); +} + +void UIStyle::PaintLayers(EsPainter *painter, EsRectangle location, int childType, int whichLayers) { + EsBuffer data = {}; + data.in = (uint8_t *) (this + 1); + data.bytes = layerDataByteCount; + + if (!THEME_RECT_VALID(painter->clip)) { + return; + } + + EsRectangle opaqueRegion = {}; + EsRectangle _bounds = Translate(location, painter->offsetX, painter->offsetY); + + if (opaqueInsets.l != 0x7F && opaqueInsets.r != 0x7F + && opaqueInsets.t != 0x7F && opaqueInsets.b != 0x7F) { + opaqueRegion = THEME_RECT_4(_bounds.l + opaqueInsets.l, _bounds.r - opaqueInsets.r, + _bounds.t + opaqueInsets.t, _bounds.b - opaqueInsets.b); + } + + if (appearance && whichLayers == 0) { + EsDrawRectangle(painter, _bounds, appearance->backgroundColor, appearance->borderColor, appearance->borderSize); + return; + } + + for (uintptr_t i = 0; i < style->layerCount; i++) { + const ThemeLayer *layer = (const ThemeLayer *) EsBufferRead(&data, sizeof(ThemeLayer)); + + if (!layer) { + return; + } + + EsRectangle bounds; + bounds.l = _bounds.l + (int) (scale * layer->offset.l) + THEME_RECT_WIDTH(_bounds) * layer->position.l / 100 + metrics->globalOffset.l; + bounds.r = _bounds.l + (int) (scale * layer->offset.r) + THEME_RECT_WIDTH(_bounds) * layer->position.r / 100 + metrics->globalOffset.r; + bounds.t = _bounds.t + (int) (scale * layer->offset.t) + THEME_RECT_HEIGHT(_bounds) * layer->position.t / 100 + metrics->globalOffset.t; + bounds.b = _bounds.t + (int) (scale * layer->offset.b) + THEME_RECT_HEIGHT(_bounds) * layer->position.b / 100 + metrics->globalOffset.b; + + if (layer->mode == whichLayers && THEME_RECT_WIDTH(bounds) > 0 && THEME_RECT_HEIGHT(bounds) > 0 + && THEME_RECT_VALID(EsRectangleIntersection(bounds, painter->clip))) { + EsBuffer data2 = data; + + if (layer->type == THEME_LAYER_BOX) { + ThemeDrawBox(painter, bounds, &data2, scale, layer, opaqueRegion, childType); + } else if (layer->type == THEME_LAYER_PATH) { + ThemeDrawPath(painter, bounds, &data2, scale); + } + } + + EsBufferRead(&data, layer->dataByteCount - sizeof(ThemeLayer)); + } +} + +inline void UIStyle::GetTextStyle(EsTextStyle *style) { + // Also need to update PaintText. + EsMemoryZero(style, sizeof(EsTextStyle)); + style->font = font; + style->size = metrics->textSize; + style->color = metrics->textColor; +} + +bool UIStyle::IsStateChangeObserved(uint16_t state1, uint16_t state2) { + if (((state1 & ~THEME_PRIMARY_STATE_MASK) ^ (state2 & ~THEME_PRIMARY_STATE_MASK)) & observedStyleStateMask) { + return true; + } + + if (((0x10000 << (state1 & THEME_PRIMARY_STATE_MASK)) ^ (0x10000 << (state2 & THEME_PRIMARY_STATE_MASK))) & observedStyleStateMask) { + return true; + } + + return false; +} + +bool UIStyle::IsRegionCompletelyOpaque(EsRectangle region, int width, int height) { + return region.l >= opaqueInsets.l && region.r < width - opaqueInsets.r + && region.t >= opaqueInsets.t && region.b < height - opaqueInsets.b; +} + +void DrawStyledBox(EsPainter *painter, EsStyledBox box) { + ThemeLayer layer = {}; + ThemeLayerBox layerBox = {}; + EsBuffer data = {}; + + layerBox.borders = { (int8_t) box.borders.l, (int8_t) box.borders.r, (int8_t) box.borders.t, (int8_t) box.borders.b }; + layerBox.corners = { (int8_t) box.cornerRadiusTopLeft, (int8_t) box.cornerRadiusTopRight, (int8_t) box.cornerRadiusBottomLeft, (int8_t) box.cornerRadiusBottomRight }; + layerBox.mainPaintType = THEME_PAINT_SOLID; + layerBox.borderPaintType = THEME_PAINT_SOLID; + + uint8_t info[sizeof(ThemeLayerBox) + sizeof(ThemePaintCustom) + sizeof(ThemePaintSolid) * 2]; + + if (box.fragmentShader) { + ThemeLayerBox *infoBox = (ThemeLayerBox *) info; + ThemePaintCustom *infoMain = (ThemePaintCustom *) (infoBox + 1); + ThemePaintSolid *infoBorder = (ThemePaintSolid *) (infoMain + 1); + + *infoBox = layerBox; + infoBox->mainPaintType = THEME_PAINT_CUSTOM; + infoMain->callback = box.fragmentShader; + infoBorder->color = box.borderColor; + + data.in = (const uint8_t *) &info; + data.bytes = sizeof(info); + data.context = &box; + } else { + ThemeLayerBox *infoBox = (ThemeLayerBox *) info; + ThemePaintSolid *infoMain = (ThemePaintSolid *) (infoBox + 1); + ThemePaintSolid *infoBorder = (ThemePaintSolid *) (infoMain + 1); + + *infoBox = layerBox; + infoMain->color = box.backgroundColor; + infoBorder->color = box.borderColor; + + data.in = (const uint8_t *) &info; + data.bytes = sizeof(info); + } + + ThemeDrawBox(painter, box.bounds, &data, 1, &layer, {}, THEME_CHILD_TYPE_ONLY); +} + +#endif diff --git a/drivers/acpi.cpp b/drivers/acpi.cpp new file mode 100644 index 0000000..c3a3700 --- /dev/null +++ b/drivers/acpi.cpp @@ -0,0 +1,1073 @@ +// TODO ACPICA initialisation hangs on my computer when SMP is enabled when it tries to write to IO port 0xB2 (power management, generates SMI). +// This is possibly related to the hang when writing to the keyboard controller IO ports that only occurs with SMP enabled. + +#define SIGNATURE_RSDP (0x2052545020445352) + +#define SIGNATURE_RSDT (0x54445352) +#define SIGNATURE_XSDT (0x54445358) +#define SIGNATURE_MADT (0x43495041) +#define SIGNATURE_FADT (0x50434146) + +struct RootSystemDescriptorPointer { + uint64_t signature; + uint8_t checksum; + char OEMID[6]; + uint8_t revision; + uint32_t rsdtAddress; + uint32_t length; + uint64_t xsdtAddress; + uint8_t extendedChecksum; + uint8_t reserved[3]; +}; + +struct ACPIDescriptorTable { +#define ACPI_DESCRIPTOR_TABLE_HEADER_LENGTH 36 + uint32_t signature; + uint32_t length; + uint64_t id; + uint64_t tableID; + uint32_t oemRevision; + uint32_t creatorID; + uint32_t creatorRevision; + + void Check() { + if (!EsMemorySumBytes((uint8_t *) this, length)) return; + + KernelPanic("ACPI::Initialise - ACPI table with signature %s had invalid checksum: " + "length: %D, ID = %s, table = %s, OEM revision = %d, creator = %s, creator revision = %d.\n", + 4, &signature, length, 8, &id, 8, &tableID, + oemRevision, 4, &creatorID, creatorRevision); + } +}; + +struct MultipleAPICDescriptionTable { + uint32_t lapicAddress; + uint32_t flags; +}; + +struct ACPIProcessor { + uint8_t processorID, kernelProcessorID; + uint8_t apicID; + bool bootstrapProcessor; + void **kernelStack; + CPULocalStorage *local; +}; + +struct ACPIIoApic { + uint32_t ReadRegister(uint32_t reg); + void WriteRegister(uint32_t reg, uint32_t value); + + uint8_t id; + uint32_t volatile *address; + uint32_t gsiBase; +}; + +uint32_t ACPIIoApic::ReadRegister(uint32_t reg) { + address[0] = reg; + return address[4]; +} + +void ACPIIoApic::WriteRegister(uint32_t reg, uint32_t value) { + address[0] = reg; + address[4] = value; +} + +struct ACPIInterruptOverride { + uint8_t sourceIRQ; + uint32_t gsiNumber; + bool activeLow, levelTriggered; +}; + +struct ACPILapicNMI { + uint8_t processor; // 0xFF for all processors + uint8_t lintIndex; + bool activeLow, levelTriggered; +}; + +struct ACPILapic { + uint32_t ReadRegister(uint32_t reg); + void EndOfInterrupt(); + void WriteRegister(uint32_t reg, uint32_t value); + void ArchNextTimer(size_t ms); + + volatile uint32_t *address; + size_t ticksPerMs; +}; + +void ACPILapic::ArchNextTimer(size_t ms) { + WriteRegister(0x320 >> 2, TIMER_INTERRUPT | (1 << 17)); + WriteRegister(0x380 >> 2, ticksPerMs * ms); +} + +void ACPILapic::EndOfInterrupt() { + WriteRegister(0xB0 >> 2, 0); +} + +uint32_t ACPILapic::ReadRegister(uint32_t reg) { + return address[reg]; +} + +void ACPILapic::WriteRegister(uint32_t reg, uint32_t value) { + address[reg] = value; +} + +struct ACPI { + void Initialise(); + void FindRootSystemDescriptorPointer(); + void StartupApplicationProcessors(); + + size_t processorCount; + size_t ioapicCount; + size_t interruptOverrideCount; + size_t lapicNMICount; + + ACPIProcessor processors[256]; // TODO Make this a DS_ARRAY. + ACPIProcessor *bootstrapProcessor; + ACPIIoApic ioApics[16]; + ACPIInterruptOverride interruptOverrides[256]; + ACPILapicNMI lapicNMIs[32]; + ACPILapic lapic; + + RootSystemDescriptorPointer *rsdp; + ACPIDescriptorTable *sdt; bool isXSDT; + ACPIDescriptorTable *madt; + + bool ps2ControllerUnavailable, vgaControllerUnavailable; + + KDevice *computer; +}; + +ACPI acpi; + +#ifdef ARCH_X86_COMMON +void ACPI::FindRootSystemDescriptorPointer() { + PhysicalMemoryRegion searchRegions[2]; + + searchRegions[0].baseAddress = (uintptr_t) (((uint16_t *) LOW_MEMORY_MAP_START)[0x40E] << 4) + LOW_MEMORY_MAP_START; + searchRegions[0].pageCount = 0x400; + searchRegions[1].baseAddress = (uintptr_t) 0xE0000 + LOW_MEMORY_MAP_START; + searchRegions[1].pageCount = 0x20000; + + for (uintptr_t i = 0; i < 2; i++) { + for (uintptr_t address = searchRegions[i].baseAddress; + address < searchRegions[i].baseAddress + searchRegions[i].pageCount; + address += 16) { + rsdp = (RootSystemDescriptorPointer *) address; + + if (rsdp->signature != SIGNATURE_RSDP) { + continue; + } + + if (rsdp->revision == 0) { + if (EsMemorySumBytes((uint8_t *) rsdp, 20)) { + continue; + } + + return; + } else if (rsdp->revision == 2) { + if (EsMemorySumBytes((uint8_t *) rsdp, sizeof(RootSystemDescriptorPointer))) { + continue; + } + + return; + } + } + } + + // We didn't find the RSDP. + rsdp = nullptr; +} +#endif + +void *ACPIMapPhysicalMemory(uintptr_t physicalAddress, size_t length) { +#ifdef ARCH_X86_COMMON + if ((uintptr_t) physicalAddress + (uintptr_t) length < (uintptr_t) LOW_MEMORY_LIMIT) { + return (void *) (LOW_MEMORY_MAP_START + physicalAddress); + } +#endif + + void *address = MMMapPhysical(kernelMMSpace, physicalAddress, length, MM_REGION_NOT_CACHEABLE); + return address; +} + +#ifdef USE_ACPICA + +// TODO Warning: Not all of the OSL has been tested. + +extern "C" { +#pragma GCC diagnostic ignored "-Wunused-parameter" push +#include +#pragma GCC diagnostic pop +} + +bool acpiOSLayerActive = false; + +ES_EXTERN_C ACPI_STATUS AcpiOsInitialize() { + if (acpiOSLayerActive) KernelPanic("AcpiOsInitialize - ACPI has already been initialised.\n"); + acpiOSLayerActive = true; + KernelLog(LOG_INFO, "ACPI", "initialise ACPICA", "AcpiOsInitialize - Initialising ACPICA OS layer...\n"); + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsTerminate() { + if (!acpiOSLayerActive) KernelPanic("AcpiOsTerminate - ACPI has not been initialised.\n"); + acpiOSLayerActive = false; + KernelLog(LOG_INFO, "ACPI", "terminate ACPICA", "AcpiOsTerminate - Terminating ACPICA OS layer...\n"); + return AE_OK; +} + +ES_EXTERN_C ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer() { + ACPI_PHYSICAL_ADDRESS address = 0; + + uint64_t uefiRSDP = *((uint64_t *) (LOW_MEMORY_MAP_START + GetBootloaderInformationOffset() + 0x7FE8)); + + if (uefiRSDP) { + return uefiRSDP; + } + + AcpiFindRootPointer(&address); + return address; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES *predefinedObject, ACPI_STRING *newValue) { + (void) predefinedObject; + *newValue = nullptr; + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsTableOverride(ACPI_TABLE_HEADER *existingTable, ACPI_TABLE_HEADER **newTable) { + (void) existingTable; + *newTable = nullptr; + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsPhysicalTableOverride(ACPI_TABLE_HEADER *existingTable, ACPI_PHYSICAL_ADDRESS *newAddress, uint32_t *newTableLength) { + (void) existingTable; + *newAddress = 0; + *newTableLength = 0; + return AE_OK; +} + +ES_EXTERN_C void *AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS physicalAddress, ACPI_SIZE length) { + return ACPIMapPhysicalMemory(physicalAddress, length); +} + +ES_EXTERN_C void AcpiOsUnmapMemory(void *address, ACPI_SIZE length) { +#ifdef ARCH_X86_COMMON + if ((uintptr_t) address - (uintptr_t) LOW_MEMORY_MAP_START < (uintptr_t) LOW_MEMORY_LIMIT) { + return; + } +#endif + + (void) length; + MMFree(kernelMMSpace, address); +} + +ES_EXTERN_C ACPI_STATUS AcpiOsGetPhysicalAddress(void *virtualAddress, ACPI_PHYSICAL_ADDRESS *physicalAddress) { + if (!virtualAddress || !physicalAddress) { + return AE_BAD_PARAMETER; + } + + *physicalAddress = MMArchTranslateAddress(kernelMMSpace, (uintptr_t) virtualAddress); + return AE_OK; +} + +ES_EXTERN_C void *AcpiOsAllocate(ACPI_SIZE size) { + return EsHeapAllocate(size, false, K_FIXED); +} + +ES_EXTERN_C void AcpiOsFree(void *memory) { + EsHeapFree(memory, 0, K_FIXED); +} + +ES_EXTERN_C BOOLEAN AcpiOsReadable(void *memory, ACPI_SIZE length) { + (void) memory; + (void) length; + // This is only used by the debugger, which we don't use... + return TRUE; +} + +ES_EXTERN_C BOOLEAN AcpiOsWritable(void *memory, ACPI_SIZE length) { + (void) memory; + (void) length; + // This is only used by the debugger, which we don't use... + return TRUE; +} + +ES_EXTERN_C ACPI_THREAD_ID AcpiOsGetThreadId() { + return GetCurrentThread()->id + 1; +} + +Thread *acpiEvents[256]; +size_t acpiEventCount; + +struct ACPICAEvent { + ACPI_OSD_EXEC_CALLBACK function; + void *context; +}; + +void RunACPICAEvent(void *e) { + ACPICAEvent *event = (ACPICAEvent *) e; + event->function(event->context); + EsHeapFree(event, 0, K_FIXED); + scheduler.TerminateThread(GetCurrentThread()); +} + +ES_EXTERN_C ACPI_STATUS AcpiOsExecute(ACPI_EXECUTE_TYPE type, ACPI_OSD_EXEC_CALLBACK function, void *context) { + (void) type; + + if (!function) return AE_BAD_PARAMETER; + + ACPICAEvent *event = (ACPICAEvent *) EsHeapAllocate(sizeof(ACPICAEvent), true, K_FIXED); + event->function = function; + event->context = context; + + Thread *thread = scheduler.SpawnThread("ACPICAEvent", (uintptr_t) RunACPICAEvent, (uintptr_t) event); + + if (acpiEventCount == 256) { + KernelPanic("AcpiOsExecute - Exceeded maximum event count, 256.\n"); + } + + acpiEvents[acpiEventCount++] = thread; + return AE_OK; +} + +ES_EXTERN_C void AcpiOsSleep(UINT64 ms) { + KEvent event = {}; + KEventWait(&event, ms); +} + +ES_EXTERN_C void AcpiOsStall(UINT32 mcs) { + (void) mcs; + uint64_t start = ProcessorReadTimeStamp(); + uint64_t end = start + mcs * (timeStampTicksPerMs / 1000); + while (ProcessorReadTimeStamp() < end); +} + +ES_EXTERN_C void AcpiOsWaitEventsComplete() { + for (uintptr_t i = 0; i < acpiEventCount; i++) { + Thread *thread = acpiEvents[i]; + KEventWait(&thread->killedEvent, ES_WAIT_NO_TIMEOUT); + CloseHandleToObject(thread, KERNEL_OBJECT_THREAD); + } + + acpiEventCount = 0; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsCreateSemaphore(UINT32 maxUnits, UINT32 initialUnits, ACPI_SEMAPHORE *handle) { + if (!handle) return AE_BAD_PARAMETER; + + KSemaphore *semaphore = (KSemaphore *) EsHeapAllocate(sizeof(KSemaphore), true, K_FIXED); + KSemaphoreReturn(semaphore, initialUnits); + semaphore->_custom = maxUnits; + *handle = semaphore; + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsDeleteSemaphore(ACPI_SEMAPHORE handle) { + if (!handle) return AE_BAD_PARAMETER; + EsHeapFree(handle, sizeof(KSemaphore), K_FIXED); + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsWaitSemaphore(ACPI_SEMAPHORE handle, UINT32 units, UINT16 timeout) { + (void) timeout; + if (!handle) return AE_BAD_PARAMETER; + KSemaphore *semaphore = (KSemaphore *) handle; + + if (KSemaphoreTake(semaphore, units, timeout == (UINT16) -1 ? ES_WAIT_NO_TIMEOUT : timeout)) { + return AE_OK; + } else { + return AE_TIME; + } +} + +ES_EXTERN_C ACPI_STATUS AcpiOsSignalSemaphore(ACPI_SEMAPHORE handle, UINT32 units) { + if (!handle) return AE_BAD_PARAMETER; + KSemaphore *semaphore = (KSemaphore *) handle; + if (semaphore->units + units > semaphore->_custom) return AE_LIMIT; + KSemaphoreReturn(semaphore, units); + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsCreateLock(ACPI_SPINLOCK *handle) { + if (!handle) return AE_BAD_PARAMETER; + KSpinlock *spinlock = (KSpinlock *) EsHeapAllocate(sizeof(KSpinlock), true, K_FIXED); + *handle = spinlock; + return AE_OK; +} + +ES_EXTERN_C void AcpiOsDeleteLock(ACPI_HANDLE handle) { + EsHeapFree(handle, sizeof(KSpinlock), K_FIXED); +} + +ES_EXTERN_C ACPI_CPU_FLAGS AcpiOsAcquireLock(ACPI_SPINLOCK handle) { + KSpinlock *spinlock = (KSpinlock *) handle; + KSpinlockAcquire(spinlock); + return 0; +} + +ES_EXTERN_C void AcpiOsReleaseLock(ACPI_SPINLOCK handle, ACPI_CPU_FLAGS flags) { + (void) flags; + KSpinlock *spinlock = (KSpinlock *) handle; + KSpinlockRelease(spinlock); +} + +ACPI_OSD_HANDLER acpiInterruptHandlers[256]; +void *acpiInterruptContexts[256]; + +bool ACPIInterrupt(uintptr_t interruptIndex, void *) { + if (acpiInterruptHandlers[interruptIndex]) { + return ACPI_INTERRUPT_HANDLED == acpiInterruptHandlers[interruptIndex](acpiInterruptContexts[interruptIndex]); + } else { + return false; + } +} + +ES_EXTERN_C ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 interruptLevel, ACPI_OSD_HANDLER handler, void *context) { + if (interruptLevel > 256 || !handler) return AE_BAD_PARAMETER; + + if (acpiInterruptHandlers[interruptLevel]) { + return AE_ALREADY_EXISTS; + } + + acpiInterruptHandlers[interruptLevel] = handler; + acpiInterruptContexts[interruptLevel] = context; + + return KRegisterIRQ(interruptLevel, ACPIInterrupt, nullptr, "ACPICA") ? AE_OK : AE_ERROR; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsRemoveInterruptHandler(UINT32 interruptNumber, ACPI_OSD_HANDLER handler) { + if (interruptNumber > 256 || !handler) return AE_BAD_PARAMETER; + + if (!acpiInterruptHandlers[interruptNumber]) { + return AE_NOT_EXIST; + } + + if (handler != acpiInterruptHandlers[interruptNumber]) { + return AE_BAD_PARAMETER; + } + + acpiInterruptHandlers[interruptNumber] = nullptr; + + return AE_OK; +} + +uint8_t acpicaPageBuffer[K_PAGE_SIZE]; +KMutex acpicaPageBufferMutex; + +ES_EXTERN_C ACPI_STATUS AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS address, UINT64 *value, UINT32 width) { + KMutexAcquire(&acpicaPageBufferMutex); + EsDefer(KMutexRelease(&acpicaPageBufferMutex)); + + uintptr_t page = (uintptr_t) address & ~(K_PAGE_SIZE - 1); + uintptr_t offset = (uintptr_t) address & (K_PAGE_SIZE - 1); + + PMRead(page, acpicaPageBuffer, 1); + + if (width == 64) { + *value = *((uint64_t *) (acpicaPageBuffer + offset)); + } else if (width == 32) { + *value = *((uint32_t *) (acpicaPageBuffer + offset)); + } else if (width == 16) { + *value = *((uint16_t *) (acpicaPageBuffer + offset)); + } else { + *value = acpicaPageBuffer[offset]; + } + + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS address, UINT64 value, UINT32 width) { + KMutexAcquire(&acpicaPageBufferMutex); + EsDefer(KMutexRelease(&acpicaPageBufferMutex)); + + uintptr_t page = (uintptr_t) address & ~(K_PAGE_SIZE - 1); + uintptr_t offset = (uintptr_t) address & (K_PAGE_SIZE - 1); + + PMRead(page, acpicaPageBuffer, 1); + + if (width == 64) { + *((uint64_t *) (acpicaPageBuffer + offset)) = value; + } else if (width == 32) { + *((uint32_t *) (acpicaPageBuffer + offset)) = value; + } else if (width == 16) { + *((uint16_t *) (acpicaPageBuffer + offset)) = value; + } else { + *((uint8_t *) (acpicaPageBuffer + offset)) = value; + } + + PMCopy(page, acpicaPageBuffer, 1); + + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsReadPort(ACPI_IO_ADDRESS address, UINT32 *value, UINT32 width) { + // EsPrint("AcpiOsReadPort - %x, %d", address, width); + + if (width == 8) { + *value = ProcessorIn8(address); + } else if (width == 16) { + *value = ProcessorIn16(address); + } else if (width == 32) { + *value = ProcessorIn32(address); + } else { + return AE_ERROR; + } + + // EsPrint(" - %x\n", *value); + + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsWritePort(ACPI_IO_ADDRESS address, UINT32 value, UINT32 width) { + // EsPrint("AcpiOsWritePort - %x, %x, %d", address, value, width); + + if (width == 8) { + ProcessorOut8(address, (uint8_t) value); + } else if (width == 16) { + ProcessorOut16(address, (uint16_t) value); + } else if (width == 32) { + ProcessorOut32(address, (uint32_t) value); + } else { + return AE_ERROR; + } + + // EsPrint(" - ;;\n"); + + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsReadPciConfiguration(ACPI_PCI_ID *address, UINT32 reg, UINT64 *value, UINT32 width) { + if (width == 64) { + uint64_t x = (uint64_t) KPCIReadConfig(address->Bus, address->Device, address->Function, reg) + | ((uint64_t) KPCIReadConfig(address->Bus, address->Device, address->Function, reg + 4) << 32); + *value = x; + } else { + uint32_t x = KPCIReadConfig(address->Bus, address->Device, address->Function, reg & ~3); + x >>= (reg & 3) * 8; + + if (width == 8) x &= 0xFF; + if (width == 16) x &= 0xFFFF; + + *value = x; + } + + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsWritePciConfiguration(ACPI_PCI_ID *address, UINT32 reg, UINT64 value, UINT32 width) { + if (width == 64) { + KPCIWriteConfig(address->Bus, address->Device, address->Function, reg, value); + KPCIWriteConfig(address->Bus, address->Device, address->Function, reg + 4, value >> 32); + } else if (width == 32) { + KPCIWriteConfig(address->Bus, address->Device, address->Function, reg, value); + } else { + uint32_t x = KPCIReadConfig(address->Bus, address->Device, address->Function, reg & ~3); + uint32_t o = reg & 3; + + if (width == 16) { + if (o == 2) { + x = (x & ~0xFFFF0000) | (value << 16); + } else { + x = (x & ~0x0000FFFF) | (value << 0); + } + } else if (width == 8) { + if (o == 3) { + x = (x & ~0xFF000000) | (value << 24); + } else if (o == 2) { + x = (x & ~0x00FF0000) | (value << 16); + } else if (o == 1) { + x = (x & ~0x0000FF00) | (value << 8); + } else { + x = (x & ~0x000000FF) | (value << 0); + } + } + + KPCIWriteConfig(address->Bus, address->Device, address->Function, reg & ~3, x); + } + + return AE_OK; +} + +char acpiPrintf[4096]; + +#if 1 +#define ENABLE_ACPICA_OUTPUT +#endif + +ES_EXTERN_C void AcpiOsPrintf(const char *format, ...) { + va_list arguments; + va_start(arguments, format); + int x = stbsp_vsnprintf(acpiPrintf, sizeof(acpiPrintf), format, arguments); +#ifdef ENABLE_ACPICA_OUTPUT + EsPrint("%s", x, acpiPrintf); +#else + (void) x; +#endif + va_end(arguments); +} + +ES_EXTERN_C void AcpiOsVprintf(const char *format, va_list arguments) { + int x = stbsp_vsnprintf(acpiPrintf, sizeof(acpiPrintf), format, arguments); +#ifdef ENABLE_ACPICA_OUTPUT + EsPrint("%s", x, acpiPrintf); +#else + (void) x; +#endif +} + +ES_EXTERN_C UINT64 AcpiOsGetTimer() { + uint64_t tick = ProcessorReadTimeStamp(); + uint64_t ticksPerMs = timeStampTicksPerMs; + uint64_t ticksPer100Ns = ticksPerMs / 1000 / 10; + if (ticksPer100Ns == 0) return tick; + return tick / ticksPer100Ns; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsSignal(UINT32 function, void *information) { + (void) function; + (void) information; + KernelPanic("AcpiOsSignal - ACPI requested kernel panic.\n"); + return AE_OK; +} + +ES_EXTERN_C ACPI_STATUS AcpiOsEnterSleep(UINT8 sleepState, UINT32 registerAValue, UINT32 registerBValue) { + (void) sleepState; + (void) registerAValue; + (void) registerBValue; + return AE_OK; +} + +UINT32 ACPIPowerButtonPressed(void *) { + KRegisterAsyncTask([] (EsGeneric) { + _EsMessageWithObject m = { nullptr, ES_MSG_POWER_BUTTON_PRESSED }; + if (scheduler.shutdown) return; + if (desktopProcess) desktopProcess->messageQueue.SendMessage(&m); + }, nullptr, false); + + return 0; +} + +#endif + +void ACPIInitialise2() { +#ifdef USE_ACPICA + AcpiInitializeSubsystem(); + AcpiInitializeTables(nullptr, 256, true); + AcpiLoadTables(); + ProcessorDisableInterrupts(); + ProcessorEnableInterrupts(); + AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); + AcpiInitializeObjects(ACPI_FULL_INITIALIZATION); + + if (AE_OK == AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, 0) + && AE_OK == AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, ACPIPowerButtonPressed, nullptr)) { + KDeviceCreate("ACPI power button", acpi.computer, sizeof(KDevice)); + } + + void *result; + + AcpiGetDevices(nullptr, [] (ACPI_HANDLE object, uint32_t, void *, void **) -> ACPI_STATUS { + ACPI_DEVICE_INFO *information; + AcpiGetObjectInfo(object, &information); + KernelLog(LOG_INFO, "ACPI", "device object", "Found device object '%c%c%c%c' with HID '%z' and UID '%z'.\n", + (char) (information->Name >> 0), (char) (information->Name >> 8), (char) (information->Name >> 16), (char) (information->Name >> 24), + (information->Valid & ACPI_VALID_HID) ? information->HardwareId.String : "??", + (information->Valid & ACPI_VALID_UID) ? information->UniqueId.String : "??"); + ACPI_FREE(information); + return AE_OK; + }, nullptr, &result); +#endif + + acpi.StartupApplicationProcessors(); +} + +void KPS2SafeToInitialise() { + if (acpi.ps2ControllerUnavailable) { + return; + } + + // This is only called when either: + // - the PCI driver determines there are no USB controllers + // - the USB controller disables USB emulation + KThreadCreate("InitPS2", [] (uintptr_t) { KDeviceAttachByName(acpi.computer, "PS2"); }); +} + +static void DeviceAttach(KDevice *parentDevice) { + acpi.computer = KDeviceCreate("ACPI computer", parentDevice, sizeof(KDevice)); + +#ifndef SERIAL_STARTUP + KThreadCreate("InitACPI", [] (uintptr_t) { ACPIInitialise2(); }); +#else + ACPIInitialise2(); +#endif + + KDeviceAttachByName(acpi.computer, "PCI"); + + if (!acpi.vgaControllerUnavailable) { + KDeviceAttachByName(acpi.computer, "SVGA"); + } +} + +KDriver driverACPI = { + .attach = DeviceAttach, +}; + +void *KGetRSDP() { + return acpi.rsdp; +} + +inline void ArchInitialise() { + acpi.Initialise(); +} + +#ifdef USE_ACPICA +void ArchShutdown(uintptr_t action) { + if (action == SHUTDOWN_ACTION_RESTART) ArchResetCPU(); + AcpiEnterSleepStatePrep(5); + ProcessorDisableInterrupts(); + AcpiEnterSleepState(5); +} +#else +void ArchShutdown(uintptr_t action) { + if (action == SHUTDOWN_ACTION_RESTART) ArchResetCPU(); + KernelPanic("It's now safe to turn off your computer.\n"); +} +#endif + +void ACPI::Initialise() { + uint64_t uefiRSDP = *((uint64_t *) (LOW_MEMORY_MAP_START + GetBootloaderInformationOffset() + 0x7FE8)); + + if (!uefiRSDP) { +#ifdef USE_ACPICA + AcpiFindRootPointer((ACPI_PHYSICAL_ADDRESS *) &uefiRSDP); + rsdp = (RootSystemDescriptorPointer *) MMMapPhysical(kernelMMSpace, (uintptr_t) uefiRSDP, 16384, ES_FLAGS_DEFAULT); +#else + FindRootSystemDescriptorPointer(); +#endif + } else { + rsdp = (RootSystemDescriptorPointer *) MMMapPhysical(kernelMMSpace, (uintptr_t) uefiRSDP, 16384, ES_FLAGS_DEFAULT); + } + + if (rsdp) { + if (rsdp->revision == 2 && rsdp->xsdtAddress) { + isXSDT = true; + sdt = (ACPIDescriptorTable *) rsdp->xsdtAddress; + } else { + isXSDT = false; + sdt = (ACPIDescriptorTable *) (uintptr_t) rsdp->rsdtAddress; + } + + sdt = (ACPIDescriptorTable *) MMMapPhysical(kernelMMSpace, (uintptr_t) sdt, 16384, ES_FLAGS_DEFAULT); + } else { + KernelPanic("ACPI::Initialise - Could not find supported root system descriptor pointer.\nACPI support is required.\n"); + } + + if (((sdt->signature == SIGNATURE_XSDT && isXSDT) || (sdt->signature == SIGNATURE_RSDT && !isXSDT)) + && sdt->length < 16384 && !EsMemorySumBytes((uint8_t *) sdt, sdt->length)) { + size_t tablesCount = (sdt->length - sizeof(ACPIDescriptorTable)) >> (isXSDT ? 3 : 2); + + if (tablesCount < 1) { + KernelPanic("ACPI::Initialise - The system descriptor table contains an unsupported number of tables (%d).\n", tablesCount); + } + + uintptr_t tableListAddress = (uintptr_t) sdt + ACPI_DESCRIPTOR_TABLE_HEADER_LENGTH; + + KernelLog(LOG_INFO, "ACPI", "table count", "ACPI::Initialise - Found %d tables.\n", tablesCount); + + for (uintptr_t i = 0; i < tablesCount; i++) { + uintptr_t address; + + if (isXSDT) { + address = ((uint64_t *) tableListAddress)[i]; + } else { + address = ((uint32_t *) tableListAddress)[i]; + } + + ACPIDescriptorTable *header = (ACPIDescriptorTable *) MMMapPhysical(kernelMMSpace, address, sizeof(ACPIDescriptorTable), ES_FLAGS_DEFAULT); + + KernelLog(LOG_INFO, "ACPI", "table enumerated", "ACPI::Initialise - Found ACPI table '%s'.\n", 4, &header->signature); + + if (header->signature == SIGNATURE_MADT) { + madt = (ACPIDescriptorTable *) MMMapPhysical(kernelMMSpace, address, header->length, ES_FLAGS_DEFAULT); + madt->Check(); + } else if (header->signature == SIGNATURE_FADT) { + ACPIDescriptorTable *fadt = (ACPIDescriptorTable *) MMMapPhysical(kernelMMSpace, address, header->length, ES_FLAGS_DEFAULT); + fadt->Check(); + + if (header->length > 109) { + uint8_t bootArchitectureFlags = ((uint8_t *) fadt)[109]; + ps2ControllerUnavailable = ~bootArchitectureFlags & (1 << 1); + vgaControllerUnavailable = bootArchitectureFlags & (1 << 2); + KernelLog(LOG_INFO, "ACPI", "FADT", "PS/2 controller is %z; VGA controller is %z.\n", + ps2ControllerUnavailable ? "unavailble" : "present", + vgaControllerUnavailable ? "unavailble" : "present"); + } + + MMFree(kernelMMSpace, fadt); + } + + MMFree(kernelMMSpace, header); + } + } else { + KernelPanic("ACPI::Initialise - Could not find a valid or supported system descriptor table.\nACPI support is required.\n"); + } + + // Set up the APIC. + + ACPIDescriptorTable *header = this->madt; + MultipleAPICDescriptionTable *madt = (MultipleAPICDescriptionTable *) ((uint8_t *) this->madt + ACPI_DESCRIPTOR_TABLE_HEADER_LENGTH); + + if (!madt) { + KernelPanic("ACPI::Initialise - Could not find the MADT table.\nThis is required to use the APIC.\n"); + } + + uintptr_t length = header->length - ACPI_DESCRIPTOR_TABLE_HEADER_LENGTH - sizeof(MultipleAPICDescriptionTable); + uintptr_t startLength = length; + uint8_t *data = (uint8_t *) (madt + 1); + + lapic.address = (uint32_t volatile *) ACPIMapPhysicalMemory(madt->lapicAddress, 0x10000); + + while (length && length <= startLength) { + uint8_t entryType = data[0]; + uint8_t entryLength = data[1]; + + switch (entryType) { + case 0: { + // A processor and its LAPIC. + if ((data[4] & 1) == 0) goto nextEntry; + ACPIProcessor *processor = processors + processorCount; + processor->processorID = data[2]; + processor->apicID = data[3]; + processorCount++; + } break; + + case 1: { + // An I/O APIC. + ioApics[ioapicCount].id = data[2]; + ioApics[ioapicCount].address = (uint32_t volatile *) ACPIMapPhysicalMemory(((uint32_t *) data)[1], 0x10000); + ioApics[ioapicCount].ReadRegister(0); // Make sure it's mapped. + ioApics[ioapicCount].gsiBase = ((uint32_t *) data)[2]; + ioapicCount++; + } break; + + case 2: { + // An interrupt source override structure. + interruptOverrides[interruptOverrideCount].sourceIRQ = data[3]; + interruptOverrides[interruptOverrideCount].gsiNumber = ((uint32_t *) data)[1]; + interruptOverrides[interruptOverrideCount].activeLow = (data[8] & 2) ? true : false; + interruptOverrides[interruptOverrideCount].levelTriggered = (data[8] & 8) ? true : false; + KernelLog(LOG_INFO, "ACPI", "interrupt override", "ACPI::Initialise - Source IRQ %d is mapped to GSI %d%z%z.\n", + interruptOverrides[interruptOverrideCount].sourceIRQ, + interruptOverrides[interruptOverrideCount].gsiNumber, + interruptOverrides[interruptOverrideCount].activeLow ? ", active low" : ", active high", + interruptOverrides[interruptOverrideCount].levelTriggered ? ", level triggered" : ", edge triggered"); + interruptOverrideCount++; + } break; + + case 4: { + // A non-maskable interrupt. + lapicNMIs[lapicNMICount].processor = data[2]; + lapicNMIs[lapicNMICount].lintIndex = data[5]; + lapicNMIs[lapicNMICount].activeLow = (data[3] & 2) ? true : false; + lapicNMIs[lapicNMICount].levelTriggered = (data[3] & 8) ? true : false; + lapicNMICount++; + } break; + + default: { + KernelLog(LOG_ERROR, "ACPI", "unrecognised MADT entry", "ACPI::Initialise - Found unknown entry of type %d in MADT\n", entryType); + } break; + } + + nextEntry: + length -= entryLength; + data += entryLength; + } + + if (processorCount > 256 || ioapicCount > 16 || interruptOverrideCount > 256 || lapicNMICount > 32) { + KernelPanic("ACPI::KernelPanic - Invalid number of processors (%d/%d), \n" + " I/O APICs (%d/%d), interrupt overrides (%d/%d)\n" + " and LAPIC NMIs (%d/%d)\n", + processorCount, 256, ioapicCount, 16, interruptOverrideCount, 256, lapicNMICount, 32); + } + + uint8_t bootstrapLapicID = (lapic.ReadRegister(0x20 >> 2) >> 24); + + for (uintptr_t i = 0; i < processorCount; i++) { + if (processors[i].apicID == bootstrapLapicID) { + // That's us! + bootstrapProcessor = processors + i; + bootstrapProcessor->bootstrapProcessor = true; + } + } + + if (!bootstrapProcessor) { + KernelPanic("ACPI::Initialise - Could not find the bootstrap processor\n"); + } + + // Calibrate the LAPIC's timer and processor's timestamp counter. + ProcessorDisableInterrupts(); + uint64_t start = ProcessorReadTimeStamp(); + acpi.lapic.WriteRegister(0x380 >> 2, (uint32_t) -1); + for (int i = 0; i < 8; i++) ArchDelay1Ms(); // Average over 8ms + acpi.lapic.ticksPerMs = ((uint32_t) -1 - acpi.lapic.ReadRegister(0x390 >> 2)) >> 4; + EsRandomAddEntropy(acpi.lapic.ReadRegister(0x390 >> 2)); + uint64_t end = ProcessorReadTimeStamp(); + timeStampTicksPerMs = (end - start) >> 3; + ProcessorEnableInterrupts(); + + // Add some entropy. + { + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 0); + EsRandomAddEntropy(ProcessorIn8(0x71) << 0); + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 2); + EsRandomAddEntropy(ProcessorIn8(0x71) << 1); + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 4); + EsRandomAddEntropy(ProcessorIn8(0x71) << 2); + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 6); + EsRandomAddEntropy(ProcessorIn8(0x71) << 3); + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 7); + EsRandomAddEntropy(ProcessorIn8(0x71) << 4); + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 8); + EsRandomAddEntropy(ProcessorIn8(0x71) << 5); + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 9); + EsRandomAddEntropy(ProcessorIn8(0x71) << 6); + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 10); + EsRandomAddEntropy(ProcessorIn8(0x71) << 7); + for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 11); + EsRandomAddEntropy(ProcessorIn8(0x71) << 8); + } + + // Finish processor initialisation. + // This sets up interrupts, the timer, CPULocalStorage, the GDT and TSS, + // and registers the processor with the scheduler. + + for (uintptr_t i = 0; i <= acpi.processorCount; i++) { + if (i == acpi.processorCount) { + KernelPanic("ACPI::Initialise - Could not find the bootstrap processor to perform second-stage initialisation.\n"); + } + + if (acpi.processors[i].bootstrapProcessor) { + NewProcessorStorage storage = AllocateNewProcessorStorage(acpi.processors + i); + SetupProcessor2(&storage); + break; + } + } +} + +void Wait1Ms() { + if (scheduler.started) { + KEvent event = {}; + KEventWait(&event, 1); + } else { + ArchDelay1Ms(); + } +} + +void ACPI::StartupApplicationProcessors() { +#ifdef USE_SMP + // TODO How do we know that this address is usable? +#define AP_TRAMPOLINE 0x10000 + + uint8_t *startupData = (uint8_t *) (LOW_MEMORY_MAP_START + AP_TRAMPOLINE); + + // Put the trampoline code in memory. + EsMemoryCopy(startupData, (void *) ProcessorAPStartup, 0x1000); // Assume that the AP trampoline code <=4KB. + + // Put the paging table location at AP_TRAMPOLINE + 0xFF0. + *((uint64_t *) (startupData + 0xFF0)) = ProcessorReadCR3(); + + // Put the 64-bit GDTR at AP_TRAMPOLINE + 0xFE0. + EsMemoryCopy(startupData + 0xFE0, (void *) processorGDTR, 0x10); + + // Put the GDT at AP_TRAMPOLINE + 0x1000. + EsMemoryCopy(startupData + 0x1000, (void *) gdt_data, 0x1000); + + // Put the startup flag at AP_TRAMPOLINE + 0xFC0 + uint8_t volatile *startupFlag = (uint8_t *) (LOW_MEMORY_MAP_START + AP_TRAMPOLINE + 0xFC0); + + // Temporarily identity map 2 pages in at 0x10000. + MMArchMapPage(kernelMMSpace, AP_TRAMPOLINE, AP_TRAMPOLINE, MM_MAP_PAGE_COMMIT_TABLES_NOW); + MMArchMapPage(kernelMMSpace, AP_TRAMPOLINE + 0x1000, AP_TRAMPOLINE + 0x1000, MM_MAP_PAGE_COMMIT_TABLES_NOW); + + for (uintptr_t i = 0; i < processorCount; i++) { + ACPIProcessor *processor = processors + i; + if (processor->bootstrapProcessor) continue; + + // Allocate state for the processor. + NewProcessorStorage storage = AllocateNewProcessorStorage(processor); + + // Clear the startup flag. + *startupFlag = 0; + + // Put the stack at AP_TRAMPOLINE + 0xFD0, and the address of the NewProcessorStorage at AP_TRAMPOLINE + 0xFB0. + void *stack = (void *) ((uintptr_t) MMStandardAllocate(kernelMMSpace, 0x1000, MM_REGION_FIXED) + 0x1000); + *((void **) (startupData + 0xFD0)) = stack; + *((NewProcessorStorage **) (startupData + 0xFB0)) = &storage; + + KernelLog(LOG_INFO, "ACPI", "starting processor", "Starting processor %d with local storage %x...\n", i, storage.local); + + // Send an INIT IPI. + ProcessorDisableInterrupts(); // Don't be interrupted between writes... + lapic.WriteRegister(0x310 >> 2, processor->apicID << 24); + lapic.WriteRegister(0x300 >> 2, 0x4500); + ProcessorEnableInterrupts(); + for (uintptr_t i = 0; i < 10; i++) Wait1Ms(); + + // Send a startup IPI. + ProcessorDisableInterrupts(); + lapic.WriteRegister(0x310 >> 2, processor->apicID << 24); + lapic.WriteRegister(0x300 >> 2, 0x4600 | (AP_TRAMPOLINE >> K_PAGE_BITS)); + ProcessorEnableInterrupts(); + for (uintptr_t i = 0; i < 100 && *startupFlag == 0; i++) Wait1Ms(); + + if (*startupFlag) { + // The processor started correctly. + } else { + // Send a startup IPI, again. + ProcessorDisableInterrupts(); + lapic.WriteRegister(0x310 >> 2, processor->apicID << 24); + lapic.WriteRegister(0x300 >> 2, 0x4600 | (AP_TRAMPOLINE >> K_PAGE_BITS)); + ProcessorEnableInterrupts(); + for (uintptr_t i = 0; i < 1000 && *startupFlag == 0; i++) Wait1Ms(); // Wait longer this time. + + if (*startupFlag) { + // The processor started correctly. + } else { + // The processor could not be started. + KernelLog(LOG_ERROR, "ACPI", "processor startup failure", + "ACPI::Initialise - Could not start processor %d\n", processor->processorID); + continue; + } + } + + // EsPrint("Startup flag 1 reached!\n"); + + for (uintptr_t i = 0; i < 10000 && *startupFlag != 2; i++) Wait1Ms(); + + if (*startupFlag == 2) { + // The processor started! + } else { + // The processor did not report it completed initilisation, worringly. + // Don't let it continue. + + KernelLog(LOG_ERROR, "ACPI", "processor startup failure", + "ACPI::Initialise - Could not initialise processor %d\n", processor->processorID); + + // TODO Send IPI to stop the processor. + } + } + + // Remove the identity pages needed for the trampoline code. + MMArchUnmapPages(kernelMMSpace, AP_TRAMPOLINE, 2, ES_FLAGS_DEFAULT); +#endif +} + +size_t KGetCPUCount() { + return acpi.processorCount; +} + +CPULocalStorage *KGetCPULocal(uintptr_t index) { + return acpi.processors[index].local; +} diff --git a/drivers/ahci.cpp b/drivers/ahci.cpp new file mode 100644 index 0000000..b841256 --- /dev/null +++ b/drivers/ahci.cpp @@ -0,0 +1,886 @@ +#include + +// TODO Inserting/removing CDs. + +#define GENERAL_TIMEOUT (5000) + +#define COMMAND_LIST_SIZE (0x400) +#define RECEIVED_FIS_SIZE (0x100) +#define PRDT_ENTRY_COUNT (0x48) // If one page each, this covers more than CC_ACTIVE_SECTION_SIZE. This must be a multiple of 8. +#define COMMAND_TABLE_SIZE (0x80 + PRDT_ENTRY_COUNT * 0x10) + +// Global registers. +#define RD_REGISTER_CAP() pci->ReadBAR32(5, 0x00) // HBA capababilities. +#define RD_REGISTER_GHC() pci->ReadBAR32(5, 0x04) // Global host control. +#define WR_REGISTER_GHC(x) pci->WriteBAR32(5, 0x04, x) +#define RD_REGISTER_IS() pci->ReadBAR32(5, 0x08) // Interrupt status. +#define WR_REGISTER_IS(x) pci->WriteBAR32(5, 0x08, x) +#define RD_REGISTER_PI() pci->ReadBAR32(5, 0x0C) // Ports implemented. +#define RD_REGISTER_CAP2() pci->ReadBAR32(5, 0x24) // HBA capababilities extended. +#define RD_REGISTER_BOHC() pci->ReadBAR32(5, 0x28) // BIOS/OS handoff control and status. +#define WR_REGISTER_BOHC(x) pci->WriteBAR32(5, 0x28, x) + +// Port-specific registers. +#define RD_REGISTER_PCLB(p) pci->ReadBAR32(5, 0x100 + (p) * 0x80) // Command list base address (low DWORD). +#define WR_REGISTER_PCLB(p, x) pci->WriteBAR32(5, 0x100 + (p) * 0x80, x) +#define RD_REGISTER_PCLBU(p) pci->ReadBAR32(5, 0x104 + (p) * 0x80) // Command list base address (high DWORD). +#define WR_REGISTER_PCLBU(p, x) pci->WriteBAR32(5, 0x104 + (p) * 0x80, x) +#define RD_REGISTER_PFB(p) pci->ReadBAR32(5, 0x108 + (p) * 0x80) // FIS base address (low DWORD). +#define WR_REGISTER_PFB(p, x) pci->WriteBAR32(5, 0x108 + (p) * 0x80, x) +#define RD_REGISTER_PFBU(p) pci->ReadBAR32(5, 0x10C + (p) * 0x80) // FIS base address (high DWORD). +#define WR_REGISTER_PFBU(p, x) pci->WriteBAR32(5, 0x10C + (p) * 0x80, x) +#define RD_REGISTER_PIS(p) pci->ReadBAR32(5, 0x110 + (p) * 0x80) // Interrupt status. +#define WR_REGISTER_PIS(p, x) pci->WriteBAR32(5, 0x110 + (p) * 0x80, x) +#define RD_REGISTER_PIE(p) pci->ReadBAR32(5, 0x114 + (p) * 0x80) // Interrupt enable. +#define WR_REGISTER_PIE(p, x) pci->WriteBAR32(5, 0x114 + (p) * 0x80, x) +#define RD_REGISTER_PCMD(p) pci->ReadBAR32(5, 0x118 + (p) * 0x80) // Command and status. +#define WR_REGISTER_PCMD(p, x) pci->WriteBAR32(5, 0x118 + (p) * 0x80, x) +#define RD_REGISTER_PTFD(p) pci->ReadBAR32(5, 0x120 + (p) * 0x80) // Task file data. +#define RD_REGISTER_PSIG(p) pci->ReadBAR32(5, 0x124 + (p) * 0x80) // Signature. +#define RD_REGISTER_PSSTS(p) pci->ReadBAR32(5, 0x128 + (p) * 0x80) // SATA status. +#define RD_REGISTER_PSCTL(p) pci->ReadBAR32(5, 0x12C + (p) * 0x80) // SATA control. +#define WR_REGISTER_PSCTL(p, x) pci->WriteBAR32(5, 0x12C + (p) * 0x80, x) +#define RD_REGISTER_PSERR(p) pci->ReadBAR32(5, 0x130 + (p) * 0x80) // SATA error. +#define WR_REGISTER_PSERR(p, x) pci->WriteBAR32(5, 0x130 + (p) * 0x80, x) +#define RD_REGISTER_PCI(p) pci->ReadBAR32(5, 0x138 + (p) * 0x80) // Command issue. +#define WR_REGISTER_PCI(p, x) pci->WriteBAR32(5, 0x138 + (p) * 0x80, x) + +struct AHCIPort { + bool connected, atapi, ssd; + + uint32_t *commandList; + uint8_t *commandTables; + + size_t sectorBytes; + uint64_t sectorCount; + + KWorkGroup *commandContexts[32]; // Set to indicate command in use. + uint64_t commandStartTimeStamps[32]; + uint32_t runningCommands; + + KSpinlock commandSpinlock; + KEvent commandSlotsAvailable; + + char model[41]; +}; + +struct AHCIController : KDevice { + KPCIDevice *pci; + + uint32_t capabilities, capabilities2; + bool dma64Supported; + size_t commandSlotCount; + + KTimer timeoutTimer; + +#define MAX_PORTS (32) + AHCIPort ports[MAX_PORTS]; + + void Initialise(); + bool Access(uintptr_t port, uint64_t offsetBytes, size_t countBytes, int operation, + KDMABuffer *buffer, uint64_t flags, KWorkGroup *dispatchGroup); + bool HandleIRQ(); + bool SendSingleCommand(uintptr_t port); + void DumpState(); +}; + +struct AHCIDrive : KBlockDevice { + AHCIController *controller; + uintptr_t port; +}; + +struct InterruptEvent { + uint64_t timeStamp; + uint32_t globalInterruptStatus; + uint32_t port0CommandsRunning; + uint32_t port0CommandsIssued; + bool complete; +}; + +volatile uintptr_t recentInterruptEventsPointer; +volatile InterruptEvent recentInterruptEvents[64]; + +void AHCIController::DumpState() { + uint64_t timeStamp = KGetTimeInMs(); + + EsPrint("AHCI controller state:\n"); + + EsPrint("\t--- Registers ---\n"); + EsPrint("\t\tHBA capabilities: %x.\n", RD_REGISTER_CAP()); + EsPrint("\t\tGlobal host control: %x.\n", RD_REGISTER_GHC()); + EsPrint("\t\tInterrupt status: %x.\n", RD_REGISTER_IS()); + EsPrint("\t\tPorts implemented: %x.\n", RD_REGISTER_PI()); + EsPrint("\t\tHBA capabilities extended: %x.\n", RD_REGISTER_CAP2()); + EsPrint("\t\tBIOS/OS handoff control and status: %x.\n", RD_REGISTER_BOHC()); + + for (uintptr_t i = 0; i < MAX_PORTS; i++) { + AHCIPort *port = ports + i; + + if (!port->connected) { + continue; + } + + EsPrint("\t--- Port %d ---\n", i); + EsPrint("\t\tCommand list base address (low DWORD): %x.\n", RD_REGISTER_PCLB(i)); + EsPrint("\t\tCommand list base address (high DWORD): %x.\n", RD_REGISTER_PCLBU(i)); + EsPrint("\t\tFIS base address (low DWORD): %x.\n", RD_REGISTER_PFB(i)); + EsPrint("\t\tFIS base address (high DWORD): %x.\n", RD_REGISTER_PFBU(i)); + EsPrint("\t\tInterrupt status: %x.\n", RD_REGISTER_PIS(i)); + EsPrint("\t\tInterrupt enable: %x.\n", RD_REGISTER_PIE(i)); + EsPrint("\t\tCommand and status: %x.\n", RD_REGISTER_PCMD(i)); + EsPrint("\t\tTask file data: %x.\n", RD_REGISTER_PTFD(i)); + EsPrint("\t\tSignature: %x.\n", RD_REGISTER_PSIG(i)); + EsPrint("\t\tSATA status: %x.\n", RD_REGISTER_PSSTS(i)); + EsPrint("\t\tSATA error: %x.\n", RD_REGISTER_PSERR(i)); + EsPrint("\t\tCommand issue: %x.\n", RD_REGISTER_PCI(i)); + EsPrint("\t\tATAPI: %d.\n", port->atapi); + EsPrint("\t\tBytes per sector: %D.\n", port->sectorBytes); + EsPrint("\t\tTotal capacity: %D.\n", port->sectorBytes * port->sectorCount); + EsPrint("\t\tCommand slots available: %d.\n", port->commandSlotsAvailable.state); + EsPrint("\t\tRunning commands: %x.\n", port->runningCommands); + + uint8_t *receivedFIS = (uint8_t *) port->commandList + 0x400; + + EsPrint("\t\tReceived FIS D2H register: type %X, interrupt %X, status %X, error %X, device/head %X, sector %x, sector count %x.\n", + receivedFIS[0x40 + 0], receivedFIS[0x40 + 1], receivedFIS[0x40 + 2], receivedFIS[0x40 + 3], receivedFIS[0x40 + 7], + (uint64_t) receivedFIS[0x40 + 4] | ((uint64_t) receivedFIS[0x40 + 5] << 8) | ((uint64_t) receivedFIS[0x40 + 6] << 16) + | ((uint64_t) receivedFIS[0x40 + 8] << 24) | ((uint64_t) receivedFIS[0x40 + 9] << 32) | ((uint64_t) receivedFIS[0x40 + 10] << 40), + (uint64_t) receivedFIS[0x40 + 12] | ((uint64_t) receivedFIS[0x40 + 13] << 8)); + EsPrint("\t\tReceived FIS set device bits: type %X, interrupt %X, status %X, error %X.\n", + receivedFIS[0x58 + 0], receivedFIS[0x58 + 1], receivedFIS[0x58 + 2], receivedFIS[0x58 + 3]); + EsPrint("\t\tReceived FIS DMA setup: type %X, flags %X, buffer identifier low %x, buffer identifier high %x, buffer offset %x, transfer count %x.\n", + receivedFIS[0], receivedFIS[1], ((uint32_t *) receivedFIS)[1], + ((uint32_t *) receivedFIS)[2], ((uint32_t *) receivedFIS)[4], ((uint32_t *) receivedFIS)[5]); + + for (uintptr_t j = 0; j < 32; j++) { + if (~port->runningCommands & (1 << j)) continue; + + EsPrint("\t\tCommand %d: started %dms ago for dispatch group %x.\n", j, + timeStamp - port->commandStartTimeStamps[j], port->commandContexts[j]); + + EsPrint("\t\t\tDW0 %x: %d FIS bytes, %z, %z, %d PRDT entries.\n", + port->commandList[j * 8 + 0], (port->commandList[j * 8 + 0]) & 31, + ((port->commandList[j * 8 + 0]) & (1 << 5)) ? "SATAPI" : "SATA", + ((port->commandList[j * 8 + 0]) & (1 << 6)) ? "write" : "read", + port->commandList[j * 8 + 0] >> 16); + EsPrint("\t\t\tDW1 transferring %D.\n", port->commandList[j * 8 + 1]); + EsPrint("\t\t\tDW2/3 command table base address: %x.\n", *(uint64_t *) &port->commandList[j * 8 + 2]); + + uint8_t *commandFIS = port->commandTables + COMMAND_TABLE_SIZE * j; + + EsPrint("\t\t\tH2D FIS: type %X, command %X, features %X, device/head %X, features 2 %X, control %X, sector %x, sector count %x.\n", + commandFIS[0], commandFIS[2], commandFIS[3], commandFIS[7], commandFIS[11], commandFIS[15], + (uint64_t) commandFIS[4] | ((uint64_t) commandFIS[5] << 8) | ((uint64_t) commandFIS[6] << 16) + | ((uint64_t) commandFIS[8] << 24) | ((uint64_t) commandFIS[9] << 32) | ((uint64_t) commandFIS[10] << 40), + (uint64_t) commandFIS[12] | ((uint64_t) commandFIS[13] << 8)); + + uint8_t *atapiCommand = commandFIS + 64; + + if (((port->commandList[j * 8 + 0]) & (1 << 5))) { + EsPrint("\t\t\tATAPI command: %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X.\n", + atapiCommand[0], atapiCommand[1], atapiCommand[2], atapiCommand[3], + atapiCommand[4], atapiCommand[5], atapiCommand[6], atapiCommand[7], + atapiCommand[8], atapiCommand[9], atapiCommand[10], atapiCommand[11], + atapiCommand[12], atapiCommand[13], atapiCommand[14], atapiCommand[15]); + } + + uint32_t *prdt = (uint32_t *) (commandFIS + 128); + + for (uintptr_t k = 0; k < (port->commandList[j * 8 + 0] >> 16); k++) { + EsPrint("\t\t\tPRDT entry %d: base address %x, byte count %x%z.\n", + k, *(uint64_t *) (prdt + k * 4), (prdt[k * 4 + 3] & 0xFFFFFFF) + 1, + (prdt[k * 4 + 3] & 0x80000000) ? ", interrupt on completion" : ""); + } + } + } + + EsPrint("\t--- Most recent interrupts ---\n"); + + for (uintptr_t i = 0; i < sizeof(recentInterruptEvents) / sizeof(recentInterruptEvents[0]); i++) { + if (recentInterruptEventsPointer) recentInterruptEventsPointer--; + else recentInterruptEventsPointer = sizeof(recentInterruptEvents) / sizeof(recentInterruptEvents[0]) - 1; + + volatile InterruptEvent *event = recentInterruptEvents + recentInterruptEventsPointer; + + EsPrint("\t\tEvent %d: fired %dms ago, GIS %x, CI0 %x, CR0 %x%z.\n", + i, timeStamp - event->timeStamp, + event->globalInterruptStatus, event->port0CommandsIssued, + event->port0CommandsRunning, event->complete ? "" : ", incomplete"); + } +} + +bool AHCIController::Access(uintptr_t portIndex, uint64_t offsetBytes, size_t countBytes, int operation, + KDMABuffer *buffer, uint64_t, KWorkGroup *dispatchGroup) { + AHCIPort *port = ports + portIndex; + +#if 0 + // TODO Temporary. + + if (operation == K_ACCESS_WRITE) { + KernelPanic("AHCIController::Access - Attempted write.\n"); + } +#endif + + // Find a command slot to use. + + uintptr_t commandIndex = 0; + + while (true) { + KSpinlockAcquire(&port->commandSpinlock); + + uint32_t commandsAvailable = ~RD_REGISTER_PCI(portIndex); + bool found = false; + + for (uintptr_t i = 0; i < commandSlotCount; i++) { + if ((commandsAvailable & (1 << i)) && !port->commandContexts[i]) { + commandIndex = i; + found = true; + break; + } + } + + if (!found) { + KEventReset(&port->commandSlotsAvailable); + } else { + port->commandContexts[commandIndex] = dispatchGroup; + } + + KSpinlockRelease(&port->commandSpinlock); + + if (!found) { + KEventWait(&port->commandSlotsAvailable); + } else { + break; + } + } + + // Setup the command FIS. + + uint32_t countSectors = countBytes / port->sectorBytes; + uint64_t offsetSectors = offsetBytes / port->sectorBytes; + + if (countSectors & ~0xFFFF) { + KernelPanic("AHCIController::Access - Too many sectors to read.\n"); + } + + uint32_t *commandFIS = (uint32_t *) (port->commandTables + COMMAND_TABLE_SIZE * commandIndex); + commandFIS[0] = 0x27 /* H2D */ | (1 << 15) /* command */ | ((operation == K_ACCESS_WRITE ? 0x35 /* write DMA 48 */ : 0x25 /* read DMA 48 */) << 16); + commandFIS[1] = (offsetSectors & 0xFFFFFF) | (1 << 30); + commandFIS[2] = (offsetSectors >> 24) & 0xFFFFFF; + commandFIS[3] = countSectors & 0xFFFF; + commandFIS[4] = 0; + + // Setup the PRDT. + + size_t prdtEntryCount = 0; + uint32_t *prdt = (uint32_t *) (port->commandTables + COMMAND_TABLE_SIZE * commandIndex + 0x80); + + while (!KDMABufferIsComplete(buffer)) { + if (prdtEntryCount == PRDT_ENTRY_COUNT) { + KernelPanic("AHCIController::Access - Too many PRDT entries.\n"); + } + + KDMASegment segment = KDMABufferNextSegment(buffer); + + prdt[0 + 4 * prdtEntryCount] = segment.physicalAddress; + prdt[1 + 4 * prdtEntryCount] = segment.physicalAddress >> 32; + prdt[2 + 4 * prdtEntryCount] = 0; + prdt[3 + 4 * prdtEntryCount] = (segment.byteCount - 1) | (segment.isLast ? (1 << 31) /* IRQ when done */ : 0); + + prdtEntryCount++; + } + + // Setup the command list entry, and issue the command. + + port->commandList[commandIndex * 8 + 0] = 5 /* FIS is 5 DWORDs */ | (prdtEntryCount << 16) | (operation == K_ACCESS_WRITE ? (1 << 6) : 0); + port->commandList[commandIndex * 8 + 1] = 0; + + // Setup SCSI command if ATAPI. + + if (port->atapi) { + port->commandList[commandIndex * 8 + 0] |= (1 << 5) /* ATAPI */; + commandFIS[0] = 0x27 /* H2D */ | (1 << 15) /* command */ | (0xA0 /* packet */ << 16); + commandFIS[1] = countBytes << 8; + + uint8_t *scsiCommand = (uint8_t *) commandFIS + 0x40; + EsMemoryZero(scsiCommand, 10); + scsiCommand[0] = 0xA8 /* READ (12) */; + scsiCommand[2] = (offsetSectors >> 0x18) & 0xFF; + scsiCommand[3] = (offsetSectors >> 0x10) & 0xFF; + scsiCommand[4] = (offsetSectors >> 0x08) & 0xFF; + scsiCommand[5] = (offsetSectors >> 0x00) & 0xFF; + scsiCommand[9] = countSectors; + } + + // Start executing the command. + + KSpinlockAcquire(&port->commandSpinlock); + port->runningCommands |= 1 << commandIndex; + __sync_synchronize(); + WR_REGISTER_PCI(portIndex, 1 << commandIndex); + port->commandStartTimeStamps[commandIndex] = KGetTimeInMs(); + KSpinlockRelease(&port->commandSpinlock); + + return true; +} + +bool AHCIController::HandleIRQ() { + uint32_t globalInterruptStatus = RD_REGISTER_IS(); + KernelLog(LOG_VERBOSE, "AHCI", "received IRQ", "Received IRQ with status: %x.\n", globalInterruptStatus); + if (!globalInterruptStatus) return false; + WR_REGISTER_IS(globalInterruptStatus); + + volatile InterruptEvent *event = recentInterruptEvents + recentInterruptEventsPointer; + event->timeStamp = KGetTimeInMs(); + event->globalInterruptStatus = globalInterruptStatus; + event->complete = false; + recentInterruptEventsPointer = (recentInterruptEventsPointer + 1) % (sizeof(recentInterruptEvents) / sizeof(recentInterruptEvents[0])); + + bool commandCompleted = false; + + for (uintptr_t i = 0; i < MAX_PORTS; i++) { + if (~globalInterruptStatus & (1 << i)) continue; + + uint32_t interruptStatus = RD_REGISTER_PIS(i); + if (!interruptStatus) continue; + WR_REGISTER_PIS(i, interruptStatus); + + AHCIPort *port = ports + i; + + if (interruptStatus & ((1 << 30) | (1 << 29) | (1 << 28) | (1 << 27) | (1 << 26) | (1 << 24) | (1 << 23))) { + KernelLog(LOG_ERROR, "AHCI", "error IRQ", "Received IRQ error interrupt status bit set: %x.\n", interruptStatus); + + KSpinlockAcquire(&port->commandSpinlock); + + // Stop command processing. + + WR_REGISTER_PCMD(i, RD_REGISTER_PCMD(i) & ~(1 << 0)); + + // Fail all outstanding commands. + + for (uintptr_t j = 0; j < 32; j++) { + if (port->runningCommands & (1 << j)) { + port->commandContexts[j]->End(false /* failed */); + port->commandContexts[j] = nullptr; + } + } + + port->runningCommands = 0; + KEventSet(&port->commandSlotsAvailable, false, true /* maybe already set */); + + // Restart command processing. + + WR_REGISTER_PSERR(i, 0xFFFFFFFF); + KTimeout timeout(5); + while ((RD_REGISTER_PCMD(i) & (1 << 15)) && !timeout.Hit()); + WR_REGISTER_PCMD(i, RD_REGISTER_PCMD(i) | (1 << 0)); + + KSpinlockRelease(&port->commandSpinlock); + + continue; + } + + KSpinlockAcquire(&port->commandSpinlock); + + uint32_t commandsIssued = RD_REGISTER_PCI(i); + + if (i == 0) event->port0CommandsIssued = commandsIssued, event->port0CommandsRunning = port->runningCommands; + + for (uintptr_t j = 0; j < 32; j++) { + if (~port->runningCommands & (1 << j)) continue; // Command not started. + if (commandsIssued & (1 << j)) continue; // Command still running. + + // The command has completed. + + port->commandContexts[j]->End(true /* success */); + port->commandContexts[j] = nullptr; + KEventSet(&port->commandSlotsAvailable, false, true /* maybe already set */); + port->runningCommands &= ~(1 << j); + + commandCompleted = true; + } + + KSpinlockRelease(&port->commandSpinlock); + } + + if (commandCompleted) { + KSwitchThreadAfterIRQ(); + } + + event->complete = true; + + return true; +} + +void TimeoutTimerHit(EsGeneric argument) { + AHCIController *controller = (AHCIController *) argument.p; + + uint64_t currentTimeStamp = KGetTimeInMs(); + + for (uintptr_t i = 0; i < MAX_PORTS; i++) { + AHCIPort *port = controller->ports + i; + + KSpinlockAcquire(&port->commandSpinlock); + + for (uintptr_t j = 0; j < controller->commandSlotCount; j++) { + if ((port->runningCommands & (1 << j)) + && port->commandStartTimeStamps[j] + GENERAL_TIMEOUT < currentTimeStamp) { + KernelLog(LOG_ERROR, "AHCI", "command timeout", "Command %d on port %d timed out.\n", j, i); + + port->commandContexts[j]->End(false /* failure */); + port->commandContexts[j] = nullptr; + port->runningCommands &= ~(1 << j); + + // Don't set the commandSlotsAvailable event, since the controller still thinks the command is in use. + // TODO What happens if there are no commands left? + } + } + + KSpinlockRelease(&port->commandSpinlock); + } + + KTimerSet(&controller->timeoutTimer, GENERAL_TIMEOUT, TimeoutTimerHit, controller); +} + +bool AHCIController::SendSingleCommand(uintptr_t port) { + KTimeout timeout(GENERAL_TIMEOUT); + + // Wait for the port to be ready, then issue the command. + + while ((RD_REGISTER_PTFD(port) & ((1 << 7) | (1 << 3))) && !timeout.Hit()); + + if (timeout.Hit()) { + KernelLog(LOG_ERROR, "AHCI", "port hung", "Port %d bits DRQ/BSY won't clear.\n", port); + return false; + } + + __sync_synchronize(); + WR_REGISTER_PCI(port, 1 << 0); + + // Wait for command to complete. + + bool complete = false; + + while (!timeout.Hit()) { + if (~RD_REGISTER_PCI(port) & (1 << 0)) { + complete = true; + break; + } + } + + return complete; +} + +void AHCIController::Initialise() { + // Perform BIOS/OS handoff, if necessary. + + if (RD_REGISTER_CAP2() & (1 << 0)) { + KernelLog(LOG_INFO, "AHCI", "perform handoff", "Performing BIOS/OS handoff...\n"); + + WR_REGISTER_BOHC(RD_REGISTER_BOHC() | (1 << 1)); + + KTimeout timeout(25 /* ms */); + uint32_t status; + + while (true) { + status = RD_REGISTER_BOHC(); + if (~status & (1 << 0)) break; + if (timeout.Hit()) break; + } + + if (status & (1 << 0)) { + KEvent event = {}; + KernelLog(LOG_ERROR, "AHCI", "handoff error", "BIOS/OS handoff did not succeed, waiting 2 seconds to proceed...\n"); + KEventWait(&event, 2000 /* ms */); + } + } + + // Reset controller. + + { + KTimeout timeout(GENERAL_TIMEOUT); + WR_REGISTER_GHC(RD_REGISTER_GHC() | (1 << 0)); + while ((RD_REGISTER_GHC() & (1 << 0)) && !timeout.Hit()); + + if (timeout.Hit()) { + KernelLog(LOG_ERROR, "AHCI", "reset controller timeout", "The controller did not reset within the timeout.\n"); + return; + } + } + + // Register IRQ handler. + + KIRQHandler handler = [] (uintptr_t, void *context) { return ((AHCIController *) context)->HandleIRQ(); }; + + if (!pci->EnableSingleInterrupt(handler, this, "AHCI")) { + KernelLog(LOG_ERROR, "AHCI", "IRQ registration failure", "Could not register intrrupt handler.\n"); + return; + } + + // Enable AHCI mode and interrupts. + + WR_REGISTER_GHC(RD_REGISTER_GHC() | (1 << 31) | (1 << 1)); + + capabilities = RD_REGISTER_CAP(); + capabilities2 = RD_REGISTER_CAP2(); + commandSlotCount = ((capabilities >> 8) & 31) + 1; + dma64Supported = capabilities & (1 << 31); + +#ifdef ARCH_64 + if (!dma64Supported) { + KernelLog(LOG_ERROR, "AHCI", "controller cannot DMA", "The controller reports it cannot use 64-bit addresses in DMA transfer.\n"); + return; + } +#endif + + // Work out which ports have drives connected. + + size_t maximumNumberOfPorts = (capabilities & 31) + 1; + size_t portsFound = 0; + + uint32_t portsImplemented = RD_REGISTER_PI(); + + for (uintptr_t i = 0; i < MAX_PORTS; i++) { + if (portsImplemented & (1 << i)) { + portsFound++; + + if (portsFound <= maximumNumberOfPorts) { + ports[i].connected = true; + } + } + } + + KernelLog(LOG_INFO, "AHCI", "information", "Capabilities: %x, %x. Command slot count: %d. Implemented ports: %x.\n", + capabilities, capabilities2, commandSlotCount, portsImplemented); + + // Setup the command lists, FISes and command tables. + + for (uintptr_t i = 0; i < MAX_PORTS; i++) { + if (!ports[i].connected) continue; + + size_t bytesNeeded = COMMAND_LIST_SIZE + RECEIVED_FIS_SIZE + COMMAND_TABLE_SIZE * commandSlotCount; + + uint8_t *virtualAddress; + uintptr_t physicalAddress; + + if (!MMPhysicalAllocateAndMap(bytesNeeded, K_PAGE_SIZE, dma64Supported ? 64 : 32, true, MM_REGION_NOT_CACHEABLE, &virtualAddress, &physicalAddress)) { + KernelLog(LOG_ERROR, "AHCI", "allocation failure", "Could not allocate physical memory for port %d.\n", i); + break; + } + + ports[i].commandList = (uint32_t *) virtualAddress; + ports[i].commandTables = virtualAddress + COMMAND_LIST_SIZE + RECEIVED_FIS_SIZE; + + // Set the registers to the physical addresses. + + WR_REGISTER_PCLB(i, physicalAddress); + if (dma64Supported) WR_REGISTER_PCLBU(i, physicalAddress >> 32); + WR_REGISTER_PFB(i, (physicalAddress + 0x400)); + if (dma64Supported) WR_REGISTER_PFBU(i, (physicalAddress + 0x400) >> 32); + + // Point each command list entry to the corresponding command table. + + uint32_t *commandList = ports[i].commandList; + + for (uintptr_t j = 0; j < commandSlotCount; j++) { + uintptr_t address = physicalAddress + COMMAND_LIST_SIZE + RECEIVED_FIS_SIZE + COMMAND_TABLE_SIZE * j; + commandList[j * 8 + 2] = address; + commandList[j * 8 + 3] = address >> 32; + } + + // Reset the port. + + KTimeout timeout(GENERAL_TIMEOUT); + + const uint32_t runningBits = ((1 << 0 /* start */) | (1 << 4 /* receive FIS enable */) + | (1 << 15 /* command list running */) | (1 << 14 /* receive FIS running */)); + + while (true) { + uint32_t status = RD_REGISTER_PCMD(i); + + if (!(status & runningBits) || timeout.Hit()) { + break; + } + + // Stop command list processing and receive FIS. + WR_REGISTER_PCMD(i, status & ~((1 << 0) | (1 << 4))); + } + + if (RD_REGISTER_PCMD(i) & runningBits) { + KernelLog(LOG_ERROR, "AHCI", "reset port timeout", "Resetting port %d timed out. PCMD: %x.\n", + i, RD_REGISTER_PCMD(i)); + ports[i].connected = false; + continue; + } + + // Clear IRQs. + + WR_REGISTER_PIE(i, RD_REGISTER_PIE(i) & 0x0E3FFF00); + WR_REGISTER_PIS(i, RD_REGISTER_PIS(i)); + + // Enable receive FIS and activate the drive. + + WR_REGISTER_PSCTL(i, RD_REGISTER_PSCTL(i) | (3 << 8)); // Disable transitions to partial and slumber states. + WR_REGISTER_PCMD(i, (RD_REGISTER_PCMD(i) & 0x0FFFFFFF) + | (1 << 1 /* spin up */) | (1 << 2 /* power on */) | (1 << 4 /* FIS receive */) | (1 << 28 /* activate */)); + + KTimeout linkTimeout(10); + + while ((RD_REGISTER_PSSTS(i) & 0x0F) != 3 && !linkTimeout.Hit()); + + if ((RD_REGISTER_PSSTS(i) & 0x0F) != 3) { + KernelLog(LOG_ERROR, "AHCI", "activate port timeout", "Activating port %d timed out. PSSTS: %x.\n", + i, RD_REGISTER_PSSTS(i)); + ports[i].connected = false; + continue; + } + + // Clear errors. + + WR_REGISTER_PSERR(i, RD_REGISTER_PSERR(i)); + + // Wait for device to be ready. + + while ((RD_REGISTER_PTFD(i) & 0x88 /* BSY and DRQ */) && !timeout.Hit()); + + if (RD_REGISTER_PTFD(i) & 0x88) { + KernelLog(LOG_ERROR, "AHCI", "port ready timeout", "Port %d hung at busy state. PTFD: %x.\n", + i, RD_REGISTER_PTFD(i)); + ports[i].connected = false; + continue; + } + + // Start command list processing. + + KernelLog(LOG_INFO, "AHCI", "start command processing", "Starting command processing for port %d...\n", i); + WR_REGISTER_PCMD(i, RD_REGISTER_PCMD(i) | (1 << 0)); + + // Enable interrupts. + + KernelLog(LOG_INFO, "AHCI", "enable interrupts", "Enabling interrupts for port %d...\n", i); + WR_REGISTER_PIE(i, RD_REGISTER_PIE(i) | (1 << 5) /* descriptor complete */ | (1 << 0) /* D2H */ + | (1 << 30) | (1 << 29) | (1 << 28) | (1 << 27) | (1 << 26) | (1 << 24) | (1 << 23) /* errors */); + } + + // Read the status and signature for each implemented port to work out if it is connected. + + for (uintptr_t i = 0; i < MAX_PORTS; i++) { + if (!ports[i].connected) continue; + + uint32_t status = RD_REGISTER_PSSTS(i); + + if ((status & 0x00F) != 0x003 || (status & 0x0F0) == 0x000 || (status & 0xF00) != 0x100) { + ports[i].connected = false; + KernelLog(LOG_INFO, "AHCI", "no drive", "No drive connected to port %d (1).\n", i); + continue; + } + + uint32_t signature = RD_REGISTER_PSIG(i); + + if (signature == 0x00000101) { + // SATA drive. + KernelLog(LOG_INFO, "AHCI", "found drive", "Found SATA drive on port %d.\n", i); + } else if (signature == 0xEB140101) { + // SATAPI drive. + ports[i].atapi = true; + KernelLog(LOG_INFO, "AHCI", "found drive", "Found SATAPI drive on port %d.\n", i); + } else if (!signature) { + // No drive connected. + ports[i].connected = false; + KernelLog(LOG_INFO, "AHCI", "no drive", "No drive connected to port %d (2).\n", i); + } else { + KernelLog(LOG_ERROR, "AHCI", "unrecognised drive signature", "Unrecognised drive signature %x on port %d.\n", signature, i); + ports[i].connected = false; + } + } + + // Identify each connected drive. + + uint16_t *identifyData; + uintptr_t identifyDataPhysical; + + if (!MMPhysicalAllocateAndMap(0x200, K_PAGE_SIZE, dma64Supported ? 64 : 32, true, MM_REGION_NOT_CACHEABLE, (uint8_t **) &identifyData, &identifyDataPhysical)) { + KernelLog(LOG_ERROR, "AHCI", "allocation failure", "Could not allocate physical memory for identify data buffer.\n"); + return; + } + + KernelLog(LOG_INFO, "AHCI", "identify data", "Identify data buffer allocated at physical address %x.\n", identifyDataPhysical); + + for (uintptr_t i = 0; i < MAX_PORTS; i++) { + if (!ports[i].connected) continue; + + EsMemoryZero(identifyData, 0x200); + + // Setup the command list entry. + + ports[i].commandList[0] = 5 /* FIS is 5 DWORDs */ | (1 << 16) /* 1 PRDT entry */; + ports[i].commandList[1] = 0; + + // Setup the command FIS. + + uint8_t opcode = ports[i].atapi ? 0xA1 /* IDENTIFY PACKET */ : 0xEC /* IDENTIFY */; + uint32_t *commandFIS = (uint32_t *) ports[i].commandTables; + commandFIS[0] = 0x27 /* H2D */ | (1 << 15) /* command */ | (opcode << 16); + commandFIS[1] = commandFIS[2] = commandFIS[3] = commandFIS[4] = 0; + + // Setup the PRDT. + + uint32_t *prdt = (uint32_t *) (ports[i].commandTables + 0x80); + prdt[0] = identifyDataPhysical; + prdt[1] = identifyDataPhysical >> 32; + prdt[2] = 0; + prdt[3] = 0x200 - 1; + + KernelLog(LOG_INFO, "AHCI", "identifying drive", "Sending IDENTIFY command to port %d...\n", i); + + if (!SendSingleCommand(i)) { + KernelLog(LOG_ERROR, "AHCI", "identify failure", "Could not read identify data for port %d.\n", i); + WR_REGISTER_PCMD(i, RD_REGISTER_PCMD(i) & ~(1 << 0)); // Stop command processing. + ports[i].connected = false; + continue; + } + + ports[i].sectorBytes = 0x200; + + if ((identifyData[106] & (1 << 14)) && (~identifyData[106] & (1 << 15)) && (identifyData[106] & (1 << 12))) { + // Device has a logical sector size larger than 0x200 bytes. + ports[i].sectorBytes = (uint32_t) identifyData[117] | ((uint32_t) identifyData[118] << 16); + } + + ports[i].sectorCount = ((uint64_t) identifyData[100] << 0) + ((uint64_t) identifyData[101] << 16) + + ((uint64_t) identifyData[102] << 32) + ((uint64_t) identifyData[103] << 48); + + if (!((identifyData[49] & (1 << 9)) && (identifyData[49] & (1 << 8)))) { + KernelLog(LOG_ERROR, "AHCI", "unsupported feature", "Drive on port %d does not support a required feature.\n", i); + ports[i].connected = false; + continue; + } + + if (ports[i].atapi) { + // Send a read capacity command. + + ports[i].commandList[0] = 5 /* FIS is 5 DWORDs */ | (1 << 16) /* 1 PRDT entry */ | (1 << 5) /* ATAPI */; + commandFIS[0] = 0x27 /* H2D */ | (1 << 15) /* command */ | (0xA0 /* packet */ << 16); + commandFIS[1] = 8 /* maximum byte count transfer */ << 8; + prdt[3] = 8 - 1; + + uint8_t *scsiCommand = (uint8_t *) commandFIS + 0x40; + EsMemoryZero(scsiCommand, 10); + scsiCommand[0] = 0x25 /* READ CAPACITY (10) */; + + if (!SendSingleCommand(i)) { + KernelLog(LOG_ERROR, "AHCI", "identify failure", "Could not read SCSI read capacity data for port %d.\n", i); + WR_REGISTER_PCMD(i, RD_REGISTER_PCMD(i) & ~(1 << 0)); // Stop command processing. + ports[i].connected = false; + continue; + } + + uint8_t *capacity = (uint8_t *) identifyData; + + ports[i].sectorCount = (((uint64_t) capacity[3] << 0) + ((uint64_t) capacity[2] << 8) + + ((uint64_t) capacity[1] << 16) + ((uint64_t) capacity[0] << 24)) + 1; + ports[i].sectorBytes = ((uint64_t) capacity[7] << 0) + ((uint64_t) capacity[6] << 8) + + ((uint64_t) capacity[5] << 16) + ((uint64_t) capacity[4] << 24); + } + + if (ports[i].sectorCount <= 128 || (ports[i].sectorBytes & 0x1FF) || !ports[i].sectorBytes || ports[i].sectorBytes > 0x1000) { + KernelLog(LOG_ERROR, "AHCI", "unsupported feature", "Drive on port %d has invalid sector configuration (count: %d, size: %D).\n", + i, ports[i].sectorCount, ports[i].sectorBytes); + ports[i].connected = false; + continue; + } + + for (uintptr_t j = 0; j < 20; j++) { + ports[i].model[j * 2 + 0] = identifyData[27 + j] >> 8; + ports[i].model[j * 2 + 1] = identifyData[27 + j] & 0xFF; + } + + ports[i].model[40] = 0; + + for (uintptr_t j = 39; j > 0; j--) { + if (ports[i].model[j] == ' ') { + ports[i].model[j] = 0; + } else { + break; + } + } + + ports[i].ssd = identifyData[217] == 1; + + for (uintptr_t i = 10; i < 20; i++) identifyData[i] = (identifyData[i] >> 8) | (identifyData[i] << 8); + for (uintptr_t i = 23; i < 27; i++) identifyData[i] = (identifyData[i] >> 8) | (identifyData[i] << 8); + for (uintptr_t i = 27; i < 47; i++) identifyData[i] = (identifyData[i] >> 8) | (identifyData[i] << 8); + + KernelLog(LOG_INFO, "AHCI", "identified drive", "Identified drive on port %d; serial - '%s', firmware - '%s', model - '%s', sector size - %D, sector count - %d.\n", + i, 20, identifyData + 10, 8, identifyData + 23, 40, identifyData + 27, ports[i].sectorBytes, ports[i].sectorCount); + } + + MMFree(MMGetKernelSpace(), identifyData); + MMPhysicalFree(identifyDataPhysical); + + // Start the timeout timer. + + KTimerSet(&timeoutTimer, GENERAL_TIMEOUT, TimeoutTimerHit, this); + + // Register drives. + + for (uintptr_t i = 0; i < MAX_PORTS; i++) { + if (!ports[i].connected) continue; + + AHCIDrive *device = (AHCIDrive *) KDeviceCreate("AHCI drive", this, sizeof(AHCIDrive)); + + if (!device) { + KernelLog(LOG_ERROR, "AHCI", "allocation failure", "Could not create device for port %d.\n", i); + break; + } + + device->controller = this; + device->port = i; + + device->sectorSize = ports[i].sectorBytes; + device->sectorCount = ports[i].sectorCount; + device->maxAccessSectorCount = ports[i].atapi ? (65535 / device->sectorSize) + : ((PRDT_ENTRY_COUNT - 1 /* need one extra if not page aligned */) * K_PAGE_SIZE / device->sectorSize); + device->readOnly = ports[i].atapi; + device->cModel = ports[i].model; + device->driveType = ports[i].atapi ? ES_DRIVE_TYPE_CDROM : ports[i].ssd ? ES_DRIVE_TYPE_SSD : ES_DRIVE_TYPE_HDD; + + device->access = [] (KBlockDeviceAccessRequest request) { + AHCIDrive *drive = (AHCIDrive *) request.device; + + request.dispatchGroup->Start(); + + if (!drive->controller->Access(drive->port, request.offset, request.count, request.operation, + request.buffer, request.flags, request.dispatchGroup)) { + request.dispatchGroup->End(false); + } + }; + + FSRegisterBlockDevice(device); + } +} + +static void DeviceAttach(KDevice *_parent) { + KPCIDevice *parent = (KPCIDevice *) _parent; + + AHCIController *device = (AHCIController *) KDeviceCreate("AHCI controller", parent, sizeof(AHCIController)); + if (!device) return; + device->pci = parent; + + device->dumpState = [] (KDevice *device) { + ((AHCIController *) device)->DumpState(); + }; + + // Enable PCI features. + parent->EnableFeatures(K_PCI_FEATURE_INTERRUPTS + | K_PCI_FEATURE_BUSMASTERING_DMA + | K_PCI_FEATURE_MEMORY_SPACE_ACCESS + | K_PCI_FEATURE_BAR_5); + + // Initialise the controller. + device->Initialise(); +} + +KDriver driverAHCI = { + .attach = DeviceAttach, +}; diff --git a/drivers/bga.cpp b/drivers/bga.cpp new file mode 100644 index 0000000..a17579b --- /dev/null +++ b/drivers/bga.cpp @@ -0,0 +1,81 @@ +#include + +struct BGADisplay : KGraphicsTarget { +}; + +BGADisplay *vboxDisplay; + +void BGAUpdateScreen(K_USER_BUFFER const uint8_t *source, uint32_t sourceWidth, uint32_t sourceHeight, uint32_t sourceStride, + uint32_t destinationX, uint32_t destinationY) { + GraphicsUpdateScreen32(source, sourceWidth, sourceHeight, sourceStride, destinationX, destinationY, + vboxDisplay->screenWidth, vboxDisplay->screenHeight, + vboxDisplay->screenWidth * 4, + ((KPCIDevice *) vboxDisplay->parent)->baseAddressesVirtual[0]); +} + +void BGADebugPutBlock(uintptr_t x, uintptr_t y, bool toggle) { + GraphicsDebugPutBlock32(x, y, toggle, + vboxDisplay->screenWidth, vboxDisplay->screenHeight, + vboxDisplay->screenWidth * 4, + ((KPCIDevice *) vboxDisplay->parent)->baseAddressesVirtual[0]); +} + +void BGADebugClearScreen() { + GraphicsDebugClearScreen32(vboxDisplay->screenWidth, vboxDisplay->screenHeight, + vboxDisplay->screenWidth * 4, + ((KPCIDevice *) vboxDisplay->parent)->baseAddressesVirtual[0]); +} + +void BGADeviceAttached(KDevice *_parent) { + KPCIDevice *parent = (KPCIDevice *) _parent; + + BGADisplay *device = (BGADisplay *) KDeviceCreate("BGA", parent, sizeof(BGADisplay)); + if (!device) return; + + parent->EnableFeatures(K_PCI_FEATURE_IO_PORT_ACCESS | K_PCI_FEATURE_MEMORY_SPACE_ACCESS | K_PCI_FEATURE_BAR_0); + + if (KGraphicsIsTargetRegistered()) { + return; + } + + ProcessorOut16(0x01CE, 0 /* version */); + uint16_t version = ProcessorIn16(0x01CF); + KernelLog(LOG_INFO, "BGA", "version", "Detected version %X%X.\n", version >> 8, version); + + if (version < 0xB0C0 || version > 0xB0C5) { + KernelLog(LOG_INFO, "BGA", "unsupported version", "Currently, the only supported versions are B0C0-B0C5.\n"); + return; + } + + // Set the mode. + ProcessorOut16(0x01CE, 4 /* enable */); + ProcessorOut16(0x01CF, 0); + ProcessorOut16(0x01CE, 1 /* x resolution */); + ProcessorOut16(0x01CF, BGA_RESOLUTION_WIDTH); + ProcessorOut16(0x01CE, 2 /* y resolution */); + ProcessorOut16(0x01CF, BGA_RESOLUTION_HEIGHT); + ProcessorOut16(0x01CE, 3 /* bpp */); + ProcessorOut16(0x01CF, 32); + ProcessorOut16(0x01CE, 4 /* enable */); + ProcessorOut16(0x01CF, 0x41 /* linear frame-buffer */); + + // Setup the graphics target. + device->updateScreen = BGAUpdateScreen; + device->debugPutBlock = BGADebugPutBlock; + device->debugClearScreen = BGADebugClearScreen; + ProcessorOut16(0x01CE, 1 /* x resolution */); + device->screenWidth = ProcessorIn16(0x01CF); + ProcessorOut16(0x01CE, 2 /* y resolution */); + device->screenHeight = ProcessorIn16(0x01CF); + + // Register the display. + KernelLog(LOG_INFO, "BGA", "register target", + "Registering graphics target with resolution %d by %d. Linear framebuffer is at virtual address %x.\n", + device->screenWidth, device->screenHeight, parent->baseAddressesVirtual[0]); + vboxDisplay = device; + KRegisterGraphicsTarget(device); +} + +KDriver driverBGA = { + .attach = BGADeviceAttached, +}; diff --git a/drivers/esfs2.cpp b/drivers/esfs2.cpp new file mode 100644 index 0000000..0fef2dd --- /dev/null +++ b/drivers/esfs2.cpp @@ -0,0 +1,2009 @@ +#include + +// Filesystem structures and constant definitions. +#include + +// TODO Calling FSDirectoryEntryFound on all directory entries seen during scanning, even if they're not the target. +// TODO Informing the block cache when a directory is truncated and its extents are freed. +// TODO Renaming directories does not work? +// TODO ESFS_CHECK_XXX are used to report out of memory errors, which shouldn't report KERNEL_PROBLEM_DAMAGED_FILESYSTEM. + +#define ESFS_CHECK(x, y) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", y "\n"); return false; } +#define ESFS_CHECK_ERROR(x, y) if ((x) != ES_SUCCESS) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", y "\n"); return x; } +#define ESFS_CHECK_TO_ERROR(x, y, z) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", y "\n"); return z; } +#define ESFS_CHECK_VA(x, y, ...) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", y "\n", __VA_ARGS__); return false; } +#define ESFS_CHECK_RETURN(x, y) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", y "\n"); return; } +#define ESFS_CHECK_CORRUPT(x, y) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", y "\n"); return ES_ERROR_CORRUPT_DATA; } +#define ESFS_CHECK_FATAL(x, y) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", "Mount - " y "\n"); return false; } +#define ESFS_CHECK_READ_ONLY(x, y) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "mount read only", "Mount - " y " Mounting as read only.\n"); volume->readOnly = true; } + +struct Volume : KDevice { + Superblock superblock; + KFileSystem *fileSystem; + struct FSNode *root; + bool readOnly; + KWriterLock blockBitmapLock; + GroupDescriptor *groupDescriptorTable; + KMutex nextIdentifierMutex; +}; + +struct FSNode { + Volume *volume; + DirectoryEntry entry; + DirectoryEntryReference reference; + EsUniqueIdentifier identifier; + EsNodeType type; + bool corrupt; +}; + +static bool AccessBlock(Volume *volume, uint64_t index, uint64_t count, void *buffer, uint64_t flags, int driveAccess) { + // TODO Return EsError. + Superblock *superblock = &volume->superblock; + bool result = volume->fileSystem->Access(index * superblock->blockSize, count * superblock->blockSize, driveAccess, buffer, flags, nullptr); + ESFS_CHECK(result, "AccessBlock - Could not access blocks."); + return result; +} + +static bool ValidateIndexVertex(Superblock *superblock, IndexVertex *vertex) { + uint32_t checksum = vertex->checksum; + vertex->checksum = 0; + uint32_t calculated = CalculateCRC32(vertex, superblock->blockSize); + + ESFS_CHECK(checksum == calculated, "ValidateIndexVertex - Invalid vertex checksum."); + ESFS_CHECK(0 == EsMemoryCompare(vertex->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4), "ValidateIndexVertex - Invalid vertex signature."); + ESFS_CHECK(vertex->offset + vertex->maxCount * sizeof(IndexKey) < superblock->blockSize, "ValidateIndexVertex - Keys do not fit in vertex."); + ESFS_CHECK(vertex->count <= vertex->maxCount, "ValidateIndexVertex - Too many keys in vertex."); + + return true; +} + +static EsError FindDirectoryEntryReferenceFromIndex(Volume *volume, uint8_t *buffer /* superblock->blockSize */, + DirectoryEntryReference *entry, const char *name, size_t nameLength, uint64_t rootBlock) { + // EsPrint("FindDirectoryEntryReferenceFromIndex: %s (%d)\n", nameLength, name, rootBlock); + if (!rootBlock) return ES_ERROR_FILE_DOES_NOT_EXIST; // No index - the directory is empty? + + Superblock *superblock = &volume->superblock; + + // Get the root vertex. + uint64_t nameHash = CalculateCRC64(name, nameLength); + IndexVertex *vertex = (IndexVertex *) buffer; + + if (!AccessBlock(volume, rootBlock, 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) { + return ES_ERROR_DRIVE_CONTROLLER_REPORTED; + } + + int depth = 0; + + while (true) { + ESFS_CHECK(depth++ < ESFS_INDEX_MAX_DEPTH - 1, "FindDirectoryEntryReferenceFromIndex - Reached tree max depth."); + + if (!ValidateIndexVertex(superblock, vertex)) return ES_ERROR_CORRUPT_DATA; + IndexKey *keys = (IndexKey *) ((uint8_t *) vertex + vertex->offset); + + // For every key... + for (int i = 0; i <= vertex->count; i++) { + if (i == vertex->count || keys[i].value > nameHash) { + if (keys[i].child) { + // The directory is in the child. + if (!AccessBlock(volume, keys[i].child, 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) return ES_ERROR_DRIVE_CONTROLLER_REPORTED; + else goto nextVertex; + } else { + // We couldn't find the entry. + return ES_ERROR_FILE_DOES_NOT_EXIST; + } + } else if (keys[i].value == nameHash) { + // We've found the directory. + ESFS_CHECK_CORRUPT(keys[i].data.block < superblock->blockCount + && keys[i].data.offsetIntoBlock + sizeof(DirectoryEntry) <= superblock->blockSize, + "FindDirectoryEntryReferenceFromIndex - Invalid key entry."); + if (entry) *entry = keys[i].data; + return ES_SUCCESS; + } + } + + nextVertex:; + } +} + +static bool ValidateDirectoryEntry(DirectoryEntry *entry) { + uint32_t checksum = entry->checksum; + entry->checksum = 0; + uint32_t calculated = CalculateCRC32(entry, sizeof(DirectoryEntry)); + entry->checksum = calculated; + + ESFS_CHECK_VA(checksum == calculated, "ValidateDirectoryEntry - Invalid checksum (%x, calculated %x).", checksum, calculated); + ESFS_CHECK(0 == EsMemoryCompare(entry->signature, ESFS_DIRECTORY_ENTRY_SIGNATURE, 8), "ValidateDirectoryEntry - Invalid signature."); + ESFS_CHECK(entry->attributeOffset < sizeof(DirectoryEntry) - sizeof(Attribute), "ValidateDirectoryEntry - Invalid attribute offset."); + + Attribute *attribute = (Attribute *) ((uint8_t *) entry + entry->attributeOffset); + + for (uintptr_t i = 0; i < entry->attributeCount; i++) { + ESFS_CHECK(attribute->size && attribute->type, "ValidateDirectoryEntry - Invalid attribute."); + ESFS_CHECK((uintptr_t) attribute <= (uintptr_t) entry + sizeof(DirectoryEntry), "ValidateDirectoryEntry - Too many attributes."); + + if (attribute->type == ESFS_ATTRIBUTE_DATA) { + AttributeData *data = (AttributeData *) attribute; + + if (data->indirection == ESFS_INDIRECTION_DIRECT) { + ESFS_CHECK(data->dataOffset + data->count <= data->size, "ValidateDirectoryEntry - Data too long."); + ESFS_CHECK(data->count == entry->fileSize, "ValidateDirectoryEntry - Expected direct attribute to cover entire file."); + } + } else if (attribute->type == ESFS_ATTRIBUTE_DIRECTORY) { + } else if (attribute->type == ESFS_ATTRIBUTE_FILENAME) { + AttributeFilename *filename = (AttributeFilename *) attribute; + ESFS_CHECK(filename->length + 8 <= filename->size, "ValidateDirectoryEntry - Filename too long."); + } else { + // Unrecognised attribute. + } + + attribute = (Attribute *) ((uint8_t *) attribute + attribute->size); + } + + return true; +} + +static Attribute *FindAttribute(DirectoryEntry *entry, uint16_t type) { + Attribute *attribute = (Attribute *) ((uint8_t *) entry + entry->attributeOffset); + int count = 0; + + while (attribute->type != type) { + if (!attribute->size) { + KernelLog(LOG_ERROR, "EsFS", "damaged file system", "FindAttribute - Attribute size was 0.\n"); + return nullptr; + } + + attribute = (Attribute *) ((uint8_t *) attribute + attribute->size); + + if (count++ == entry->attributeCount) { + return nullptr; + } + } + + return attribute; +} + +static bool ReadWrite(FSNode *file, uint64_t offset, uint64_t count, uint8_t *buffer, bool needBlockBuffer, bool write, + DirectoryEntryReference *reference = nullptr /* Returns the position of a directory just accessed */) { + // TODO Return EsError. + // TODO Support KWorkGroup. + + Volume *volume = file->volume; + Superblock *superblock = &volume->superblock; + DirectoryEntry *entry = &file->entry; + + uint64_t accessBlockFlags = 0; + + if (file->type == ES_NODE_DIRECTORY) { + accessBlockFlags |= BLOCK_ACCESS_CACHED; + } + + uint8_t *blockBuffer = !needBlockBuffer ? nullptr : (uint8_t *) EsHeapAllocate(superblock->blockSize, false, K_FIXED); + EsDefer(EsHeapFree(blockBuffer, 0, K_FIXED)); + ESFS_CHECK(!needBlockBuffer || blockBuffer, "Read - Could not allocate block buffer."); + + // EsPrint("ReadWrite - %d, %d, %x, %d\n", offset, count, buffer, write); + + if (!count) { + return true; + } + + AttributeData *data = (AttributeData *) FindAttribute(entry, ESFS_ATTRIBUTE_DATA); + ESFS_CHECK(data, "Read - Expected data attribute."); + + if (data->indirection == ESFS_INDIRECTION_DIRECT) { + if (write) { + EsMemoryCopy((uint8_t *) data + data->dataOffset + offset, buffer, count); + } else { + EsMemoryCopy(buffer, (uint8_t *) data + data->dataOffset + offset, count); + } + } else if (data->indirection == ESFS_INDIRECTION_L1) { + uint64_t offsetBlock = offset / superblock->blockSize; + uint64_t offsetIntoCurrentBlock = offset % superblock->blockSize; + uint8_t *extentList = (uint8_t *) data + data->dataOffset; + uint64_t previousExtentStart = 0, positionInExtentList = 0, blockInFile = 0, extentIndex = 0; + + while (count) { + // Find the extent containing offsetBlock. + + uint64_t extentStart = 0, extentCount = 0; + + while (!extentStart) { + if (extentIndex == data->count) { + ESFS_CHECK(false, "Read - Invalid extent."); + } + + uint64_t count = 0; + + if (!DecodeExtent(&previousExtentStart, &count, extentList, &positionInExtentList, data->size - data->dataOffset) + || !count || !previousExtentStart) { + ESFS_CHECK(false, "Read - Invalid extent."); + } + + // EsPrint("\tExtent %d -> %d covers blocks %d -> %d\n", previousExtentStart, previousExtentStart + count, blockInFile, blockInFile + count); + + if (blockInFile + count > offsetBlock) { + uint64_t offsetIntoExtent = offsetBlock - blockInFile; + extentStart = previousExtentStart + offsetIntoExtent; + extentCount = count - offsetIntoExtent; + // EsPrint("\t\tUsing section %d -> %d for reading from block %d\n", extentStart, extentStart + extentCount, offsetBlock); + } + + blockInFile += count; + extentIndex++; + } + + // Read the data. + + repeatExtent:; + + if (offsetIntoCurrentBlock || count < superblock->blockSize) { + if (!needBlockBuffer) { + KernelPanic("EsFS::Read - Need a block buffer, but needBlockBuffer was false.\n"); + } + + uint64_t copyCount = superblock->blockSize - offsetIntoCurrentBlock; + if (copyCount > count) copyCount = count; + + // EsPrint("\tCopying %d bytes through block buffer.\n", copyCount); + + if (!AccessBlock(volume, extentStart, 1, blockBuffer, accessBlockFlags, K_ACCESS_READ)) { + return false; + } + + if (reference) { + reference->block = extentStart; + reference->offsetIntoBlock = offsetIntoCurrentBlock; + } + + if (write) { + EsMemoryCopy(blockBuffer + offsetIntoCurrentBlock, buffer, copyCount); + + if (!AccessBlock(volume, extentStart, 1, blockBuffer, accessBlockFlags, K_ACCESS_WRITE)) { + return false; + } + } else { + EsMemoryCopy(buffer, blockBuffer + offsetIntoCurrentBlock, copyCount); + } + + buffer += copyCount, count -= copyCount; + offsetIntoCurrentBlock = 0, offsetBlock++; + extentStart++, extentCount--; + + // EsPrint("\t\tUsing section %d -> %d for reading from block %d\n", extentStart, extentCount, offsetBlock); + } + + { + uint64_t bytesToRead = extentCount * superblock->blockSize; + if (bytesToRead > count) bytesToRead = count; + bytesToRead -= bytesToRead % superblock->blockSize; + uint64_t blocksRead = bytesToRead / superblock->blockSize; + + // EsPrint("\tReading %d blocks from %d.\n", blocksRead, extentStart); + + if (reference && bytesToRead) { + reference->block = extentStart; + reference->offsetIntoBlock = 0; + } + + if (!AccessBlock(volume, extentStart, blocksRead, buffer, accessBlockFlags, + write ? K_ACCESS_WRITE : K_ACCESS_READ)) { + return false; + } + + buffer += bytesToRead, count -= bytesToRead; + + offsetBlock += blocksRead; + extentStart += blocksRead, extentCount -= blocksRead; + + if (extentCount && count) { + goto repeatExtent; + } + } + } + } else { + ESFS_CHECK(data, "Read - Unrecognised indirection mode."); + return false; + } + + return true; +} + +static size_t Read(KNode *node, void *_buffer, EsFileOffset offset, EsFileOffset count) { + FSNode *file = (FSNode *) node->driverNode; + if (file->corrupt) return ES_ERROR_CORRUPT_DATA; + return ReadWrite(file, offset, count, (uint8_t *) _buffer, true, false) ? count : ES_ERROR_UNKNOWN; +} + +static size_t Write(KNode *node, const void *_buffer, EsFileOffset offset, EsFileOffset count) { + FSNode *file = (FSNode *) node->driverNode; + if (file->corrupt) return ES_ERROR_CORRUPT_DATA; + return ReadWrite(file, offset, count, (uint8_t *) _buffer, true, true) ? count : ES_ERROR_UNKNOWN; +} + +static void Sync(KNode *_directory, KNode *node) { + (void) _directory; + FSNode *file = (FSNode *) node->driverNode; + if (!file) KernelPanic("EsFS::Sync - Node %x has null driver node.\n", node); + if (file->corrupt) return; + Volume *volume = file->volume; + Superblock *superblock = &volume->superblock; + + // EsPrint("SYNC! %d,%d\n", file->reference.block, file->reference.offsetIntoBlock); + + if (file->type == ES_NODE_DIRECTORY) { + // Get the most recent totalSize for the directory. + AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&file->entry, ESFS_ATTRIBUTE_DIRECTORY); + directoryAttribute->totalSize = FSNodeGetTotalSize(node); + } + + { + file->entry.checksum = 0; + file->entry.checksum = CalculateCRC32(&file->entry, sizeof(DirectoryEntry)); + } + + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(superblock->blockSize, false, K_FIXED); + EsDefer(EsHeapFree(blockBuffer, 0, K_FIXED)); + ESFS_CHECK_RETURN(blockBuffer, "Sync - Could not allocate block buffer."); + + if (!AccessBlock(volume, file->reference.block, 1, blockBuffer, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) { + KernelLog(LOG_ERROR, "EsFS", "drive access failure", "Sync - Could not read reference block.\n"); + return; + } + + if (!ValidateDirectoryEntry((DirectoryEntry *) (blockBuffer + file->reference.offsetIntoBlock))) { + return; + } + + EsMemoryCopy(blockBuffer + file->reference.offsetIntoBlock, &file->entry, sizeof(DirectoryEntry)); + + if (!AccessBlock(volume, file->reference.block, 1, blockBuffer, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE)) { + KernelLog(LOG_ERROR, "EsFS", "drive access failure", "Sync - Could not write reference block.\n"); + return; + } +} + +static EsError Enumerate(KNode *node) { + // TODO Support KWorkGroup. + + FSNode *file = (FSNode *) node->driverNode; + if (file->corrupt) return ES_ERROR_CORRUPT_DATA; + Volume *volume = file->volume; + Superblock *superblock = &volume->superblock; + DirectoryEntry *entry = &file->entry; + + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(superblock->blockSize, false, K_FIXED); + if (!blockBuffer) return ES_ERROR_INSUFFICIENT_RESOURCES; + EsDefer(EsHeapFree(blockBuffer, 0, K_FIXED)); + + DirectoryEntryReference reference = {}; + AttributeDirectory *directory = (AttributeDirectory *) FindAttribute(entry, ESFS_ATTRIBUTE_DIRECTORY); + uint64_t blocksInDirectory = (directory->childNodes + superblock->directoryEntriesPerBlock - 1) / superblock->directoryEntriesPerBlock; + + for (uint64_t i = 0; i < blocksInDirectory; i++) { + if (!ReadWrite(file, i * superblock->blockSize, superblock->blockSize, blockBuffer, false, false, &reference)) { + return ES_ERROR_UNKNOWN; + } + + uint64_t entriesInThisBlock = superblock->directoryEntriesPerBlock; + + if (i == blocksInDirectory - 1 && directory->childNodes % superblock->directoryEntriesPerBlock) { + entriesInThisBlock = directory->childNodes % superblock->directoryEntriesPerBlock; + } + + for (uint64_t j = 0; j < entriesInThisBlock; j++, reference.offsetIntoBlock += sizeof(DirectoryEntry)) { + DirectoryEntry *entry = (DirectoryEntry *) blockBuffer + j; + + if (!ValidateDirectoryEntry(entry)) { + // Try the entries in the next block. + break; + } + + AttributeFilename *filename = (AttributeFilename *) FindAttribute(entry, ESFS_ATTRIBUTE_FILENAME); + if (!filename) continue; + + KNodeMetadata metadata = {}; + + metadata.type = entry->nodeType == ESFS_NODE_TYPE_DIRECTORY ? ES_NODE_DIRECTORY : ES_NODE_FILE; + + if (metadata.type == ES_NODE_DIRECTORY) { + AttributeDirectory *directory = (AttributeDirectory *) FindAttribute(entry, ESFS_ATTRIBUTE_DIRECTORY); + + if (directory) { + metadata.directoryChildren = directory->childNodes; + metadata.totalSize = directory->totalSize; + } + } else if (metadata.type == ES_NODE_FILE) { + metadata.totalSize = entry->fileSize; + } + + EsError error = FSDirectoryEntryFound(node, &metadata, &reference, + (const char *) filename->filename, filename->length, false); + + if (error != ES_SUCCESS) { + return error; + } + } + } + + return ES_SUCCESS; +} + +static uint64_t FindLargestExtent(uint8_t *bitmap, Superblock *superblock) { + uint64_t largestExtentCount = 0, i = 0; + + while (i < superblock->blocksPerGroup) { + if (bitmap[i / 8] & (1 << (i % 8))) { + i++; + } else { + uint64_t count = 0; + + while (i < superblock->blocksPerGroup) { + if (bitmap[i / 8] & (1 << (i % 8))) break; + else count++, i++; + } + + if (largestExtentCount < count) { + largestExtentCount = count; + } + } + } + + return largestExtentCount; +} + +static bool ValidateGroupDescriptor(GroupDescriptor *descriptor) { + uint32_t checksum = descriptor->checksum; + descriptor->checksum = 0; + uint32_t calculated = CalculateCRC32(descriptor, sizeof(GroupDescriptor)); + ESFS_CHECK(checksum == calculated, "ValidateGroupDescriptor - Invalid checksum."); + ESFS_CHECK(0 == EsMemoryCompare(descriptor->signature, ESFS_GROUP_DESCRIPTOR_SIGNATURE, 4), "ValidateGroupDescriptor - Invalid signature."); + return true; +} + +static bool ValidateBlockBitmap(GroupDescriptor *descriptor, uint8_t *bitmap, Superblock *superblock) { + uint32_t calculated = CalculateCRC32(bitmap, superblock->blocksPerGroupBlockBitmap * superblock->blockSize); + ESFS_CHECK(calculated == descriptor->bitmapChecksum, "ValidateBlockBitmap - Invalid checksum."); + + uint32_t blocksUsed = 0; + + for (uint64_t i = 0; i < superblock->blocksPerGroup; i++) { + if (bitmap[i / 8] & (1 << (i % 8))) { + blocksUsed++; + } + } + + ESFS_CHECK(blocksUsed == descriptor->blocksUsed, "ValidateBlockBitmap - Used block count mismatch."); + + return true; +} + +static bool AllocateExtent(Volume *volume, uint64_t nearby, uint64_t increaseBlocks, uint64_t *extentStart, uint64_t *extentCount, bool zero) { + Superblock *superblock = &volume->superblock; + KWriterLockAssertExclusive(&volume->blockBitmapLock); + + (void) nearby; + // TODO Smarter extent allocation. + + uint8_t *zeroBuffer = nullptr; + EsDefer(EsHeapFree(zeroBuffer, 0, K_FIXED)); + size_t zeroBufferSize = superblock->blockSize * (increaseBlocks > 16 ? 16 : increaseBlocks); + + if (zero) { + zeroBuffer = (uint8_t *) EsHeapAllocate(zeroBufferSize, true, K_FIXED); + ESFS_CHECK(zeroBuffer, "AllocateExtent - Could not allocate buffer for zeroing extent."); + } + + // Find a group to allocate the next extent from. + + GroupDescriptor *target = nullptr; + + { + for (uint64_t i = 0; !target && i < superblock->groupCount; i++) { + GroupDescriptor *group = volume->groupDescriptorTable + i; + if (!group->blocksUsed) group->largestExtent = superblock->blocksPerGroup - superblock->blocksPerGroupBlockBitmap; + if (group->largestExtent >= increaseBlocks) target = group; + } + + for (uint64_t i = 0; !target && i < superblock->groupCount; i++) { + GroupDescriptor *group = volume->groupDescriptorTable + i; + if (superblock->blocksPerGroup - group->blocksUsed >= increaseBlocks) target = group; + } + + for (uint64_t i = 0; !target && i < superblock->groupCount; i++) { + GroupDescriptor *group = volume->groupDescriptorTable + i; + if (superblock->blocksPerGroup != group->blocksUsed) target = group; + } + } + + if (!target) { + return false; + } + + ESFS_CHECK(ValidateGroupDescriptor(target), "AllocateExtent - Invalid group descriptor."); + + // Load the bitmap, find the largest extent, and mark it as in use. + + uint8_t *bitmap = (uint8_t *) EsHeapAllocate(superblock->blocksPerGroupBlockBitmap * superblock->blockSize, false, K_FIXED); + EsDefer(EsHeapFree(bitmap, 0, K_FIXED)); + ESFS_CHECK(bitmap, "AllocateExtent - Could not allocate buffer for block bitmap."); + + { + if (target->blockBitmap) { + if (!AccessBlock(volume, target->blockBitmap, superblock->blocksPerGroupBlockBitmap, bitmap, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) { + return false; + } + + ESFS_CHECK(ValidateBlockBitmap(target, bitmap, superblock), "AllocateExtent - Invalid block bitmap."); + } else { + EsMemoryZero(bitmap, superblock->blocksPerGroupBlockBitmap * superblock->blockSize); + for (uint64_t i = 0; i < superblock->blocksPerGroupBlockBitmap; i++) bitmap[i / 8] |= 1 << (i % 8); + target->blockBitmap = superblock->blocksPerGroup * (target - volume->groupDescriptorTable); + target->blocksUsed = superblock->blocksPerGroupBlockBitmap; + } + + uint64_t largestExtentStart = 0, largestExtentCount = 0, i = 0; + + while (i < superblock->blocksPerGroup) { + if (bitmap[i / 8] & (1 << (i % 8))) { + i++; + } else { + uint64_t start = i, count = 0; + + while (i < superblock->blocksPerGroup) { + if (bitmap[i / 8] & (1 << (i % 8))) break; + else count++, i++; + } + + if (largestExtentCount < count) { + largestExtentStart = start; + largestExtentCount = count; + } + } + } + + *extentStart = largestExtentStart; + *extentCount = largestExtentCount; + + if (*extentCount > increaseBlocks) { + *extentCount = increaseBlocks; + } + + for (uint64_t i = *extentStart; i < *extentStart + *extentCount; i++) { + bitmap[i / 8] |= 1 << (i % 8); + } + + if (!AccessBlock(volume, target->blockBitmap, superblock->blocksPerGroupBlockBitmap, bitmap, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE)) { + return false; + } + + target->largestExtent = FindLargestExtent(bitmap, superblock); + target->blocksUsed += *extentCount; + target->bitmapChecksum = CalculateCRC32(bitmap, superblock->blocksPerGroupBlockBitmap * superblock->blockSize); + target->checksum = 0; + target->checksum = CalculateCRC32(target, sizeof(GroupDescriptor)); + } + + *extentStart += (target - volume->groupDescriptorTable) * superblock->blocksPerGroup; + superblock->blocksUsed += *extentCount; + volume->fileSystem->spaceUsed += *extentCount * superblock->blockSize; + + if (zero) { + // TODO This is really slow - introduce K_ACCESS_ZERO? + // TODO Support KWorkGroup. + + for (uint64_t i = 0; i < *extentCount * superblock->blockSize; i += zeroBufferSize) { +#if 0 + if ((i / zeroBufferSize) % 100 == 0) { + EsPrint("AllocateExtent zeroing %d/%d\n", i / zeroBufferSize, extentCount * superblock->blockSize / zeroBufferSize); + } +#endif + + uint64_t count = zeroBufferSize; + + if (i + count >= *extentCount * superblock->blockSize) { + count = *extentCount * superblock->blockSize - i; + } + + if (!AccessBlock(volume, *extentStart + i / superblock->blockSize, count / superblock->blockSize, zeroBuffer, ES_FLAGS_DEFAULT, K_ACCESS_WRITE)) { + return false; + } + } + } + + return true; +} + +static bool FreeExtent(Volume *volume, uint64_t extentStart, uint64_t extentCount) { + // TODO Return EsError. + Superblock *superblock = &volume->superblock; + KWriterLockAssertExclusive(&volume->blockBitmapLock); + + uint64_t blockGroup = extentStart / superblock->blocksPerGroup; + + // Validate the extent. + + ESFS_CHECK((extentStart + extentCount - 1) / superblock->blocksPerGroup == blockGroup, "FreeExtent - Extent spans multiple block groups."); + ESFS_CHECK(extentCount < superblock->blocksUsed, "FreeExtent - Extent is larged than the number of used blocks."); + ESFS_CHECK(extentStart + extentCount < superblock->blockCount, "FreeExtent - Extent goes past end of the volume."); + + // Load the block bitmap. + + GroupDescriptor *target = volume->groupDescriptorTable + blockGroup; + ESFS_CHECK(ValidateGroupDescriptor(target), "FreeExtent - Invalid group descriptor."); + uint8_t *bitmap = (uint8_t *) EsHeapAllocate(superblock->blocksPerGroupBlockBitmap * superblock->blockSize, false, K_FIXED); + EsDefer(EsHeapFree(bitmap, 0, K_FIXED)); + ESFS_CHECK(bitmap, "FreeExtent - Could not allocate buffer for block bitmap."); + ESFS_CHECK(target->blockBitmap, "FreeExtent - Group descriptor does not have block bitmap."); + ESFS_CHECK(target->blocksUsed >= extentCount, "FreeExtent - Group descriptor indicates fewer blocks are used than are given in this extent."); + ESFS_CHECK(AccessBlock(volume, target->blockBitmap, superblock->blocksPerGroupBlockBitmap, bitmap, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "FreeExtent - Could not read block bitmap."); + ESFS_CHECK(ValidateBlockBitmap(target, bitmap, superblock), "FreeExtent - Invalid block bitmap."); + + // Clear the bits representing the freed blocks. + + for (uint64_t i = 0; i < extentCount; i++) { + uint64_t blockInGroup = (extentStart % superblock->blocksPerGroup) + i; + uint8_t bit = bitmap[blockInGroup / 8] & (1 << (blockInGroup % 8)); + ESFS_CHECK(bit, "FreeExtent - Attempting to free a block that has not been allocated."); + bitmap[blockInGroup / 8] &= ~(1 << (blockInGroup % 8)); + } + + // Write out the modified bitmap and update the group descriptor. + + if (!AccessBlock(volume, target->blockBitmap, superblock->blocksPerGroupBlockBitmap, bitmap, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE)) { + return false; + } + + target->largestExtent = FindLargestExtent(bitmap, superblock); + target->bitmapChecksum = CalculateCRC32(bitmap, superblock->blocksPerGroupBlockBitmap * superblock->blockSize); + target->blocksUsed -= extentCount; + target->checksum = 0; + target->checksum = CalculateCRC32(target, sizeof(GroupDescriptor)); + superblock->blocksUsed -= extentCount; + volume->fileSystem->spaceUsed -= extentCount * superblock->blockSize; + + return true; +} + +static uint64_t ResizeInternal(FSNode *file, uint64_t newSize, EsError *error, uint64_t newDataAttributeSize = 0) { + if (file->corrupt) return *error = ES_ERROR_CORRUPT_DATA, 0; + + Volume *volume = file->volume; + Superblock *superblock = &volume->superblock; + DirectoryEntry *entry = &file->entry; + + uint64_t oldSize = entry->fileSize; + + if (newDataAttributeSize && newSize != oldSize) { + KernelPanic("EsFS::ResizeInternal - Attempting to change data attribute and node size at the same time.\n"); + } + + if (!newDataAttributeSize && newSize == oldSize) { + // The file size hasn't changed. + return newSize; + } + + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(superblock->blockSize, true, K_FIXED); + EsDefer(EsHeapFree(blockBuffer, 0, K_FIXED)); + + *error = ES_ERROR_INSUFFICIENT_RESOURCES; + ESFS_CHECK(blockBuffer, "Resize - Could not allocate block buffer."); + + AttributeData *data = (AttributeData *) FindAttribute(entry, ESFS_ATTRIBUTE_DATA); + uint8_t *dataBuffer = (uint8_t *) data + data->dataOffset; + size_t dataBufferSize = data->size - data->dataOffset; + size_t newDataBufferSize = (newDataAttributeSize ? newDataAttributeSize : data->size) - data->dataOffset; + + if (newDataBufferSize >= newSize && entry->nodeType != ESFS_NODE_TYPE_DIRECTORY) { + if (data->indirection == ESFS_INDIRECTION_DIRECT) { + } else if (data->indirection == ESFS_INDIRECTION_L1) { + // Load the data from the indirect storage. + + if (entry->fileSize) { + if (!ReadWrite(file, 0, superblock->blockSize, blockBuffer, false, false)) { + return *error = ES_ERROR_DRIVE_ERROR_FILE_DAMAGED, entry->fileSize; + } + } + + // Free the extents. + + uint64_t previousExtentStart = 0, extentCount = 0, position = 0; + + for (uintptr_t i = 0; i < data->count; i++) { + if (!DecodeExtent(&previousExtentStart, &extentCount, dataBuffer, &position, dataBufferSize)) { + file->corrupt = true; + *error = ES_ERROR_CORRUPT_DATA; + return (entry->fileSize = 0); + } + + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE)); + + if (!FreeExtent(volume, previousExtentStart, extentCount)) { + file->corrupt = true; + entry->fileSize = 0; + *error = ES_ERROR_DRIVE_ERROR_FILE_DAMAGED; + return (entry->fileSize = 0); + } + } + + // Store the existing data in the entry. + + EsMemoryCopy(dataBuffer, blockBuffer, newSize); + } else { + *error = ES_ERROR_UNSUPPORTED_FEATURE; + return entry->fileSize; // Unrecognised indirection. + } + + data->indirection = ESFS_INDIRECTION_DIRECT; + data->count = newSize; + + // Zero out everything past the new size. + EsMemoryZero(dataBuffer + newSize, newDataBufferSize - newSize); + } else { + uint64_t oldBlocks = (entry->fileSize + superblock->blockSize - 1) / superblock->blockSize; + uint64_t newBlocks = (newSize + superblock->blockSize - 1) / superblock->blockSize; + bool copyData = false; + + if (data->indirection == ESFS_INDIRECTION_DIRECT) { + if (!ReadWrite(file, 0, entry->fileSize, blockBuffer, false, false)) { + *error = ES_ERROR_DRIVE_ERROR_FILE_DAMAGED; + return entry->fileSize; + } + + copyData = entry->fileSize > 0; + data->count = 0; + oldBlocks = 0; + entry->fileSize = 0; + } else if (data->indirection != ESFS_INDIRECTION_L1) { + *error = ES_ERROR_UNSUPPORTED_FEATURE; + return entry->fileSize; // Unrecognised indirection. + } + + if (oldBlocks < newBlocks) { + uint64_t previousExtentStart = 0, oldPreviousExtentStart = 0, extentCount = 0, position = 0, previousPosition = 0; + + for (uintptr_t i = 0; i < data->count; i++) { + previousPosition = position; + oldPreviousExtentStart = previousExtentStart; + + if (!DecodeExtent(&previousExtentStart, &extentCount, dataBuffer, &position, dataBufferSize)) { + *error = ES_ERROR_CORRUPT_DATA; + return entry->fileSize; + } + } + + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE)); + + uint64_t remaining = newBlocks - oldBlocks; + + if (superblock->blocksUsed + remaining >= superblock->blockCount) { + // There isn't enough space to grow the file. + *error = ES_ERROR_DRIVE_FULL; + return entry->fileSize; + } + + while (remaining) { + uint64_t allocatedStart, allocatedCount; + + bool success = AllocateExtent(volume, + previousExtentStart + extentCount /* Attempt to allocate near the end of the last extent */, + remaining /* Attempt to get an extent covering all the remaining blocks */, + &allocatedStart, &allocatedCount, true /* Zero the blocks */); + + if (!success) { + *error = ES_ERROR_DRIVE_ERROR_FILE_DAMAGED; + return entry->fileSize; + } + + if (previousExtentStart + extentCount == allocatedStart) { + // We need to grow the previous extent. + + allocatedStart = previousExtentStart; + previousExtentStart = oldPreviousExtentStart; + remaining += extentCount; + allocatedCount += extentCount; + position = previousPosition; + data->count--; + } + + oldPreviousExtentStart = previousExtentStart; + uint8_t encode[32]; + uint64_t length = EncodeExtent(allocatedStart, previousExtentStart, allocatedCount, encode); + + if (length + position > newDataBufferSize) { + // The data buffer is full. + *error = ES_ERROR_FILE_TOO_FRAGMENTED; + return entry->fileSize; + } else { + EsMemoryCopy(dataBuffer + position, encode, length); + previousPosition = position; + position += length; + data->count++; + remaining -= allocatedCount; + entry->fileSize += allocatedCount * superblock->blockSize; + previousExtentStart = allocatedStart; + } + } + } else if (oldBlocks > newBlocks) { + uint64_t previousExtentStart = 0, extentCount = 0, + position = 0, blockInFile = 0; + + file->corrupt = true; + entry->fileSize = 0; + *error = ES_ERROR_DRIVE_ERROR_FILE_DAMAGED; + + // Free the removed extents. + + for (uintptr_t i = 0; i < data->count; i++) { + if (!DecodeExtent(&previousExtentStart, &extentCount, dataBuffer, &position, dataBufferSize)) { + return 0; + } + + if (blockInFile + extentCount > newBlocks) { + uint64_t extentStart = previousExtentStart, extentCount2 = extentCount; + + if (blockInFile < newBlocks) { + extentStart += newBlocks - blockInFile; + extentCount2 -= newBlocks - blockInFile; + } + + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE)); + + if (!FreeExtent(volume, extentStart, extentCount2)) { + return 0; + } + } + + blockInFile += extentCount; + } + + // Modify the last extent. + + previousExtentStart = 0, position = 0, blockInFile = 0; + + for (uintptr_t i = 0; i < data->count; i++) { + uint64_t previousPosition = position, lastExtentStart = previousExtentStart; + + if (!DecodeExtent(&previousExtentStart, &extentCount, dataBuffer, &position, dataBufferSize)) { + return 0; + } + + if (blockInFile + extentCount > newBlocks) { + uint64_t extentStart = previousExtentStart; + + if (blockInFile < newBlocks) { + uint8_t encode[32]; + uint64_t length = EncodeExtent(extentStart, lastExtentStart, newBlocks - blockInFile, encode); + EsMemoryCopy(dataBuffer + previousPosition, encode, length); + data->count = i + 1; + break; + } else { + data->count = i; + break; + } + } + + blockInFile += extentCount; + } + } else { + // Do nothing. + } + + data->indirection = ESFS_INDIRECTION_L1; + + if (copyData) { + if (!ReadWrite(file, 0, superblock->blockSize, blockBuffer, false, true)) { + // Rollback changes. + data->indirection = ESFS_INDIRECTION_DIRECT; + data->count = entry->fileSize = oldSize; + EsMemoryCopy(dataBuffer, blockBuffer, data->count); + *error = ES_ERROR_DRIVE_ERROR_FILE_DAMAGED; + return (entry->fileSize = oldSize); + } + } + } + + file->corrupt = false; + *error = ES_SUCCESS; + if (newDataAttributeSize) data->size = newDataAttributeSize; + return (entry->fileSize = newSize); +} + +static uint64_t Resize(KNode *node, uint64_t newSize, EsError *error) { + // EsPrint("Resize %s to %d\n", node->name.bytes, node->name.buffer, newSize); + return ResizeInternal((FSNode *) node->driverNode, newSize, error); +} + +static IndexKey *InsertKeyIntoVertex(uint64_t newKey, IndexVertex *vertex) { + // Find where in this vertex we should insert the key. + + int position; + + for (position = 0; position < vertex->count; position++) { + if (newKey < ESFS_VERTEX_KEY(vertex, position)->value) { + break; + } + } + + // Insert the key. + + IndexKey *insertionPosition = ESFS_VERTEX_KEY(vertex, position); + EsMemoryMove(insertionPosition, ESFS_VERTEX_KEY(vertex, vertex->count + 1), sizeof(IndexKey), true); + vertex->count++; + insertionPosition->value = newKey; + + return insertionPosition; +} + +static bool IndexModifyKey(Volume *volume, uint64_t newKey, DirectoryEntryReference reference, uint64_t rootBlock, uint8_t *buffer /* superblock->blockSize */) { + // TODO Return EsError. + if (!rootBlock) return false; // No index - the directory is empty? + + Superblock *superblock = &volume->superblock; + + // Get the root vertex. + IndexVertex *vertex = (IndexVertex *) buffer; + uint64_t block; + + if (!AccessBlock(volume, (block = rootBlock), 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) { + return false; + } + + int depth = 0; + + while (true) { + ESFS_CHECK(depth++ < ESFS_INDEX_MAX_DEPTH - 1, "IndexModifyKey - Reached tree max depth."); + + if (!ValidateIndexVertex(superblock, vertex)) return false; + IndexKey *keys = (IndexKey *) ((uint8_t *) vertex + vertex->offset); + + // For every key... + for (int i = 0; i <= vertex->count; i++) { + if (i == vertex->count || keys[i].value > newKey) { + if (keys[i].child) { + // The directory is in the child. + if (!AccessBlock(volume, (block = keys[i].child), 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) return false; + else goto nextVertex; + } else { + // We couldn't find the entry. + return false; + } + } else if (keys[i].value == newKey) { + // We've found the key. + ESFS_CHECK_CORRUPT(keys[i].data.block < superblock->blockCount + && keys[i].data.offsetIntoBlock + sizeof(DirectoryEntry) <= superblock->blockSize, + "IndexModifyKey - Invalid key entry."); + keys[i].data = reference; + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock->blockSize); + return AccessBlock(volume, block, 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE); + } + } + + nextVertex:; + } +} + +static bool IndexAddKey(Volume *volume, uint64_t newKey, DirectoryEntryReference reference, uint64_t *rootBlock) { + // TODO Return EsError. + // TODO Support KWorkGroup. + + // EsPrint("adding key %x\n", newKey); + + Superblock *superblock = &volume->superblock; + uint8_t *blockBuffers = (uint8_t *) EsHeapAllocate(superblock->blockSize * 3, true, K_FIXED); + EsDefer(EsHeapFree(blockBuffers, 0, K_FIXED)); + ESFS_CHECK(blockBuffers, "IndexAddKey - Could not allocate block buffers."); + + uint64_t _unused; + + // Find the leaf to insert the key into. + + uint8_t *buffer = blockBuffers + 0 * superblock->blockSize; + IndexVertex *vertex = (IndexVertex *) buffer; + uint64_t depth = 0, blocks[ESFS_INDEX_MAX_DEPTH] = { *rootBlock }; + bool skipFirst = false; + + if (blocks[0] == 0) { + // Directory is empty - create the root vertex. + + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + ESFS_CHECK(AllocateExtent(volume, 0 /* TODO */, 1, &blocks[0], &_unused, false), "IndexAddKey - Could not allocate space."); + KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + *rootBlock = blocks[0]; + vertex->maxCount = (superblock->blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; + vertex->offset = ESFS_INDEX_KEY_OFFSET; + EsMemoryCopy(vertex->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4); + skipFirst = true; + } + + { + next:; + + if (!skipFirst) { + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexAddKey - Could not read index."); + + if (!ValidateIndexVertex(superblock, vertex)) { + return false; + } + } + + for (int i = 0; i < vertex->count; i++) { + if (ESFS_VERTEX_KEY(vertex, i)->value == newKey) { + // The key is already in the tree. + // TODO Hash collisions. + ESFS_CHECK(false, "IndexAddKey - Possible hash collision?"); + } + } + + for (int i = 0; i <= vertex->count; i++) { + IndexKey *key = ESFS_VERTEX_KEY(vertex, i); + + if ((i == vertex->count || newKey < key->value) && key->child) { + ESFS_CHECK(depth < ESFS_INDEX_MAX_DEPTH - 1, "IndexAddKey - Reached tree max depth."); + + blocks[++depth] = key->child; + goto next; + } + } + } + + ESFS_CHECK(vertex->count < vertex->maxCount, "IndexAddKey - Vertex is full; unbalanced tree."); + + // Insert the key into the vertex. + + InsertKeyIntoVertex(newKey, vertex)->data = reference; + + // While the vertex is full... + + if (vertex->count > vertex->maxCount) { + KernelPanic("IndexAddKey - Corrupt vertex."); + } + + while (vertex->count == vertex->maxCount) { + // printf("\tsplit!\n"); + + uint8_t *_buffer0 = blockBuffers + 1 * superblock->blockSize; + uint8_t *_buffer1 = blockBuffers + 2 * superblock->blockSize; + + // Create a new sibling. + + uint64_t siblingBlock = 0; + + { + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE)); + ESFS_CHECK(AllocateExtent(volume, blocks[depth], 1, &siblingBlock, &_unused, false), "IndexAddKey - Could not allocate space."); + } + + IndexVertex *sibling = (IndexVertex *) _buffer0; + sibling->maxCount = (superblock->blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; + sibling->offset = ESFS_INDEX_KEY_OFFSET; + EsMemoryCopy(sibling->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4); + + // Load the parent vertex. + + bool newRoot = !depth; + IndexVertex *parent = (IndexVertex *) _buffer1; + + if (newRoot) { + // Create a new root block. + + blocks[1] = blocks[0]; + depth++; + + { + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE)); + ESFS_CHECK(AllocateExtent(volume, blocks[1], 1, &blocks[0], &_unused, false), "IndexAddKey - Could not allocate space."); + } + + parent->maxCount = (superblock->blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; + parent->offset = ESFS_INDEX_KEY_OFFSET; + EsMemoryCopy(parent->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4); + + // The superblock points to the new root, and the +1 key of the new root points to the old root. + // It has no other keys yet. + + parent->keys[0].child = blocks[1]; + *rootBlock = blocks[0]; + } else { + ESFS_CHECK(AccessBlock(volume, blocks[depth - 1], 1, parent, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexAddKey - Could not read index."); + } + + IndexKey *parentKeys = (IndexKey *) ((uint8_t *) parent + parent->offset); + IndexKey *vertexKeys = (IndexKey *) ((uint8_t *) vertex + vertex->offset); + IndexKey *siblingKeys = (IndexKey *) ((uint8_t *) sibling + sibling->offset); + + // Change the link to this vertex to point to the sibling. + + int found = 0; + + for (uint64_t i = 0; i <= parent->count; i++) { + if (parentKeys[i].child == blocks[depth]) { + parentKeys[i].child = siblingBlock; + found++; + } + } + + ESFS_CHECK(found == 1, "IndexAddKey - Could not find current vertex in its parent."); + + // Move the median key to the parent. + // If this makes the parent full we'll fix it next iteration. + + uint64_t median = (vertex->maxCount - 1) / 2; + uint64_t newKey = vertexKeys[median].value; + + for (uint64_t i = 0; i <= parent->count; i++) { + if (i == parent->count || newKey < parentKeys[i].value) { + parent->count++; + EsMemoryMove(parentKeys + i, parentKeys + parent->count, sizeof(IndexKey), true); + parentKeys[i].value = newKey; + parentKeys[i].data = vertexKeys[median].data; + parentKeys[i].child = blocks[depth]; + break; + } + } + + // Move all keys above the median key to the new sibling. + + sibling->count = vertex->count - median /*Kept in the node*/ - 1 /*Added to the parent*/; + vertex->count = median; // The data on the median key becomes the +1 key's data. + EsMemoryCopy(siblingKeys, vertexKeys + median + 1, (sibling->count + 1) * sizeof(IndexKey)); + + // Write the blocks. + + sibling->checksum = 0; sibling->checksum = CalculateCRC32(sibling, superblock->blockSize); + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock->blockSize); + ESFS_CHECK(AccessBlock(volume, siblingBlock, 1, sibling, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexAddKey - Could not update index."); + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexAddKey - Could not update index."); + + // Check if the parent vertex is full. + + EsMemoryCopy(vertex, parent, superblock->blockSize); + depth--; + } + + // Write the block. + + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock->blockSize); + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexAddKey - Could not update index."); + + return true; +} + +static bool IndexRemoveKey(Volume *volume, uint64_t removeKey, uint64_t *rootBlock) { + // TODO Return EsError. + // TODO Support KWorkGroup. + + Superblock *superblock = &volume->superblock; + uint8_t *blockBuffers = (uint8_t *) EsHeapAllocate(superblock->blockSize * 3, true, K_FIXED); + EsDefer(EsHeapFree(blockBuffers, 0, K_FIXED)); + ESFS_CHECK(blockBuffers, "IndexRemoveKey - Could not allocate block buffers."); + + // Find the vertex that contains this key. + + uint8_t *buffer = blockBuffers + 0 * superblock->blockSize; + IndexVertex *vertex = (IndexVertex *) buffer; + uint64_t depth = 0, blocks[ESFS_INDEX_MAX_DEPTH] = { *rootBlock }; + ESFS_CHECK(blocks[0], "IndexRemoveKey - Index has no root."); + int position = 0; + + { + next:; + int i; + + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexRemoveKey - Could not read index."); + if (!ValidateIndexVertex(superblock, vertex)) return false; + + for (i = 0; i <= vertex->count; i++) { + IndexKey *key = ESFS_VERTEX_KEY(vertex, i); + + if (i != vertex->count && key->value == removeKey) { + // EsPrint("found key %x at depth %d block %d position %d\n", removeKey, depth, blocks[depth], i); + goto done; + } else if ((i == vertex->count || removeKey < key->value) && key->child) { + ESFS_CHECK(depth < ESFS_INDEX_MAX_DEPTH - 1, "IndexRemoveKey - Reached tree max depth."); + blocks[++depth] = key->child; + // EsPrint("recurse into block %d at depth %d position %d\n", blocks[depth], depth, i); + goto next; + } + } + + ESFS_CHECK(false, "IndexRemoveKey - The key was not in the tree."); + done:; + position = i; + } + + if (ESFS_VERTEX_KEY(vertex, position)->child) { + // If the removed key has children, replace it with the smallest above, then consider that leaf. + + uint64_t startDepth = depth; + uint8_t *buffer2 = blockBuffers + 1 * superblock->blockSize; + IndexVertex *search = (IndexVertex *) buffer2; + blocks[++depth] = ESFS_VERTEX_KEY(vertex, position + 1)->child; + + while (true) { + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, search, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexRemoveKey - Could not read index."); + if (!ValidateIndexVertex(superblock, search)) return false; + + if (ESFS_VERTEX_KEY(search, 0)->child) { + ESFS_CHECK(depth < ESFS_INDEX_MAX_DEPTH - 1, "IndexRemoveKey - Reached tree max depth."); + blocks[++depth] = ESFS_VERTEX_KEY(vertex, 1)->child; + } else break; + } + + ESFS_VERTEX_KEY(vertex, position)->value = ESFS_VERTEX_KEY(search, 0)->value; + ESFS_VERTEX_KEY(vertex, position)->data = ESFS_VERTEX_KEY(search, 0)->data; + + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock->blockSize); + ESFS_CHECK(AccessBlock(volume, blocks[startDepth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + + EsMemoryCopy(vertex, search, superblock->blockSize); + position = 0; + } + + // Remove the key. + + // EsPrint("Removing key from vertex...\n"); + EsMemoryMove(ESFS_VERTEX_KEY(vertex, position + 1), ESFS_VERTEX_KEY(vertex, vertex->count + 1), ES_MEMORY_MOVE_BACKWARDS sizeof(IndexKey), true); + vertex->count--; + + repeat:; + + // If the vertex still has enough keys, return. + + if (vertex->count >= (vertex->maxCount - 1) / 2) { + // EsPrint("Vertex has enough keys, exiting...\n"); + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock->blockSize); + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + return true; + } + + // If the we reach the root of the tree, we're done. + + if (depth == 0) { + if (!vertex->count && vertex->keys[0].child) { + // Reduce the height of the tree. + + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE)); + ESFS_CHECK(FreeExtent(volume, blocks[0], 1), "IndexRemoveKey - Could not free the old root index block."); + *rootBlock = vertex->keys[0].child; + } else { + // EsPrint("Vertex is at root, exiting...\n"); + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock->blockSize); + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + } + + return true; + } + + // Find the position of vertex in its parent. + + uint8_t *buffer2 = blockBuffers + 1 * superblock->blockSize; + IndexVertex *parent = (IndexVertex *) buffer2; + ESFS_CHECK(AccessBlock(volume, blocks[depth - 1], 1, parent, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexRemoveKey - Could not read index."); + if (!ValidateIndexVertex(superblock, parent)) return false; + + int positionInParent = -1; + + for (int i = 0; i <= parent->count; i++) { + if (ESFS_VERTEX_KEY(parent, i)->child == blocks[depth]) { + positionInParent = i; + break; + } + } + + ESFS_CHECK(positionInParent != -1, "IndexRemoveKey - Could not find position in parent."); + + uint8_t *buffer3 = blockBuffers + 2 * superblock->blockSize; + IndexVertex *sibling = (IndexVertex *) buffer3; + + if (positionInParent) { + ESFS_CHECK(AccessBlock(volume, ESFS_VERTEX_KEY(parent, positionInParent - 1)->child, 1, sibling, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexRemoveKey - Could not read index."); + + if (sibling->count > (sibling->maxCount - 1) / 2) { + // Steal left. + + EsMemoryMove(ESFS_VERTEX_KEY(vertex, 0), ESFS_VERTEX_KEY(vertex, vertex->count + 1), sizeof(IndexKey), true); + + ESFS_VERTEX_KEY(vertex, 0)-> value = ESFS_VERTEX_KEY(parent, positionInParent - 1)-> value; + ESFS_VERTEX_KEY(vertex, 0)-> data = ESFS_VERTEX_KEY(parent, positionInParent - 1)-> data; + ESFS_VERTEX_KEY(vertex, 0)-> child = ESFS_VERTEX_KEY(sibling, sibling->count)-> child; + ESFS_VERTEX_KEY(parent, positionInParent - 1)-> value = ESFS_VERTEX_KEY(sibling, sibling->count - 1)-> value; + ESFS_VERTEX_KEY(parent, positionInParent - 1)-> data = ESFS_VERTEX_KEY(sibling, sibling->count - 1)-> data; + + sibling->count--, vertex->count++; + + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock->blockSize); + sibling->checksum = 0; sibling->checksum = CalculateCRC32(sibling, superblock->blockSize); + parent->checksum = 0; parent->checksum = CalculateCRC32(parent, superblock->blockSize); + + ESFS_CHECK(AccessBlock(volume, ESFS_VERTEX_KEY(parent, positionInParent - 1)->child, 1, sibling, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + ESFS_CHECK(AccessBlock(volume, blocks[depth - 1], 1, parent, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + + return true; + } + } + + if (positionInParent != parent->count) { + ESFS_CHECK(AccessBlock(volume, ESFS_VERTEX_KEY(parent, positionInParent + 1)->child, 1, sibling, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexRemoveKey - Could not read index."); + + if (sibling->count > (sibling->maxCount - 1) / 2) { + // Steal right. + + ESFS_VERTEX_KEY(vertex, vertex->count)-> value = ESFS_VERTEX_KEY(parent, positionInParent)-> value; + ESFS_VERTEX_KEY(vertex, vertex->count)-> data = ESFS_VERTEX_KEY(parent, positionInParent)-> data; + ESFS_VERTEX_KEY(vertex, vertex->count + 1)-> child = ESFS_VERTEX_KEY(sibling, 0)-> child; + ESFS_VERTEX_KEY(parent, positionInParent)-> value = ESFS_VERTEX_KEY(sibling, 0)-> value; + ESFS_VERTEX_KEY(parent, positionInParent)-> data = ESFS_VERTEX_KEY(sibling, 0)-> data; + + EsMemoryMove(ESFS_VERTEX_KEY(sibling, 1), ESFS_VERTEX_KEY(sibling, sibling->count + 1), ES_MEMORY_MOVE_BACKWARDS sizeof(IndexKey), true); + + sibling->count--, vertex->count++; + + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock->blockSize); + sibling->checksum = 0; sibling->checksum = CalculateCRC32(sibling, superblock->blockSize); + parent->checksum = 0; parent->checksum = CalculateCRC32(parent, superblock->blockSize); + + ESFS_CHECK(AccessBlock(volume, ESFS_VERTEX_KEY(parent, positionInParent + 1)->child, 1, sibling, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + ESFS_CHECK(AccessBlock(volume, blocks[depth - 1], 1, parent, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + + return true; + } + } + + { + // Merge nodes. + + if (!positionInParent) { + EsMemoryCopy(sibling, vertex, superblock->blockSize); + positionInParent = 1; + blocks[depth] = ESFS_VERTEX_KEY(parent, positionInParent)->child; + ESFS_CHECK(AccessBlock(volume, blocks[depth], 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexRemoveKey - Could not read index."); + if (!ValidateIndexVertex(superblock, vertex)) return false; + } else { + ESFS_CHECK(AccessBlock(volume, ESFS_VERTEX_KEY(parent, positionInParent - 1)->child, 1, sibling, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "IndexRemoveKey - Could not read index."); + if (!ValidateIndexVertex(superblock, sibling)) return false; + } + + // TODO I'm fairly certain this won't happen (as we should have stolen a key), but it needs to be double-checked. + ESFS_CHECK(sibling->count + vertex->count + 1 < sibling->maxCount, "IndexRemoveKey - Merged node would be too large."); + + ESFS_VERTEX_KEY(sibling, sibling->count)-> value = ESFS_VERTEX_KEY(parent, positionInParent - 1)->value; + ESFS_VERTEX_KEY(sibling, sibling->count)-> data = ESFS_VERTEX_KEY(parent, positionInParent - 1)->data; + ESFS_VERTEX_KEY(parent, positionInParent)-> child = ESFS_VERTEX_KEY(parent, positionInParent - 1)->child; + + EsMemoryCopy(ESFS_VERTEX_KEY(sibling, sibling->count + 1), ESFS_VERTEX_KEY(vertex, 0), (vertex->count + 1) * sizeof(IndexKey)); + EsMemoryMove(ESFS_VERTEX_KEY(parent, positionInParent), ESFS_VERTEX_KEY(parent, parent->count + 1), ES_MEMORY_MOVE_BACKWARDS sizeof(IndexKey), true); + + sibling->count += vertex->count + 1, parent->count--; + + { + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE)); + ESFS_CHECK(FreeExtent(volume, blocks[depth], 1), "IndexRemoveKey - Could not free merged vertex."); + } + + sibling->checksum = 0; sibling->checksum = CalculateCRC32(sibling, superblock->blockSize); + ESFS_CHECK(AccessBlock(volume, ESFS_VERTEX_KEY(parent, positionInParent - 1)->child, 1, sibling, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "IndexRemoveKey - Could not write index."); + + EsMemoryCopy(vertex, parent, superblock->blockSize); + depth--; + + goto repeat; + } +} + +static EsError RemoveDirectoryEntry(FSNode *file, uint8_t *blockBuffers /* superblock->blockSize * 2 */, FSNode *directory, KNode *_directory) { + // EsPrint("RemoveDirectoryEntry for %s from %s\n", node->name.bytes, node->name.buffer, + // node->parent->name.bytes, node->parent->name.buffer); + + Volume *volume = file->volume; + Superblock *superblock = &volume->superblock; + DirectoryEntry *entry = &file->entry; + AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory->entry, ESFS_ATTRIBUTE_DIRECTORY); + EsError error; + + // EsPrint("\tChildren = %d\n", directoryAttribute->childNodes); + + // Step 1: Replace the directory entry with the last entry in the directory. + + uint64_t positionOfLastEntry = (directoryAttribute->childNodes - 1) * sizeof(DirectoryEntry); + + // EsPrint("\tpositionOfLastEntry = %d\n\tThis node Reference = %d/%d\n", positionOfLastEntry, file->reference.block, file->reference.offsetIntoBlock); + + ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, BLOCK_ACCESS_CACHED, K_ACCESS_READ), "Remove - Could not load the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED); + ESFS_CHECK_TO_ERROR(ReadWrite(directory, positionOfLastEntry & ~(superblock->blockSize - 1), superblock->blockSize, + blockBuffers + superblock->blockSize, false, false), "Remove - Could not load the last block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED); + ESFS_CHECK_TO_ERROR(0 == EsMemoryCompare(blockBuffers + file->reference.offsetIntoBlock, &file->entry, sizeof(DirectoryEntry)), "Remove - Inconsistent file entry.", ES_ERROR_DRIVE_CONTROLLER_REPORTED); + + DirectoryEntry *movedEntry = (DirectoryEntry *) (blockBuffers + superblock->blockSize + (positionOfLastEntry & (superblock->blockSize - 1))); + DirectoryEntry *deletedEntry = (DirectoryEntry *) (blockBuffers + file->reference.offsetIntoBlock); + EsMemoryCopy(deletedEntry, movedEntry, sizeof(DirectoryEntry)); + ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "Remove - Could not save the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED); + + // Step 2: Update the node for the moved entry. + + if (EsMemoryCompare(movedEntry->identifier.d, entry->identifier.d, sizeof(EsUniqueIdentifier))) { + AttributeFilename *filename = (AttributeFilename *) FindAttribute(movedEntry, ESFS_ATTRIBUTE_FILENAME); + + if (filename) { + KNode *node = nullptr; + + FSDirectoryEntryFound(_directory, nullptr, &file->reference, + (const char *) filename->filename, filename->length, true, &node); + + if (node) { + ((FSNode *) node->driverNode)->reference = file->reference; + } + + uint64_t key = CalculateCRC64(filename->filename, filename->length); + // EsPrint("\tModify index key for %s\n", filename->length, filename->filename); + ESFS_CHECK_TO_ERROR(IndexModifyKey(volume, key, file->reference, directoryAttribute->indexRootBlock, blockBuffers + superblock->blockSize), "Remove - Could not update index (2).", ES_ERROR_DRIVE_CONTROLLER_REPORTED); + } + } + + // Step 3: Decrease the size of the directory. + + directoryAttribute->childNodes--; + + if (!(directoryAttribute->childNodes % superblock->directoryEntriesPerBlock)) { + uint64_t newSize = directory->entry.fileSize - superblock->blockSize; + ESFS_CHECK_TO_ERROR(newSize == ResizeInternal(directory, newSize, &error), "Remove - Could not resize directory.", ES_ERROR_DRIVE_CONTROLLER_REPORTED); + } + + // Step 4: Remove the entry from the index. + + AttributeFilename *filename = (AttributeFilename *) FindAttribute(entry, ESFS_ATTRIBUTE_FILENAME); + // EsPrint("\tRemoving %s from index\n", filename->length, filename->filename); + + if (filename) { + uint64_t removeKey = CalculateCRC64(filename->filename, filename->length); + ESFS_CHECK_TO_ERROR(IndexRemoveKey(volume, removeKey, &directoryAttribute->indexRootBlock), "Remove - Could not update index.", ES_ERROR_DRIVE_CONTROLLER_REPORTED); + } + + return ES_SUCCESS; +} + +static EsError Remove(KNode *_directory, KNode *node) { + FSNode *directory = (FSNode *) _directory->driverNode; + FSNode *file = (FSNode *) node->driverNode; + Volume *volume = file->volume; + Superblock *superblock = &volume->superblock; + DirectoryEntry *entry = &file->entry; + AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory->entry, ESFS_ATTRIBUTE_DIRECTORY); + ESFS_CHECK_TO_ERROR(directoryAttribute->childNodes, "Remove - Directory is empty.", ES_ERROR_CORRUPT_DATA); + + uint8_t *blockBuffers = (uint8_t *) EsHeapAllocate(superblock->blockSize * 2, false, K_FIXED); + if (!blockBuffers) return ES_ERROR_INSUFFICIENT_RESOURCES; + EsDefer(EsHeapFree(blockBuffers, 0, K_FIXED)); + + // Step 1: If we're deleting a directory, deallocate its empty index. + + if (entry->nodeType == ESFS_NODE_TYPE_DIRECTORY) { + AttributeDirectory *attribute = (AttributeDirectory *) FindAttribute(entry, ESFS_ATTRIBUTE_DIRECTORY); + ESFS_CHECK_TO_ERROR(!attribute->childNodes, "Remove - Directory was not empty.", ES_ERROR_CORRUPT_DATA); + + if (attribute->indexRootBlock) { + IndexVertex *vertex = (IndexVertex *) blockBuffers; + ESFS_CHECK_TO_ERROR(AccessBlock(volume, attribute->indexRootBlock, 1, vertex, BLOCK_ACCESS_CACHED, K_ACCESS_READ), + "Remove - Could not access index root.", ES_ERROR_DRIVE_CONTROLLER_REPORTED); + ESFS_CHECK_TO_ERROR(!vertex->count, "Remove - Index was not empty (although it should be as the directory is empty).", ES_ERROR_CORRUPT_DATA); + KWriterLockTake(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&volume->blockBitmapLock, K_LOCK_EXCLUSIVE)); + ESFS_CHECK_TO_ERROR(FreeExtent(volume, attribute->indexRootBlock, 1), + "Remove - Could not free the root index block.", ES_ERROR_UNKNOWN); + } + } + + // Step 2: Truncate the node to 0 bytes. + + EsError error; + + if (ResizeInternal(file, 0, &error)) { + ESFS_CHECK_TO_ERROR(false, "Remove - Could not resize node.", error); + } + + // Step 3: Sync the file, and remove its directory entry. + + Sync(_directory, node); + return RemoveDirectoryEntry(file, blockBuffers, directory, _directory); +} + +static bool RenameInternal(FSNode *existingNode, DirectoryEntry *entry, const void *name, size_t nameLength) { + // Size of name + size of header, rounded up to the nearest 8 bytes. + size_t newFilenameSize = ((nameLength + ESFS_FILENAME_HEADER_SIZE - 1) & ~7) + 8; + + AttributeFilename *filename = (AttributeFilename *) FindAttribute(entry, ESFS_ATTRIBUTE_FILENAME); + AttributeData *data = (AttributeData *) FindAttribute(entry, ESFS_ATTRIBUTE_DATA); + + if (filename && data && (uint8_t *) filename - (uint8_t *) data == data->size) { + // TODO Improve this. + // TODO Renaming directories does not work! + + intptr_t filenameSizeChange = newFilenameSize - filename->size; + size_t newDataSize = data->size - filenameSizeChange; + + EsError error; + ESFS_CHECK(existingNode->entry.fileSize == ResizeInternal(existingNode, existingNode->entry.fileSize, &error, newDataSize), + "CreateInternal - Could not resize data attribute."); + ESFS_CHECK(error == ES_SUCCESS, "CreateInternal - Could not resize data attribute."); + + AttributeFilename *filename = (AttributeFilename *) ((uint8_t *) data + data->size); + filename->type = ESFS_ATTRIBUTE_FILENAME; + filename->size = newFilenameSize; + filename->length = nameLength; + EsMemoryCopy(filename->filename, name, filename->length); + } else { + ESFS_CHECK(false, "CreateInternal - Could not rename node."); + } + + return true; +} + +static bool CreateInternal(const char *name, size_t nameLength, EsNodeType type, FSNode *parent, uint8_t *buffer /* superblock->blockSize */, + FSNode *existingNode = nullptr, DirectoryEntryReference *outReference = nullptr) { + // TODO Return EsError. + Volume *volume = parent->volume; + Superblock *superblock = &volume->superblock; + EsError error; + + if (type != ES_NODE_DIRECTORY && type != ES_NODE_FILE) { + return false; + } + + AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&parent->entry, ESFS_ATTRIBUTE_DIRECTORY); + + // Resize the directory so that it can fit another directory entry. + + if (!(directoryAttribute->childNodes % superblock->directoryEntriesPerBlock)) { + uint64_t newSize = parent->entry.fileSize + superblock->blockSize; + ESFS_CHECK(newSize == ResizeInternal(parent, newSize, &error), "Create - Could not resize directory."); + } + + DirectoryEntry *entry = nullptr; + size_t newFilenameSize = ((nameLength + ESFS_FILENAME_HEADER_SIZE - 1) & ~7) + 8; // Size of name + size of header, rounded up to the nearest 8 bytes. + + if (!existingNode) { + // Create the directory entry. + + entry = (DirectoryEntry *) buffer; // NOTE This must use the provided buffer; see Create. + EsMemoryZero(entry, sizeof(DirectoryEntry)); + + EsMemoryCopy(entry->signature, ESFS_DIRECTORY_ENTRY_SIGNATURE, 8); + + { + KMutexAcquire(&volume->nextIdentifierMutex); + + entry->identifier = superblock->nextIdentifier; + + for (int i = 0; i < 16; i++) { + superblock->nextIdentifier.d[i]++; + if (superblock->nextIdentifier.d[i]) break; + } + + KMutexRelease(&volume->nextIdentifierMutex); + } + + entry->attributeOffset = ESFS_ATTRIBUTE_OFFSET; + entry->nodeType = type == ES_NODE_DIRECTORY ? ESFS_NODE_TYPE_DIRECTORY : ESFS_NODE_TYPE_FILE; + entry->parent = parent->identifier; + + uint8_t *position = entry->attributes; + + if (entry->nodeType == ESFS_NODE_TYPE_DIRECTORY) { + AttributeDirectory *directory = (AttributeDirectory *) position; + directory->type = ESFS_ATTRIBUTE_DIRECTORY; + directory->size = sizeof(AttributeDirectory); + directory->indexRootBlock = 0; + entry->attributeCount++; + position += directory->size; + } + + AttributeData *data = (AttributeData *) position; + data->type = ESFS_ATTRIBUTE_DATA; + data->size = sizeof(DirectoryEntry) - newFilenameSize - (position - (uint8_t *) entry); + data->indirection = ESFS_INDIRECTION_DIRECT; + data->dataOffset = ESFS_DATA_OFFSET; + entry->attributeCount++; + position += data->size; + + AttributeFilename *filename = (AttributeFilename *) position; + filename->type = ESFS_ATTRIBUTE_FILENAME; + filename->size = newFilenameSize; + filename->length = nameLength; + EsMemoryCopy(filename->filename, name, filename->length); + entry->attributeCount++; + position += filename->size; + + if (position - (uint8_t *) entry != sizeof(DirectoryEntry)) KernelPanic("EsFS::CreateInternal - Directory entry has incorrect size.\n"); + } else { + // Update the existing directory entry. + + entry = &existingNode->entry; + entry->parent = parent->identifier; + + if (!RenameInternal(existingNode, entry, name, nameLength)) { + return false; + } + } + + entry->checksum = 0; + entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry)); + if (!ValidateDirectoryEntry(entry)) KernelPanic("EsFS::CreateInternal - Created directory entry is invalid.\n"); + + // Write the directory entry. + + DirectoryEntryReference reference = {}; + ESFS_CHECK(ReadWrite(parent, directoryAttribute->childNodes * sizeof(DirectoryEntry), + sizeof(DirectoryEntry), (uint8_t *) entry, true, true, &reference), "Create - Could not update directory."); + if (existingNode) existingNode->reference = reference; + + // Add the node into the index. + + uint64_t newKey = CalculateCRC64(name, nameLength); + ESFS_CHECK(IndexAddKey(volume, newKey, reference, &directoryAttribute->indexRootBlock), "Create - Could not add file to index."); + + directoryAttribute->childNodes++; + + if (outReference) { + *outReference = reference; + } + + return true; +} + +static EsError Move(KNode *_oldDirectory, KNode *_file, KNode *_newDirectory, const char *newName, size_t newNameLength) { + FSNode *file = (FSNode *) _file->driverNode; + FSNode *newDirectory = (FSNode *) _newDirectory->driverNode; + FSNode *oldDirectory = (FSNode *) _oldDirectory->driverNode; + + Volume *volume = file->volume; + Superblock *superblock = &volume->superblock; + + if (oldDirectory->type != ES_NODE_DIRECTORY || newDirectory->type != ES_NODE_DIRECTORY) KernelPanic("EsFS::Move - Incorrect node types.\n"); + + file->entry.checksum = 0; + file->entry.checksum = CalculateCRC32(&file->entry, sizeof(DirectoryEntry)); + if (!ValidateDirectoryEntry(&file->entry)) KernelPanic("EsFS::Move - Existing entry is invalid.\n"); + + uint8_t *buffers = (uint8_t *) EsHeapAllocate(superblock->blockSize * 2, true, K_FIXED); + if (!buffers) return ES_ERROR_INSUFFICIENT_RESOURCES; + EsDefer(EsHeapFree(buffers, 0, K_FIXED)); + + // Remove the node from the old directory. + + Sync(_oldDirectory, _file); + ESFS_CHECK_ERROR(RemoveDirectoryEntry(file, buffers, oldDirectory, _oldDirectory), "Move - Could not remove old directory entry."); + + // Add the node to the new directory. + + DirectoryEntryReference reference = {}; + ESFS_CHECK_TO_ERROR(CreateInternal(newName, newNameLength, file->type, newDirectory, nullptr, + file, &reference), "Move - Could not create new directory entry.", ES_ERROR_UNKNOWN); + FSNodeUpdateDriverData(_file, &reference); + + return ES_SUCCESS; +} + +static void Close(KNode *node) { + EsHeapFree(node->driverNode, sizeof(FSNode), K_FIXED); +} + +static EsError LoadInternal(Volume *volume, KNode *_node, DirectoryEntry *entry, DirectoryEntryReference reference) { + FSNode *node = (FSNode *) EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!node) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + _node->driverNode = node; + node->reference = reference; + node->volume = volume; + node->identifier = entry->identifier; + node->type = entry->nodeType == ESFS_NODE_TYPE_DIRECTORY ? ES_NODE_DIRECTORY : ES_NODE_FILE; + EsMemoryCopy(&node->entry, entry, sizeof(DirectoryEntry)); + return ES_SUCCESS; +} + +static EsError Load(KNode *_directory, KNode *_node, KNodeMetadata *, const void *entryData) { + DirectoryEntryReference reference = *(DirectoryEntryReference *) entryData; + FSNode *directory = (FSNode *) _directory->driverNode; + Superblock *superblock = &directory->volume->superblock; + + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(superblock->blockSize, false, K_FIXED); + if (!blockBuffer) return ES_ERROR_INSUFFICIENT_RESOURCES; + EsDefer(EsHeapFree(blockBuffer, 0, K_FIXED)); + + if (!AccessBlock(directory->volume, reference.block, 1, blockBuffer, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) { + KernelLog(LOG_ERROR, "EsFS", "drive access failure", "Load - Could not load directory entry.\n"); + return ES_ERROR_UNKNOWN; + } + + DirectoryEntry *entry = (DirectoryEntry *) (blockBuffer + reference.offsetIntoBlock); + + if (!ValidateDirectoryEntry(entry)) { + return ES_ERROR_CORRUPT_DATA; + } + + if ((entry->nodeType == ESFS_NODE_TYPE_DIRECTORY && !FindAttribute(entry, ESFS_ATTRIBUTE_DIRECTORY)) + || (entry->nodeType == ESFS_NODE_TYPE_FILE && !FindAttribute(entry, ESFS_ATTRIBUTE_DATA))) { + KernelLog(LOG_ERROR, "EsFS", "damaged file system", "Load - Node is missing attribute.\n"); + return ES_ERROR_CORRUPT_DATA; + } + + return LoadInternal(directory->volume, _node, entry, reference); +} + +static EsError Create(const char *name, size_t nameLength, EsNodeType type, KNode *_parent, KNode *node, void *driverData) { + FSNode *parent = (FSNode *) _parent->driverNode; + if (!parent) return ES_ERROR_UNKNOWN; + Volume *volume = parent->volume; + Superblock *superblock = &volume->superblock; + + uint8_t *buffer = (uint8_t *) EsHeapAllocate(superblock->blockSize, true, K_FIXED); + if (!buffer) return ES_ERROR_INSUFFICIENT_RESOURCES; + EsDefer(EsHeapFree(buffer, 0, K_FIXED)); + + DirectoryEntryReference reference = {}; + + if (!CreateInternal(name, nameLength, type, parent, buffer, nullptr, &reference)) { + return ES_ERROR_UNKNOWN; + } + + EsMemoryCopy(driverData, &reference, sizeof(DirectoryEntryReference)); + return LoadInternal(volume, node, (DirectoryEntry *) buffer, reference); +} + +static EsError Scan(const char *name, size_t nameLength, KNode *_directory) { + // EsPrint("Scan: %s, %x\n", offsetToName + nameLength, name, _directory); + + DirectoryEntryReference reference = {}; + FSNode *directory = (FSNode *) _directory->driverNode; + if (directory->corrupt) return ES_ERROR_CORRUPT_DATA; + Volume *volume = directory->volume; + Superblock *superblock = &volume->superblock; + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(superblock->blockSize, false, K_FIXED); + if (!blockBuffer) return ES_ERROR_INSUFFICIENT_RESOURCES; + EsDefer(EsHeapFree(blockBuffer, 0, K_FIXED)); + + AttributeDirectory *attributeDirectory = (AttributeDirectory *) FindAttribute(&directory->entry, ESFS_ATTRIBUTE_DIRECTORY); + EsError error = FindDirectoryEntryReferenceFromIndex(volume, blockBuffer, &reference, name, nameLength, attributeDirectory->indexRootBlock); + + if (error != ES_SUCCESS) { + // EsPrint("\tCould not find in directory. (%d - %s)\n", error, nameLength, name); + return error; + } + + // EsPrint("\t%d/%d\n", reference.block, reference.offsetIntoBlock); + + if (!AccessBlock(volume, reference.block, 1, blockBuffer, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) { + KernelLog(LOG_ERROR, "EsFS", "drive access failure", "Scan - Could not load directory entry.\n"); + return ES_ERROR_UNKNOWN; + } + + DirectoryEntry *entry = (DirectoryEntry *) (blockBuffer + reference.offsetIntoBlock); + if (!ValidateDirectoryEntry(entry)) return ES_ERROR_CORRUPT_DATA; + + if ((entry->nodeType == ESFS_NODE_TYPE_DIRECTORY && !FindAttribute(entry, ESFS_ATTRIBUTE_DIRECTORY)) + || (entry->nodeType == ESFS_NODE_TYPE_FILE && !FindAttribute(entry, ESFS_ATTRIBUTE_DATA))) { + KernelLog(LOG_ERROR, "EsFS", "damaged file system", "Scan - Node is missing attribute.\n"); + return ES_ERROR_CORRUPT_DATA; + } + + KNodeMetadata metadata = {}; + + if (entry->nodeType == ESFS_NODE_TYPE_DIRECTORY) { + AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(entry, ESFS_ATTRIBUTE_DIRECTORY); + + if (directoryAttribute) { + metadata.directoryChildren = directoryAttribute->childNodes; + metadata.totalSize = directoryAttribute->totalSize; + } + } else { + metadata.totalSize = entry->fileSize; + } + + metadata.type = entry->nodeType == ESFS_NODE_TYPE_DIRECTORY ? ES_NODE_DIRECTORY : ES_NODE_FILE; + + KNode *_node; + error = FSDirectoryEntryFound(_directory, &metadata, &reference, name, nameLength, false, &_node); + + if (error != ES_SUCCESS) { + return error; + } + + error = LoadInternal(volume, _node, entry, reference); + FSNodeScanAndLoadComplete(_node, error == ES_SUCCESS); + return error; +} + +static bool Mount(Volume *volume, EsFileOffsetDifference *rootDirectoryChildren) { + // TODO Return EsError. + // Load the superblock. + + Superblock *superblock = &volume->superblock; + + if (!volume->fileSystem->Access(ESFS_BOOT_SUPER_BLOCK_SIZE, ESFS_BOOT_SUPER_BLOCK_SIZE, K_ACCESS_READ, (uint8_t *) superblock, ES_FLAGS_DEFAULT)) { + KernelLog(LOG_ERROR, "EsFS", "drive access failure", "Mount - Could not read superblock.\n"); + return false; + } + + if (volume->fileSystem->block->readOnly) { + volume->readOnly = true; + } + + // Check the superblock is valid. + + uint32_t checksum = volume->superblock.checksum; + volume->superblock.checksum = 0; + uint32_t calculated = CalculateCRC32(&volume->superblock, sizeof(Superblock)); + ESFS_CHECK_FATAL(checksum == calculated, "Invalid superblock checksum."); + + ESFS_CHECK_FATAL(0 == EsMemoryCompare(volume->superblock.signature, ESFS_SIGNATURE_STRING, 16), "Invalid superblock signature."); + ESFS_CHECK_FATAL(volume->superblock.requiredReadVersion <= ESFS_DRIVER_VERSION, "Incompatible file system version."); + ESFS_CHECK_FATAL(superblock->blockSize >= 1024 && superblock->blockSize <= 16384 && (superblock->blockSize % volume->fileSystem->block->sectorSize) == 0, "Invalid block size."); + ESFS_CHECK_FATAL(superblock->blockCount * superblock->blockSize / volume->fileSystem->block->sectorSize <= volume->fileSystem->block->sectorCount, "More blocks than drive."); + ESFS_CHECK_FATAL(superblock->blocksUsed <= superblock->blockCount, "More blocks used than exist."); + ESFS_CHECK_FATAL(superblock->blocksPerGroup <= 65536 && superblock->blocksPerGroup < superblock->blockCount && superblock->blocksPerGroup >= 1024, "Invalid block group size."); + ESFS_CHECK_FATAL((superblock->groupCount - 1) * superblock->blocksPerGroup <= superblock->blockCount, "Invalid number of block groups."); + ESFS_CHECK_FATAL(superblock->blocksPerGroupBlockBitmap < superblock->blocksPerGroup, "Invalid number of blocks per group block bitmap."); + ESFS_CHECK_FATAL(superblock->gdtFirstBlock < superblock->blockCount, "First GDT block not within volume.\n"); + ESFS_CHECK_FATAL(superblock->directoryEntriesPerBlock <= superblock->blockSize / sizeof(DirectoryEntry), "Invalid number of directory entries per block."); + ESFS_CHECK_FATAL(superblock->root.block < superblock->blockCount && superblock->root.offsetIntoBlock < superblock->blockSize, "Invalid root directory position in volume.\n"); + ESFS_CHECK_READ_ONLY(!superblock->nextIdentifier.d[15], "Too many nodes created and deleted."); + ESFS_CHECK_READ_ONLY(superblock->requiredWriteVersion <= ESFS_DRIVER_VERSION, "Outdated file system version."); + + // ESFS_CHECK_READ_ONLY(!superblock->mounted, "Volume already mounted."); + + if (superblock->mounted) { + KernelLog(LOG_ERROR, "EsFS", "volume already mounted", + "Superblock indicates that the volume was either unmounted incorrectly, or is mounted by another driver instance.\n"); + } + + if (!volume->readOnly) { + superblock->mounted = true; + superblock->checksum = 0; + superblock->checksum = CalculateCRC32(superblock, sizeof(Superblock)); + ESFS_CHECK_READ_ONLY(volume->fileSystem->Access(ESFS_BOOT_SUPER_BLOCK_SIZE, ESFS_BOOT_SUPER_BLOCK_SIZE, + K_ACCESS_WRITE, (uint8_t *) superblock, ES_FLAGS_DEFAULT), "Could not mark volume as mounted."); + } + + // Load the group descriptor table. + + { + volume->groupDescriptorTable = (GroupDescriptor *) EsHeapAllocate((superblock->groupCount * sizeof(GroupDescriptor) + superblock->blockSize - 1), false, K_FIXED); + + if (!AccessBlock(volume, superblock->gdtFirstBlock, (superblock->groupCount * sizeof(GroupDescriptor) + superblock->blockSize - 1) / superblock->blockSize, + volume->groupDescriptorTable, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) { + EsHeapFree(volume->groupDescriptorTable, 0, K_FIXED); + ESFS_CHECK_FATAL(false, "Could not read group descriptor table."); + } + } + + // Load the root directory. + + { + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(superblock->blockSize, false, K_FIXED); + EsDefer(if (blockBuffer) EsHeapFree(blockBuffer, superblock->blockSize, K_FIXED)); + FSNode *node = nullptr; + + if (!blockBuffer) { + KernelLog(LOG_ERROR, "EsFS", "allocation failure", "Mount - Could not allocate block buffer.\n"); + goto failure; + } + + { + DirectoryEntryReference rootReference = superblock->root; + + if (!AccessBlock(volume, rootReference.block, 1, blockBuffer, BLOCK_ACCESS_CACHED, K_ACCESS_READ)) { + KernelLog(LOG_ERROR, "EsFS", "drive access failure", "Mount - Could not load root directory.\n"); + goto failure; + } + + DirectoryEntry *entry = (DirectoryEntry *) (blockBuffer + rootReference.offsetIntoBlock); + if (!ValidateDirectoryEntry(entry)) goto failure; + AttributeDirectory *directory = (AttributeDirectory *) FindAttribute(entry, ESFS_ATTRIBUTE_DIRECTORY); + + if (!directory || !FindAttribute(entry, ESFS_ATTRIBUTE_DATA)) { + KernelLog(LOG_ERROR, "EsFS", "damaged file system", "Mount - Root directory is missing attributes.\n"); + goto failure; + } + + volume->root = node = (FSNode *) EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + node->volume = volume; + node->reference = rootReference; + node->identifier = entry->identifier; + node->type = ES_NODE_DIRECTORY; + *rootDirectoryChildren = directory->childNodes; + EsMemoryCopy(&node->entry, entry, sizeof(DirectoryEntry)); + + goto success; + } + + failure:; + if (node) EsHeapFree(node, sizeof(FSNode), K_FIXED); + return false; + } + + success:; + return true; +} + +static void Unmount(KFileSystem *fileSystem) { + Volume *volume = (Volume *) fileSystem->driverData; + Superblock *superblock = &volume->superblock; + + if (!volume->readOnly) { + AccessBlock(volume, superblock->gdtFirstBlock, (superblock->groupCount * sizeof(GroupDescriptor) + superblock->blockSize - 1) / superblock->blockSize, + volume->groupDescriptorTable, BLOCK_ACCESS_CACHED, K_ACCESS_WRITE); + + superblock->mounted = false; + superblock->checksum = 0; + superblock->checksum = CalculateCRC32(superblock, sizeof(Superblock)); + volume->fileSystem->Access(ESFS_BOOT_SUPER_BLOCK_SIZE, ESFS_BOOT_SUPER_BLOCK_SIZE, K_ACCESS_WRITE, + (uint8_t *) superblock, ES_FLAGS_DEFAULT); + } + + EsHeapFree(volume->groupDescriptorTable, 0, K_FIXED); +} + +static void Register(KDevice *_parent) { + KFileSystem *fileSystem = (KFileSystem *) _parent; + Volume *volume = (Volume *) KDeviceCreate("EssenceFS", fileSystem, sizeof(Volume)); + + if (!volume) { + KernelLog(LOG_ERROR, "EsFS", "allocation failure", "Register - Could not allocate Volume structure.\n"); + return; + } + + volume->fileSystem = fileSystem; + + EsFileOffsetDifference rootDirectoryChildren; + + if (!Mount(volume, &rootDirectoryChildren)) { + KernelLog(LOG_ERROR, "EsFS", "mount error", "Register - Could not mount EsFS volume.\n"); + KDeviceDestroy(volume); + return; + } + + fileSystem->spaceUsed = volume->superblock.blocksUsed * volume->superblock.blockSize; + fileSystem->spaceTotal = volume->superblock.blockCount * volume->superblock.blockSize; + + fileSystem->read = Read; + fileSystem->scan = Scan; + fileSystem->load = Load; + fileSystem->enumerate = Enumerate; + fileSystem->unmount = Unmount; + fileSystem->close = Close; + + if (!volume->readOnly) { + fileSystem->write = Write; + fileSystem->sync = Sync; + fileSystem->resize = Resize; + fileSystem->create = Create; + fileSystem->remove = Remove; + fileSystem->move = Move; + } + + volume->superblock.volumeName[ESFS_MAXIMUM_VOLUME_NAME_LENGTH - 1] = 0; + fileSystem->nameBytes = EsCStringLength(volume->superblock.volumeName); + EsMemoryCopy(fileSystem->name, volume->superblock.volumeName, fileSystem->nameBytes); + + fileSystem->driverData = volume; + fileSystem->rootDirectory->driverNode = volume->root; + fileSystem->rootDirectoryInitialChildren = rootDirectoryChildren; + fileSystem->directoryEntryDataBytes = sizeof(DirectoryEntryReference); + fileSystem->nodeDataBytes = sizeof(FSNode); + + FSRegisterBootFileSystem(fileSystem, volume->superblock.osInstallation); +} + +KDriver driverEssenceFS = { + .attach = Register, +}; diff --git a/drivers/ext2.cpp b/drivers/ext2.cpp new file mode 100644 index 0000000..9b533b9 --- /dev/null +++ b/drivers/ext2.cpp @@ -0,0 +1,650 @@ +// TODO Validation of all fields. +// TODO Contiguous block reading in Scan and Enumerate. +// TODO Make GetDataBlock use (not yet implemented) system block cache. + +#include + +struct SuperBlock { + uint32_t inodeCount; + uint32_t blockCount; + uint32_t reservedBlockCount; + uint32_t unallocatedBlockCount; + uint32_t unallocatedInodeCount; + + uint32_t superBlockContainer; + uint32_t blockSizeExponent; + uint32_t fragmentSizeExponent; + + uint32_t blocksPerBlockGroup; + uint32_t fragmentsPerBlockGroup; + uint32_t inodesPerBlockGroup; + + uint32_t lastMountTime; + uint32_t lastWriteTime; + + uint16_t mountsSinceLastCheck; + uint16_t mountsAllowedBetweenChecks; + + uint16_t signature; + + uint16_t state; + uint16_t errorHandling; + + uint16_t minorVersion; + + uint32_t lastCheckTime; + uint32_t intervalCheckTime; + + uint32_t creatorID; + uint32_t majorVersion; + + uint16_t superUserID; + uint16_t superGroupID; + + uint32_t firstNonReservedInode; + uint16_t inodeStructureBytes; + uint16_t blockGroupOfSuperBlock; + + uint32_t optionalFeatures; + uint32_t requiredFeatures; + uint32_t writeFeatures; + + uint8_t fileSystemID[16]; + uint8_t volumeName[16]; + uint8_t lastMountPath[64]; + + uint32_t compressionAlgorithms; + + uint8_t preallocateFileBlocks; + uint8_t preallocateDirectoryBlocks; + + uint16_t _unused0; + + uint8_t journalID[16]; + uint32_t journalInode; + uint32_t journalDevice; + + uint32_t orphanInodeList; +}; + +struct BlockGroupDescriptor { + uint32_t blockUsageBitmap; + uint32_t inodeUsageBitmap; + uint32_t inodeTable; + + uint16_t unallocatedBlockCount; + uint16_t unallocatedInodeCount; + uint16_t directoryCount; + + uint8_t _unused1[14]; +}; + +struct Inode { +#define INODE_TYPE_DIRECTORY (0x4000) +#define INODE_TYPE_REGULAR (0x8000) + uint16_t type; + + uint16_t userID; + uint32_t fileSizeLow; + + uint32_t accessTime; + uint32_t creationTime; + uint32_t modificationTime; + uint32_t deletionTime; + + uint16_t groupID; + uint16_t hardLinkCount; + uint32_t usedSectorCount; + uint32_t flags; + uint32_t _unused0; + + uint32_t directBlockPointers[12]; + uint32_t indirectBlockPointers[3]; + + uint32_t generation; + uint32_t extendedAttributeBlock; + uint32_t fileSizeHigh; + uint32_t fragmentBlock; + uint8_t osSpecific[12]; +}; + +struct DirectoryEntry { + uint32_t inode; + uint16_t entrySize; + uint8_t nameLengthLow; + + union { + uint8_t nameLengthHigh; + +#define DIRENT_TYPE_REGULAR (1) +#define DIRENT_TYPE_DIRECTORY (2) + uint8_t type; + }; + + // Followed by name. +}; + +struct FSNode { + struct Volume *volume; + Inode inode; +}; + +struct Volume : KDevice { + KFileSystem *fileSystem; + SuperBlock superBlock; + BlockGroupDescriptor *blockGroupDescriptorTable; + size_t blockBytes; +}; + +static bool Mount(Volume *volume) { +#define MOUNT_FAILURE(message) do { KernelLog(LOG_ERROR, "Ext2", "mount failure", "Mount - " message); return false; } while (0) + + // Load the superblock. + + uint8_t *sectorBuffer = (uint8_t *) EsHeapAllocate(volume->fileSystem->block->sectorSize, false, K_FIXED); + + if (!sectorBuffer) { + MOUNT_FAILURE("Could not allocate buffer.\n"); + } + + EsDefer(EsHeapFree(sectorBuffer, volume->fileSystem->block->sectorSize, K_FIXED)); + + { + if (!volume->fileSystem->Access(1024, volume->fileSystem->block->sectorSize, K_ACCESS_READ, sectorBuffer, ES_FLAGS_DEFAULT)) { + MOUNT_FAILURE("Could not read boot sector.\n"); + } + + EsMemoryCopy(&volume->superBlock, sectorBuffer, sizeof(SuperBlock)); + + if (volume->superBlock.majorVersion < 1) { + MOUNT_FAILURE("Volumes below major version 1 not supprted.\n"); + } + + if (volume->superBlock.requiredFeatures != 2) { + MOUNT_FAILURE("Volume uses unsupported features that are required to read it.\n"); + } + + if (volume->superBlock.inodeStructureBytes < sizeof(Inode)) { + MOUNT_FAILURE("Inode structure size too small.\n"); + } + + volume->blockBytes = 1024 << volume->superBlock.blockSizeExponent; + + if (volume->blockBytes < volume->fileSystem->block->sectorSize) { + MOUNT_FAILURE("Block size smaller than drive sector size.\n"); + } + } + + // Load the block group descriptor table. + + { + uint32_t blockGroupCount = (volume->superBlock.blockCount + volume->superBlock.blocksPerBlockGroup - 1) / volume->superBlock.blocksPerBlockGroup; + uint32_t firstBlockContainingBlockGroupDescriptorTable = volume->blockBytes == 1024 ? 2 : 1; + uint32_t blockGroupDescriptorTableLengthInBlocks = (blockGroupCount * sizeof(BlockGroupDescriptor) + volume->blockBytes - 1) / volume->blockBytes; + + volume->blockGroupDescriptorTable = (BlockGroupDescriptor *) EsHeapAllocate(blockGroupDescriptorTableLengthInBlocks * volume->blockBytes, false, K_FIXED); + + if (!volume->blockGroupDescriptorTable) { + MOUNT_FAILURE("Could not allocate the block group descriptor table.\n"); + } + + if (!volume->fileSystem->Access(firstBlockContainingBlockGroupDescriptorTable * volume->blockBytes, + blockGroupDescriptorTableLengthInBlocks * volume->blockBytes, + K_ACCESS_READ, volume->blockGroupDescriptorTable, ES_FLAGS_DEFAULT)) { + MOUNT_FAILURE("Could not read the block group descriptor table from the drive.\n"); + } + } + + // Load the root directory. + + { + uint32_t inode = 2; + + uint32_t blockGroup = (inode - 1) / volume->superBlock.inodesPerBlockGroup; + uint32_t indexInInodeTable = (inode - 1) % volume->superBlock.inodesPerBlockGroup; + uint32_t sectorInInodeTable = (indexInInodeTable * volume->superBlock.inodeStructureBytes) / volume->fileSystem->block->sectorSize; + uint32_t offsetInSector = (indexInInodeTable * volume->superBlock.inodeStructureBytes) % volume->fileSystem->block->sectorSize; + + BlockGroupDescriptor *blockGroupDescriptor = volume->blockGroupDescriptorTable + blockGroup; + + if (!volume->fileSystem->Access(blockGroupDescriptor->inodeTable * volume->blockBytes + + sectorInInodeTable * volume->fileSystem->block->sectorSize, + volume->fileSystem->block->sectorSize, + K_ACCESS_READ, sectorBuffer, ES_FLAGS_DEFAULT)) { + MOUNT_FAILURE("Could not read the inode table.\n"); + } + + volume->fileSystem->rootDirectory->driverNode = EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!volume->fileSystem->rootDirectory->driverNode) { + MOUNT_FAILURE("Could not allocate root node.\n"); + } + + FSNode *root = (FSNode *) volume->fileSystem->rootDirectory->driverNode; + root->volume = volume; + EsMemoryCopy(&root->inode, sectorBuffer + offsetInSector, sizeof(Inode)); + + volume->fileSystem->rootDirectoryInitialChildren = root->inode.fileSizeLow / sizeof(DirectoryEntry); // TODO This is a terrible upper-bound! + + if ((root->inode.type & 0xF000) != INODE_TYPE_DIRECTORY) { + MOUNT_FAILURE("Root directory is not a directory.\n"); + } + } + + return true; +} + +static uint32_t GetDataBlock(Volume *volume, Inode *node, uint64_t blockIndex, uint8_t *blockBuffer) { +#define CHECK_BLOCK_INDEX() if (offset == 0 || offset / volume->fileSystem->block->sectorSize > volume->fileSystem->block->sectorCount) { \ + KernelLog(LOG_ERROR, "Ext2", "invalid block index", "GetDataBlock - Block out of bounds.\n"); return 0; } +#define GET_DATA_BLOCK_ACCESS_FAILURE() do { KernelLog(LOG_ERROR, "Ext2", "block access failure", "GetDataBlock - Could not read block.\n"); return 0; } while (0) + + size_t blockPointersPerBlock = volume->blockBytes / 4; + uint32_t *blockPointers = (uint32_t *) blockBuffer; + uint64_t offset; + + if (blockIndex < 12) { + offset = node->directBlockPointers[blockIndex]; + CHECK_BLOCK_INDEX(); + return offset; + } + + blockIndex -= 12; + + if (blockIndex < blockPointersPerBlock) { + offset = node->indirectBlockPointers[0] * volume->blockBytes; + CHECK_BLOCK_INDEX(); + if (!volume->fileSystem->Access(offset, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) GET_DATA_BLOCK_ACCESS_FAILURE(); + offset = blockPointers[blockIndex]; + CHECK_BLOCK_INDEX(); + return offset; + } + + blockIndex -= blockPointersPerBlock; + + if (blockIndex < blockPointersPerBlock * blockPointersPerBlock) { + offset = node->indirectBlockPointers[1] * volume->blockBytes; + CHECK_BLOCK_INDEX(); + if (!volume->fileSystem->Access(offset, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) GET_DATA_BLOCK_ACCESS_FAILURE(); + offset = blockPointers[blockIndex / blockPointersPerBlock]; + CHECK_BLOCK_INDEX(); + if (!volume->fileSystem->Access(offset, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) GET_DATA_BLOCK_ACCESS_FAILURE(); + offset = blockPointers[blockIndex % blockPointersPerBlock]; + CHECK_BLOCK_INDEX(); + return offset; + } + + blockIndex -= blockPointersPerBlock * blockPointersPerBlock; + + if (blockIndex < blockPointersPerBlock * blockPointersPerBlock * blockPointersPerBlock) { + offset = node->indirectBlockPointers[2] * volume->blockBytes; + CHECK_BLOCK_INDEX(); + if (!volume->fileSystem->Access(offset, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) GET_DATA_BLOCK_ACCESS_FAILURE(); + offset = blockPointers[blockIndex / blockPointersPerBlock / blockPointersPerBlock]; + CHECK_BLOCK_INDEX(); + if (!volume->fileSystem->Access(offset, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) GET_DATA_BLOCK_ACCESS_FAILURE(); + offset = blockPointers[(blockIndex / blockPointersPerBlock) % blockPointersPerBlock]; + CHECK_BLOCK_INDEX(); + if (!volume->fileSystem->Access(offset, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) GET_DATA_BLOCK_ACCESS_FAILURE(); + offset = blockPointers[blockIndex % blockPointersPerBlock]; + CHECK_BLOCK_INDEX(); + return offset; + } + + KernelLog(LOG_ERROR, "Ext2", "invalid index in inode", "GetDataBlock - Index %d out of bounds.\n", blockIndex); + return 0; +} + +static EsError Enumerate(KNode *node) { +#define ENUMERATE_FAILURE(message) do { KernelLog(LOG_ERROR, "Ext2", "enumerate failure", "Enumerate - " message); return ES_ERROR_UNKNOWN; } while (0) + + FSNode *directory = (FSNode *) node->driverNode; + Volume *volume = directory->volume; + + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(volume->blockBytes, false, K_FIXED); + + if (!blockBuffer) { + ENUMERATE_FAILURE("Could not allocate buffer.\n"); + } + + EsDefer(EsHeapFree(blockBuffer, volume->blockBytes, K_FIXED)); + + uint32_t blocksInDirectory = directory->inode.fileSizeLow / volume->blockBytes; + + for (uintptr_t i = 0; i < blocksInDirectory; i++) { + uint32_t block = GetDataBlock(volume, &directory->inode, i, blockBuffer); + + if (!block) { + return ES_ERROR_DRIVE_CONTROLLER_REPORTED; + } + + if (!volume->fileSystem->Access((uint64_t) block * volume->blockBytes, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) { + ENUMERATE_FAILURE("Could not read block.\n"); + } + + uintptr_t positionInBlock = 0; + + while (positionInBlock + sizeof(DirectoryEntry) < volume->blockBytes) { + DirectoryEntry *entry = (DirectoryEntry *) (blockBuffer + positionInBlock); + + if (entry->entrySize > volume->blockBytes - positionInBlock + || entry->nameLengthLow > volume->blockBytes - positionInBlock - sizeof(DirectoryEntry)) { + ENUMERATE_FAILURE("Invalid directory entry size.\n"); + } + + KNodeMetadata metadata = {}; + + const char *name = (const char *) (blockBuffer + positionInBlock + sizeof(DirectoryEntry)); + size_t nameBytes = entry->nameLengthLow; + + metadata.type = entry->type == DIRENT_TYPE_DIRECTORY ? ES_NODE_DIRECTORY : entry->type == DIRENT_TYPE_REGULAR ? ES_NODE_FILE : ES_NODE_INVALID; + + if (metadata.type == ES_NODE_DIRECTORY) { + metadata.directoryChildren = ES_DIRECTORY_CHILDREN_UNKNOWN; + } + + if (metadata.type != ES_NODE_INVALID + && !(nameBytes == 1 && name[0] == '.') + && !(nameBytes == 2 && name[0] == '.' && name[1] == '.')) { + EsError error = FSDirectoryEntryFound(node, &metadata, &entry->inode, name, nameBytes, false); + + if (error != ES_SUCCESS) { + return error; + } + } + + positionInBlock += entry->entrySize; + } + } + + return ES_SUCCESS; +} + +static EsError Scan(const char *name, size_t nameBytes, KNode *_directory) { +#define SCAN_FAILURE(message) do { KernelLog(LOG_ERROR, "Ext2", "scan failure", "Scan - " message); return ES_ERROR_UNKNOWN; } while (0) + + if (nameBytes == 2 && name[0] == '.' && name[1] == '.') return ES_ERROR_FILE_DOES_NOT_EXIST; + if (nameBytes == 1 && name[0] == '.') return ES_ERROR_FILE_DOES_NOT_EXIST; + + FSNode *directory = (FSNode *) _directory->driverNode; + Volume *volume = directory->volume; + DirectoryEntry *entry = nullptr; + + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(volume->blockBytes, false, K_FIXED); + + if (!blockBuffer) { + SCAN_FAILURE("Could not allocate buffer.\n"); + } + + EsDefer(EsHeapFree(blockBuffer, volume->blockBytes, K_FIXED)); + + uint32_t blocksInDirectory = directory->inode.fileSizeLow / volume->blockBytes; + uint32_t inode = 0; + + for (uintptr_t i = 0; i < blocksInDirectory; i++) { + uint32_t block = GetDataBlock(volume, &directory->inode, i, blockBuffer); + + if (!block) { + return ES_ERROR_UNKNOWN; + } + + if (!volume->fileSystem->Access((uint64_t) block * volume->blockBytes, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) { + SCAN_FAILURE("Could not read block.\n"); + } + + uintptr_t positionInBlock = 0; + + while (positionInBlock + sizeof(DirectoryEntry) < volume->blockBytes) { + entry = (DirectoryEntry *) (blockBuffer + positionInBlock); + + if (entry->entrySize > volume->blockBytes - positionInBlock + || entry->nameLengthLow > volume->blockBytes - positionInBlock - sizeof(DirectoryEntry)) { + SCAN_FAILURE("Invalid directory entry size.\n"); + } + + if (entry->nameLengthLow == nameBytes && 0 == EsMemoryCompare(name, blockBuffer + positionInBlock + sizeof(DirectoryEntry), nameBytes)) { + inode = entry->inode; + goto foundInode; + } + + positionInBlock += entry->entrySize; + } + } + + return ES_ERROR_FILE_DOES_NOT_EXIST; + + foundInode:; + + if (inode >= volume->superBlock.inodeCount || inode == 0) { + SCAN_FAILURE("Invalid inode index.\n"); + } + + KNodeMetadata metadata = {}; + + if (entry->type == DIRENT_TYPE_DIRECTORY) { + metadata.type = ES_NODE_DIRECTORY; + metadata.directoryChildren = ES_DIRECTORY_CHILDREN_UNKNOWN; + } else if (entry->type == DIRENT_TYPE_REGULAR) { + metadata.type = ES_NODE_FILE; + } else { + SCAN_FAILURE("Unsupported file type.\n"); + } + + return FSDirectoryEntryFound(_directory, &metadata, &inode, name, nameBytes, false); +} + +static EsError Load(KNode *_directory, KNode *node, KNodeMetadata *metadata, const void *entryData) { + uint32_t inode = *(uint32_t *) entryData; + + FSNode *directory = (FSNode *) _directory->driverNode; + Volume *volume = directory->volume; + + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(volume->blockBytes, false, K_FIXED); + + if (!blockBuffer) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + EsDefer(EsHeapFree(blockBuffer, volume->blockBytes, K_FIXED)); + + uint32_t blockGroup = (inode - 1) / volume->superBlock.inodesPerBlockGroup; + uint32_t indexInInodeTable = (inode - 1) % volume->superBlock.inodesPerBlockGroup; + uint32_t sectorInInodeTable = (indexInInodeTable * volume->superBlock.inodeStructureBytes) / volume->fileSystem->block->sectorSize; + uint32_t offsetInSector = (indexInInodeTable * volume->superBlock.inodeStructureBytes) % volume->fileSystem->block->sectorSize; + + BlockGroupDescriptor *blockGroupDescriptor = volume->blockGroupDescriptorTable + blockGroup; + + if (!volume->fileSystem->Access(blockGroupDescriptor->inodeTable * volume->blockBytes + + sectorInInodeTable * volume->fileSystem->block->sectorSize, + volume->fileSystem->block->sectorSize, + K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) { + return ES_ERROR_DRIVE_CONTROLLER_REPORTED; + } + + FSNode *data = (FSNode *) EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!data) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + data->volume = volume; + node->driverNode = data; + + EsMemoryCopy(&data->inode, blockBuffer + offsetInSector, sizeof(Inode)); + + if ((data->inode.type & 0xF000) == INODE_TYPE_DIRECTORY) { + if (metadata->type != ES_NODE_DIRECTORY) { + EsHeapFree(data, sizeof(FSNode), K_FIXED); + return ES_ERROR_CORRUPT_DATA; + } + + metadata->directoryChildren = data->inode.fileSizeLow / sizeof(DirectoryEntry); // TODO This is a terrible upper-bound! + } else if ((data->inode.type & 0xF000) == INODE_TYPE_REGULAR) { + if (metadata->type != ES_NODE_FILE) { + EsHeapFree(data, sizeof(FSNode), K_FIXED); + return ES_ERROR_CORRUPT_DATA; + } + + metadata->totalSize = (uint64_t) data->inode.fileSizeLow | ((uint64_t) data->inode.fileSizeHigh << 32); + } else { + if (metadata->type != ES_NODE_INVALID) { + EsHeapFree(data, sizeof(FSNode), K_FIXED); + return ES_ERROR_CORRUPT_DATA; + } + } + + return ES_SUCCESS; +} + +struct ReadDispatchGroup : KWorkGroup { + uint64_t extentIndex; + uint64_t extentCount; + uint8_t *extentBuffer; + Volume *volume; + + void QueueExtent() { + if (!extentCount) return; + + volume->fileSystem->Access(extentIndex * volume->blockBytes, + volume->blockBytes * extentCount, K_ACCESS_READ, extentBuffer, ES_FLAGS_DEFAULT, this); + } + + void QueueBlock(Volume *_volume, uint64_t index, uint8_t *buffer) { + if (extentIndex + extentCount == index && extentCount + && extentBuffer + extentCount * volume->blockBytes == buffer) { + extentCount++; + } else { + QueueExtent(); + extentIndex = index; + extentCount = 1; + extentBuffer = buffer; + volume = _volume; + } + } + + bool Read() { + QueueExtent(); + return Wait(); + } +}; + +static size_t Read(KNode *node, void *_buffer, EsFileOffset offset, EsFileOffset count) { +#define READ_FAILURE(message) do { KernelLog(LOG_ERROR, "Ext2", "read failure", "Read - " message); return ES_ERROR_UNKNOWN; } while (0) + + FSNode *file = (FSNode *) node->driverNode; + Volume *volume = file->volume; + + uint8_t *blockBuffer = (uint8_t *) EsHeapAllocate(volume->blockBytes, false, K_FIXED); + + if (!blockBuffer) { + READ_FAILURE("Could not allocate sector buffer.\n"); + } + + EsDefer(EsHeapFree(blockBuffer, volume->blockBytes, K_FIXED)); + + uint8_t *outputBuffer = (uint8_t *) _buffer; + uintptr_t outputPosition = 0; + + uint32_t firstBlock = offset / volume->blockBytes, + lastBlock = (offset + count) / volume->blockBytes, + currentBlock = firstBlock; + + ReadDispatchGroup dispatchGroup = {}; + dispatchGroup.Initialise(); + + while (currentBlock <= lastBlock) { + uint32_t block = GetDataBlock(volume, &file->inode, currentBlock, blockBuffer); + + if (!block) { + return false; + } + + uintptr_t readStart = currentBlock == firstBlock ? (offset % volume->blockBytes) : 0; + uintptr_t readEnd = currentBlock == lastBlock ? ((offset + count) % volume->blockBytes) : volume->blockBytes; + + bool readEntireBlock = readStart == 0 && readEnd == volume->blockBytes; + + if (readEntireBlock) { + dispatchGroup.QueueBlock(volume, block, outputBuffer + outputPosition); + outputPosition += volume->blockBytes; + } else { + if (!volume->fileSystem->Access((uint64_t) block * volume->blockBytes, volume->blockBytes, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) { + READ_FAILURE("Could not read blocks from drive.\n"); + } + + EsMemoryCopy(outputBuffer + outputPosition, blockBuffer + readStart, readEnd - readStart); + outputPosition += readEnd - readStart; + } + + currentBlock++; + } + + bool success = dispatchGroup.Read(); + + if (!success) { + READ_FAILURE("Could not read blocks from drive.\n"); + return false; + } + + return true; +} + +static void Close(KNode *node) { + EsHeapFree(node->driverNode, sizeof(FSNode), K_FIXED); +} + +static void DeviceAttach(KDevice *parent) { + Volume *volume = (Volume *) KDeviceCreate("ext2", parent, sizeof(Volume)); + + if (!volume) { + KernelLog(LOG_ERROR, "Ext2", "allocate error", "Could not allocate Volume structure.\n"); + return; + } + + volume->fileSystem = (KFileSystem *) parent; + + if (volume->fileSystem->block->sectorSize & 0x1FF) { + KernelLog(LOG_ERROR, "Ext2", "incorrect sector size", "Expected sector size to be a multiple of 512, but drive's sectors are %D.\n", + volume->fileSystem->block->sectorSize); + KDeviceDestroy(volume); + return; + } + + if (!Mount(volume)) { + KernelLog(LOG_ERROR, "Ext2", "mount failure", "Could not mount Ext2 volume.\n"); + EsHeapFree(volume->fileSystem->rootDirectory->driverNode, 0, K_FIXED); + EsHeapFree(volume->blockGroupDescriptorTable, 0, K_FIXED); + KDeviceDestroy(volume); + return; + } + + volume->fileSystem->read = Read; + volume->fileSystem->scan = Scan; + volume->fileSystem->load = Load; + volume->fileSystem->enumerate = Enumerate; + volume->fileSystem->close = Close; + + volume->fileSystem->spaceTotal = volume->superBlock.blockCount * volume->blockBytes; + volume->fileSystem->spaceUsed = (volume->superBlock.blockCount - volume->superBlock.unallocatedBlockCount) * volume->blockBytes; + + volume->fileSystem->nameBytes = sizeof(volume->superBlock.volumeName); + if (volume->fileSystem->nameBytes > sizeof(volume->fileSystem->name)) volume->fileSystem->nameBytes = sizeof(volume->fileSystem->name); + EsMemoryCopy(volume->fileSystem->name, volume->superBlock.volumeName, volume->fileSystem->nameBytes); + + for (uintptr_t i = 0; i < volume->fileSystem->nameBytes; i++) { + if (!volume->fileSystem->name[i]) { + volume->fileSystem->nameBytes = i; + } + } + + volume->fileSystem->directoryEntryDataBytes = sizeof(uint32_t); + volume->fileSystem->nodeDataBytes = sizeof(FSNode); + + KernelLog(LOG_INFO, "Ext2", "register file system", "Registering file system with name '%s'.\n", + volume->fileSystem->nameBytes, volume->fileSystem->name); + FSRegisterFileSystem(volume->fileSystem); +} + +KDriver driverExt2 = { + .attach = DeviceAttach, +}; diff --git a/drivers/fat.cpp b/drivers/fat.cpp new file mode 100644 index 0000000..ad267ca --- /dev/null +++ b/drivers/fat.cpp @@ -0,0 +1,514 @@ +// TODO Validation of all fields. +// TODO Don't load entire FAT in memory. +// TODO Long file names. + +#include + +#define SECTOR_SIZE (512) + +struct SuperBlockCommon { + uint8_t _unused0[11]; + uint16_t bytesPerSector; + uint8_t sectorsPerCluster; + uint16_t reservedSectors; + uint8_t fatCount; + uint16_t rootDirectoryEntries; + uint16_t totalSectors; + uint8_t mediaDescriptor; + uint16_t sectorsPerFAT16; + uint16_t sectorsPerTrack; + uint16_t heads; + uint32_t hiddenSectors; + uint32_t largeSectorCount; +} __attribute__((packed)); + +struct SuperBlock16 : SuperBlockCommon { + uint8_t deviceID; + uint8_t flags; + uint8_t signature; + uint32_t serial; + uint8_t label[11]; + uint64_t systemIdentifier; + uint8_t _unused1[450]; +} __attribute__((packed)); + +struct SuperBlock32 : SuperBlockCommon { + uint32_t sectorsPerFAT32; + uint16_t flags; + uint16_t version; + uint32_t rootDirectoryCluster; + uint16_t fsInfoSector; + uint16_t backupBootSector; + uint8_t _unused0[12]; + uint8_t deviceID; + uint8_t flags2; + uint8_t signature; + uint32_t serial; + uint8_t label[11]; + uint64_t systemIdentifier; + uint8_t _unused1[422]; +} __attribute__((packed)); + +struct DirectoryEntry { + uint8_t name[11]; + uint8_t attributes; + uint8_t _reserved0; + uint8_t creationTimeSeconds; + uint16_t creationTime; + uint16_t creationDate; + uint16_t accessedDate; + uint16_t firstClusterHigh; + uint16_t modificationTime; + uint16_t modificationDate; + uint16_t firstClusterLow; + uint32_t fileSizeBytes; +} __attribute__((packed)); + +struct Volume : KDevice { + KFileSystem *fileSystem; + + union { + char _unused0[SECTOR_SIZE]; + SuperBlock16 sb16; + SuperBlock32 sb32; + SuperBlockCommon superBlock; + }; + + KNode *root; + uint8_t *fat; + uintptr_t sectorOffset; + uint32_t terminateCluster; + +#define TYPE_FAT12 (12) +#define TYPE_FAT16 (16) +#define TYPE_FAT32 (32) + int type; + + DirectoryEntry *rootDirectory; +}; + +struct DirectoryEntryReference { + uint32_t cluster, offset; +}; + +struct FSNode { + Volume *volume; + DirectoryEntry entry; + + // The root directory is loaded during fileSystem mount. + // If this is non-null, run directory data from here. + DirectoryEntry *rootDirectory; +}; + +static uint32_t NextCluster(Volume *volume, uint32_t currentCluster) { + if (volume->type == TYPE_FAT12) { + uint8_t byte1 = volume->fat[currentCluster * 3 / 2 + 0], + byte2 = volume->fat[currentCluster * 3 / 2 + 1]; + + if (currentCluster & 1) currentCluster = (byte2 << 4) + (byte1 >> 4); + else currentCluster = (byte2 << 8) + (byte1 >> 0); + + return currentCluster & 0xFFF; + } else if (volume->type == TYPE_FAT16) { + return ((uint16_t *) volume->fat)[currentCluster]; + } else if (volume->type == TYPE_FAT32) { + return ((uint32_t *) volume->fat)[currentCluster]; + } else { + KernelPanic("[FAT] NextCluster - Unsupported FAT type.\n"); + return 0; + } +} + +static uint32_t CountUsedClusters(Volume *volume) { + size_t total = 0; + + if (volume->type == TYPE_FAT12) { + total = volume->sb16.sectorsPerFAT16 * volume->superBlock.bytesPerSector * 2 / 3; + } else if (volume->type == TYPE_FAT16) { + total = volume->sb16.sectorsPerFAT16 * volume->superBlock.bytesPerSector / 2; + } else if (volume->type == TYPE_FAT32) { + total = volume->sb16.sectorsPerFAT16 * volume->superBlock.bytesPerSector / 4; + } + + size_t count = 0; + + for (uintptr_t i = 0; i < total; i++) { + if (NextCluster(volume, i)) { + count++; + } + } + + return count; +} + +static EsError Load(KNode *_directory, KNode *_node, KNodeMetadata *, const void *entryData) { + FSNode *directory = (FSNode *) _directory->driverNode; + Volume *volume = directory->volume; + SuperBlockCommon *superBlock = &volume->superBlock; + + uint8_t *clusterBuffer = (uint8_t *) EsHeapAllocate(superBlock->sectorsPerCluster * SECTOR_SIZE, false, K_FIXED); + if (!clusterBuffer) return ES_ERROR_INSUFFICIENT_RESOURCES; + EsDefer(EsHeapFree(clusterBuffer, 0, K_FIXED)); + + DirectoryEntryReference reference = *(DirectoryEntryReference *) entryData; + DirectoryEntry entry; + + if (!directory->rootDirectory) { + if (!volume->fileSystem->Access((reference.cluster * superBlock->sectorsPerCluster + volume->sectorOffset) * SECTOR_SIZE, + superBlock->sectorsPerCluster * SECTOR_SIZE, K_ACCESS_READ, (uint8_t *) clusterBuffer, ES_FLAGS_DEFAULT)) { + return ES_ERROR_UNKNOWN; + } + + entry = *(DirectoryEntry *) (clusterBuffer + reference.offset); + } else { + entry = directory->rootDirectory[reference.offset]; + } + + FSNode *node = (FSNode *) EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!node) { + EsHeapFree(node, 0, K_FIXED); + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + _node->driverNode = node; + node->volume = volume; + node->entry = entry; + + return ES_SUCCESS; +} + +static size_t Read(KNode *node, void *_buffer, EsFileOffset offset, EsFileOffset count) { +#define READ_FAILURE(message) do { KernelLog(LOG_ERROR, "FAT", "read failure", "Read - " message); return ES_ERROR_UNKNOWN; } while (0) + + FSNode *file = (FSNode *) node->driverNode; + Volume *volume = file->volume; + SuperBlockCommon *superBlock = &volume->superBlock; + + uint8_t *clusterBuffer = (uint8_t *) EsHeapAllocate(superBlock->sectorsPerCluster * SECTOR_SIZE, false, K_FIXED); + EsDefer(EsHeapFree(clusterBuffer, 0, K_FIXED)); + if (!clusterBuffer) READ_FAILURE("Could not allocate cluster buffer.\n"); + + uint8_t *outputBuffer = (uint8_t *) _buffer; + uint64_t firstCluster = offset / (SECTOR_SIZE * superBlock->sectorsPerCluster); + uint32_t currentCluster = file->entry.firstClusterLow + (file->entry.firstClusterHigh << 16); + for (uintptr_t i = 0; i < firstCluster; i++) currentCluster = NextCluster(volume, currentCluster); + offset %= (SECTOR_SIZE * superBlock->sectorsPerCluster); + + while (count) { + uint32_t bytesFromThisCluster = superBlock->sectorsPerCluster * SECTOR_SIZE - offset; + if (bytesFromThisCluster > count) bytesFromThisCluster = count; + + if (!volume->fileSystem->Access((currentCluster * superBlock->sectorsPerCluster + volume->sectorOffset) * SECTOR_SIZE, + superBlock->sectorsPerCluster * SECTOR_SIZE, K_ACCESS_READ, + (uint8_t *) clusterBuffer, ES_FLAGS_DEFAULT)) { + READ_FAILURE("Could not read cluster.\n"); + } + + EsMemoryCopy(outputBuffer, clusterBuffer + offset, bytesFromThisCluster); + count -= bytesFromThisCluster, outputBuffer += bytesFromThisCluster, offset = 0; + currentCluster = NextCluster(volume, currentCluster); + } + + return true; +} + +static EsError Scan(const char *_name, size_t nameLength, KNode *node) { +#define SCAN_FAILURE(message) do { KernelLog(LOG_ERROR, "FAT", "scan failure", "Scan - " message); return ES_ERROR_UNKNOWN; } while (0) +#define SCAN_FAILURE_2(message) do { KernelLog(LOG_ERROR, "FAT", "scan failure", "Scan - " message); goto failure; } while (0) + + uint8_t name[] = " "; + + { + uintptr_t i = 0, j = 0; + bool inExtension = false; + + while (i < nameLength) { + if (j == 11) return ES_ERROR_FILE_DOES_NOT_EXIST; // Name too long. + uint8_t c = _name[i++]; + if (c == '.' && !inExtension) j = 8, inExtension = true; + else name[j++] = (c >= 'a' && c <= 'z') ? (c + 'A' - 'a') : c; + } + } + + FSNode *directory = (FSNode *) node->driverNode; + Volume *volume = directory->volume; + SuperBlockCommon *superBlock = &volume->superBlock; + + uint8_t *clusterBuffer = (uint8_t *) EsHeapAllocate(superBlock->sectorsPerCluster * SECTOR_SIZE, false, K_FIXED); + EsDefer(EsHeapFree(clusterBuffer, 0, K_FIXED)); + if (!clusterBuffer) SCAN_FAILURE("Could not allocate cluster buffer.\n"); + + uint32_t currentCluster = directory->entry.firstClusterLow + (directory->entry.firstClusterHigh << 16); + uintptr_t directoryPosition = 0; + + while (currentCluster < volume->terminateCluster) { + if (!directory->rootDirectory) { + if (!volume->fileSystem->Access((currentCluster * superBlock->sectorsPerCluster + volume->sectorOffset) * SECTOR_SIZE, + superBlock->sectorsPerCluster * SECTOR_SIZE, K_ACCESS_READ, (uint8_t *) clusterBuffer, ES_FLAGS_DEFAULT)) { + SCAN_FAILURE("Could not read cluster.\n"); + } + } + + for (uintptr_t i = 0; i < superBlock->sectorsPerCluster * SECTOR_SIZE / sizeof(DirectoryEntry); i++, directoryPosition++) { + DirectoryEntry *entry = directory->rootDirectory ? (directory->rootDirectory + directoryPosition) : ((DirectoryEntry *) clusterBuffer + i); + if (entry->name[0] == 0xE5 || entry->attributes == 0x0F || (entry->attributes & 8)) goto nextEntry; + if (!entry->name[0]) return ES_ERROR_FILE_DOES_NOT_EXIST; + + for (uintptr_t j = 0; j < 11; j++) { + uint8_t c = entry->name[j]; + + if (name[j] != ((c >= 'a' && c <= 'z') ? (c + 'A' - 'a') : c)) { + goto nextEntry; + } + } + + { + KNodeMetadata metadata = {}; + metadata.type = (entry->attributes & 0x10) ? ES_NODE_DIRECTORY : ES_NODE_FILE; + + if (metadata.type == ES_NODE_FILE) { + metadata.totalSize = entry->fileSizeBytes; + } else if (metadata.type == ES_NODE_DIRECTORY) { + uint32_t currentCluster = entry->firstClusterLow + (entry->firstClusterHigh << 16); + + while (currentCluster < volume->terminateCluster) { + currentCluster = NextCluster(volume, currentCluster); + metadata.directoryChildren += SECTOR_SIZE * superBlock->sectorsPerCluster / sizeof(DirectoryEntry); + } + } + + DirectoryEntryReference reference = {}; + reference.cluster = directory->rootDirectory ? 0 : currentCluster; + reference.offset = directory->rootDirectory ? directoryPosition : i; + return FSDirectoryEntryFound(node, &metadata, &reference, _name, nameLength, false); + } + + nextEntry:; + } + + if (!directory->rootDirectory) { + currentCluster = NextCluster(volume, currentCluster); + } + } + + return ES_ERROR_FILE_DOES_NOT_EXIST; +} + +static EsError Enumerate(KNode *node) { +#define ENUMERATE_FAILURE(message) do { KernelLog(LOG_ERROR, "FAT", "enumerate failure", "Enumerate - " message); return ES_ERROR_UNKNOWN; } while (0) + + FSNode *directory = (FSNode *) node->driverNode; + Volume *volume = directory->volume; + SuperBlockCommon *superBlock = &volume->superBlock; + + uint8_t *clusterBuffer = (uint8_t *) EsHeapAllocate(superBlock->sectorsPerCluster * SECTOR_SIZE, false, K_FIXED); + EsDefer(EsHeapFree(clusterBuffer, 0, K_FIXED)); + if (!clusterBuffer) ENUMERATE_FAILURE("Could not allocate cluster buffer.\n"); + + uint32_t currentCluster = directory->entry.firstClusterLow + (directory->entry.firstClusterHigh << 16); + uint64_t directoryPosition = 0; + + while (currentCluster < volume->terminateCluster) { + if (!directory->rootDirectory) { + if (!volume->fileSystem->Access((currentCluster * superBlock->sectorsPerCluster + volume->sectorOffset) * SECTOR_SIZE, + superBlock->sectorsPerCluster * SECTOR_SIZE, K_ACCESS_READ, (uint8_t *) clusterBuffer, ES_FLAGS_DEFAULT)) { + ENUMERATE_FAILURE("Could not read cluster.\n"); + } + } + + for (uintptr_t i = 0; i < superBlock->sectorsPerCluster * SECTOR_SIZE / sizeof(DirectoryEntry); i++, directoryPosition++) { + DirectoryEntry *entry = directory->rootDirectory ? (directory->rootDirectory + directoryPosition) : ((DirectoryEntry *) clusterBuffer + i); + if (entry->name[0] == 0xE5 || entry->attributes == 0x0F || (entry->attributes & 8)) continue; + + if (!entry->name[0]) { + return ES_SUCCESS; + } + + uint8_t name[12]; + size_t nameLength = 0; + bool hasExtension = entry->name[8] != ' ' || entry->name[9] != ' ' || entry->name[10] != ' '; + + if (entry->name[0] == '.' && (entry->name[1] == '.' || entry->name[1] == ' ') && entry->name[2] == ' ') { + continue; + } + + for (uintptr_t i = 0; i < 11; i++) { + if (i == 8 && hasExtension) name[nameLength++] = '.'; + if (entry->name[i] != ' ') name[nameLength++] = entry->name[i]; + } + + KNodeMetadata metadata = {}; + + metadata.type = (entry->attributes & 0x10) ? ES_NODE_DIRECTORY : ES_NODE_FILE; + + if (metadata.type == ES_NODE_DIRECTORY) { + metadata.directoryChildren = ES_DIRECTORY_CHILDREN_UNKNOWN; + } else if (metadata.type == ES_NODE_FILE) { + metadata.totalSize = entry->fileSizeBytes; + } + + DirectoryEntryReference reference = {}; + reference.cluster = directory->rootDirectory ? 0 : currentCluster; + reference.offset = directory->rootDirectory ? directoryPosition : i; + + EsError error = FSDirectoryEntryFound(node, &metadata, &reference, + (const char *) name, nameLength, false); + + if (error != ES_SUCCESS) { + return error; + } + } + + if (!directory->rootDirectory) { + currentCluster = NextCluster(volume, currentCluster); + } + } + + return ES_SUCCESS; +} + +static bool Mount(Volume *volume) { +#define MOUNT_FAILURE(message) do { KernelLog(LOG_ERROR, "FAT", "mount failure", "Mount - " message); goto failure; } while (0) + + { + SuperBlockCommon *superBlock = &volume->superBlock; + if (!volume->fileSystem->Access(0, SECTOR_SIZE, K_ACCESS_READ, (uint8_t *) superBlock, ES_FLAGS_DEFAULT)) MOUNT_FAILURE("Could not read superBlock.\n"); + + uint32_t sectorCount = superBlock->totalSectors ?: superBlock->largeSectorCount; + uint32_t clusterCount = sectorCount / superBlock->sectorsPerCluster; + uint32_t sectorsPerFAT = 0; + + if (clusterCount < 0x00000FF5) { + volume->type = TYPE_FAT12; + volume->terminateCluster = 0xFF8; + sectorsPerFAT = volume->sb16.sectorsPerFAT16; + } else if (clusterCount < 0x0000FFF5) { + volume->type = TYPE_FAT16; + volume->terminateCluster = 0xFFF8; + sectorsPerFAT = volume->sb16.sectorsPerFAT16; + } else if (clusterCount < 0x0FFFFFF5) { + volume->type = TYPE_FAT32; + volume->terminateCluster = 0xFFFFFF8; + sectorsPerFAT = volume->sb32.sectorsPerFAT32; + } else { + MOUNT_FAILURE("Unsupported cluster count. Maybe ExFAT?\n"); + } + + uint32_t rootDirectoryOffset = superBlock->reservedSectors + superBlock->fatCount * sectorsPerFAT; + uint32_t rootDirectorySectors = (superBlock->rootDirectoryEntries * sizeof(DirectoryEntry) + (SECTOR_SIZE - 1)) / SECTOR_SIZE; + + volume->sectorOffset = rootDirectoryOffset + rootDirectorySectors - 2 * superBlock->sectorsPerCluster; + + volume->fat = (uint8_t *) EsHeapAllocate(sectorsPerFAT * SECTOR_SIZE, true, K_FIXED); + if (!volume->fat) MOUNT_FAILURE("Could not allocate FAT.\n"); + if (!volume->fileSystem->Access(superBlock->reservedSectors * SECTOR_SIZE, + sectorsPerFAT * SECTOR_SIZE, K_ACCESS_READ, volume->fat, ES_FLAGS_DEFAULT)) MOUNT_FAILURE("Could not read FAT.\n"); + + volume->fileSystem->spaceUsed = CountUsedClusters(volume) * superBlock->sectorsPerCluster * superBlock->bytesPerSector; + volume->fileSystem->spaceTotal = volume->fileSystem->block->sectorSize * volume->fileSystem->block->sectorCount; + + volume->fileSystem->rootDirectory->driverNode = EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + if (!volume->fileSystem->rootDirectory->driverNode) MOUNT_FAILURE("Could not allocate root node.\n"); + + FSNode *root = (FSNode *) volume->fileSystem->rootDirectory->driverNode; + root->volume = volume; + + if (volume->type == TYPE_FAT32) { + root->entry.firstClusterLow = volume->sb32.rootDirectoryCluster & 0xFFFF; + root->entry.firstClusterHigh = (volume->sb32.rootDirectoryCluster >> 16) & 0xFFFF; + + uint32_t currentCluster = volume->sb32.rootDirectoryCluster; + + while (currentCluster < volume->terminateCluster) { + currentCluster = NextCluster(volume, currentCluster); + volume->fileSystem->rootDirectoryInitialChildren += SECTOR_SIZE * superBlock->sectorsPerCluster / sizeof(DirectoryEntry); + } + } else { + root->rootDirectory = (DirectoryEntry *) EsHeapAllocate(rootDirectorySectors * SECTOR_SIZE, true, K_FIXED); + volume->rootDirectory = root->rootDirectory; + + if (!volume->fileSystem->Access(rootDirectoryOffset * SECTOR_SIZE, rootDirectorySectors * SECTOR_SIZE, + K_ACCESS_READ, (uint8_t *) root->rootDirectory, ES_FLAGS_DEFAULT)) { + MOUNT_FAILURE("Could not read root directory.\n"); + } + + for (uintptr_t i = 0; i < superBlock->rootDirectoryEntries; i++) { + if (root->rootDirectory[i].name[0] == 0xE5 || root->rootDirectory[i].attributes == 0x0F || (root->rootDirectory[i].attributes & 0x08)) continue; + else if (root->rootDirectory[i].name[0] == 0x00) break; + else volume->fileSystem->rootDirectoryInitialChildren++; + } + } + + return true; + } + + failure: + if (volume->root && volume->root->driverNode) EsHeapFree(((FSNode *) volume->root->driverNode)->rootDirectory, 0, K_FIXED); + if (volume->root) EsHeapFree(volume->root->driverNode, 0, K_FIXED); + EsHeapFree(volume->root, 0, K_FIXED); + EsHeapFree(volume->fat, 0, K_FIXED); + return false; +} + +static void Close(KNode *node) { + EsHeapFree(node->driverNode, sizeof(FSNode), K_FIXED); +} + +static void DeviceAttach(KDevice *parent) { + Volume *volume = (Volume *) KDeviceCreate("FAT", parent, sizeof(Volume)); + + if (!volume) { + KernelLog(LOG_ERROR, "FAT", "allocate error", "EntryFAT - Could not allocate Volume structure.\n"); + return; + } + + volume->fileSystem = (KFileSystem *) parent; + + if (!volume->fileSystem) { + KernelLog(LOG_ERROR, "FAT", "device error", "EntryFAT - Could not create file system device.\n"); + KDeviceDestroy(volume); + return; + } + + if (volume->fileSystem->block->sectorSize != SECTOR_SIZE) { + KernelLog(LOG_ERROR, "FAT", "mount failure", "EntryFAT - Unsupported sector size.\n"); + KDeviceDestroy(volume); + return; + } + + if (!Mount(volume)) { + KernelLog(LOG_ERROR, "FAT", "mount failure", "EntryFAT - Could not mount FAT volume.\n"); + KDeviceDestroy(volume); + return; + } + + volume->fileSystem->read = Read; + volume->fileSystem->load = Load; + volume->fileSystem->scan = Scan; + volume->fileSystem->enumerate = Enumerate; + volume->fileSystem->close = Close; + + if (volume->type == TYPE_FAT32) { + volume->fileSystem->nameBytes = sizeof(volume->sb32.label); + EsMemoryCopy(volume->fileSystem->name, volume->sb32.label, volume->fileSystem->nameBytes); + } else { + if (volume->rootDirectory[0].attributes & 8) { + volume->fileSystem->nameBytes = sizeof(volume->rootDirectory[0].name); + EsMemoryCopy(volume->fileSystem->name, volume->rootDirectory[0].name, volume->fileSystem->nameBytes); + } else { + volume->fileSystem->nameBytes = sizeof(volume->sb16.label); + EsMemoryCopy(volume->fileSystem->name, volume->sb16.label, volume->fileSystem->nameBytes); + } + } + + volume->fileSystem->rootDirectory->driverNode = volume->root; + volume->fileSystem->directoryEntryDataBytes = sizeof(DirectoryEntryReference); + volume->fileSystem->nodeDataBytes = sizeof(FSNode); + + FSRegisterFileSystem(volume->fileSystem); +} + +KDriver driverFAT = { + .attach = DeviceAttach, +}; diff --git a/drivers/hda.cpp b/drivers/hda.cpp new file mode 100644 index 0000000..b11f79b --- /dev/null +++ b/drivers/hda.cpp @@ -0,0 +1,520 @@ +#include + +#define RD_REGISTER_GCAP() controller->pci->ReadBAR16(0, 0x00) // Global capabilities. +#define RD_REGISTER_VMIN() controller->pci->ReadBAR8(0, 0x02) // Minor version number. +#define RD_REGISTER_VMAJ() controller->pci->ReadBAR8(0, 0x03) // Major version number. +#define RD_REGISTER_GCTL() controller->pci->ReadBAR32(0, 0x08) // Global control. +#define WR_REGISTER_GCTL(x) controller->pci->WriteBAR32(0, 0x08, x) +#define RD_REGISTER_STATESTS() controller->pci->ReadBAR16(0, 0x0E) // State change status. +#define RD_REGISTER_INTCTL() controller->pci->ReadBAR32(0, 0x20) // Interrupt control. +#define WR_REGISTER_INTCTL(x) controller->pci->WriteBAR32(0, 0x20, x) +#define RD_REGISTER_INTSTS() controller->pci->ReadBAR32(0, 0x24) // Interrupt status. +#define WR_REGISTER_CORBLBASE(x) controller->pci->WriteBAR32(0, 0x40, x) // CORB base address. +#define WR_REGISTER_CORBUBASE(x) controller->pci->WriteBAR32(0, 0x44, x) +#define RD_REGISTER_CORBWP(x) controller->pci->ReadBAR16(0, 0x48) // CORB write pointer. +#define WR_REGISTER_CORBWP(x) controller->pci->WriteBAR16(0, 0x48, x) +#define RD_REGISTER_CORBRP(x) controller->pci->ReadBAR16(0, 0x4A) // CORB read pointer. +#define WR_REGISTER_CORBRP(x) controller->pci->WriteBAR16(0, 0x4A, x) +#define RD_REGISTER_CORBCTL() controller->pci->ReadBAR8(0, 0x4C) // CORB control. +#define WR_REGISTER_CORBCTL(x) controller->pci->WriteBAR8(0, 0x4C, x) +#define RD_REGISTER_CORBSIZE() controller->pci->ReadBAR8(0, 0x4E) // CORB size. +#define WR_REGISTER_CORBSIZE(x) controller->pci->WriteBAR8(0, 0x4E, x) +#define WR_REGISTER_RIRBLBASE(x) controller->pci->WriteBAR32(0, 0x50, x) // RIRB base address. +#define WR_REGISTER_RIRBUBASE(x) controller->pci->WriteBAR32(0, 0x54, x) +#define RD_REGISTER_RIRBWP(x) controller->pci->ReadBAR16(0, 0x58) // RIRB write pointer. +#define WR_REGISTER_RIRBWP(x) controller->pci->WriteBAR16(0, 0x58, x) +#define RD_REGISTER_RINTCNT() controller->pci->ReadBAR16(0, 0x5A) // Response interrupt count. +#define WR_REGISTER_RINTCNT(x) controller->pci->WriteBAR16(0, 0x5A, x) +#define RD_REGISTER_RIRBCTL() controller->pci->ReadBAR8(0, 0x5C) // RIRB control. +#define WR_REGISTER_RIRBCTL(x) controller->pci->WriteBAR8(0, 0x5C, x) +#define RD_REGISTER_RIRBSTS() controller->pci->ReadBAR8(0, 0x5D) // RIRB status. +#define WR_REGISTER_RIRBSTS(x) controller->pci->WriteBAR8(0, 0x5D, x) +#define RD_REGISTER_RIRBSIZE() controller->pci->ReadBAR8(0, 0x5E) // RIRB size. +#define WR_REGISTER_RIRBSIZE(x) controller->pci->WriteBAR8(0, 0x5E, x) +#define WR_REGISTER_ImmComOut(x) controller->pci->WriteBAR32(0, 0x60, x) // Immediate command output. +#define RD_REGISTER_ImmComIn() controller->pci->ReadBAR32(0, 0x64) // Immediate command input. +#define RD_REGISTER_ImmComStat() controller->pci->ReadBAR16(0, 0x68) // Immediate command status. +#define WR_REGISTER_ImmComStat(x) controller->pci->WriteBAR16(0, 0x68, x) +#define RD_REGISTER_SDCTL(n) controller->pci->ReadBAR32(0, 0x80 + 0x20 * (n)) // Stream descriptor control. +#define WR_REGISTER_SDCTL(n, x) controller->pci->WriteBAR32(0, 0x80 + 0x20 * (n), x) +#define RD_REGISTER_SDSTS(n) controller->pci->ReadBAR8(0, 0x83 + 0x20 * (n)) // Stream descriptor status. +#define WR_REGISTER_SDSTS(n, x) controller->pci->WriteBAR8(0, 0x83 + 0x20 * (n), x) +#define RD_REGISTER_SDLPIB(n) controller->pci->ReadBAR32(0, 0x84 + 0x20 * (n)) // Stream descriptor link position in cyclic buffer. +#define WR_REGISTER_SDCBL(n, x) controller->pci->WriteBAR32(0, 0x88 + 0x20 * (n), x) // Stream descriptor cyclic buffer length. +#define RD_REGISTER_SDLVI(n) controller->pci->ReadBAR16(0, 0x8C + 0x20 * (n)) // Stream descriptor last valid index. +#define WR_REGISTER_SDLVI(n, x) controller->pci->WriteBAR16(0, 0x8C + 0x20 * (n), x) +#define RD_REGISTER_SDFMT(n) controller->pci->ReadBAR16(0, 0x92 + 0x20 * (n)) // Stream descriptor format. +#define WR_REGISTER_SDFMT(n, x) controller->pci->WriteBAR16(0, 0x92 + 0x20 * (n), x) +#define WR_REGISTER_SDBDPL(n, x) controller->pci->WriteBAR32(0, 0x98 + 0x20 * (n), x) // Stream descriptor BDL pointer lower base address. +#define WR_REGISTER_SDBDPU(n, x) controller->pci->WriteBAR32(0, 0x9C + 0x20 * (n), x) // Stream descriptor BDL pointer upper base address. + +#define READ_PARAMETER_VENDOR_ID (0xF0000) +#define READ_PARAMETER_REVISION_ID (0xF0002) +#define READ_PARAMETER_CHILD_NODES (0xF0004) +#define READ_PARAMETER_FUNCTION_GROUP_TYPE (0xF0005) +#define READ_PARAMETER_AUDIO_FUNCTION_CAPABILITIES (0xF0008) +#define READ_PARAMETER_AUDIO_WIDGET_CAPABILITIES (0xF0009) +#define READ_PARAMETER_FORMAT_CAPABILITIES (0xF000A) +#define READ_PARAMETER_STREAM_FORMATS (0xF000B) +#define READ_PARAMETER_PIN_CAPABILITIES (0xF000C) +#define READ_PARAMETER_INPUT_AMP_CAPABILITIES (0xF000D) +#define READ_PARAMETER_CONNECTION_LIST_LENGTH (0xF000E) +#define READ_PARAMETER_OUTPUT_AMP_CAPABILITIES (0xF0012) + +#define COMMAND_GET_CONNECTION_LIST_ENTRY(offset) (0xF0200 | (offset)) +#define COMMAND_SET_CONNECTION_SELECT(index) (0x70100 | (index)) +#define COMMAND_GET_AMPLIFIER_GAIN_MUTE(out, left, index) (0xB0000 | ((out) ? (1 << 15) : 0) | ((left) ? (1 << 13) : 0) | (index)) +#define COMMAND_SET_AMPLIFIER_GAIN_MUTE(out, left, index, mute, gain) (0x30000 | ((out) ? (1 << 15) : (1 << 14)) | ((left) ? (1 << 13) : (1 << 12)) \ + | ((index) << 8) | ((mute) ? (1 << 7) : 0) | (gain)) +#define COMMAND_SET_CONVERTER_FORMAT(format) (0x20000 | (format)) +#define COMMAND_SET_STREAM_NUMBER(stream, channel) (0x70600 | ((stream) << 4) | ((channel) << 0)) +#define COMMAND_GET_PIN_WIDGET_CONTROL() (0xF0700) +#define COMMAND_SET_PIN_WIDGET_CONTROL(control) (0x70700 | (control)) +#define COMMAND_PIN_SENSE() (0xF0900) +#define COMMAND_GET_PIN_CONFIGURATION() (0xF1C00) +#define COMMAND_RESET() (0x7FF00) + +#define HDA_WIDGET_AUDIO_OUTPUT (0) +#define HDA_WIDGET_AUDIO_INPUT (1) +#define HDA_WIDGET_PIN_COMPLEX (4) + +#define PIN_MAYBE_CONNECTED (0) +#define PIN_UNCONNECTED (1) +#define PIN_CONNECTED (2) + +struct HDAWidget : KDevice { + uint32_t codec; + uint32_t node; + uint32_t functionGroup; + uint32_t type; + +#define MAXIMUM_INPUTS (32) + uint8_t inputs[MAXIMUM_INPUTS]; + + union { + struct { + uint32_t pinCapabilities, pinConfiguration; + uint8_t pinIsConnected; + bool pinIsInput, pinIsOutput; + }; + }; +}; + +struct HDAController : KDevice { + KPCIDevice *pci; + + size_t outputStreamsSupported; + size_t inputStreamsSupported; + size_t bidirectionalStreamsSupported; + + size_t corbEntries, rirbEntries; + uint8_t *corbVirtual, *rirbVirtual; + uintptr_t corbPhysical, rirbPhysical; + uintptr_t corbWritePointer, rirbReadPointer; + uint32_t rirbLastSolicitedResponse; + KEvent rirbReceivedSolicitedResponse; +}; + +static const char *const widgetTypeStrings[] = { + "Audio output", + "Audio input", + "Audio mixer", + "Audio selector", + "Pin complex", + "Power widget", + "Volume knob", + "Beep generator", +}; + +static const char *const portConnectivityStrings[] = { + "jack", + "none", + "integrated", + "jack and integrated", +}; + +static const char *const locationHighStrings[] = { + "external", + "internal", + "separate", + "other", +}; + +static const char *const locationLowStrings[] = { + "??", + "rear", + "front", + "left", + "right", + "top", + "bottom", + "special", + "special", + "special", + "??", + "??", + "??", + "??", + "??", + "??", +}; + +static const char *const defaultDeviceStrings[] = { + "line out", + "speaker", + "HP out", + "CD", + "SPDIF out", + "digital other out", + "modem line side", + "modem handset side", + "line in", + "AUX", + "microphone in", + "telephony", + "SPDIF in", + "digital other in", + "??", + "??", +}; + +static const char *const connectionTypeStrings[] = { + "unknown", + "1/8\" stereo/mono", + "1/4\" stereo/mono", + "ATAPI internal", + "RCA", + "optical", + "other digital", + "other analog", + "multichannel analog (DIN)", + "XLR/Professional", + "RJ-11 (Modem)", + "combination", + "??", + "??", + "??", + "??", +}; + +static const char *const colorStrings[] = { + "unknown", + "black", + "grey", + "blue", + "green", + "red", + "orange", + "yellow", + "purple", + "pink", + "??", + "??", + "??", + "??", + "white", + "other", +}; + +static bool HDAControllerSendCommand(HDAController *controller, uint32_t codec, uint32_t node, uint32_t data, uint32_t *response) { + // TODO Test wrap-around. + + uint32_t command = (codec << 28) | (node << 20) | data; + uintptr_t corbWritePointer = controller->corbWritePointer; + corbWritePointer = (corbWritePointer + 1) % controller->corbEntries; + ((volatile uint32_t *) controller->corbVirtual)[corbWritePointer] = command; + WR_REGISTER_CORBWP(ES_ISOLATE_BITS(RD_REGISTER_CORBWP(), 15, 8) | corbWritePointer); + controller->corbWritePointer = corbWritePointer; + if (!KEventWait(&controller->rirbReceivedSolicitedResponse, 500 /* half a second timeout */)) return false; + if (response) *response = controller->rirbLastSolicitedResponse; + return true; +} + +static bool HDAControllerHandleIRQ(uintptr_t, void *context) { + HDAController *controller = (HDAController *) context; + uint32_t interruptStatus = RD_REGISTER_INTSTS(); + + if (~interruptStatus & (1 << 31 /* global interrupt status */)) { + return false; + } + + if (interruptStatus & (1 << 30)) { + uint8_t rirbStatus = RD_REGISTER_RIRBSTS(); + WR_REGISTER_RIRBSTS(rirbStatus); + + if (rirbStatus & (1 << 0 /* response interrupt */)) { + uint8_t rirbWritePointer = RD_REGISTER_RIRBWP(); + + while (controller->rirbReadPointer != rirbWritePointer) { + controller->rirbReadPointer = (controller->rirbReadPointer + 1) % controller->rirbEntries; + uint32_t response = ((volatile uint32_t *) controller->rirbVirtual)[controller->rirbReadPointer * 2 + 0]; + uint32_t extended = ((volatile uint32_t *) controller->rirbVirtual)[controller->rirbReadPointer * 2 + 1]; + + if (~extended & (1 << 4)) { + controller->rirbLastSolicitedResponse = response; + KEventSet(&controller->rirbReceivedSolicitedResponse); + } + } + } + + } + + return true; +} + +static void HDAControllerExploreFunctionGroup(HDAController *controller, uint32_t codec, uint32_t functionGroupNode) { + uint32_t type, childNodeCount; + + if (!HDAControllerSendCommand(controller, codec, functionGroupNode, READ_PARAMETER_FUNCTION_GROUP_TYPE, &type) + || !HDAControllerSendCommand(controller, codec, functionGroupNode, READ_PARAMETER_CHILD_NODES, &childNodeCount)) { + return; + } + + uint32_t firstChildNode = ES_EXTRACT_BITS(childNodeCount, 23, 16); + childNodeCount = ES_EXTRACT_BITS(childNodeCount, 7, 0); + type = ES_EXTRACT_BITS(type, 7, 0); + + KernelLog(LOG_INFO, "HDA", "found function group", "Found function group with type %d (%z), and child nodes %d to %d.\n", + type, type == 1 ? "audio" : type == 2 ? "modem" : "??", firstChildNode, firstChildNode + childNodeCount - 1); + + for (uintptr_t j = firstChildNode; j < firstChildNode + childNodeCount; j++) { + uint32_t widgetCapabilities; + + if (!HDAControllerSendCommand(controller, codec, j, READ_PARAMETER_AUDIO_WIDGET_CAPABILITIES, &widgetCapabilities)) { + continue; + } + + uint32_t widgetType = ES_EXTRACT_BITS(widgetCapabilities, 23, 20); + + HDAWidget *widget = (HDAWidget *) KDeviceCreate("HD Audio widget", controller, sizeof(HDAWidget)); + widget->codec = codec; + widget->node = j; + widget->functionGroup = functionGroupNode; + widget->type = widgetType; + + KernelLog(LOG_INFO, "HDA", "found widget", "Widget at node %d has type \"%z\".\n", + widget->node, widgetType >= sizeof(widgetTypeStrings) / sizeof(widgetTypeStrings[0]) ? "Other" : widgetTypeStrings[widgetType]); + + if (widgetCapabilities & (1 << 8)) { + uint32_t connectionListLength, connectionList; + + if (HDAControllerSendCommand(controller, codec, widget->node, READ_PARAMETER_CONNECTION_LIST_LENGTH, &connectionListLength) + && (~connectionListLength & (1 << 7) /* long form not supported */) + && ES_EXTRACT_BITS(connectionListLength, 6, 0)) { + uintptr_t index = 0; + + for (uintptr_t command = 0; command < (connectionListLength + 3) / 4; command++) { + if (!HDAControllerSendCommand(controller, codec, widget->node, COMMAND_GET_CONNECTION_LIST_ENTRY(command * 4), &connectionList)) { + break; + } + + for (uintptr_t i = 0; i < (connectionListLength - command * 4) && index < MAXIMUM_INPUTS; i++) { + uint8_t entry = connectionList >> (i * 8); + + if ((entry & 0x80) && index) { + for (uintptr_t node = widget->inputs[index - 1]; node <= (entry & 0x7F) && index < MAXIMUM_INPUTS; node++) { + widget->inputs[index++] = node; + } + } else { + widget->inputs[index++] = entry; + } + } + } + } + } + + for (uintptr_t i = 0; i < MAXIMUM_INPUTS; i++) { + if (!widget->inputs[i]) break; + KernelLog(LOG_INFO, "HDA", "widget connection", "Widget %d has possible input %d.\n", widget->node, widget->inputs[i]); + } + } + + for (uintptr_t i = 0; i < controller->children.Length(); i++) { + HDAWidget *widget = (HDAWidget *) controller->children[i]; + + if (widget->type == HDA_WIDGET_PIN_COMPLEX) { + if (!HDAControllerSendCommand(controller, codec, widget->node, READ_PARAMETER_PIN_CAPABILITIES, &widget->pinCapabilities) + || !HDAControllerSendCommand(controller, codec, widget->node, COMMAND_GET_PIN_CONFIGURATION(), &widget->pinConfiguration)) { + continue; + } + + widget->pinIsOutput = widget->pinCapabilities & (1 << 4); + widget->pinIsInput = widget->pinCapabilities & (1 << 5); + + KernelLog(LOG_INFO, "HDA", "pin information", "Pin %d has capabilities %x and configuration %x.%z%z\n", + widget->node, widget->pinCapabilities, widget->pinConfiguration, + widget->pinIsOutput ? " Output." : "", widget->pinIsInput ? " Input." : ""); + + if (!widget->pinIsOutput && !widget->pinIsInput) { + continue; + } + + uint32_t portConnectivity = ES_EXTRACT_BITS(widget->pinConfiguration, 31, 30); + uint32_t location = ES_EXTRACT_BITS(widget->pinConfiguration, 29, 24); + uint32_t defaultDevice = ES_EXTRACT_BITS(widget->pinConfiguration, 23, 20); + uint32_t connectionType = ES_EXTRACT_BITS(widget->pinConfiguration, 19, 16); + uint32_t color = ES_EXTRACT_BITS(widget->pinConfiguration, 15, 12); + + KernelLog(LOG_INFO, "HDA", "pin information", "Connectivity: %z; location: %z %z; default device: %z; connection type: %z; color: %z.\n", + portConnectivityStrings[portConnectivity], + locationHighStrings[ES_EXTRACT_BITS(location, 5, 4)], locationLowStrings[ES_EXTRACT_BITS(location, 3, 0)], + defaultDeviceStrings[defaultDevice], connectionTypeStrings[connectionType], colorStrings[color]); + + if (widget->pinCapabilities & (1 << 2)) { + uint32_t pinSense; + + if (HDAControllerSendCommand(controller, codec, widget->node, COMMAND_PIN_SENSE(), &pinSense)) { + widget->pinIsConnected = (pinSense & (1 << 31)) ? PIN_CONNECTED : PIN_UNCONNECTED; + KernelLog(LOG_INFO, "HDA", "pin sense", "Pin sense: %z.\n", widget->pinIsConnected == PIN_CONNECTED ? "connected" : "unconnected"); + } + } + + // TODO Register the device with the audio subsystem. + } + } +} + +static void HDAControllerDestroy(KDevice *_controller) { + HDAController *controller = (HDAController *) _controller; + if (controller->corbVirtual) MMPhysicalFreeAndUnmap(controller->corbVirtual, controller->corbPhysical); + if (controller->rirbVirtual) MMPhysicalFreeAndUnmap(controller->rirbVirtual, controller->rirbPhysical); + // TODO Unregister interrupt handler. +} + +static void HDAControllerAttach(KDevice *_parent) { + HDAController *controller = (HDAController *) KDeviceCreate("HD Audio controller", _parent, sizeof(HDAController)); + + if (!controller) { + return; + } + + controller->destroy = HDAControllerDestroy; + controller->rirbReceivedSolicitedResponse.autoReset = true; + + controller->pci = (KPCIDevice *) _parent; + controller->pci->EnableFeatures(K_PCI_FEATURE_INTERRUPTS | K_PCI_FEATURE_BUSMASTERING_DMA + | K_PCI_FEATURE_MEMORY_SPACE_ACCESS | K_PCI_FEATURE_BAR_0); + + uint16_t globalCapabilities = RD_REGISTER_GCAP(); + bool supports64BitAddresses = globalCapabilities & (1 << 0); + +#ifdef ARCH_64 + if (!supports64BitAddresses) { + KernelLog(LOG_ERROR, "HDA", "controller unsupported", "Controller does not support 64-bit addresses.\n"); + KDeviceDestroy(controller); + return; + } +#endif + + controller->outputStreamsSupported = ES_EXTRACT_BITS(globalCapabilities, 15, 12); + controller->inputStreamsSupported = ES_EXTRACT_BITS(globalCapabilities, 11, 8); + controller->bidirectionalStreamsSupported = ES_EXTRACT_BITS(globalCapabilities, 7, 3); + + KernelLog(LOG_INFO, "HDA", "global capabilities", "Controller supports %d output streams, %d input streams and %d bidi streams.\n", + controller->outputStreamsSupported, controller->inputStreamsSupported, controller->bidirectionalStreamsSupported); + KernelLog(LOG_INFO, "HDA", "version", "Controller reports version %d.%d.\n", + RD_REGISTER_VMAJ(), RD_REGISTER_VMIN()); + + KTimeout timeout(1000); // The initialisation process shouldn't take more than a second. + +#define CHECK_TIMEOUT(message) \ + if (timeout.Hit()) { \ + KernelLog(LOG_ERROR, "HDA", "timeout", "Timeout during initialization: " message ".\n"); \ + KDeviceDestroy(controller); \ + return; \ + } + + // Reset the controller. + + WR_REGISTER_GCTL(RD_REGISTER_GCTL() & ~(1 << 0 /* CRST */)); + while ((RD_REGISTER_GCTL() & (1 << 0)) && timeout.Hit()); + CHECK_TIMEOUT("clear CRST bit"); + WR_REGISTER_GCTL(RD_REGISTER_GCTL() | (1 << 0 /* CRST */)); + while ((~RD_REGISTER_GCTL() & (1 << 0)) && timeout.Hit()); + CHECK_TIMEOUT("set CRST bit"); + + // Setup CORB/RIRB. + + uint8_t corbSize = RD_REGISTER_CORBSIZE(); + controller->corbEntries = (corbSize & (1 << 6)) ? 256 : (corbSize & (1 << 5)) ? 16 : (corbSize & (1 << 4)) ? 2 : 0; + uint8_t rirbSize = RD_REGISTER_RIRBSIZE(); + controller->rirbEntries = (rirbSize & (1 << 6)) ? 256 : (rirbSize & (1 << 5)) ? 16 : (rirbSize & (1 << 4)) ? 2 : 0; + + if (!controller->corbEntries || !controller->rirbEntries) { + KernelLog(LOG_ERROR, "HDA", "unsupported", "Controller does not support any recognised CORB/RIRB sizes.\n"); + KDeviceDestroy(controller); + return; + } + + if (!MMPhysicalAllocateAndMap(controller->corbEntries * 4, 128, 0, true, + MM_REGION_NOT_CACHEABLE, &controller->corbVirtual, &controller->corbPhysical) + || !MMPhysicalAllocateAndMap(controller->rirbEntries * 8, 128, 0, true, + MM_REGION_NOT_CACHEABLE, &controller->rirbVirtual, &controller->rirbPhysical)) { + KernelLog(LOG_ERROR, "HDA", "insufficient resources", "Could not allocate memory for CORB/RIRB.\n"); + KDeviceDestroy(controller); + return; + } + + WR_REGISTER_CORBSIZE(ES_ISOLATE_BITS(RD_REGISTER_CORBSIZE(), 7, 2) | (controller->corbEntries == 16 ? 1 : controller->corbEntries == 256 ? 2 : 0)); + WR_REGISTER_RIRBSIZE(ES_ISOLATE_BITS(RD_REGISTER_RIRBSIZE(), 7, 2) | (controller->rirbEntries == 16 ? 1 : controller->rirbEntries == 256 ? 2 : 0)); + + WR_REGISTER_CORBLBASE(controller->corbPhysical & 0xFFFFFFFF); + if (supports64BitAddresses) WR_REGISTER_CORBUBASE(controller->corbPhysical >> 32); + WR_REGISTER_RIRBLBASE(controller->rirbPhysical & 0xFFFFFFFF); + if (supports64BitAddresses) WR_REGISTER_RIRBUBASE(controller->rirbPhysical >> 32); + + WR_REGISTER_RINTCNT(ES_ISOLATE_BITS(RD_REGISTER_RINTCNT(), 15, 8) | 1 /* interrupt after every response */); + + WR_REGISTER_CORBCTL(ES_ISOLATE_BITS(RD_REGISTER_CORBCTL(), 7, 2) | (1 << 1 /* run */) | (1 << 0 /* interrupt on error */)); + WR_REGISTER_RIRBCTL(ES_ISOLATE_BITS(RD_REGISTER_RIRBCTL(), 7, 3) | (1 << 1 /* run */) | (1 << 0 /* interrupt on response */)); + + if ((~RD_REGISTER_CORBCTL() & (1 << 1)) || (~RD_REGISTER_RIRBCTL() & (1 << 1))) { + KernelLog(LOG_ERROR, "HDA", "start error", "Could not start the CORB/RIRB.\n"); + KDeviceDestroy(controller); + return; + } + + // Setup interrupts. + + if (!controller->pci->EnableSingleInterrupt(HDAControllerHandleIRQ, controller, "HDA")) { + KernelLog(LOG_ERROR, "HDA", "insufficient resources", "Could not register interrupt handler.\n"); + KDeviceDestroy(controller); + return; + } + + WR_REGISTER_INTCTL((1 << 31) | (1 << 30)); + + // Enumerate codecs. + + uint16_t codecs = RD_REGISTER_STATESTS(); + + for (uintptr_t i = 0; i < 15; i++) { + if (~codecs & (1 << i)) { + continue; + } + + uint32_t vendorID, childNodeCount; + + if (HDAControllerSendCommand(controller, i, 0, READ_PARAMETER_VENDOR_ID, &vendorID) + && HDAControllerSendCommand(controller, i, 0, READ_PARAMETER_CHILD_NODES, &childNodeCount)) { + uint32_t firstChildNode = ES_EXTRACT_BITS(childNodeCount, 23, 16); + childNodeCount = ES_EXTRACT_BITS(childNodeCount, 7, 0); + + KernelLog(LOG_INFO, "HDA", "found codec", "Found codec with vendor ID %x, and child nodes %d to %d.\n", + vendorID, firstChildNode, firstChildNode + childNodeCount - 1); + + for (uintptr_t j = firstChildNode; j < firstChildNode + childNodeCount; j++) { + HDAControllerExploreFunctionGroup(controller, i, j); + } + } + } + + // TODO Enable unsolicited responses. + // TODO Support hotplugging. + + KernelLog(LOG_INFO, "HDA", "ready", "Controller %x successfully initialized.\n", controller); +} + +KDriver driverHDAudio = { + .attach = HDAControllerAttach, +}; diff --git a/drivers/i8254x.cpp b/drivers/i8254x.cpp new file mode 100644 index 0000000..36d5f2b --- /dev/null +++ b/drivers/i8254x.cpp @@ -0,0 +1,499 @@ +// TODO Initialise on a separate thread. +// TODO Checksum off-loading. + +#include + +#define RD_REGISTER_CTRL() Read(0x00) // Device control. +#define WR_REGISTER_CTRL(x) Write(0x00, (x) & ~0x20000416) +#define RD_REGISTER_STATUS() Read(0x08) // Device status. +#define RD_REGISTER_EECD() Read(0x10) // EEPROM data. +#define RD_REGISTER_EERD() Read(0x14) // EEPROM read. +#define WR_REGISTER_EERD(x) Write(0x14, x) +#define WR_REGISTER_FCAL(x) Write(0x28, x) // Flow control low. +#define WR_REGISTER_FCAH(x) Write(0x2C, x) // Flow control high. +#define WR_REGISTER_FCT(x) Write(0x30, x) // Flow control type. +#define RD_REGISTER_ICR() Read(0xC0) // Interrupt cause read. +#define RD_REGISTER_IMS() Read(0xD0) // Interrupt mask set/read. +#define WR_REGISTER_IMS(x) Write(0xD0, x) +#define WR_REGISTER_IMC(x) Write(0xD8, x) // Interrupt mask clear. +#define RD_REGISTER_RCTL() Read(0x100) // Receive control. +#define WR_REGISTER_RCTL(x) Write(0x100, (x) & ~0xF9204C01) +#define RD_REGISTER_RDBAL() Read(0x2800) // Receive descriptor base address low. +#define WR_REGISTER_RDBAL(x) Write(0x2800, x) +#define RD_REGISTER_RDBAH() Read(0x2804) // Receive descriptor base address high. +#define WR_REGISTER_RDBAH(x) Write(0x2804, x) +#define RD_REGISTER_RDLEN() Read(0x2808) // Receive descriptor length. +#define WR_REGISTER_RDLEN(x) Write(0x2808, x) +#define RD_REGISTER_RDH() Read(0x2810) // Receive descriptor head. +#define WR_REGISTER_RDH(x) Write(0x2810, x) +#define RD_REGISTER_RDT() Read(0x2818) // Receive descriptor tail. +#define WR_REGISTER_RDT(x) Write(0x2818, x) +#define WR_REGISTER_MTA(x, y) Write(0x5200 + x * 4, y) // Multicast table array. +#define RD_REGISTER_RAL() Read(0x5400) // Receive address low. +#define WR_REGISTER_RAL(x) Write(0x5400, x) +#define RD_REGISTER_RAH() Read(0x5404) // Receive address high. +#define WR_REGISTER_RAH(x) Write(0x5404, x) +#define RD_REGISTER_TCTL() Read(0x400) // Transmit control. +#define WR_REGISTER_TCTL(x) Write(0x400, (x) & ~0xFC800005) +#define RD_REGISTER_TDBAL() Read(0x3800) // Transmit descriptor base address low. +#define WR_REGISTER_TDBAL(x) Write(0x3800, x) +#define RD_REGISTER_TDBAH() Read(0x3804) // Transmit descriptor base address high. +#define WR_REGISTER_TDBAH(x) Write(0x3804, x) +#define RD_REGISTER_TDLEN() Read(0x3808) // Transmit descriptor length. +#define WR_REGISTER_TDLEN(x) Write(0x3808, x) +#define RD_REGISTER_TDH() Read(0x3810) // Transmit descriptor head. +#define WR_REGISTER_TDH(x) Write(0x3810, x) +#define RD_REGISTER_TDT() Read(0x3818) // Transmit descriptor tail. +#define WR_REGISTER_TDT(x) Write(0x3818, x) + +#define RECEIVE_DESCRIPTOR_COUNT (64) +#define TRANSMIT_DESCRIPTOR_COUNT (64) + +#define RECEIVE_BUFFER_SIZE (8192) +#define TRANSMIT_BUFFER_SIZE (8192) +#define TRANSFER_BUFFER_EXTRA (16) // TODO What are these for? + +struct ReceiveDescriptor { + uint64_t address; + uint16_t length; + uint16_t checksum; + uint8_t status, errors; + uint16_t special; +}; + +struct TransmitDescriptor { + uint64_t address; + uint16_t length; + uint8_t checksumOffset; + uint8_t command; + uint8_t status; + uint8_t checksumStartField; + uint16_t special; +}; + +struct Controller : NetInterface { + KPCIDevice *pci; + + bool hasEEPROM; + + ReceiveDescriptor *receiveDescriptors; + TransmitDescriptor *transmitDescriptors; + uint8_t *receiveBuffers[RECEIVE_DESCRIPTOR_COUNT]; + void *transmitBuffers[TRANSMIT_DESCRIPTOR_COUNT]; + uintptr_t receiveTail; + uintptr_t transmitTail; + + // Used by the dispatch thread. + uint8_t *dispatchBuffers[RECEIVE_DESCRIPTOR_COUNT]; + size_t dispatchByteCounts[RECEIVE_DESCRIPTOR_COUNT]; + uintptr_t dispatchPhysicalAddresses[RECEIVE_DESCRIPTOR_COUNT]; + + KMutex transmitMutex; + KEvent receiveEvent; + + uint32_t Read(uintptr_t offset); + void Write(uintptr_t offset, uint32_t value); + bool ReadEEPROM(uint8_t address, uint16_t *data); + + void Initialise(); + bool Transmit(void *dataVirtual, uintptr_t dataPhysical, size_t dataBytes); + bool HandleIRQ(); + void DispatchThread(); + void DumpState(); +}; + +void Controller::DumpState() { + EsPrint("I8254x controller state:\n"); + + EsPrint("\t--- Internal ---\n"); + EsPrint("\t\tHas EEPROM: %z.\n", hasEEPROM ? "yes" : "no"); + EsPrint("\t\tMAC address: %X:%X:%X:%X:%X:%X.\n", macAddress.d[0], macAddress.d[1], macAddress.d[2], + macAddress.d[3], macAddress.d[4], macAddress.d[5]); + + EsPrint("\t--- Registers ---\n"); + EsPrint("\t\tDevice control: %x.\n", RD_REGISTER_CTRL()); + EsPrint("\t\tDevice status: %x.\n", RD_REGISTER_STATUS()); + EsPrint("\t\tEEPROM data: %x.\n", RD_REGISTER_EECD()); + EsPrint("\t\tEEPROM read: %x.\n", RD_REGISTER_EERD()); + EsPrint("\t\tReceive descriptor base address: %x.\n", (uint64_t) RD_REGISTER_RDBAL() | ((uint64_t) RD_REGISTER_RDBAH() << 32)); + EsPrint("\t\tReceive descriptor length: %x.\n", RD_REGISTER_RDLEN()); + EsPrint("\t\tReceive descriptor head: %x.\n", RD_REGISTER_RDH()); + EsPrint("\t\tReceive descriptor tail: %x.\n", RD_REGISTER_RDT()); + EsPrint("\t\tReceive control: %x.\n", RD_REGISTER_RCTL()); + EsPrint("\t\tReceive MAC address: %x.\n", (uint64_t) RD_REGISTER_RAL() | ((uint64_t) RD_REGISTER_RAH() << 32)); + EsPrint("\t\tTransmit descriptor base address: %x.\n", (uint64_t) RD_REGISTER_TDBAL() | ((uint64_t) RD_REGISTER_TDBAH() << 32)); + EsPrint("\t\tTransmit descriptor length: %x.\n", RD_REGISTER_TDLEN()); + EsPrint("\t\tTransmit descriptor head: %x.\n", RD_REGISTER_TDH()); + EsPrint("\t\tTransmit descriptor tail: %x.\n", RD_REGISTER_TDT()); + EsPrint("\t\tTransmit control: %x.\n", RD_REGISTER_TCTL()); +} + +bool Controller::Transmit(void *dataVirtual, uintptr_t dataPhysical, size_t dataBytes) { + if (!dataBytes) { + KernelPanic("Controller::Transmit - dataBytes is zero.\n"); + } + + KMutexAcquire(&transmitMutex); + EsDefer(KMutexRelease(&transmitMutex)); + + // Get a next index to use for the transmit descriptor. + + uint32_t head = RD_REGISTER_TDH(); + uint32_t index = transmitTail; + uint32_t tail = (index + 1) % TRANSMIT_DESCRIPTOR_COUNT; + + if (head == tail) { + // Wait upto 20ms for the head to move. + KTimeout timeout(20); + while (!timeout.Hit() && (RD_REGISTER_TDH() == tail)); + head = RD_REGISTER_TDH(); + } + + if (head == tail) { + KernelLog(LOG_ERROR, "I8254x", "transmit overrun", "Attempting to transmit a packet with the head at the same position as the tail.\n"); + return false; + } + + // Free any unused transmit buffers. + + if (transmitBuffers[index]) { + NetTransmitBufferReturn(transmitBuffers[index]); + } + + for (uintptr_t i = tail; i != head; i = (i + 1) % TRANSMIT_DESCRIPTOR_COUNT) { + if (transmitBuffers[i]) { + NetTransmitBufferReturn(transmitBuffers[i]); + transmitBuffers[i] = nullptr; + } + } + + // Set up transmit descriptor. + + transmitDescriptors[index].length = dataBytes; + transmitDescriptors[index].status = 0; + transmitDescriptors[index].address = dataPhysical; + transmitDescriptors[index].command = (1 << 0 /* end of packet */) | (1 << 1 /* insert CRC in Ethernet packet */) | (1 << 3 /* report status */); + + transmitBuffers[index] = dataVirtual; + + if ((dataPhysical >> K_PAGE_BITS) != ((dataPhysical + dataBytes - 1) >> K_PAGE_BITS)) { + KernelPanic("Controller::Transmit - Data spanned over page boundary.\n"); + } + + // Submit the transmit descriptor to the controller. + + transmitTail = tail; + __sync_synchronize(); + WR_REGISTER_TDT(tail); + + return true; +} + +void Controller::DispatchThread() { + while (true) { + KEvent *events[] = { &receiveEvent }; + KWaitEvents(events, 1); + + NetInterfaceSetConnected(this, RD_REGISTER_STATUS() & (1 << 1)); + + uint32_t tail = receiveTail, head = RD_REGISTER_RDH(); + uintptr_t dispatchCount = 0; + + while (true) { + uint32_t nextTail = (tail + 1) % RECEIVE_DESCRIPTOR_COUNT; + + if (nextTail == head) { + // Keep the tail one behind the head, otherwise controller assumes queue is empty of usable slots. + break; + } + + if (~receiveDescriptors[nextTail].status & (1 << 0 /* descriptor done */)) { + break; + } + + tail = nextTail; + + uint16_t status = receiveDescriptors[tail].status; + receiveDescriptors[tail].status = 0; + + if (~status & (1 << 1 /* end of packet */)) { + KernelLog(LOG_ERROR, "I8254x", "clear EOP bit", "Received descriptor with clear end of packet bit; this is unsupported.\n"); + goto next; + } + + if (receiveDescriptors[tail].errors) { + KernelLog(LOG_ERROR, "I8254x", "received error", "Received descriptor with error bits %X set.\n", receiveDescriptors[tail].errors); + goto next; + } + + if (receiveDescriptors[tail].length < 60) { + KernelLog(LOG_ERROR, "I8254x", "short packet", "Received descriptor with packet less than 60 bytes; this is unsupported.\n"); + goto next; + } + + KernelLog(LOG_VERBOSE, "I8254x", "received packet", "Received packet at index %d with length %D.\n", tail, receiveDescriptors[tail].length); + + uint8_t *newVirtualAddress; + uintptr_t newPhysicalAddress; + + if (!MMPhysicalAllocateAndMap(RECEIVE_BUFFER_SIZE + TRANSFER_BUFFER_EXTRA, + 16, 64, false, 0, &newVirtualAddress, &newPhysicalAddress)) { + // If we couldn't allocate memory, dispatch the buffer immediately. + + NetInterfaceReceive(this, receiveBuffers[tail], receiveDescriptors[tail].length, NET_PACKET_ETHERNET); + } else { + // Queue the buffer to be dispatched. + + dispatchBuffers[dispatchCount] = receiveBuffers[tail]; + dispatchByteCounts[dispatchCount] = receiveDescriptors[tail].length; + dispatchPhysicalAddresses[dispatchCount] = receiveDescriptors[tail].address; + dispatchCount++; + + receiveBuffers[tail] = newVirtualAddress; + receiveDescriptors[tail].address = newPhysicalAddress; + } + + next:; + } + + __sync_synchronize(); + receiveTail = tail; + WR_REGISTER_RDT(tail); + + for (uintptr_t i = 0; i < dispatchCount; i++) { + NetInterfaceReceive(this, dispatchBuffers[i], dispatchByteCounts[i], NET_PACKET_ETHERNET); + MMFree(MMGetKernelSpace(), dispatchBuffers[i], RECEIVE_BUFFER_SIZE + TRANSFER_BUFFER_EXTRA); + MMPhysicalFree(dispatchPhysicalAddresses[i], false, (RECEIVE_BUFFER_SIZE + TRANSFER_BUFFER_EXTRA + K_PAGE_SIZE - 1) / K_PAGE_SIZE); + } + } +} + +bool Controller::HandleIRQ() { + uint32_t cause = RD_REGISTER_ICR(); + + if (!cause) { + return false; + } + + KernelLog(LOG_VERBOSE, "I8254x", "received IRQ", "Received IRQ with cause %x.\n", cause); + + if (cause & (1 << 2)) { + KernelLog(LOG_INFO, "I8254x", "link status change", "Link is now %z.\n", + (RD_REGISTER_STATUS() & (1 << 1)) ? "up" : "down"); + KEventSet(&receiveEvent, false, true); + } + + if (cause & (1 << 6)) { + KernelLog(LOG_ERROR, "I8254x", "receive underrun", "Controller reported receive underrun; packets have been lost.\n"); + } + + if (cause & ((1 << 6) | (1 << 7) | (1 << 4))) { + KEventSet(&receiveEvent, false, true); + } + + return true; +} + +uint32_t Controller::Read(uintptr_t offset) { + if (pci->baseAddresses[0] & 1) { + pci->WriteBAR32(0, 0, offset); + return pci->ReadBAR32(0, 4); + } else { + return pci->ReadBAR32(0, offset); + } +} + +void Controller::Write(uintptr_t offset, uint32_t value) { + if (pci->baseAddresses[0] & 1) { + pci->WriteBAR32(0, 0, offset); + pci->WriteBAR32(0, 4, value); + } else { + pci->WriteBAR32(0, offset, value); + } +} + +bool Controller::ReadEEPROM(uint8_t address, uint16_t *data) { + if (!hasEEPROM) { + KernelPanic("Controller::ReadEEPROM - EEPROM not present.\n"); + } + + WR_REGISTER_EERD(1 | ((uint32_t) address << 8)); + KTimeout timeout(20); + while (!timeout.Hit() && (RD_REGISTER_EERD() & (1 << 4))); + if (data) *data = RD_REGISTER_EERD() >> 16; + return RD_REGISTER_EERD() & (1 << 4); +} + +void Controller::Initialise() { + KEvent wait = {}; + + // Create a thread for dispatching received packets. + + receiveEvent.autoReset = true; + + if (!KThreadCreate("I8254xDispatch", [] (uintptr_t self) { ((Controller *) self)->DispatchThread(); }, (uintptr_t) this)) { + KernelLog(LOG_ERROR, "I8254x", "thread error", "Could not create the dispatch thread.\n"); + return; + } + + // Detect the EEPROM. + + hasEEPROM = true; + hasEEPROM = ReadEEPROM(0, nullptr); + + // Reset the controller. + + uint32_t controlReset = RD_REGISTER_CTRL(); + + WR_REGISTER_CTRL(controlReset | (1 << 31 /* PHY_RST */)); + RD_REGISTER_STATUS(); + KEventWait(&wait, 20 /* specification says minimum time is 10ms, double for safety */); + + WR_REGISTER_CTRL(controlReset | (1 << 26 /* RST */)); + RD_REGISTER_STATUS(); + KEventWait(&wait, 20); + + if (RD_REGISTER_CTRL() & (1 << 26)) { + KernelLog(LOG_ERROR, "I8254x", "reset timeout", "Reset bit in control register did not clear after 20ms.\n"); + return; + } + + // Configure the control register. + + uint32_t controlClearBits = (1 << 3 /* LRST */) | (1 << 31 /* PHY_RST */) | (1 << 7 /* ILOS */) | (1 << 30 /* VME */); + uint32_t controlSetBits = (1 << 5 /* ASDE */) | (1 << 6 /* SLU */); + WR_REGISTER_CTRL((RD_REGISTER_CTRL() & ~controlClearBits) | controlSetBits); + + // Allocate receive and transmit descriptors and their buffers. + + uintptr_t receiveDescriptorsPhysical, transmitDescriptorsPhysical; + + if (!MMPhysicalAllocateAndMap(sizeof(ReceiveDescriptor) * RECEIVE_DESCRIPTOR_COUNT, 16, 64, true, + 0, (uint8_t **) &receiveDescriptors, &receiveDescriptorsPhysical)) { + KernelLog(LOG_ERROR, "I8254x", "allocation failure", "Could not allocate receive descriptors.\n"); + return; + } + + if (!MMPhysicalAllocateAndMap(sizeof(TransmitDescriptor) * TRANSMIT_DESCRIPTOR_COUNT, 16, 64, true, + 0, (uint8_t **) &transmitDescriptors, &transmitDescriptorsPhysical)) { + KernelLog(LOG_ERROR, "I8254x", "allocation failure", "Could not allocate transmit descriptors.\n"); + return; + } + + for (uintptr_t i = 0; i < RECEIVE_DESCRIPTOR_COUNT; i++) { + if (!MMPhysicalAllocateAndMap(RECEIVE_BUFFER_SIZE + TRANSFER_BUFFER_EXTRA, + 16, 64, false, 0, receiveBuffers + i, &receiveDescriptors[i].address)) { + KernelLog(LOG_ERROR, "I8254x", "allocation failure", "Could not allocate receive buffers.\n"); + return; + } + } + + // Disable flow control. + + WR_REGISTER_FCAL(0); + WR_REGISTER_FCAH(0); + WR_REGISTER_FCT(0); + + // Get the MAC address. + + if (hasEEPROM) { + if (!ReadEEPROM(0, (uint16_t *) &macAddress.d[0]) + || !ReadEEPROM(1, (uint16_t *) &macAddress.d[2]) + || !ReadEEPROM(2, (uint16_t *) &macAddress.d[4])) { + KernelLog(LOG_ERROR, "I8254x", "EEPROM error", "Could not read the MAC address from the EEPROM.\n"); + return; + } + } else { + macAddress64 = ((uint64_t) RD_REGISTER_RAL() | ((uint64_t) RD_REGISTER_RAH() << 32)) & 0xFFFFFFFFFFFF; + } + + // Enable interrupts and the register the handler. + + WR_REGISTER_IMC((1 << 17) - 1); + WR_REGISTER_IMS((1 << 6 /* RXO */) | (1 << 7 /* RXT */) | (1 << 4 /* RXDMT */) | (1 << 2 /* LSC */)); + RD_REGISTER_ICR(); + + if (!pci->EnableSingleInterrupt([] (uintptr_t, void *context) { return ((Controller *) context)->HandleIRQ(); }, this, "I8254x")) { + KernelLog(LOG_ERROR, "I8254x", "IRQ registration failure", "Could not register IRQ %d.\n", pci->interruptLine); + return; + } + + // Setup receive registers. + + WR_REGISTER_RAL(macAddress64 & 0xFFFFFFFF); + WR_REGISTER_RAH(((macAddress64 >> 32) & 0xFFFF) | (1 << 31 /* AV */)); + + WR_REGISTER_RDBAL(receiveDescriptorsPhysical & 0xFFFFFFFF); + WR_REGISTER_RDBAH(receiveDescriptorsPhysical >> 32); + WR_REGISTER_RDLEN(sizeof(ReceiveDescriptor) * RECEIVE_DESCRIPTOR_COUNT); + + WR_REGISTER_RDH(0); + WR_REGISTER_RDT(RECEIVE_DESCRIPTOR_COUNT - 1); + receiveTail = RECEIVE_DESCRIPTOR_COUNT - 1; + + for (uintptr_t i = 0; i < 128; i++) { + // Clear the multicast table array. + WR_REGISTER_MTA(i, 0); + } + + uint32_t receiveControlClearBits = (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 16) | (1 << 17) | (1 << 25) | (1 << 26); + uint32_t receiveControlSetBits = (1 << 1) | (1 << 4) | (1 << 15); + WR_REGISTER_RCTL((RD_REGISTER_RCTL() & ~receiveControlClearBits) | receiveControlSetBits); + + // Setup transmit registers. + + WR_REGISTER_TDBAL(transmitDescriptorsPhysical & 0xFFFFFFFF); + WR_REGISTER_TDBAH(transmitDescriptorsPhysical >> 32); + WR_REGISTER_TDLEN(sizeof(TransmitDescriptor) * TRANSMIT_DESCRIPTOR_COUNT); + + WR_REGISTER_TDH(0); + WR_REGISTER_TDT(0); + transmitTail = 0; + + // TODO Is the TCTL.COLD value correct? + WR_REGISTER_TCTL((1 << 1) | (1 << 3) | (0x0F << 4) | (0x40 << 12)); + + // Register the device. + + transmit = [] (NetInterface *self, void *dataVirtual, uintptr_t dataPhysical, size_t dataBytes) { + return ((Controller *) self)->Transmit(dataVirtual, dataPhysical, dataBytes); + }; + + KRegisterNetInterface(this); + + if (RD_REGISTER_STATUS() & (1 << 1 /* link up */)) { + NetInterfaceSetConnected(this, true); + } +} + +static void DeviceAttach(KDevice *_parent) { + KPCIDevice *parent = (KPCIDevice *) _parent; + + Controller *device = (Controller *) KDeviceCreate("I8254x", parent, sizeof(Controller)); + if (!device) return; + + device->shutdown = [] (KDevice *device) { + NetInterfaceShutdown((Controller *) device); + + // Wait a little bit for the transmit descriptors to be processed. + // TODO Can this be done asynchronously? + KEvent wait = {}; + KEventWait(&wait, 50); + }; + + parent->EnableFeatures(K_PCI_FEATURE_MEMORY_SPACE_ACCESS + | K_PCI_FEATURE_BUSMASTERING_DMA + | K_PCI_FEATURE_INTERRUPTS + | K_PCI_FEATURE_IO_PORT_ACCESS + | K_PCI_FEATURE_BAR_0); + + KernelLog(LOG_INFO, "I8254x", "found controller", "Found I8254x controller with ID %x.\n", parent->deviceID); + + device->pci = parent; + device->Initialise(); + // device->DumpState(); +} + +KDriver driverI8254x = { + .attach = DeviceAttach, +}; diff --git a/drivers/ide.cpp b/drivers/ide.cpp new file mode 100644 index 0000000..2d34f1e --- /dev/null +++ b/drivers/ide.cpp @@ -0,0 +1,602 @@ +// TODO Asynchronous timeout. +// TODO Inserting/removing ATAPI devices. + +#include + +#define ATA_BUSES 2 +#define ATA_DRIVES (ATA_BUSES * 2) +#define ATA_SECTOR_SIZE (512) +#define ATA_TIMEOUT (10000) +#define ATAPI_SECTOR_SIZE (2048) + +#define ATA_REGISTER(_bus, _reg) (_reg != -1 ? ((_bus ? 0x170 : 0x1F0) + _reg) : (_bus ? 0x376 : 0x3F6)) +#define ATA_IRQ(_bus) (_bus ? 15 : 14) +#define ATA_DATA 0 +#define ATA_FEATURES 1 +#define ATA_SECTOR_COUNT 2 +#define ATA_LBA1 3 +#define ATA_LBA2 4 +#define ATA_LBA3 5 +#define ATA_DRIVE_SELECT 6 +#define ATA_STATUS 7 +#define ATA_COMMAND 7 +#define ATA_DCR -1 +#define ATA_IDENTIFY 0xEC +#define ATA_IDENTIFY_PACKET 0xA1 +#define ATA_READ_PIO 0x20 +#define ATA_READ_PIO_48 0x24 +#define ATA_READ_DMA 0xC8 +#define ATA_READ_DMA_48 0x25 +#define ATA_WRITE_PIO 0x30 +#define ATA_WRITE_PIO_48 0x34 +#define ATA_PACKET 0xA0 +#define ATA_WRITE_DMA 0xCA +#define ATA_WRITE_DMA_48 0x35 + +#define DMA_REGISTER(_bus, _reg) 4, ((_bus ? (_reg + 8) : _reg)) +#define DMA_COMMAND 0 +#define DMA_STATUS 2 +#define DMA_PRDT 4 + +struct PRD { + volatile uint32_t base; + volatile uint16_t size; + volatile uint16_t end; +}; + +struct ATAOperation { + void *buffer; + uintptr_t offsetIntoSector, readIndex; + size_t countBytes, sectorsNeededToLoad; + uint8_t operation, readingData, bus, slave; + bool pio; +}; + +struct ATAController : KDevice { + void Initialise(); + bool Access(uintptr_t drive, uint64_t sector, size_t count, int operation, uint8_t *buffer); // Returns true on success. + bool AccessStart(int bus, int slave, uint64_t sector, uintptr_t offsetIntoSector, size_t sectorsNeededToLoad, size_t countBytes, int operation, uint8_t *buffer, bool atapi); + bool AccessEnd(int bus, int slave); + + void SetDrive(int bus, int slave, int extra = 0); + void Unblock(); + + KPCIDevice *pci; + + uint64_t sectorCount[ATA_DRIVES]; + bool isATAPI[ATA_DRIVES]; + + KSemaphore semaphore; + + PRD *prdts[ATA_BUSES]; + void *buffers[ATA_BUSES]; + KEvent irqs[ATA_BUSES]; + + uint16_t identifyData[ATA_SECTOR_SIZE / 2]; + + volatile ATAOperation op; + + KMutex blockedPacketsMutex; +}; + +static ATAController *ataController; + +struct ATADrive : KBlockDevice { + uintptr_t index; +}; + +void ATAController::SetDrive(int bus, int slave, int extra) { + ProcessorOut8(ATA_REGISTER(bus, ATA_DRIVE_SELECT), extra | 0xA0 | (slave << 4)); + for (int i = 0; i < 4; i++) ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)); +} + +bool ATAController::AccessStart(int bus, int slave, uint64_t sector, uintptr_t offsetIntoSector, size_t sectorsNeededToLoad, size_t countBytes, + int operation, uint8_t *_buffer, bool atapi) { + uint16_t *buffer = (uint16_t *) _buffer; + + bool s48 = false; + + // Start a timeout. + KTimeout timeout(1000); + + while ((ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 0x80) && !timeout.Hit()); + + if (timeout.Hit()) return false; + + if (atapi) { + SetDrive(bus, slave); + ProcessorOut8(ATA_REGISTER(bus, ATA_FEATURES), 1); // Using DMA. + uint32_t maxByteCount = sectorsNeededToLoad * ATAPI_SECTOR_SIZE; + if (maxByteCount > 65535) KernelPanic("ATAController::AccessStart - Access too large for ATAPI drive (max 64KB).\n"); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA2), maxByteCount & 0xFF); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA3), (maxByteCount >> 8) & 0xFF); + } else if (sector >= 0x10000000) { + s48 = true; + + SetDrive(bus, slave, 0x40); + + ProcessorOut8(ATA_REGISTER(bus, ATA_SECTOR_COUNT), 0); + ProcessorOut8(ATA_REGISTER(bus, ATA_SECTOR_COUNT), sectorsNeededToLoad); + + // Set the sector to access. + // The drive will keep track of the previous and current values of these registers, + // allowing it to construct a 48-bit sector number. + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA3), sector >> 40); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA2), sector >> 32); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA1), sector >> 24); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA3), sector >> 16); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA2), sector >> 8); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA1), sector >> 0); + } else { + SetDrive(bus, slave, 0x40 | (sector >> 24)); + ProcessorOut8(ATA_REGISTER(bus, ATA_SECTOR_COUNT), sectorsNeededToLoad); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA3), sector >> 16); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA2), sector >> 8); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA1), sector >> 0); + } + + KEvent *event = irqs + bus; + event->autoReset = false; + KEventReset(event); + + // Save the operation information. + op.buffer = buffer; + op.offsetIntoSector = offsetIntoSector; + op.countBytes = countBytes; + op.operation = operation; + op.readingData = false; + op.readIndex = 0; + op.sectorsNeededToLoad = sectorsNeededToLoad; + op.pio = false; + op.bus = bus; + op.slave = slave; + + { + // Make sure the previous request has completed. + ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)); + pci->ReadBAR8(DMA_REGISTER(bus, DMA_STATUS)); + + // Prepare the PRDT and buffer + prdts[bus]->size = sectorsNeededToLoad * (atapi ? ATAPI_SECTOR_SIZE : ATA_SECTOR_SIZE); + if (operation == K_ACCESS_WRITE) EsMemoryCopy((uint8_t *) buffers[bus] + offsetIntoSector, buffer, countBytes); + + // Set the mode. + pci->WriteBAR8(DMA_REGISTER(bus, DMA_COMMAND), operation == K_ACCESS_WRITE ? 0 : 8); + pci->WriteBAR8(DMA_REGISTER(bus, DMA_STATUS), 6); + + // Wait for the RDY bit to set. + while (!(ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & (1 << 6)) && !timeout.Hit()); + if (timeout.Hit()) return false; + + // Issue the command. + if (atapi) ProcessorOut8(ATA_REGISTER(bus, ATA_COMMAND), ATA_PACKET); + else if (s48) ProcessorOut8(ATA_REGISTER(bus, ATA_COMMAND), operation == K_ACCESS_READ ? ATA_READ_DMA_48 : ATA_WRITE_DMA_48); + else ProcessorOut8(ATA_REGISTER(bus, ATA_COMMAND), operation == K_ACCESS_READ ? ATA_READ_DMA : ATA_WRITE_DMA ); + + // Wait for the DRQ bit to set. + while (!(ProcessorIn8(ATA_REGISTER(bus, ATA_DCR)) & (1 << 3)) && !timeout.Hit()); + + if (timeout.Hit()) return false; + + if (atapi) { + uint8_t packet[12] = {}; + packet[0] = 0xA8; // Read sectors. + packet[2] = (sector >> 0x18) & 0xFF; + packet[3] = (sector >> 0x10) & 0xFF; + packet[4] = (sector >> 0x08) & 0xFF; + packet[5] = (sector >> 0x00) & 0xFF; + packet[9] = sectorsNeededToLoad; + + // Wait for the BSY bit to clear. + while ((ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & (1 << 7)) && !timeout.Hit()); + if (timeout.Hit()) return false; + + // Send the ATAPI command. + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), ((uint16_t *) packet)[0]); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), ((uint16_t *) packet)[1]); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), ((uint16_t *) packet)[2]); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), ((uint16_t *) packet)[3]); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), ((uint16_t *) packet)[4]); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), ((uint16_t *) packet)[5]); + } + + pci->WriteBAR8(DMA_REGISTER(bus, DMA_COMMAND), operation == K_ACCESS_WRITE ? 1 : 9); + if (pci->ReadBAR8(DMA_REGISTER(bus, DMA_STATUS)) & 2) return false; + if (ProcessorIn8(ATA_REGISTER(bus, ATA_DCR)) & 33) return false; + } + + return true; +} + +bool ATAController::AccessEnd(int bus, int slave) { + (void) slave; + KEvent *event = irqs + bus; + + { + // Wait for the command to complete. + KEventWait(event, ATA_TIMEOUT); + + // Copy the data that we read. + ATAOperation *op = (ATAOperation *) &ataController->op; + if (op->buffer && op->operation == K_ACCESS_READ) { + // EsPrint("copying %d to %x\n", op->countBytes, op->buffer); + EsMemoryCopy((void *) op->buffer, (uint8_t *) ataController->buffers[op->bus] + op->offsetIntoSector, op->countBytes); + // EsPrint("done\n"); + } + + // Check for error. + if (ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 33) return false; + if (pci->ReadBAR8(DMA_REGISTER(bus, DMA_STATUS)) & 3) return false; + + // Check if the command has completed. + if (!KEventPoll(event)) { + return false; + } + + return true; + } +} + +void ATAController::Unblock() { + KMutexAcquire(&blockedPacketsMutex); + // EsPrint("unblock!\n"); + KSemaphoreReturn(&semaphore, 1); + KMutexRelease(&blockedPacketsMutex); +} + +bool ATAController::Access(uintptr_t drive, uint64_t offset, size_t countBytes, int operation, uint8_t *_buffer) { + bool atapi = isATAPI[drive]; + uint64_t sectorSize = atapi ? ATAPI_SECTOR_SIZE : ATA_SECTOR_SIZE; + uint64_t sector = offset / sectorSize; + uint64_t offsetIntoSector = offset % sectorSize; + uint64_t sectorsNeededToLoad = (countBytes + offsetIntoSector + sectorSize - 1) / sectorSize; + uintptr_t bus = drive >> 1; + uintptr_t slave = drive & 1; + + if (drive >= ATA_DRIVES) KernelPanic("ATAController::Access - Drive %d exceedes the maximum number of ATA driver (%d).\n", drive, ATA_DRIVES); + if (atapi && operation == K_ACCESS_WRITE) KernelPanic("ATAController::Access - Drive %d is an ATAPI drive. ATAPI write operations are currently not supported.\n", drive); + if (!sectorCount[drive] && !atapi) KernelPanic("ATAController::Access - Drive %d is invalid.\n", drive); + if ((sector > sectorCount[drive] || (sector + sectorsNeededToLoad) > sectorCount[drive]) && !atapi) KernelPanic("ATAController::Access - Attempt to access sector %d when drive only has %d sectors.\n", sector, sectorCount[drive]); + if (sectorsNeededToLoad > 64) KernelPanic("ATAController::Access - Attempt to read more than 64 consecutive sectors in 1 function call.\n"); + + // Lock the driver. + { + while (true) { + KEventWait(&semaphore.available, ES_WAIT_NO_TIMEOUT); + KMutexAcquire(&blockedPacketsMutex); + + if (semaphore.units) { + KSemaphoreTake(&semaphore, 1); + break; + } + + KMutexRelease(&blockedPacketsMutex); + } + + KMutexRelease(&blockedPacketsMutex); + } + + // EsPrint("locked (%d/%x)!\n", countBytes, _buffer); + + op.bus = bus; + op.slave = slave; + + if (!AccessStart(bus, slave, sector, offsetIntoSector, sectorsNeededToLoad, countBytes, operation, _buffer, atapi)) { + KSemaphoreReturn(&semaphore, 1); + return false; + } + + bool result = AccessEnd(bus, slave); + Unblock(); + return result; +} + +bool ATAIRQHandler(uintptr_t interruptIndex, void *) { + int bus = interruptIndex - ATA_IRQ(0); + + // Acknowledge the interrupt. + ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)); + ataController->pci->ReadBAR8(DMA_REGISTER(bus, DMA_STATUS)); + + // *Don't* queue an asynchronous task. + // First of all, we don't need to (it's slower), + // and secondly, we need to Sync() nodes we're closing during process handle table termination, + // which takes place in the asynchronous task thread. (Meaning we'd get deadlock). + // TODO Is there a better way to do this, preventing similar bugs in the future? + + ATAOperation *op = (ATAOperation *) &ataController->op; + KEvent *event = ataController->irqs + op->bus; + + if (op->pio) { + KEventSet(event); + } else if (!(ataController->pci->ReadBAR8(DMA_REGISTER(op->bus, DMA_STATUS)) & 4)) { + // The interrupt bit was not set, so the IRQ must have been generated by a different device. + } else { + if (!event->state) { + // Stop the transfer. + ataController->pci->WriteBAR8(DMA_REGISTER(op->bus, DMA_COMMAND), 0); + KEventSet(event); + } else { + KernelLog(LOG_ERROR, "IDE", "too many IRQs", "ATAIRQHandler - Received more interrupts than expected.\n"); + } + } + + KSwitchThreadAfterIRQ(); + + return true; +} + +inline uint32_t ByteSwap32(uint32_t x) { + return ((x & 0xFF000000) >> 24) + | ((x & 0x000000FF) << 24) + | ((x & 0x00FF0000) >> 8) + | ((x & 0x0000FF00) << 8); +} + +void ATAController::Initialise() { + KSemaphoreReturn(&semaphore, 1); + + KernelLog(LOG_INFO, "IDE", "found controller", "ATAController::Initialise - Found an ATA controller.\n"); + + for (uintptr_t bus = 0; bus < ATA_BUSES; bus++) { + // If the status is 0xFF, then the bus does not exist. + if (ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) == 0xFF) { + continue; + } + + // Check that the LBA registers are RW. + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA1), 0xAB); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA2), 0xCD); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA3), 0xEF); + + // Otherwise, the bus doesn't exist. + if (ProcessorIn8(ATA_REGISTER(bus, ATA_LBA1) != 0xAB)) continue; + if (ProcessorIn8(ATA_REGISTER(bus, ATA_LBA2) != 0xCD)) continue; + if (ProcessorIn8(ATA_REGISTER(bus, ATA_LBA3) != 0xEF)) continue; + + // Clear the device command register. + ProcessorOut8(ATA_REGISTER(bus, ATA_DCR), 0); + + int dmaDrivesOnBus = 0; + int drivesOnBus = 0; + uint8_t status; + + size_t drivesPerBus = 2; + + for (uintptr_t slave = 0; slave < drivesPerBus; slave++) { + // Issue the IDENTIFY command to the drive. + SetDrive(bus, slave); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA2), 0); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA3), 0); + ProcessorOut8(ATA_REGISTER(bus, ATA_COMMAND), ATA_IDENTIFY); + + // Start a timeout. + KTimeout timeout(100); + + // Check for error. + bool atapi = false; + if (ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 32) continue; + if (ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 1) { + uint8_t a = ProcessorIn8(ATA_REGISTER(bus, ATA_LBA2)); + uint8_t b = ProcessorIn8(ATA_REGISTER(bus, ATA_LBA3)); + if (a == 0x14 && b == 0xEB) { + atapi = true; + ProcessorOut8(ATA_REGISTER(bus, ATA_COMMAND), ATA_IDENTIFY_PACKET); + } else { + continue; + } + } + + // Wait for the drive to be ready for the data transfer. + while ((ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 0x80) && !timeout.Hit()); + if (timeout.Hit()) continue; + while ((!(status = ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 9)) && !timeout.Hit()); + if (timeout.Hit()) continue; + if (status & 33) continue; + + // Transfer the data. + for (uintptr_t i = 0; i < 256; i++) { + identifyData[i] = ProcessorIn16(ATA_REGISTER(bus, ATA_DATA)); + } + + // Check if the device supports LBA/DMA. + if (!(identifyData[49] & 0x200)) continue; + if (!(identifyData[49] & 0x100)) continue; + dmaDrivesOnBus |= 1; + drivesOnBus |= 1; + + // Work out the number of sectors in the drive. + uint32_t lba28Sectors = ((uint32_t) identifyData[60] << 0) + ((uint32_t) identifyData[61] << 16); + uint64_t lba48Sectors = ((uint64_t) identifyData[100] << 0) + ((uint64_t) identifyData[101] << 16) + + ((uint64_t) identifyData[102] << 32) + ((uint64_t) identifyData[103] << 48); + bool supportsLBA48 = lba48Sectors && (identifyData[83] & (1 << 10)); + uint64_t sectors = supportsLBA48 ? lba48Sectors : lba28Sectors; + sectorCount[slave + bus * 2] = sectors; + + if (atapi) { + isATAPI[slave + bus * 2] = true; + KernelLog(LOG_INFO, "IDE", "found drive", "ATAController::Initialise - Found ATAPI drive: %d/%d%z.\n", + bus, slave, supportsLBA48 ? "; supports LBA48" : ""); + } else { + KernelLog(LOG_INFO, "IDE", "found drive", "ATAController::Initialise - Found ATA drive: %d/%d with %x sectors%z.\n", + bus, slave, sectors, supportsLBA48 ? "; supports LBA48" : ""); + } + } + + if (dmaDrivesOnBus) { + uint8_t *dataVirtual; + uintptr_t dataPhysical; + + if (!MMPhysicalAllocateAndMap(131072, 131072, 32, true, ES_FLAGS_DEFAULT, &dataVirtual, &dataPhysical)) { + KernelLog(LOG_ERROR, "IDE", "allocation failure", "ATAController::Initialise - Could not allocate memory for DMA on bus %d.\n", bus); + sectorCount[bus * 2 + 0] = sectorCount[bus * 2 + 1] = 0; + drivesOnBus = 0; + continue; + } + + PRD *prdt = (PRD *) dataVirtual; + prdt->end = 0x8000; + prdt->base = dataPhysical + 65536; + prdts[bus] = prdt; + + void *buffer = (void *) (dataVirtual + 65536); + buffers[bus] = buffer; + + pci->WriteBAR32(DMA_REGISTER(bus, DMA_PRDT), dataPhysical); + } + + if (drivesOnBus) { + if (!KRegisterIRQ(ATA_IRQ(bus), ATAIRQHandler, nullptr, "IDE")) { + KernelLog(LOG_ERROR, "IDE", "IRQ registration failure", "ATAController::Initialise - Could not register IRQ for bus %d.\n", bus); + + // Disable the drives on this bus. + sectorCount[bus * 2 + 0] = 0; + sectorCount[bus * 2 + 1] = 0; + isATAPI[bus * 2 + 0] = false; + isATAPI[bus * 2 + 1] = false; + } + } + + for (uintptr_t slave = 0; slave < 2; slave++) { + if (sectorCount[slave + bus * 2]) { + bool success = Access(bus * 2 + slave, 0, ATA_SECTOR_SIZE, K_ACCESS_READ, (uint8_t *) identifyData); + + if (!success) { + KernelLog(LOG_ERROR, "IDE", "test read failure", "ATAController::Initialise - Could not perform test read on drive.\n"); + continue; + } + + success = Access(bus * 2 + slave, 0, ATA_SECTOR_SIZE, K_ACCESS_WRITE, (uint8_t *) identifyData); + + if (!success) { + KernelLog(LOG_ERROR, "IDE", "test write failure", "ATAController::Initialise - Could not perform test write to drive.\n"); + } + } else if (isATAPI[slave + bus * 2]) { + KEvent *event = irqs + bus; + event->autoReset = false; + KEventReset(event); + + op.bus = bus; + op.slave = slave; + op.pio = true; + + uint16_t capacity[4]; + + SetDrive(bus, slave); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA2), 0); + ProcessorOut8(ATA_REGISTER(bus, ATA_LBA3), 8); + ProcessorOut8(ATA_REGISTER(bus, ATA_FEATURES), 0); + ProcessorOut8(ATA_REGISTER(bus, ATA_COMMAND), ATA_PACKET); + + KTimeout timeout(100); + + if (ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 33) { + goto readCapacityFailure; + } + + while ((ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 0x80) && !timeout.Hit()); + if (timeout.Hit()) goto readCapacityFailure; + while ((!(status = ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 9)) && !timeout.Hit()); + if (timeout.Hit()) goto readCapacityFailure; + if (status & 33) goto readCapacityFailure; + + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), 0x0025); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), 0x0000); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), 0x0000); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), 0x0000); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), 0x0000); + ProcessorOut16(ATA_REGISTER(bus, ATA_DATA), 0x0000); + + KEventWait(event, ATA_TIMEOUT); + KEventReset(event); + + while ((ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 0x80) && !timeout.Hit()); + if (timeout.Hit()) goto readCapacityFailure; + while ((!(status = ProcessorIn8(ATA_REGISTER(bus, ATA_STATUS)) & 9)) && !timeout.Hit()); + if (timeout.Hit()) goto readCapacityFailure; + if (status & 33) goto readCapacityFailure; + + capacity[0] = ProcessorIn16(ATA_REGISTER(bus, ATA_DATA)); + capacity[1] = ProcessorIn16(ATA_REGISTER(bus, ATA_DATA)); + capacity[2] = ProcessorIn16(ATA_REGISTER(bus, ATA_DATA)); + capacity[3] = ProcessorIn16(ATA_REGISTER(bus, ATA_DATA)); + + KEventWait(event, ATA_TIMEOUT); + KEventReset(event); + + { + uint32_t blockCount = ByteSwap32(capacity[0] | ((uint32_t) capacity[1] << 16)) + 1; + uint32_t blockLength = ByteSwap32(capacity[2] | ((uint32_t) capacity[3] << 16)); + + if (blockLength != ATAPI_SECTOR_SIZE) { + KernelLog(LOG_ERROR, "IDE", "unsupported ATAPI block length", + "ATAController::Initialise - ATAPI drive reported block length of %d bytes, which is unsupported.\n", blockLength); + continue; + } + + KernelLog(LOG_INFO, "IDE", "ATAPI capacity", "ATAController::Initialise - ATAPI drive has %d blocks (%D).\n", + blockCount, blockCount * ATAPI_SECTOR_SIZE); + + sectorCount[slave + bus * 2] = blockCount; + continue; + } + + readCapacityFailure:; + KernelLog(LOG_ERROR, "IDE", "read capacity failure", "ATAController::Initialise - Could not read capacity of ATAPI drive %d/%d.\n", bus, slave); + continue; + } + } + } + + for (uintptr_t i = 0; i < ATA_DRIVES; i++) { + if (sectorCount[i]) { + // Register the drive. + ATADrive *device = (ATADrive *) KDeviceCreate("IDE drive", this, sizeof(ATADrive)); + + if (!device) { + KernelLog(LOG_ERROR, "IDE", "allocation failure", "Could not create device for drive %d.\n", i); + break; + } + + device->index = i; + device->sectorSize = isATAPI[i] ? ATAPI_SECTOR_SIZE : ATA_SECTOR_SIZE; + device->sectorCount = sectorCount[i]; + device->maxAccessSectorCount = isATAPI[i] ? 31 : 64; + device->readOnly = isATAPI[i]; + device->driveType = isATAPI[i] ? ES_DRIVE_TYPE_CDROM : ES_DRIVE_TYPE_HDD; + + device->access = [] (KBlockDeviceAccessRequest request) { + request.dispatchGroup->Start(); + bool success = ataController->Access(((ATADrive *) request.device)->index, + request.offset, request.count, request.operation, (uint8_t *) KDMABufferGetVirtualAddress(request.buffer)); + request.dispatchGroup->End(success); + }; + + FSRegisterBlockDevice(device); + } + } +} + +static void DeviceAttach(KDevice *_parent) { + KPCIDevice *parent = (KPCIDevice *) _parent; + + if (ataController) { + KernelLog(LOG_ERROR, "IDE", "multiple controllers", "EntryIDE - Attempt to register multiple IDE controllers; ignored.\n"); + return; + } + + ATAController *device = (ATAController *) KDeviceCreate("IDE controller", parent, sizeof(ATAController)); + if (!device) return; + ataController = device; + device->pci = parent; + + // Enable busmastering DMA and interrupts. + parent->EnableFeatures(K_PCI_FEATURE_INTERRUPTS | K_PCI_FEATURE_BUSMASTERING_DMA | K_PCI_FEATURE_BAR_4); + + // Initialise the controller. + device->Initialise(); +} + +KDriver driverIDE = { + .attach = DeviceAttach, +}; diff --git a/drivers/iso9660.cpp b/drivers/iso9660.cpp new file mode 100644 index 0000000..e29ee85 --- /dev/null +++ b/drivers/iso9660.cpp @@ -0,0 +1,545 @@ +// TODO Validation of all fields. + +#include + +#define SECTOR_SIZE (2048) + +struct LBE16 { +#ifdef __BIG_ENDIAN__ + uint16_t _u, x; +#else + uint16_t x, _u; +#endif +}; + +struct LBE32 { +#ifdef __BIG_ENDIAN__ + uint32_t _u, x; +#else + uint32_t x, _u; +#endif +}; + +struct DateTime { + char year[4]; + char month[2]; + char day[2]; + char hour[2]; + char minute[2]; + char second[2]; + char centiseconds[2]; + int8_t timeZoneOffset; +} __attribute__((packed)); + +struct DateTime2 { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + int8_t timeZoneOffset; +} __attribute__((packed)); + +struct DirectoryRecord { + uint8_t length; + uint8_t extendedAttributeLength; + LBE32 extentStart; + LBE32 extentSize; + DateTime2 recordingTime; + uint8_t flags; + uint8_t interleavedUnitSize; + uint8_t interleavedGapSize; + LBE16 volumeSequenceNumber; + uint8_t fileNameBytes; +} __attribute__((packed)); + +struct PrimaryDescriptor { + uint8_t typeCode; + char signature[5]; + uint8_t version; + uint8_t _unused0; + char systemIdentifier[32]; + char volumeIdentifier[32]; + uint8_t _unused1[8]; + LBE32 volumeSize; + uint8_t _unused2[32]; + LBE16 volumeSetSize; + LBE16 volumeSequenceNumber; + LBE16 logicalBlockSize; + LBE32 pathTableSize; + uint32_t pathTableLittle; + uint32_t optionalPathTableLittle; + uint32_t pathTableBig; + uint32_t optionalPathTableBig; + DirectoryRecord rootDirectory; + char rootDirectoryName; + char volumeSetIdentifier[128]; + char publisherIdentifier[128]; + char dataPreparerIdentifier[128]; + char applicationIdentifier[128]; + char copyrightFileIdentifier[38]; + char abstractFileIdentifier[36]; + char bibliographicFileIdentifier[37]; + DateTime volumeCreationTime; + DateTime volumeModificationTime; + DateTime volumeExpirationTime; + DateTime volumeEffectiveTime; + uint8_t fileStructureVersion; + uint8_t _unused3; + char applicationSpecific[512]; + uint8_t _unused4[653]; +} __attribute__((packed)); + +struct DirectoryRecordReference { + uint32_t sector, offset; +}; + +struct FSNode { + struct Volume *volume; + DirectoryRecord record; +}; + +struct Volume : KDevice { + KFileSystem *fileSystem; + PrimaryDescriptor primaryDescriptor; +}; + +static EsError ScanInternal(const char *name, size_t nameBytes, KNode *_directory, DirectoryRecord *_record = nullptr); + +static bool Mount(Volume *volume) { +#define MOUNT_FAILURE(message) do { KernelLog(LOG_ERROR, "ISO9660", "mount failure", "Mount - " message); return false; } while (0) + + uintptr_t descriptorIndex = 0; + + while (true) { + if (!volume->fileSystem->Access(32768 + SECTOR_SIZE * descriptorIndex, SECTOR_SIZE, K_ACCESS_READ, &volume->primaryDescriptor, ES_FLAGS_DEFAULT)) { + MOUNT_FAILURE("Could not access descriptor list.\n"); + } + + if (0 != EsMemoryCompare(volume->primaryDescriptor.signature, "CD001", 5)) { + MOUNT_FAILURE("Invalid descriptor signature.\n"); + } + + if (volume->primaryDescriptor.typeCode == 1) { + break; + } + + if (volume->primaryDescriptor.typeCode == 0xFF) { + MOUNT_FAILURE("Could not find primary descriptor in descriptor list.\n"); + } + + if (++descriptorIndex > 16) { + MOUNT_FAILURE("Could not find end of descriptor list.\n"); + } + } + + if (volume->primaryDescriptor.version != 1 || volume->primaryDescriptor.fileStructureVersion != 1) { + MOUNT_FAILURE("Unsupported fileSystem version.\n"); + } + + if (volume->primaryDescriptor.logicalBlockSize.x != SECTOR_SIZE) { + MOUNT_FAILURE("Unsupported block size.\n"); + } + + { + FSNode *root = (FSNode *) EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!root) { + MOUNT_FAILURE("Could not allocate root node.\n"); + } + + volume->fileSystem->rootDirectory->driverNode = root; + volume->fileSystem->rootDirectoryInitialChildren = volume->primaryDescriptor.rootDirectory.extentSize.x / sizeof(DirectoryRecord); + + root->volume = volume; + root->record = volume->primaryDescriptor.rootDirectory; + } + + { + // Is this the boot disc? + + EsUniqueIdentifier identifier = KGetBootIdentifier(); + + if (0 != EsMemoryCompare("Essence::", volume->primaryDescriptor.applicationSpecific, 9)) { + goto notBoot; + } + + if (EsMemoryCompare(&identifier, volume->primaryDescriptor.applicationSpecific + 9, 16)) { + goto notBoot; + } + + DirectoryRecord record = {}; + ScanInternal(EsLiteral("ESSENCE.DAT;1"), volume->fileSystem->rootDirectory, &record); + record.extentSize.x = (record.extentSize.x + SECTOR_SIZE - 1) / SECTOR_SIZE; + + if (!record.length || record.extentStart.x >= volume->fileSystem->block->sectorCount + || record.extentSize.x >= volume->fileSystem->block->sectorCount - record.extentStart.x) { + goto notBoot; + } + + // Load the first sector to look at the MBR. + + uint8_t *firstSector = (uint8_t *) EsHeapAllocate(SECTOR_SIZE, false, K_FIXED); + + if (!firstSector) { + KernelLog(LOG_ERROR, "ISO9660", "allocation failure", "Could not allocate sector buffer to check MBR.\n"); + goto notBoot; + } + + EsDefer(EsHeapFree(firstSector, SECTOR_SIZE, K_FIXED)); + + if (!volume->fileSystem->Access(record.extentStart.x * SECTOR_SIZE, SECTOR_SIZE, K_ACCESS_READ, firstSector, ES_FLAGS_DEFAULT)) { + goto notBoot; + } + + uint32_t sectorOffset = ((uint32_t) firstSector[0x1BE + 8] << 0) + ((uint32_t) firstSector[0x1BE + 9] << 8) + + ((uint32_t) firstSector[0x1BE + 10] << 16) + ((uint32_t) firstSector[0x1BE + 11] << 24); + sectorOffset /= (SECTOR_SIZE / 512); // Convert to disc sectors. + + if (sectorOffset >= record.extentSize.x) { + goto notBoot; + } + + record.extentStart.x += sectorOffset; + record.extentSize.x -= sectorOffset; + + KernelLog(LOG_INFO, "ISO9660", "found boot disc", "Found boot disc. Image at %d/%d.\n", + record.extentStart.x, record.extentSize.x); + FSPartitionDeviceCreate(volume->fileSystem->block, record.extentStart.x, record.extentSize.x, ES_FLAGS_DEFAULT, "CD-ROM boot partition"); + } + + notBoot:; + + return true; +} + +static size_t Read(KNode *node, void *_buffer, EsFileOffset offset, EsFileOffset count) { +#define READ_FAILURE(message) do { KernelLog(LOG_ERROR, "ISO9660", "read failure", "Read - " message); return ES_ERROR_UNKNOWN; } while (0) + + FSNode *file = (FSNode *) node->driverNode; + Volume *volume = file->volume; + + uint8_t *sectorBuffer = (uint8_t *) EsHeapAllocate(SECTOR_SIZE, false, K_FIXED); + + if (!sectorBuffer) { + READ_FAILURE("Could not allocate sector buffer.\n"); + } + + EsDefer(EsHeapFree(sectorBuffer, SECTOR_SIZE, K_FIXED)); + + uint8_t *outputBuffer = (uint8_t *) _buffer; + + uint64_t firstSector = offset / SECTOR_SIZE; + uint32_t lba = file->record.extentStart.x + firstSector; + offset %= SECTOR_SIZE; + + while (count) { + if (offset || count < SECTOR_SIZE) { + if (!volume->fileSystem->Access(lba * SECTOR_SIZE, SECTOR_SIZE, K_ACCESS_READ, sectorBuffer, ES_FLAGS_DEFAULT)) { + READ_FAILURE("Could not read file sector.\n"); + } + + uint64_t bytesToRead = (count > SECTOR_SIZE - offset) ? (SECTOR_SIZE - offset) : count; + EsMemoryCopy(outputBuffer, sectorBuffer + offset, bytesToRead); + + lba++, count -= bytesToRead, offset = 0, outputBuffer += bytesToRead; + } else { + uint64_t sectorsToRead = count / SECTOR_SIZE; + + if (!volume->fileSystem->Access(lba * SECTOR_SIZE, sectorsToRead * SECTOR_SIZE, K_ACCESS_READ, outputBuffer, ES_FLAGS_DEFAULT)) { + READ_FAILURE("Could not read file sectors.\n"); + } + + lba += sectorsToRead, count -= SECTOR_SIZE * sectorsToRead, outputBuffer += SECTOR_SIZE * sectorsToRead; + } + } + + return true; +} + +static EsError Enumerate(KNode *node) { +#define ENUMERATE_FAILURE(message) do { KernelLog(LOG_ERROR, "ISO9660", "enumerate failure", "Enumerate - " message); return false; } while (0) + + FSNode *directory = (FSNode *) node->driverNode; + Volume *volume = directory->volume; + + // TODO Load multiple sectors at once? + + uint8_t *sectorBuffer = (uint8_t *) EsHeapAllocate(SECTOR_SIZE, false, K_FIXED); + + if (!sectorBuffer) { + ENUMERATE_FAILURE("Could not allocate sector buffer.\n"); + } + + EsDefer(EsHeapFree(sectorBuffer, SECTOR_SIZE, K_FIXED)); + + uint32_t currentSector = directory->record.extentStart.x; + uint32_t remainingBytes = directory->record.extentSize.x; + + while (remainingBytes) { + bool accessResult = volume->fileSystem->Access(currentSector * SECTOR_SIZE, SECTOR_SIZE, K_ACCESS_READ, (uint8_t *) sectorBuffer, ES_FLAGS_DEFAULT); + + if (!accessResult) { + ENUMERATE_FAILURE("Could not read sector.\n"); + } + + uintptr_t positionInSector = 0; + + while (positionInSector < SECTOR_SIZE && positionInSector < remainingBytes) { + DirectoryRecord *record = (DirectoryRecord *) (sectorBuffer + positionInSector); + + if (!record->length) { + break; + } + + if (positionInSector + record->length > SECTOR_SIZE || record->length < sizeof(DirectoryRecord)) { + ENUMERATE_FAILURE("Invalid directory record.\n"); + } + + if (record->fileNameBytes <= 2) { + goto nextEntry; + } + + { + KNodeMetadata metadata = {}; + + size_t nameBytes = record->fileNameBytes; + + for (uintptr_t i = 0; i < record->fileNameBytes; i++) { + if (((char *) (record + 1))[i] == ';') { + nameBytes = i; + break; + } + } + + metadata.type = (record->flags & (1 << 1)) ? ES_NODE_DIRECTORY : ES_NODE_FILE; + + if (metadata.type == ES_NODE_DIRECTORY) { + metadata.directoryChildren = ES_DIRECTORY_CHILDREN_UNKNOWN; + metadata.totalSize = 0; + } else if (metadata.type == ES_NODE_FILE) { + metadata.totalSize = record->extentSize.x; + } + + DirectoryRecordReference reference = {}; + reference.sector = currentSector; + reference.offset = positionInSector; + + EsError error = FSDirectoryEntryFound(node, &metadata, &reference, + (const char *) (record + 1), nameBytes, false); + + if (error != ES_SUCCESS) { + return error; + } + } + + nextEntry:; + positionInSector += record->length; + } + + if (remainingBytes < SECTOR_SIZE) { + remainingBytes = 0; + } else { + remainingBytes -= SECTOR_SIZE; + } + } + + return ES_SUCCESS; +} + +static EsError ScanInternal(const char *name, size_t nameBytes, KNode *_directory, DirectoryRecord *_record) { +#define SCAN_FAILURE(message) do { KernelLog(LOG_ERROR, "ISO9660", "scan failure", "Scan - " message); return ES_ERROR_UNKNOWN; } while (0) + + // Check for invalid characters. + + for (uintptr_t i = 0; i < nameBytes; i++) { + bool validCharacter = name[i] == '.' || name[i] == ';' || name[i] == '_' + || (name[i] >= 'A' && name[i] <= 'Z') + || (name[i] >= '0' && name[i] <= '9'); + + if (!validCharacter) { + return ES_ERROR_FILE_DOES_NOT_EXIST; + } + } + + FSNode *directory = (FSNode *) _directory->driverNode; + Volume *volume = directory->volume; + + // TODO Load multiple sectors at once? + + uint8_t *sectorBuffer = (uint8_t *) EsHeapAllocate(SECTOR_SIZE, false, K_FIXED); + + if (!sectorBuffer) { + SCAN_FAILURE("Could not allocate sector buffer.\n"); + } + + EsDefer(EsHeapFree(sectorBuffer, SECTOR_SIZE, K_FIXED)); + + uint32_t currentSector = directory->record.extentStart.x; + uint32_t remainingBytes = directory->record.extentSize.x; + + while (remainingBytes) { + bool accessResult = volume->fileSystem->Access(currentSector * SECTOR_SIZE, SECTOR_SIZE, K_ACCESS_READ, (uint8_t *) sectorBuffer, ES_FLAGS_DEFAULT); + + if (!accessResult) { + SCAN_FAILURE("Could not read sector.\n"); + } + + uintptr_t positionInSector = 0; + + while (positionInSector < SECTOR_SIZE && positionInSector < remainingBytes) { + DirectoryRecord *record = (DirectoryRecord *) (sectorBuffer + positionInSector); + + if (!record->length) { + break; + } + + if (positionInSector + record->length > SECTOR_SIZE || record->length < sizeof(DirectoryRecord)) { + SCAN_FAILURE("Invalid directory record.\n"); + } + + if (record->fileNameBytes <= 2) { + goto nextEntry; + } + + if (!((nameBytes == record->fileNameBytes && 0 == EsMemoryCompare(record + 1, name, nameBytes)) + || (nameBytes + 2 == record->fileNameBytes && 0 == EsMemoryCompare(record + 1, name, nameBytes) + && 0 == EsMemoryCompare((char *) (record + 1) + record->fileNameBytes - 2, ";1", 2)))) { + goto nextEntry; + } + + if (_record) { + EsMemoryCopy(_record, record, sizeof(DirectoryRecord)); + return ES_SUCCESS; + } + + { + KNodeMetadata metadata = {}; + + metadata.type = (record->flags & (1 << 1)) ? ES_NODE_DIRECTORY : ES_NODE_FILE; + + if (metadata.type == ES_NODE_DIRECTORY) { + metadata.directoryChildren = ES_DIRECTORY_CHILDREN_UNKNOWN; + metadata.totalSize = 0; + } else if (metadata.type == ES_NODE_FILE) { + metadata.totalSize = record->extentSize.x; + } + + DirectoryRecordReference reference = {}; + reference.sector = currentSector; + reference.offset = positionInSector; + + return FSDirectoryEntryFound(_directory, &metadata, &reference, + name, nameBytes, false); + } + + nextEntry:; + positionInSector += record->length; + } + + if (remainingBytes < SECTOR_SIZE) { + remainingBytes = 0; + } else { + remainingBytes -= SECTOR_SIZE; + } + } + + return ES_ERROR_FILE_DOES_NOT_EXIST; +} + +static EsError Scan(const char *name, size_t nameBytes, KNode *_directory) { + return ScanInternal(name, nameBytes, _directory); +} + +static EsError Load(KNode *_directory, KNode *_node, KNodeMetadata *, const void *entryData) { + DirectoryRecordReference reference = *(DirectoryRecordReference *) entryData; + FSNode *directory = (FSNode *) _directory->driverNode; + Volume *volume = directory->volume; + + uint8_t *sectorBuffer = (uint8_t *) EsHeapAllocate(SECTOR_SIZE, false, K_FIXED); + + if (!sectorBuffer) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + EsDefer(EsHeapFree(sectorBuffer, SECTOR_SIZE, K_FIXED)); + + if (!volume->fileSystem->Access(reference.sector * SECTOR_SIZE, SECTOR_SIZE, K_ACCESS_READ, (uint8_t *) sectorBuffer, ES_FLAGS_DEFAULT)) { + return ES_ERROR_DRIVE_CONTROLLER_REPORTED; + } + + FSNode *data = (FSNode *) EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!data) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + data->volume = volume; + _node->driverNode = data; + + DirectoryRecord *record = (DirectoryRecord *) (sectorBuffer + reference.offset); + EsMemoryCopy(&data->record, record, sizeof(DirectoryRecord)); + + return ES_SUCCESS; +} + +static void Close(KNode *node) { + EsHeapFree(node->driverNode, sizeof(FSNode), K_FIXED); +} + +static void DeviceAttach(KDevice *parent) { + Volume *volume = (Volume *) KDeviceCreate("ISO9660", parent, sizeof(Volume)); + + if (!volume) { + KernelLog(LOG_ERROR, "ISO9660", "allocate error", "EntryISO9660 - Could not allocate Volume structure.\n"); + return; + } + + volume->fileSystem = (KFileSystem *) parent; + + if (volume->fileSystem->block->sectorSize != SECTOR_SIZE) { + KernelLog(LOG_ERROR, "ISO9660", "incorrect sector size", "EntryISO9660 - Expected 2KB sectors, but drive's sectors are %D.\n", + volume->fileSystem->block->sectorSize); + KDeviceDestroy(volume); + return; + } + + if (!Mount(volume)) { + KernelLog(LOG_ERROR, "ISO9660", "mount failure", "EntryISO9660 - Could not mount ISO9660 volume.\n"); + KDeviceDestroy(volume); + return; + } + + volume->fileSystem->read = Read; + volume->fileSystem->scan = Scan; + volume->fileSystem->load = Load; + volume->fileSystem->enumerate = Enumerate; + volume->fileSystem->close = Close; + + volume->fileSystem->spaceUsed = volume->primaryDescriptor.volumeSize.x * volume->primaryDescriptor.logicalBlockSize.x; + volume->fileSystem->spaceTotal = volume->fileSystem->spaceUsed; + + volume->fileSystem->nameBytes = sizeof(volume->primaryDescriptor.volumeIdentifier); + if (volume->fileSystem->nameBytes > sizeof(volume->fileSystem->name)) volume->fileSystem->nameBytes = sizeof(volume->fileSystem->name); + EsMemoryCopy(volume->fileSystem->name, volume->primaryDescriptor.volumeIdentifier, volume->fileSystem->nameBytes); + + for (intptr_t i = volume->fileSystem->nameBytes - 1; i >= 0; i--) { + if (volume->fileSystem->name[i] == ' ') { + volume->fileSystem->nameBytes--; + } else { + break; + } + } + + volume->fileSystem->directoryEntryDataBytes = sizeof(DirectoryRecordReference); + volume->fileSystem->nodeDataBytes = sizeof(FSNode); + + KernelLog(LOG_INFO, "ISO9660", "register file system", "EntryISO9660 - Registering file system with name '%s'.\n", + volume->fileSystem->nameBytes, volume->fileSystem->name); + FSRegisterFileSystem(volume->fileSystem); +} + +KDriver driverISO9660 = { + .attach = DeviceAttach, +}; diff --git a/drivers/ntfs.cpp b/drivers/ntfs.cpp new file mode 100644 index 0000000..9c0b423 --- /dev/null +++ b/drivers/ntfs.cpp @@ -0,0 +1,1265 @@ +// TODO Validation of all fields. +// TODO Update to the latest file subsystem changes. +// - Set spaceUsed and spaceTotal. + +#include + +struct BootSector { + uint8_t jump[3]; + char signature[8]; + uint16_t bytesPerSector; + uint8_t sectorsPerCluster; + uint16_t reservedSectors; + uint8_t unused0[3]; + uint16_t unused1; + uint8_t media; + uint16_t unused2; + uint16_t sectorsPerTrack; + uint16_t headsPerCylinder; + uint32_t hiddenSectors; + uint32_t unused3; + uint32_t unused4; + uint64_t totalSectors; + uint64_t mftStart; + uint64_t mftMirrorStart; + int8_t clustersPerFileRecord; + uint8_t unused5[3]; + int8_t clustersPerIndexBlock; + uint8_t unused6[3]; + uint64_t serialNumber; + uint32_t checksum; + uint8_t bootloader[426]; + uint16_t bootSignature; +} __attribute__((packed)); + +struct FileRecordHeader { + uint32_t magic; + uint16_t updateSequenceOffset; + uint16_t updateSequenceSize; + uint64_t logSequence; + uint16_t sequenceNumber; + uint16_t hardLinkCount; + uint16_t firstAttributeOffset; + uint16_t flags; + uint32_t usedSize; + uint32_t allocatedSize; + uint64_t fileReference; + uint16_t nextAttributeID; + uint16_t unused; + uint32_t recordNumber; +} __attribute__((packed)); + +struct AttributeHeader { + uint32_t attributeType; + uint32_t length; + uint8_t nonResident; + uint8_t nameLength; + uint16_t nameOffset; + uint16_t flags; + uint16_t attributeID; +} __attribute__((packed)); + +struct ResidentAttributeHeader : AttributeHeader { + uint32_t attributeLength; + uint16_t attributeOffset; + uint8_t indexed; + uint8_t unused; +} __attribute__((packed)); + +struct FileNameAttributeHeader { + uint64_t parentRecordNumber : 48; + uint64_t parentSequenceNumber : 16; + uint64_t creationTime; + uint64_t modificationTime; + uint64_t metadataModificationTime; + uint64_t readTime; + uint64_t allocatedSize; + uint64_t realSize; + uint32_t flags; + uint32_t reparse; + uint8_t fileNameLength; + uint8_t namespaceType; +} __attribute__((packed)); + +struct NonResidentAttributeHeader : AttributeHeader { + uint64_t firstCluster; + uint64_t lastCluster; + uint16_t dataRunsOffset; + uint16_t compressionUnit; + uint32_t unused; + uint64_t attributeAllocated; + uint64_t attributeSize; + uint64_t streamDataSize; +} __attribute__((packed)); + +struct RunHeader { + uint8_t lengthFieldBytes : 4; + uint8_t offsetFieldBytes : 4; +} __attribute__((packed)); + +struct IndexBlockHeader { + uint32_t magic; + uint16_t updateSequenceOffset; + uint16_t updateSequenceSize; + uint64_t logSequence; + uint64_t selfVirtualCluster; + uint32_t firstEntryOffset; + uint32_t totalEntrySize; + uint32_t allocatedSize; + uint32_t flags; +} __attribute__((packed)); + +struct IndexRootHeader { + uint32_t attributeType; + uint32_t collationRule; + uint32_t bytesPerIndexRecord; + uint8_t clustersPerIndexRecord; + uint8_t unused[3]; + uint32_t firstEntryOffset; + uint32_t totalEntrySize; + uint32_t allocatedSize; + uint32_t flags; +} __attribute__((packed)); + +struct IndexEntryHeader { + uint64_t fileRecordNumber : 48; + uint64_t fileSequenceNumber : 16; + uint16_t indexEntryLength; + uint16_t streamLength; + uint32_t flags; +} __attribute__((packed)); + +// TODO Support other MFT file record sizes. +#define MFT_FILE_SIZE (1024) + +struct FSNode { + struct Volume *volume; + + union { + uint8_t fileRecord[MFT_FILE_SIZE]; + FileRecordHeader header; + }; +}; + +struct Volume : KDevice { + KFileSystem *fileSystem; + KNode *root; + BootSector bootSector; + + size_t clusterBytes, + mftRecordBytes, + indexBlockBytes, + clusterCount, + sectorBytes; + + FSNode mftNode, volumeNode; + + uint16_t *upCaseLookup[256]; +}; + +static uint16_t ToUpper(Volume *volume, uint16_t character) { + uint16_t *table = volume->upCaseLookup[character >> 8]; + return table ? table[character & 0xFF] : character; +} + +static uint64_t GetDataRunLength(RunHeader *dataRun) { + uint64_t length = 0; + + for (int i = 0; i < dataRun->lengthFieldBytes; i++) { + length |= (uint64_t) (((uint8_t *) dataRun)[1 + i]) << (i * 8); + } + + return length; +} + +static uint64_t GetDataRunOffset(RunHeader *dataRun) { + uint64_t offset = 0; + + for (int i = 0; i < dataRun->offsetFieldBytes; i++) { + offset |= (uint64_t) (((uint8_t *) dataRun)[1 + dataRun->lengthFieldBytes + i]) << (i * 8); + } + + if (offset & ((uint64_t) 1 << (dataRun->offsetFieldBytes * 8 - 1))) { + for (int i = dataRun->offsetFieldBytes; i < 8; i++) { + offset |= (uint64_t) 0xFF << (i * 8); + } + } + + return offset; +} + +static bool ApplyFixup(Volume *volume, uint8_t *buffer, uint16_t fixupOffset, uint16_t fixupSize, size_t bufferBytes) { +#define FIXUP_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "fixup failure", "ApplyFixup - " message); return false; } while (0) + + // TODO Is the aliasing done by this function optimizations-safe? + + size_t sectorCount = bufferBytes / volume->sectorBytes; + + if ((fixupOffset & 1) || (fixupOffset + fixupSize > bufferBytes) || ((size_t) (fixupSize - 1) != sectorCount)) { + FIXUP_FAILURE("Invalid offset/size.\n"); + } + + uint16_t *fixupArray = (uint16_t *) (buffer + fixupOffset); + + for (uintptr_t i = 0; i < sectorCount; i++) { + uint16_t *position = (uint16_t *) (buffer + (i + 1) * volume->sectorBytes - 2); + + if (*position != fixupArray[0]) { + FIXUP_FAILURE("Incorrect sequence number.\n"); + } + + *position = fixupArray[i + 1]; + } + + return true; +} + +static bool ValidateFileRecord(Volume *volume, FSNode *node, bool isDirectory) { +#define VALIDATE_FILE_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "validate file record failure", "ValidateFileRecord - " message); return false; } while (0) + + FileRecordHeader *header = &node->header; + + if (header->magic != 0x454C4946) { + VALIDATE_FILE_FAILURE("Invalid magic number.\n"); + } + + if (!ApplyFixup(volume, node->fileRecord, header->updateSequenceOffset, header->updateSequenceSize, MFT_FILE_SIZE)) { + return false; + } + + if (~header->flags & (1 << 0)) { + VALIDATE_FILE_FAILURE("Record not in use.\n"); + } + + if (((header->flags & (1 << 1)) ? true : false) != isDirectory) { + VALIDATE_FILE_FAILURE("Incorrect isDirectory flag.\n"); + } + + if (header->allocatedSize != MFT_FILE_SIZE || header->usedSize > MFT_FILE_SIZE) { + VALIDATE_FILE_FAILURE("Invalid file header allocated/used size.\n"); + } + + if (header->firstAttributeOffset > MFT_FILE_SIZE - sizeof(AttributeHeader)) { + VALIDATE_FILE_FAILURE("Invalid first attribute offset.\n"); + } + + return true; +} + +static AttributeHeader *FindAttribute(Volume *, FSNode *node, uint8_t type, AttributeHeader *startingFrom = nullptr, bool optional = false) { +#define FIND_ATTRIBUTE_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "find attribute failure", "FindAttribute - " message); return nullptr; } while (0) + + AttributeHeader *attribute = startingFrom ?: (AttributeHeader *) (node->fileRecord + node->header.firstAttributeOffset); + bool skip = startingFrom ? true : false; + + while (true) { + if (attribute->attributeType == type && !skip) { + return attribute; + } else if (attribute->attributeType == 0xFFFFFFFF) { + if (optional) return nullptr; + FIND_ATTRIBUTE_FAILURE("Could not find attribute.\n"); + } + + skip = false; + + if ((size_t) ((uint8_t *) attribute - node->fileRecord + attribute->length) > MFT_FILE_SIZE - sizeof(AttributeHeader) + || attribute->length < sizeof(AttributeHeader)) { + FIND_ATTRIBUTE_FAILURE("Invalid attribute length.\n"); + } + + attribute = (AttributeHeader *) ((uint8_t *) attribute + attribute->length); + } +} + +static bool ReadFileCluster(Volume *volume, FSNode *node, uint64_t startCluster, void *_buffer) { +#define READ_FILE_CLUSTERS_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "read file clusters failure", "ReadFileClusters - " message); return false; } while (0) + + uint8_t *buffer = (uint8_t *) _buffer; + + // Find the data attribute. + + NonResidentAttributeHeader *dataHeader = (NonResidentAttributeHeader *) FindAttribute(volume, node, 0x80); + + if (!dataHeader) { + // TODO Support $ATTRIBUTE_LIST. + READ_FILE_CLUSTERS_FAILURE("Could not find data attribute.\n"); + } + + if (dataHeader->length < sizeof(NonResidentAttributeHeader)) { + READ_FILE_CLUSTERS_FAILURE("Data attribute is too short.\n"); + } + + if (!dataHeader->nonResident) { + // TODO Resident data attribute. + READ_FILE_CLUSTERS_FAILURE("Data attribute is resident.\n"); + } + + if (dataHeader->flags) { + READ_FILE_CLUSTERS_FAILURE("Data attribute has unsupported flags.\n"); + } + + // Find the data run containing the requested clusters. + + RunHeader *dataRun = (RunHeader *) ((uint8_t *) dataHeader + dataHeader->dataRunsOffset); + uint64_t clusterNumber = 0; + bool foundStart = false; + uint64_t clusterCount = 1; + + KWorkGroup dispatchGroup = {}; + dispatchGroup.Initialise(); + + while (((uint8_t *) dataRun - (uint8_t *) dataHeader) < dataHeader->length && dataRun->lengthFieldBytes) { + uint64_t length = GetDataRunLength(dataRun), offset = GetDataRunOffset(dataRun); + + clusterNumber += offset; + dataRun = (RunHeader *) ((uint8_t *) dataRun + 1 + dataRun->lengthFieldBytes + dataRun->offsetFieldBytes); + + if (!foundStart) { + if (length <= startCluster) { + startCluster -= length; + continue; + } else { + foundStart = true; + } + } + + if (foundStart) { + uint64_t firstClusterToRead = clusterNumber + startCluster; + uint64_t clustersToRead = 1; + startCluster = 0; + + // Read the clusters. + + volume->fileSystem->Access(firstClusterToRead * volume->clusterBytes, + clustersToRead * volume->clusterBytes, K_ACCESS_READ, + buffer, ES_FLAGS_DEFAULT, &dispatchGroup); + + clusterCount -= clustersToRead; + buffer += clustersToRead * volume->clusterBytes; + + if (!clusterCount) { + break; + } + } + } + + if (clusterCount) { + READ_FILE_CLUSTERS_FAILURE("Trying to read past the end of the data runs.\n"); + } + + // Wait for outstanding IO operations to complete. + + bool success = dispatchGroup.Wait(); + + if (!success) { + READ_FILE_CLUSTERS_FAILURE("Could not read clusters from block device.\n"); + } + + return true; +} + +static bool ReadFileRecord(KNode *kNode, FSNode *node, uint64_t index, EsNodeType nodeType, void *clusterBuffer) { +#define READ_FILE_RECORD_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "read file record failure", "ReadFileRecord - " message); return false; } while (0) + + Volume *volume = node->volume; + + // Work out the cluster containing the file record. + + uint64_t cluster = index * MFT_FILE_SIZE / volume->clusterBytes; + uint64_t offsetInCluster = index * MFT_FILE_SIZE % volume->clusterBytes; + + // Read this cluster. + + if (!ReadFileCluster(volume, &volume->mftNode, cluster, clusterBuffer)) { + READ_FILE_RECORD_FAILURE("Could not read the file record from the MFT.\n"); + } + + // Copy into the node. + + EsMemoryCopy(node->fileRecord, (uint8_t *) clusterBuffer + offsetInCluster, MFT_FILE_SIZE); + + if (!ValidateFileRecord(volume, node, nodeType == ES_NODE_DIRECTORY)) { + return false; + } + + // Store information about the node. + + if (!kNode) { + return true; + } + + if (nodeType == ES_NODE_FILE) { + AttributeHeader *dataHeader = (AttributeHeader *) FindAttribute(volume, node, 0x80); + + if (!dataHeader) { + READ_FILE_RECORD_FAILURE("File did not have a data attribute.\n"); + } + + if (dataHeader->nonResident) { + kNode->data.fileSize = ((NonResidentAttributeHeader *) dataHeader)->attributeSize; + } else { + kNode->data.fileSize = ((ResidentAttributeHeader *) dataHeader)->attributeLength; + } + + kNode->data.type = ES_NODE_FILE; + } else if (nodeType == ES_NODE_DIRECTORY) { + NonResidentAttributeHeader *indexAllocationHeader = (NonResidentAttributeHeader *) FindAttribute(volume, node, 0xA0, nullptr, true); + + if (!indexAllocationHeader || indexAllocationHeader->flags || !indexAllocationHeader->nonResident) { + kNode->data.directoryChildren = MFT_FILE_SIZE / 16; + } else { + // TODO This is a terrible upper estimate! Find a better one? + kNode->data.directoryChildren = indexAllocationHeader->attributeSize / 16; + } + + kNode->data.type = ES_NODE_DIRECTORY; + } + + return true; +} + +static bool Mount(Volume *volume) { +#define MOUNT_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "mount failure", "Mount - " message); return false; } while (0) + + // Load the boot sector. + + { + void *buffer = EsHeapAllocate(volume->fileSystem->block->sectorSize, false, K_FIXED); + + if (!buffer) { + MOUNT_FAILURE("Could not allocate buffer.\n"); + } + + EsDefer(EsHeapFree(buffer, volume->fileSystem->block->sectorSize, K_FIXED)); + + if (!volume->fileSystem->Access(0, volume->fileSystem->block->sectorSize, K_ACCESS_READ, buffer, ES_FLAGS_DEFAULT)) { + MOUNT_FAILURE("Could not read boot sector.\n"); + } + + EsMemoryCopy(&volume->bootSector, buffer, sizeof(BootSector)); + + volume->sectorBytes = volume->bootSector.bytesPerSector; + volume->clusterBytes = volume->bootSector.sectorsPerCluster * volume->bootSector.bytesPerSector; + volume->mftRecordBytes = volume->bootSector.clustersPerFileRecord >= 0 + ? volume->bootSector.clustersPerFileRecord * volume->clusterBytes : (1 << -volume->bootSector.clustersPerFileRecord); + volume->indexBlockBytes = volume->bootSector.clustersPerIndexBlock >= 0 + ? volume->bootSector.clustersPerIndexBlock * volume->clusterBytes : (1 << -volume->bootSector.clustersPerIndexBlock); + volume->clusterCount = volume->fileSystem->block->sectorCount / volume->bootSector.sectorsPerCluster; + + if (volume->bootSector.bytesPerSector != volume->fileSystem->block->sectorSize) MOUNT_FAILURE("Invalid bytes per sector.\n"); + if ((volume->bootSector.sectorsPerCluster - 1) & volume->bootSector.sectorsPerCluster) MOUNT_FAILURE("Invalid sectors per cluster.\n"); + if (volume->mftRecordBytes != MFT_FILE_SIZE) MOUNT_FAILURE("Unsupported MFT record size.\n"); + if (volume->mftRecordBytes > volume->clusterBytes) MOUNT_FAILURE("MFT record size bigger than cluster size.\n"); + if (volume->indexBlockBytes % volume->clusterBytes) MOUNT_FAILURE("Index block size is not a multiple of the cluster size.\n"); + if (volume->bootSector.mftStart >= volume->clusterCount) MOUNT_FAILURE("MFT starts past end of volume.\n"); + } + + void *buffer = EsHeapAllocate(volume->clusterBytes, false, K_FIXED); + + if (!buffer) { + MOUNT_FAILURE("Could not allocate buffer.\n"); + } + + EsDefer(EsHeapFree(buffer, volume->clusterBytes, K_FIXED)); + + // Load the MFT. + + { + if (!volume->fileSystem->Access(volume->bootSector.mftStart * volume->clusterBytes, + volume->clusterBytes, K_ACCESS_READ, buffer, ES_FLAGS_DEFAULT)) { + MOUNT_FAILURE("Could not read MFT file.\n"); + } + + EsMemoryCopy(volume->mftNode.fileRecord, buffer, MFT_FILE_SIZE); + + if (!ValidateFileRecord(volume, &volume->mftNode, false)) { + return false; + } + } + + // Load the volume node. + + { + volume->volumeNode.volume = volume; + + if (!ReadFileRecord(nullptr, &volume->volumeNode, 3, ES_NODE_FILE, buffer)) { + return false; + } + } + + // Load the root directory. + + { + volume->root = FSNodeAllocate(); + + if (!volume->root) { + MOUNT_FAILURE("Could not allocate root node.\n"); + } + + volume->root->driverNode = EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!volume->root->driverNode) { + MOUNT_FAILURE("Could not allocate root node.\n"); + } + + FSNode *root = (FSNode *) volume->root->driverNode; + root->volume = volume; + + if (!ReadFileRecord(volume->root, root, 5, ES_NODE_DIRECTORY, buffer)) { + return false; + } + + if (!FSRegisterNewNode(volume->root, nullptr, ES_NODE_DIRECTORY, EsLiteral("$Root"))) { + MOUNT_FAILURE("Could not register root directory node.\n"); + } + } + + // Load $UpCase. + + { + FSNode *upCase = (FSNode *) EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!upCase) { + MOUNT_FAILURE("Could not allocate upCase node.\n"); + } + + EsDefer(EsHeapFree(upCase, sizeof(FSNode), K_FIXED)); + + upCase->volume = volume; + + if (!ReadFileRecord(nullptr, upCase, 10, ES_NODE_FILE, buffer)) { + return false; + } + + for (uintptr_t i = 0; i < 131072 / volume->clusterBytes; i++) { + if (!ReadFileCluster(volume, upCase, i, buffer)) { + return false; + } + + for (uint16_t j = 0, codepoint = i * volume->clusterBytes / 2; j < volume->clusterBytes / 2; j++, codepoint++) { + uint16_t upperCase = ((uint16_t *) buffer)[j]; + if (codepoint == upperCase) continue; + + uint8_t msb = codepoint >> 8, lsb = codepoint & 0xFF; + + if (!volume->upCaseLookup[msb]) { + volume->upCaseLookup[msb] = (uint16_t *) EsHeapAllocate(512, false, K_FIXED); + + if (!volume->upCaseLookup[msb]) { + MOUNT_FAILURE("Could not allocate upCase table.\n"); + } + + for (uintptr_t i = 0; i < 256; i++) { + volume->upCaseLookup[msb][i] = (msb << 8) | i; + } + } + + volume->upCaseLookup[msb][lsb] = upperCase; + } + } + } + + return true; +} + +#define BAD_ATTRIBUTE_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "bad attribute failure", "GetIndexAllocationHeader - " message); return nullptr; } while (0) + +static NonResidentAttributeHeader *GetIndexAllocationHeader(Volume *volume, FSNode *directory) { + NonResidentAttributeHeader *indexAllocationHeader = (NonResidentAttributeHeader *) FindAttribute(volume, directory, 0xA0); + + if (!indexAllocationHeader) { + // TODO Support $ATTRIBUTE_LIST. + BAD_ATTRIBUTE_FAILURE("Could not find index allocation attribute.\n"); + } + + if (indexAllocationHeader->length < sizeof(NonResidentAttributeHeader)) { + BAD_ATTRIBUTE_FAILURE("Index allocation attribute is too short.\n"); + } + + if (!indexAllocationHeader->nonResident) { + BAD_ATTRIBUTE_FAILURE("Index allocation attribute is resident.\n"); + } + + if (indexAllocationHeader->flags) { + BAD_ATTRIBUTE_FAILURE("Index allocation attribute has unsupported flags.\n"); + } + + return indexAllocationHeader; +} + +#define ENUMERATE_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "enumerate failure", "Enumerate - " message); return ES_ERROR_UNKNOWN; } while (0) + +static EsError EnumerateIndexEntry(IndexEntryHeader *entry, uint8_t *bufferLimit, KNode *directory) { + if (entry->indexEntryLength < sizeof(IndexEntryHeader)) { + ENUMERATE_FAILURE("Invalid index entry length.\n"); + } + + if (entry->flags & (1 << 1)) { + return ES_SUCCESS; + } + + FileNameAttributeHeader *fileNameAttribute = (FileNameAttributeHeader *) (entry + 1); + + if ((uint8_t *) fileNameAttribute + fileNameAttribute->fileNameLength * 2 > bufferLimit) { + ENUMERATE_FAILURE("File name attribute has length too large.\n"); + } + + if ((fileNameAttribute->namespaceType == 1 || fileNameAttribute->namespaceType == 3) && entry->fileRecordNumber >= 24) { + KNodeMetadata metadata = {}; + + metadata.type = (fileNameAttribute->flags & 0x10000000) ? ES_NODE_DIRECTORY : ES_NODE_FILE; + + if (metadata.type == ES_NODE_FILE) { + metadata.totalSize = fileNameAttribute->realSize; + } else { + metadata.directoryChildren = ES_DIRECTORY_CHILDREN_UNKNOWN; + } + + uintptr_t namePosition = 0; + uint16_t *fileName = (uint16_t *) (fileNameAttribute + 1); + size_t inputCharactersRemaining = fileNameAttribute->fileNameLength; + char childName[ES_MAX_DIRECTORY_CHILD_NAME_LENGTH]; + size_t childNameBytes = 0; + + while (inputCharactersRemaining) { + uint32_t c = *fileName; + inputCharactersRemaining--; + fileName++; + + if (c >= 0xD800 && c < 0xDC00 && inputCharactersRemaining) { + uint32_t c2 = *fileName; + + if (c2 >= 0xDC00 && c2 < 0xE000) { + inputCharactersRemaining--; + fileName++; + + c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; + } + } + + size_t encodedBytes = utf8_encode(c, nullptr); + + if (namePosition + encodedBytes <= ES_MAX_DIRECTORY_CHILD_NAME_LENGTH) { + utf8_encode(c, childName + namePosition); + namePosition += encodedBytes; + childNameBytes += encodedBytes; + } else { + // Name too long. + // TODO Now what? + } + } + + EsError error = FSDirectoryEntryFound(directory, &metadata, + &reference, sizeof(DirectoryEntryReference), + childName, childNameBytes, false); + + if (error != ES_SUCCESS) { + return error; + } + } + + return ES_SUCCESS; +} + +static EsError EnumerateIndexNode(Volume *volume, uint8_t *buffer, uint64_t clustersRead, KNode *directory) { + for (uintptr_t indexBlock = 0; indexBlock < volume->clusterBytes * clustersRead / volume->indexBlockBytes; indexBlock++) { + uint8_t *blockStart = buffer + indexBlock * volume->indexBlockBytes; + + IndexBlockHeader *header = (IndexBlockHeader *) blockStart; + + if (header->magic != 0x58444E49) { + ENUMERATE_FAILURE("Index block has incorrect magic number.\n"); + } + + if (!ApplyFixup(volume, blockStart, header->updateSequenceOffset, header->updateSequenceSize, volume->indexBlockBytes)) { + return ES_ERROR_CORRUPT_DATA; + } + + if (header->firstEntryOffset > volume->indexBlockBytes || header->firstEntryOffset + header->totalEntrySize > volume->indexBlockBytes) { + ENUMERATE_FAILURE("Index block has incorrect entries offset/size.\n"); + } + + uint8_t *entriesPosition = blockStart + header->firstEntryOffset + 0x18; + uint8_t *entriesEnd = entriesPosition + header->totalEntrySize; + + while (entriesPosition + sizeof(IndexEntryHeader) <= entriesEnd) { + IndexEntryHeader *entry = (IndexEntryHeader *) entriesPosition; + EsError error = EnumerateIndexEntry(entry, blockStart + header->firstEntryOffset + header->totalEntrySize, directory); + if (error != ES_SUCCESS) return error; + if (entry->flags & (1 << 1)) break; + entriesPosition += entry->indexEntryLength; + } + } + + return ES_SUCCESS; +} + +static EsError Enumerate(KNode *node) { + FSNode *directory = (FSNode *) node->driverNode; + Volume *volume = directory->volume; + + size_t bufferSize = volume->indexBlockBytes > volume->clusterBytes ? volume->indexBlockBytes : volume->clusterBytes; + size_t clustersPerBuffer = bufferSize / volume->clusterBytes; + + uint8_t *buffer = (uint8_t *) EsHeapAllocate(bufferSize, false, K_FIXED); + + if (!buffer) { + ENUMERATE_FAILURE("Could not allocate buffer.\n"); + } + + EsDefer(EsHeapFree(buffer, bufferSize, K_FIXED)); + + // Parse entries in the index root. + + ResidentAttributeHeader *indexRootHeader = (ResidentAttributeHeader *) FindAttribute(volume, directory, 0x90); + + if (!indexRootHeader || indexRootHeader->nonResident || indexRootHeader->attributeLength < sizeof(IndexRootHeader) + || indexRootHeader->attributeOffset > MFT_FILE_SIZE - ((uint8_t *) indexRootHeader - directory->fileRecord) + || indexRootHeader->attributeOffset + indexRootHeader->attributeLength > MFT_FILE_SIZE - ((uint8_t *) indexRootHeader - directory->fileRecord)) { + ENUMERATE_FAILURE("Invalid index root attribute.\n"); + } + + { + IndexRootHeader *header = (IndexRootHeader *) ((uint8_t *) indexRootHeader + indexRootHeader->attributeOffset); + + if (header->firstEntryOffset > indexRootHeader->attributeLength + || header->totalEntrySize > indexRootHeader->attributeLength - header->firstEntryOffset) { + ENUMERATE_FAILURE("Index root has incorrect entries offset/size.\n"); + } + + uint8_t *entriesPosition = (uint8_t *) header + header->firstEntryOffset + 0x10; + uint8_t *entriesEnd = entriesPosition + header->totalEntrySize; + + while (entriesPosition + sizeof(IndexEntryHeader) <= entriesEnd) { + IndexEntryHeader *entry = (IndexEntryHeader *) entriesPosition; + EnumerateIndexEntry(entry, entriesEnd, node); + if (entry->flags & (1 << 1)) break; + entriesPosition += entry->indexEntryLength; + } + } + + if (!FindAttribute(volume, directory, 0xA0, nullptr, true)) { + return true; + } + + // Get the index allocation attribute. + + NonResidentAttributeHeader *indexAllocationHeader = GetIndexAllocationHeader(volume, directory); + + if (!indexAllocationHeader) { + return false; + } + + // For every data run... + + RunHeader *dataRun = (RunHeader *) ((uint8_t *) indexAllocationHeader + indexAllocationHeader->dataRunsOffset); + uint64_t clusterNumber = 0; + uintptr_t clustersInBuffer = 0; + + while (((uint8_t *) dataRun - (uint8_t *) indexAllocationHeader) < indexAllocationHeader->length && dataRun->lengthFieldBytes) { + uint64_t length = GetDataRunLength(dataRun), offset = GetDataRunOffset(dataRun); + + clusterNumber += offset; + dataRun = (RunHeader *) ((uint8_t *) dataRun + 1 + dataRun->lengthFieldBytes + dataRun->offsetFieldBytes); + + uint64_t positionInRun = 0; + + while (positionInRun != length) { + size_t clustersToRead = (clustersPerBuffer - clustersInBuffer > length - positionInRun) + ? (length - positionInRun) : (clustersPerBuffer - clustersInBuffer); + + volume->fileSystem->Access((clusterNumber + positionInRun) * volume->clusterBytes, + clustersToRead * volume->clusterBytes, K_ACCESS_READ, + buffer + clustersInBuffer * volume->clusterBytes, ES_FLAGS_DEFAULT); + + clustersInBuffer += clustersToRead; + positionInRun += clustersToRead; + + if (clustersInBuffer == clustersPerBuffer) { + EsError error = EnumerateIndexNode(volume, buffer, clustersPerBuffer, node); + if (error != ES_SUCCESS) return error; + clustersInBuffer = 0; + } + } + } + + return ES_SUCCESS; +} + +static KNode *Scan(const char *_name, size_t _nameBytes, KNode *_directory) { +#define SCAN_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "scan failure", "Scan - " message); return nullptr; } while (0) + + uint16_t *searchName = (uint16_t *) EsHeapAllocate(256 * sizeof(uint16_t), false, K_FIXED); + size_t searchNameCharacters = 0; + + if (!searchName) { + SCAN_FAILURE("Could not allocate buffer for search name.\n"); + } + + EsDefer(EsHeapFree(searchName, 256 * sizeof(uint16_t), K_FIXED)); + + const char *_name2 = _name; + size_t _nameBytes2 = _nameBytes; + + while (_nameBytes) { + size_t lengthBytes = utf8_length_char(_name); + if (_nameBytes < lengthBytes) { + SCAN_FAILURE("Invalid search name.\n"); + } + + uint32_t value = utf8_value(_name); + + if (value <= 0xFFFF) { + if (searchNameCharacters >= 255) return nullptr; + searchName[searchNameCharacters++] = value; + } else { + if (searchNameCharacters >= 254) return nullptr; + value -= 0x10000; + searchName[searchNameCharacters++] = 0xD800 | ((value >> 10) & 0x3FF); + searchName[searchNameCharacters++] = 0xDC00 | ((value >> 0) & 0x3FF); + } + + _name += lengthBytes; + _nameBytes -= lengthBytes; + } + + FSNode *directory = (FSNode *) _directory->driverNode; + Volume *volume = directory->volume; + + uint8_t *buffer = (uint8_t *) EsHeapAllocate(volume->indexBlockBytes, false, K_FIXED); + + if (!buffer) { + SCAN_FAILURE("Could not allocate buffer for index block.\n"); + } + + EsDefer(EsHeapFree(buffer, volume->indexBlockBytes, K_FIXED)); + + bool hasIndexAllocation = FindAttribute(volume, directory, 0xA0, nullptr, true) ? true : false; + NonResidentAttributeHeader *indexAllocationHeader = hasIndexAllocation ? GetIndexAllocationHeader(volume, directory) : nullptr; + ResidentAttributeHeader *indexRootHeader = (ResidentAttributeHeader *) FindAttribute(volume, directory, 0x90); + + if ((!indexAllocationHeader && hasIndexAllocation) || !indexRootHeader) { + SCAN_FAILURE("Could not find necessary attributes.\n"); + } + + if (indexRootHeader->nonResident || indexRootHeader->attributeLength < sizeof(IndexRootHeader) + || indexRootHeader->attributeOffset > MFT_FILE_SIZE - ((uint8_t *) indexRootHeader - directory->fileRecord) + || indexRootHeader->attributeOffset + indexRootHeader->attributeLength > MFT_FILE_SIZE - ((uint8_t *) indexRootHeader - directory->fileRecord)) { + SCAN_FAILURE("Invalid index root attribute.\n"); + } + + IndexRootHeader *indexRoot = (IndexRootHeader *) ((uint8_t *) indexRootHeader + indexRootHeader->attributeOffset); + + if (indexRoot->firstEntryOffset > indexRootHeader->attributeLength + || indexRoot->firstEntryOffset + indexRoot->totalEntrySize > indexRootHeader->attributeLength + || indexRoot->totalEntrySize < sizeof(IndexEntryHeader) + || indexRoot->attributeType != 0x30 /* filenames */ + || indexRoot->collationRule != 1 /* Unicode strings */) { + SCAN_FAILURE("Invalid index root attribute (2).\n"); + } + + uint8_t *entriesPosition = (uint8_t *) indexRoot + indexRoot->firstEntryOffset + 0x10; + uint8_t *entriesEnd = entriesPosition + indexRoot->totalEntrySize; + bool hasSubNodes = indexRoot->flags & (1 << 0); + int depth = 0; + + while (entriesPosition + sizeof(IndexEntryHeader) <= entriesEnd) { + IndexEntryHeader *entry = (IndexEntryHeader *) entriesPosition; + + if (entry->streamLength > entry->indexEntryLength + || entriesPosition + entry->indexEntryLength > entriesEnd) { + SCAN_FAILURE("Invalid index entry.\n"); + } + + bool descend = false; + + if (entry->flags & (1 << 1)) { + // Last entry in the node. + descend = true; + } else { + if (entry->streamLength < sizeof(FileNameAttributeHeader)) { + SCAN_FAILURE("Index entry stream too short.\n"); + } + + FileNameAttributeHeader *fileNameHeader = (FileNameAttributeHeader *) (entry + 1); + + if (fileNameHeader->fileNameLength * 2 > entry->streamLength - sizeof(FileNameAttributeHeader)) { + SCAN_FAILURE("Index entry stream too short (2).\n"); + } + + if (fileNameHeader->namespaceType == 1 || fileNameHeader->namespaceType == 3) { + uint16_t *fileName = (uint16_t *) (fileNameHeader + 1); + size_t fileNameCharacters = fileNameHeader->fileNameLength; + + uintptr_t index = 0; + bool match = true; + + while (index != fileNameCharacters || index != searchNameCharacters) { + if (index == fileNameCharacters) { + match = false; + break; + } else if (index == searchNameCharacters) { + descend = true; + match = false; + break; + } + + uint16_t c1 = ToUpper(volume, fileName[index]), c2 = ToUpper(volume, searchName[index]); + + if (c1 != c2) { + if (c1 > c2) { + descend = true; + } + + match = false; + break; + } + + index++; + } + + if (match) { + // Found a match; open the node. + + KNode *child = FSNodeAllocate(); + + if (!child) { + SCAN_FAILURE("Could not allocate node.\n"); + } + + child->driverNode = EsHeapAllocate(sizeof(FSNode), true, K_FIXED); + + if (!child->driverNode) { + EsHeapFree(child, 0, K_FIXED); + SCAN_FAILURE("Could not allocate node.\n"); + } + + FSNode *node = (FSNode *) child->driverNode; + node->volume = volume; + + if (!ReadFileRecord(child, node, entry->fileRecordNumber, + (fileNameHeader->flags & 0x10000000) ? ES_NODE_DIRECTORY : ES_NODE_FILE, + buffer)) { + EsHeapFree(node, sizeof(FSNode), K_FIXED); + EsHeapFree(child, 0, K_FIXED); + return nullptr; + } + + if (!FSRegisterNewNode(child, _directory, child->data.type, _name2, _nameBytes2)) { // TODO Case-insensitivity support in the VFS. + EsHeapFree(node, sizeof(FSNode), K_FIXED); + EsHeapFree(child, 0, K_FIXED); + SCAN_FAILURE("Could not register root directory node.\n"); + } + + return child; + } + } + } + + if (descend) { + if (!hasIndexAllocation) { + SCAN_FAILURE("Cannot descend in index without allocation attribute.\n"); + } + + if (!hasSubNodes || (~entry->flags & (1 << 0))) { + // Could not find the entry. + return nullptr; + } + + uint64_t nextVCN = *(uint64_t *) (entriesPosition + entry->indexEntryLength - sizeof(uint64_t)); + + // Descend to the next index level. + + if (++depth > 16) { + SCAN_FAILURE("Directory filename index too deep.\n"); + } + + RunHeader *dataRun = (RunHeader *) ((uint8_t *) indexAllocationHeader + indexAllocationHeader->dataRunsOffset); + + // Load the next index block. + + uint64_t clusterNumber = 0; + uint64_t positionInAllocation = 0; + bool foundStart = false; + + uintptr_t positionInBuffer = 0; + size_t clustersToRead = volume->indexBlockBytes / volume->clusterBytes; // TODO Assumes a cluster fits in an index block. + + while (((uint8_t *) dataRun - (uint8_t *) indexAllocationHeader) < indexAllocationHeader->length && dataRun->lengthFieldBytes) { + uint64_t length = GetDataRunLength(dataRun), offset = GetDataRunOffset(dataRun); + + clusterNumber += offset; + + uintptr_t clusterIndex = clusterNumber; + + if (nextVCN >= positionInAllocation && nextVCN < positionInAllocation + length) { + foundStart = true; + clusterIndex += nextVCN - positionInAllocation; + length -= nextVCN - positionInAllocation; + } + + if (foundStart) { + size_t read = length > (clustersToRead - positionInBuffer) ? (clustersToRead - positionInBuffer) : length; + + if (!volume->fileSystem->Access(clusterIndex * volume->clusterBytes, + read * volume->clusterBytes, K_ACCESS_READ, + buffer + positionInBuffer * volume->clusterBytes, ES_FLAGS_DEFAULT)) { + SCAN_FAILURE("Could not read the clusters containing VCN to descend to.\n"); + } + + positionInBuffer += read; + + if (positionInBuffer == clustersToRead) { + break; + } + } + + positionInAllocation += length; + dataRun = (RunHeader *) ((uint8_t *) dataRun + 1 + dataRun->lengthFieldBytes + dataRun->offsetFieldBytes); + } + + if (positionInBuffer != clustersToRead) { + SCAN_FAILURE("Could not find all the cluster containing VCN to descend to.\n"); + } + + IndexBlockHeader *header = (IndexBlockHeader *) buffer; + + if (header->magic != 0x58444E49) { + SCAN_FAILURE("Index block has incorrect magic number.\n"); + } + + if (!ApplyFixup(volume, buffer, header->updateSequenceOffset, header->updateSequenceSize, volume->indexBlockBytes)) { + return nullptr; + } + + if (header->firstEntryOffset > volume->indexBlockBytes + || header->totalEntrySize > volume->indexBlockBytes - header->firstEntryOffset) { + SCAN_FAILURE("Index block has incorrect entries offset/size.\n"); + } + + entriesPosition = (uint8_t *) header + header->firstEntryOffset + 0x18; + entriesEnd = entriesPosition + header->totalEntrySize; + hasSubNodes = header->flags & (1 << 0); + } else { + entriesPosition += entry->indexEntryLength; + } + } + + SCAN_FAILURE("The last entry in an index node did not have the last entry flag set.\n"); +} + +static size_t Read(KNode *node, void *_buffer, EsFileOffset offset, EsFileOffset count) { +#define READ_FAILURE(message) do { KernelLog(LOG_ERROR, "NTFS", "read failure", "Read - " message); return ES_ERROR_UNKNOWN; } while (0) + + FSNode *file = (FSNode *) node->driverNode; + Volume *volume = file->volume; + + uint8_t *clusterBuffer = (uint8_t *) EsHeapAllocate(volume->clusterBytes * 2, false, K_FIXED); + + if (!clusterBuffer) { + READ_FAILURE("Could not allocate cluster buffer.\n"); + } + + EsDefer(EsHeapFree(clusterBuffer, volume->clusterBytes * 2, K_FIXED)); + + uint8_t *clusterBuffer2 = clusterBuffer + volume->clusterBytes; + uint8_t *outputBuffer = (uint8_t *) _buffer; + + // Find the data attribute. + + AttributeHeader *_dataHeader = (AttributeHeader *) FindAttribute(volume, file, 0x80); + + if (!_dataHeader) { + // TODO Support $ATTRIBUTE_LIST. + READ_FAILURE("Could not find data attribute.\n"); + } + + if (!_dataHeader->nonResident) { + // Resident data attribute. + + if (_dataHeader->length < sizeof(ResidentAttributeHeader)) { + READ_FAILURE("Data attribute is too short.\n"); + } + + ResidentAttributeHeader *residentDataHeader = (ResidentAttributeHeader *) _dataHeader; + + if (residentDataHeader->attributeOffset > MFT_FILE_SIZE - ((uint8_t *) residentDataHeader - file->fileRecord) + || residentDataHeader->attributeLength > MFT_FILE_SIZE - ((uint8_t *) residentDataHeader - file->fileRecord) + - residentDataHeader->attributeOffset) { + READ_FAILURE("Data attribute offset/length invalid.\n"); + } + + // Copy data into the buffer. + + uint8_t *residentData = (uint8_t *) residentDataHeader + residentDataHeader->attributeOffset; + + if (offset > residentDataHeader->attributeLength || count > residentDataHeader->attributeLength - offset) { + READ_FAILURE("Data attribute offset/length invalid (2).\n"); + } + + EsMemoryCopy(outputBuffer, residentData + offset, count); + return true; + } + + NonResidentAttributeHeader *dataHeader = (NonResidentAttributeHeader *) _dataHeader; + + if (dataHeader->length < sizeof(NonResidentAttributeHeader)) { + READ_FAILURE("Data attribute is too short.\n"); + } + + if (dataHeader->flags) { + READ_FAILURE("Data attribute has unsupported flags.\n"); + } + + // Find the data run containing the requested clusters. + + RunHeader *dataRun = (RunHeader *) ((uint8_t *) dataHeader + dataHeader->dataRunsOffset); + uint64_t clusterNumber = 0; + bool foundStart = false; + + uint64_t startCluster = offset / volume->clusterBytes; + uint64_t endCluster = (offset + count) / volume->clusterBytes; + uint64_t startOffset = offset - startCluster * volume->clusterBytes; + uint64_t endOffset = (offset + count) - endCluster * volume->clusterBytes; + + uint64_t clusterPosition = 0; + uint8_t *buffer = outputBuffer; + + KWorkGroup dispatchGroup = {}; + dispatchGroup.Initialise(); + + while (((uint8_t *) dataRun - (uint8_t *) dataHeader) < dataHeader->length && dataRun->lengthFieldBytes) { + uint64_t length = GetDataRunLength(dataRun), offset = GetDataRunOffset(dataRun); + + clusterNumber += offset; + dataRun = (RunHeader *) ((uint8_t *) dataRun + 1 + dataRun->lengthFieldBytes + dataRun->offsetFieldBytes); + + uint64_t runOffset = 0; + + if (!foundStart) { + if (length <= startCluster - clusterPosition) { + clusterPosition += length; + continue; + } else { + runOffset = startCluster - clusterPosition; + clusterPosition = startCluster; + foundStart = true; + } + } + + if (!foundStart) { + continue; + } + + while (runOffset < length && clusterPosition <= endCluster) { + uint64_t firstClusterToRead = clusterNumber + runOffset; + uint64_t clustersToRead = (endCluster - clusterPosition) > (length - runOffset) + ? (length - runOffset) : (endCluster - clusterPosition); + + if (clusterPosition == startCluster || clusterPosition == endCluster) { + clustersToRead = 1; + } + + // Read the clusters. + + if (clusterPosition == startCluster) { + volume->fileSystem->Access(firstClusterToRead * volume->clusterBytes, + clustersToRead * volume->clusterBytes, K_ACCESS_READ, + clusterBuffer, ES_FLAGS_DEFAULT, &dispatchGroup); + buffer += volume->clusterBytes - startOffset; + } else if (clusterPosition == endCluster) { + volume->fileSystem->Access(firstClusterToRead * volume->clusterBytes, + clustersToRead * volume->clusterBytes, K_ACCESS_READ, + clusterBuffer2, ES_FLAGS_DEFAULT, &dispatchGroup); + } else { + volume->fileSystem->Access(firstClusterToRead * volume->clusterBytes, + clustersToRead * volume->clusterBytes, K_ACCESS_READ, + buffer, ES_FLAGS_DEFAULT, &dispatchGroup); + buffer += clustersToRead * volume->clusterBytes; + } + + clusterPosition += clustersToRead; + runOffset += clustersToRead; + } + } + + if (clusterPosition <= endCluster) { + READ_FAILURE("Trying to read past the end of the data runs.\n"); + } + + // Wait for outstanding IO operations to complete. + + bool success = dispatchGroup.Wait(); + + if (!success) { + READ_FAILURE("Could not read clusters from block device.\n"); + } + + // Copy first and last clusters into the buffer. + + if (startCluster == endCluster) { + EsMemoryCopy(outputBuffer, clusterBuffer + startOffset, count); + } else { + EsMemoryCopy(outputBuffer, clusterBuffer + startOffset, volume->clusterBytes - startOffset); + EsMemoryCopy(outputBuffer + count - endOffset, clusterBuffer2, endOffset); + } + + return true; +} + +static void Close(KNode *node) { + EsHeapFree(node->driverNode, sizeof(FSNode), K_FIXED); +} + +static void DeviceAttach(KDevice *parent) { + Volume *volume = (Volume *) KDeviceCreate("NTFS", parent, sizeof(Volume)); + + if (!volume) { + KernelLog(LOG_ERROR, "NTFS", "allocate error", "EntryNTFS - Could not allocate Volume structure.\n"); + return; + } + + volume->fileSystem = (KFileSystem *) parent; + + if (!Mount(volume)) { + KernelLog(LOG_ERROR, "NTFS", "mount failure", "EntryNTFS - Could not mount NTFS volume.\n"); + + if (volume->root) EsHeapFree(volume->root->driverNode, 0, K_FIXED); + EsHeapFree(volume->root, 0, K_FIXED); + + for (uintptr_t i = 0; i < 256; i++) { + if (volume->upCaseLookup[i]) { + EsHeapFree(volume->upCaseLookup[i], 512, K_FIXED); + } + } + + KDeviceDestroy(volume); + return; + } + + { + ResidentAttributeHeader *volumeNameHeader = (ResidentAttributeHeader *) FindAttribute(volume, &volume->volumeNode, 0x60); + + if (volumeNameHeader && !volumeNameHeader->nonResident + && (volumeNameHeader->attributeOffset + volumeNameHeader->attributeLength + + ((uint8_t *) volumeNameHeader - volume->volumeNode.fileRecord) <= MFT_FILE_SIZE)) { + volume->fileSystem->nameBytes = volumeNameHeader->attributeLength; + if (volume->fileSystem->nameBytes > sizeof(volume->fileSystem->name)) volume->fileSystem->nameBytes = sizeof(volume->fileSystem->name); + EsMemoryCopy(volume->fileSystem->name, (uint8_t *) volumeNameHeader + volumeNameHeader->attributeOffset, volume->fileSystem->nameBytes); + } + } + + volume->fileSystem->read = Read; + volume->fileSystem->scan = Scan; + volume->fileSystem->load = Load; + volume->fileSystem->enumerate = Enumerate; + volume->fileSystem->close = Close; + + KernelLog(LOG_INFO, "NTFS", "register file system", "EntryNTFS - Registering file system with name '%s'.\n", + volume->fileSystem->nameBytes, volume->fileSystem->name); + FSRegisterFileSystem(volume->fileSystem); +} + +KDriver driverNTFS = { + .attach = DeviceAttach; +}; diff --git a/drivers/nvme.cpp b/drivers/nvme.cpp new file mode 100644 index 0000000..5c209fa --- /dev/null +++ b/drivers/nvme.cpp @@ -0,0 +1,878 @@ +#include + +// TODO Sometimes completion interrupts get missed? +// TODO How many IO completion/submission queues should we create, and how many entries should they contain? +// TODO Command timeout. + +#define GENERAL_TIMEOUT (5000) + +#define RD_REGISTER_CAP() pci-> ReadBAR64(0, 0x00) // Controller capababilities. +#define WR_REGISTER_CAP(x) pci->WriteBAR64(0, 0x00, x) +#define RD_REGISTER_VS() pci-> ReadBAR32(0, 0x08) // Version. +#define WR_REGISTER_VS(x) pci->WriteBAR32(0, 0x08, x) +#define RD_REGISTER_INTMS() pci-> ReadBAR32(0, 0x0C) // Interrupt mask set. +#define WR_REGISTER_INTMS(x) pci->WriteBAR32(0, 0x0C, x) +#define RD_REGISTER_INTMC() pci-> ReadBAR32(0, 0x10) // Interrupt mask clear. +#define WR_REGISTER_INTMC(x) pci->WriteBAR32(0, 0x10, x) +#define RD_REGISTER_CC() pci-> ReadBAR32(0, 0x14) // Controller configuration. +#define WR_REGISTER_CC(x) pci->WriteBAR32(0, 0x14, x) +#define RD_REGISTER_CSTS() pci-> ReadBAR32(0, 0x1C) // Controller status. +#define WR_REGISTER_CSTS(x) pci->WriteBAR32(0, 0x1C, x) +#define RD_REGISTER_AQA() pci-> ReadBAR32(0, 0x24) // Admin queue attributes. +#define WR_REGISTER_AQA(x) pci->WriteBAR32(0, 0x24, x) +#define RD_REGISTER_ASQ() pci-> ReadBAR64(0, 0x28) // Admin submission queue base address. +#define WR_REGISTER_ASQ(x) pci->WriteBAR64(0, 0x28, x) +#define RD_REGISTER_ACQ() pci-> ReadBAR64(0, 0x30) // Admin completion queue base address. +#define WR_REGISTER_ACQ(x) pci->WriteBAR64(0, 0x30, x) + +#define RD_REGISTER_SQTDBL(i) pci-> ReadBAR32(0, 0x1000 + doorbellStride * (2 * (i) + 0)) // Submission queue tail doorbell. +#define WR_REGISTER_SQTDBL(i, x) pci->WriteBAR32(0, 0x1000 + doorbellStride * (2 * (i) + 0), x) +#define RD_REGISTER_CQHDBL(i) pci-> ReadBAR32(0, 0x1000 + doorbellStride * (2 * (i) + 1)) // Completion queue head doorbell. +#define WR_REGISTER_CQHDBL(i, x) pci->WriteBAR32(0, 0x1000 + doorbellStride * (2 * (i) + 1), x) + +#define ADMIN_QUEUE_ENTRY_COUNT (2) +#define IO_QUEUE_ENTRY_COUNT (256) +#define SUBMISSION_QUEUE_ENTRY_BYTES (64) +#define COMPLETION_QUEUE_ENTRY_BYTES (16) + +struct NVMeController : KDevice { + KPCIDevice *pci; + + uint64_t capabilities; + uint32_t version; + + size_t doorbellStride; + uint64_t readyTransitionTimeout; + uint64_t maximumDataTransferBytes; + uint32_t rtd3EntryLatencyUs; + uint16_t maximumOutstandingCommands; + + uint8_t *adminCompletionQueue, *adminSubmissionQueue; + uint32_t adminCompletionQueueHead, adminSubmissionQueueTail; + KEvent adminCompletionQueueReceived; + bool adminCompletionQueuePhase; + uint32_t adminCompletionQueueLastResult; + uint16_t adminCompletionQueueLastStatus; + + uint8_t *ioCompletionQueue, *ioSubmissionQueue; + uint32_t ioCompletionQueueHead, ioSubmissionQueueTail; + volatile uint32_t ioSubmissionQueueHead; + bool ioCompletionQueuePhase; + KEvent ioSubmissionQueueNonFull; + KSpinlock ioQueueSpinlock; + KWorkGroup *dispatchGroups[IO_QUEUE_ENTRY_COUNT]; + uint64_t prpListPages[IO_QUEUE_ENTRY_COUNT]; + uint64_t *prpListVirtual; + + void Initialise(); + void Shutdown(); + + bool HandleIRQ(); + bool IssueAdminCommand(const void *command, uint32_t *result); + bool Access(struct NVMeDrive *drive, uint64_t offsetBytes, size_t countBytes, int operation, + KDMABuffer *buffer, uint64_t flags, KWorkGroup *dispatchGroup); + void DumpState(); +}; + +struct NVMeDrive : KBlockDevice { + NVMeController *controller; + uint32_t nsid; +}; + +const char *genericCommandStatusValues[] = { + "Successful completion", + "Invalid command opcode", + "Invalid field in command", + "Command ID conflict", + "Data transfer error", + "Commands aborted due to powerloss notification", + "Internal error", + "Command abort requested", + "Command aborted due to SQ deletion", + "Command aborted due to failed fused command", + "Command aborted due to missing fused command", + "Invalid namespace or format", + "Command sequence error", + "Invalid SGL segment descriptor", + "Invalid number of SGL descriptors", + "Data SGL length invalid", + "Metadata SGL length invalid", + "SGL descriptor type invalid", + "Invalid use of controller memory buffer", + "PRP offset invalid", + "Atomic write unit exceeded", + "Operation denied", + "SGL offset invalid", + "Reserved", + "Host identifier inconsistent format", + "Keep alive timer expired", + "Keep alive timeout invalid", + "Command aborted due to preempt and abort", + "Sanitize failed", + "Sanitize in progress", + "SGL data block granularity invalid", + "Command not supported for queue in CMB", + "Namespace is write protected", + "Command interrupted", + "Transient transport error", +}; + +const char *genericCommandStatusValuesNVM[] = { + "LBA out of range", + "Capacity exceeded", + "Namespace not ready", + "Reservation conflict", + "Format in progress", +}; + +const char *commandSpecificStatusValues[] = { + "Completion queue invalid", + "Invalid queue identifier", + "Invalid queue size", + "Abort command limit exceeded", + "Reserved", + "Asynchronous event request limit exceeded", + "Invalid firmware slot", + "Invalid firmware image", + "Invalid interrupt vector", + "Invalid log page", + "Invalid format", + "Firmware activation requirse conventional reset", + "Invalid queue deletion", + "Feature identifier not saveable", + "Feature not changeable", + "Feature not namespace specific", + "Firmware activation requires NVM subsystem reset", + "Firmware activation requires controller level reset", + "Firmware activation requires maximum time violation", + "Firmware activation prohibited", + "Overlapping range", + "Namespace insufficient capacity", + "Namespace identifier unavailable", + "Reserved", + "Namespace already attached", + "Namespace is private", + "Namespace not attached", + "Thin provisioning not supported", + "Controller list invalid", + "Device self-test in progress", + "Boot partition write prohibited", + "Invalid controller identifier", + "Invalid secondary controller state", + "Invalid number of controller resources", + "Invalid resource identifier", + "Sanitize prohibited while persistent memory region is enabled", + "ANA group identifier invalid", + "ANA attach failed", +}; + +const char *commandSpecificStatusValuesNVM[] = { + "Confliciting attributes", + "Invalid protection information", + "Attempted write to read only range", +}; + +const char *mediaAndDataIntegrityErrorValuesNVM[] = { + "Write fault", + "Unrecovered read error", + "End-to-end guard check error", + "End-to-end application tag check error", + "End-to-end reference tag check error", + "Compare failure", + "Access denied", + "Dealocated or unwritten logical block", +}; + +const char *pathRelatedStatusValues[] = { + "Internal path error", + "Asymmetric access persistent loss", + "Asymmetric access inaccessible", + "Asymmetric access transition", +}; + +const char *GetErrorMessage(uint8_t statusCodeType, uint8_t statusCode) { + if (statusCodeType == 0) { + if (statusCode < sizeof(genericCommandStatusValues) / sizeof(genericCommandStatusValues[0])) { + return genericCommandStatusValues[statusCode]; + } else if (statusCode > 0x80 && (uint8_t) (statusCode - 0x80) < sizeof(genericCommandStatusValuesNVM) / sizeof(genericCommandStatusValuesNVM[0])) { + return genericCommandStatusValuesNVM[statusCode - 0x80]; + } + } else if (statusCodeType == 1) { + if (statusCode < sizeof(commandSpecificStatusValues) / sizeof(commandSpecificStatusValues[0])) { + return commandSpecificStatusValues[statusCode]; + } else if (statusCode > 0x80 && (uint8_t) (statusCode - 0x80) < sizeof(commandSpecificStatusValuesNVM) / sizeof(commandSpecificStatusValuesNVM[0])) { + return commandSpecificStatusValuesNVM[statusCode - 0x80]; + } + } else if (statusCodeType == 2) { + if (statusCode > 0x80 && (uint8_t) (statusCode - 0x80) < sizeof(mediaAndDataIntegrityErrorValuesNVM) / sizeof(mediaAndDataIntegrityErrorValuesNVM[0])) { + return mediaAndDataIntegrityErrorValuesNVM[statusCode - 0x80]; + } + } else if (statusCodeType == 3) { + if (statusCode < sizeof(pathRelatedStatusValues) / sizeof(pathRelatedStatusValues[0])) { + return pathRelatedStatusValues[statusCode]; + } + } + + return "Unknown error"; +} + +void NVMeController::DumpState() { + EsPrint("NVMe controller state:\n"); + + EsPrint("\t--- Registers ---\n"); + EsPrint("\t\tController capababilities: %x.\n", RD_REGISTER_CAP()); + EsPrint("\t\tVersion: %x.\n", RD_REGISTER_VS()); + EsPrint("\t\tInterrupt mask set: %x.\n", RD_REGISTER_INTMS()); + EsPrint("\t\tInterrupt mask clear: %x.\n", RD_REGISTER_INTMC()); + EsPrint("\t\tController configuration: %x.\n", RD_REGISTER_CC()); + EsPrint("\t\tController status: %x.\n", RD_REGISTER_CSTS()); + EsPrint("\t\tAdmin queue attributes: %x.\n", RD_REGISTER_AQA()); + EsPrint("\t\tAdmin submission queue base address: %x.\n", RD_REGISTER_ASQ()); + EsPrint("\t\tAdmin completion queue base address: %x.\n", RD_REGISTER_ACQ()); + EsPrint("\t\tAdmin submission queue tail doorbell: %x.\n", RD_REGISTER_SQTDBL(0)); + EsPrint("\t\tAdmin completion queue head doorbell: %x.\n", RD_REGISTER_CQHDBL(0)); + EsPrint("\t\tIO submission queue tail doorbell: %x.\n", RD_REGISTER_SQTDBL(1)); + EsPrint("\t\tIO completion queue head doorbell: %x.\n", RD_REGISTER_CQHDBL(1)); + + EsPrint("\t--- Internal ---\n"); + EsPrint("\t\tAdmin completion queue: %x.\n", adminCompletionQueue); + EsPrint("\t\tAdmin completion queue head: %x.\n", adminCompletionQueueHead); + EsPrint("\t\tAdmin completion queue phase: %d.\n", adminCompletionQueuePhase); + EsPrint("\t\tAdmin submission queue: %x.\n", adminSubmissionQueue); + EsPrint("\t\tAdmin submission queue tail: %x.\n", adminSubmissionQueueTail); + EsPrint("\t\tIO completion queue: %x.\n", ioCompletionQueue); + EsPrint("\t\tIO completion queue head: %x.\n", ioCompletionQueueHead); + EsPrint("\t\tIO completion queue phase: %d.\n", ioCompletionQueuePhase); + EsPrint("\t\tIO submission queue: %x.\n", ioSubmissionQueue); + EsPrint("\t\tIO submission queue tail: %x.\n", ioSubmissionQueueTail); + EsPrint("\t\tIO submission queue head: %x.\n", ioSubmissionQueueHead); + EsPrint("\t\tIO submission queue non full: %d.\n", ioSubmissionQueueNonFull.state); + EsPrint("\t\tPRP list virtual: %x.\n", prpListVirtual); + + EsPrint("\t--- Outstanding commands ---\n"); + + for (uintptr_t i = ioSubmissionQueueHead; i != ioSubmissionQueueTail; i = (i + 1) % IO_QUEUE_ENTRY_COUNT) { + EsPrint("\t\t(%d) %x, %x, %x, %x, %x, %x, %x, %x.\n", i, + ((uint64_t *) ioSubmissionQueue)[i * 8 + 0], ((uint64_t *) ioSubmissionQueue)[i * 8 + 1], + ((uint64_t *) ioSubmissionQueue)[i * 8 + 2], ((uint64_t *) ioSubmissionQueue)[i * 8 + 3], + ((uint64_t *) ioSubmissionQueue)[i * 8 + 4], ((uint64_t *) ioSubmissionQueue)[i * 8 + 5], + ((uint64_t *) ioSubmissionQueue)[i * 8 + 6], ((uint64_t *) ioSubmissionQueue)[i * 8 + 7]); + } +} + +bool NVMeController::IssueAdminCommand(const void *command, uint32_t *result) { + EsMemoryCopy(adminSubmissionQueue + adminSubmissionQueueTail * SUBMISSION_QUEUE_ENTRY_BYTES, command, SUBMISSION_QUEUE_ENTRY_BYTES); + adminSubmissionQueueTail = (adminSubmissionQueueTail + 1) % ADMIN_QUEUE_ENTRY_COUNT; + KEventReset(&adminCompletionQueueReceived); + __sync_synchronize(); + WR_REGISTER_SQTDBL(0, adminSubmissionQueueTail); + + if (!KEventWait(&adminCompletionQueueReceived, GENERAL_TIMEOUT)) { + // TODO Timeout. Now what? + KernelLog(LOG_ERROR, "NVMe", "admin command timeout", "Admin command timeout when sending command %x.\n", command); + return false; + } + + if (adminCompletionQueueLastStatus) { + bool doNotRetry = adminCompletionQueueLastStatus & 0x8000; + bool more = adminCompletionQueueLastStatus & 0x4000; + uint8_t commandRetryDelay = (adminCompletionQueueLastStatus >> 12) & 0x03; + uint8_t statusCodeType = (adminCompletionQueueLastStatus >> 9) & 0x07; + uint8_t statusCode = (adminCompletionQueueLastStatus >> 1) & 0xFF; + + KernelLog(LOG_ERROR, "NVMe", "admin command failed", "Admin command failed - '%z': %z%zretry delay - %d, type - %d, code - %d.\n", + GetErrorMessage(statusCodeType, statusCode), + doNotRetry ? "do not retry, " : "", more ? "more info in log page, " : "", commandRetryDelay, statusCodeType, statusCode); + + return false; + } + + if (result) *result = adminCompletionQueueLastResult; + return true; +} + +bool NVMeController::Access(struct NVMeDrive *drive, uint64_t offsetBytes, size_t countBytes, int operation, + KDMABuffer *buffer, uint64_t, KWorkGroup *dispatchGroup) { + // TODO Temporary. + // if (operation == K_ACCESS_WRITE) KernelPanic("NVMeController::Access - Attempted write.\n"); + + // Build the PRPs. + + KDMASegment segment1 = KDMABufferNextSegment(buffer); + uint64_t prp1 = segment1.physicalAddress, prp2 = 0; + + if (!segment1.isLast) { + KDMASegment segment2 = KDMABufferNextSegment(buffer, true /* peek */); + if (segment2.isLast) prp2 = segment2.physicalAddress; + } + + retry:; + KSpinlockAcquire(&ioQueueSpinlock); + + // Is there space in the submission queue? + + uintptr_t newTail = (ioSubmissionQueueTail + 1) % IO_QUEUE_ENTRY_COUNT; + bool submissionQueueFull = newTail == ioSubmissionQueueHead; + + if (!submissionQueueFull) { + KernelLog(LOG_VERBOSE, "NVMe", "start access", "Start access of %d, offset %D, count %D, using slot %d.\n", + drive->nsid, offsetBytes, countBytes, ioSubmissionQueueTail); + + uint64_t offsetSector = offsetBytes / drive->sectorSize; + uint64_t countSectors = countBytes / drive->sectorSize; + + // Build the PRP list. + + if (!prp2) { + prp2 = prpListPages[ioSubmissionQueueTail]; + MMArchRemap(MMGetKernelSpace(), prpListVirtual, prp2); + uintptr_t index = 0; + + while (!KDMABufferIsComplete(buffer)) { + if (index == K_PAGE_SIZE / sizeof(uint64_t)) { + KernelPanic("NVMeController::Access - Out of bounds in PRP list.\n"); + } + + prpListVirtual[index++] = KDMABufferNextSegment(buffer).physicalAddress; + } + } + + // Create the command. + + uint32_t *command = (uint32_t *) (ioSubmissionQueue + ioSubmissionQueueTail * SUBMISSION_QUEUE_ENTRY_BYTES); + command[0] = (ioSubmissionQueueTail << 16) /* command identifier */ | (operation == K_ACCESS_WRITE ? 0x01 : 0x02) /* opcode */; + command[1] = drive->nsid; + command[2] = command[3] = command[4] = command[5] = 0; + command[6] = prp1 & 0xFFFFFFFF; + command[7] = (prp1 >> 32) & 0xFFFFFFFF; + command[8] = prp2 & 0xFFFFFFFF; + command[9] = (prp2 >> 32) & 0xFFFFFFFF; + command[10] = offsetSector & 0xFFFFFFFF; + command[11] = (offsetSector >> 32) & 0xFFFFFFFF; + command[12] = (countSectors - 1) & 0xFFFF; + command[13] = command[14] = command[15] = 0; + + // Store the dispatch group, and update the queue tail. + + dispatchGroups[ioSubmissionQueueTail] = dispatchGroup; + ioSubmissionQueueTail = newTail; + __sync_synchronize(); + WR_REGISTER_SQTDBL(1, newTail); + } else { + KEventReset(&ioSubmissionQueueNonFull); + } + + KSpinlockRelease(&ioQueueSpinlock); + + if (submissionQueueFull) { + // Wait for the controller to consume an entry in the submission queue. + + KEventWait(&ioSubmissionQueueNonFull); + goto retry; + } + + return true; +} + +bool NVMeController::HandleIRQ() { + bool fromAdmin = false, fromIO = false; + + // Check the phase bit of the completion queue head entry. + + if (adminCompletionQueue && (adminCompletionQueue[adminCompletionQueueHead * COMPLETION_QUEUE_ENTRY_BYTES + 14] & (1 << 0)) != adminCompletionQueuePhase) { + fromAdmin = true; + + adminCompletionQueueLastResult = *(uint32_t *) (adminCompletionQueue + adminCompletionQueueHead * COMPLETION_QUEUE_ENTRY_BYTES + 0); + adminCompletionQueueLastStatus = *(uint16_t *) (adminCompletionQueue + adminCompletionQueueHead * COMPLETION_QUEUE_ENTRY_BYTES + 14) & 0xFFFE; + + // Advance the queue head. + + adminCompletionQueueHead++; + + if (adminCompletionQueueHead == ADMIN_QUEUE_ENTRY_COUNT) { + adminCompletionQueuePhase = !adminCompletionQueuePhase; + adminCompletionQueueHead = 0; + } + + WR_REGISTER_CQHDBL(0, adminCompletionQueueHead); + + // Signal the event. + + KEventSet(&adminCompletionQueueReceived); + } + + // Check the phase bit of the IO completion queue head entry. + + while (ioCompletionQueue && (ioCompletionQueue[ioCompletionQueueHead * COMPLETION_QUEUE_ENTRY_BYTES + 14] & (1 << 0)) != ioCompletionQueuePhase) { + fromIO = true; + + uint16_t index = *(uint16_t *) (ioCompletionQueue + ioCompletionQueueHead * COMPLETION_QUEUE_ENTRY_BYTES + 12); + uint16_t status = *(uint16_t *) (ioCompletionQueue + ioCompletionQueueHead * COMPLETION_QUEUE_ENTRY_BYTES + 14) & 0xFFFE; + + KernelLog(LOG_VERBOSE, "NVMe", "end access", "End access of slot %d.\n", index); + + if (index >= IO_QUEUE_ENTRY_COUNT) { + KernelLog(LOG_ERROR, "NVMe", "invalid completion entry", "Completion entry reported invalid command index of %d.\n", + index); + } else { + KWorkGroup *dispatchGroup = dispatchGroups[index]; + + if (status) { + uint8_t statusCodeType = (status >> 9) & 0x07, statusCode = (status >> 1) & 0xFF; + KernelLog(LOG_ERROR, "NVMe", "command failed", "Command failed with status %X/%X: %z.\n", + statusCodeType, statusCode, GetErrorMessage(statusCodeType, statusCode)); + dispatchGroup->End(false /* failed */); + } else { + dispatchGroup->End(true /* success */); + } + + dispatchGroups[index] = nullptr; + } + + // Indicate the submission queue entry was consumed. + + __sync_synchronize(); + ioSubmissionQueueHead = *(uint16_t *) (ioCompletionQueue + ioCompletionQueueHead * COMPLETION_QUEUE_ENTRY_BYTES + 8); + KEventSet(&ioSubmissionQueueNonFull, false, true); + + // Advance the queue head. + + ioCompletionQueueHead++; + + if (ioCompletionQueueHead == IO_QUEUE_ENTRY_COUNT) { + ioCompletionQueuePhase = !ioCompletionQueuePhase; + ioCompletionQueueHead = 0; + } + + WR_REGISTER_CQHDBL(1, ioCompletionQueueHead); + } + + return fromAdmin || fromIO; +} + +void NVMeController::Initialise() { + capabilities = RD_REGISTER_CAP(); + version = RD_REGISTER_VS(); + + KernelLog(LOG_INFO, "NVMe", "initial register dump", + "Registers at initialisation: capabilities - %x; version - %x, configuration - %x, status - %x, admin queue attributes - %x. Mapped at %x.\n", + capabilities, version, RD_REGISTER_CC(), RD_REGISTER_CSTS(), RD_REGISTER_AQA()); + + // Check the version is acceptable. + + if ((version >> 16) < 1) { + KernelLog(LOG_ERROR, "NVMe", "unsupported version", "Controller reports major version 0, which is not supported.\n"); + return; + } + + if ((version >> 16) == 1 && ((version >> 8) & 0xFF) < 1) { + KernelLog(LOG_ERROR, "NVMe", "unsupported version", "Controller reports version before 1.1, which is not supported.\n"); + return; + } + + // Check the capabilities are acceptable. + + if ((capabilities & 0xFFFF) == 0) { + KernelLog(LOG_ERROR, "NVMe", "unsupported capabilities", "Invalid CAP.MQES value, expected at least 1.\n"); + return; + } + + if (~capabilities & (1UL << 37)) { + KernelLog(LOG_ERROR, "NVMe", "unsupported capabilities", "Controller does not support NVMe command set.\n"); + return; + } + + if (((capabilities >> 48) & 0xF) > K_PAGE_BITS - 12) { + KernelLog(LOG_ERROR, "NVMe", "unsupported capabilities", "Controller requires a minimum page size greater than the host uses.\n"); + return; + } + + if (((capabilities >> 52) & 0xF) < K_PAGE_BITS - 12) { + KernelLog(LOG_ERROR, "NVMe", "unsupported capabilities", "Controller requires a maximum page size less than the host uses.\n"); + return; + } + + doorbellStride = 4 << ((capabilities >> 32) & 0xF); + readyTransitionTimeout = ((capabilities >> 24) & 0xFF) * 500; + + uint32_t previousConfiguration = RD_REGISTER_CC(); + + // Reset the controller. + + if (previousConfiguration & (1 << 0)) { + KTimeout timeout(readyTransitionTimeout); + while ((~RD_REGISTER_CSTS() & (1 << 0)) && !timeout.Hit()); + if (timeout.Hit()) { KernelLog(LOG_ERROR, "NVMe", "reset timeout", "Timeout during reset sequence (1).\n"); return; } + + WR_REGISTER_CC(RD_REGISTER_CC() & ~(1 << 0)); + } + + { + KTimeout timeout(readyTransitionTimeout); + while ((RD_REGISTER_CSTS() & (1 << 0)) && !timeout.Hit()); + if (timeout.Hit()) { KernelLog(LOG_ERROR, "NVMe", "reset timeout", "Timeout during reset sequence (2).\n"); return; } + } + + // Configure the controller to use the NVMe command set, the host page size, the IO queue entry size, and round robin arbitration. + + WR_REGISTER_CC((RD_REGISTER_CC() & (0xFF00000F)) | (0x00460000) | ((K_PAGE_BITS - 12) << 7)); + + // Configure the admin queues to use our desired entry count, and allocate memory for them. + + WR_REGISTER_AQA((RD_REGISTER_AQA() & 0xF000F000) | ((ADMIN_QUEUE_ENTRY_COUNT - 1) << 16) | (ADMIN_QUEUE_ENTRY_COUNT - 1)); + + uint64_t adminSubmissionQueueBytes = ADMIN_QUEUE_ENTRY_COUNT * SUBMISSION_QUEUE_ENTRY_BYTES; + uint64_t adminCompletionQueueBytes = ADMIN_QUEUE_ENTRY_COUNT * COMPLETION_QUEUE_ENTRY_BYTES; + uint64_t adminQueuePages = (adminSubmissionQueueBytes + K_PAGE_SIZE - 1) / K_PAGE_SIZE + (adminCompletionQueueBytes + K_PAGE_SIZE - 1) / K_PAGE_SIZE; + uintptr_t adminQueuePhysicalAddress = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_CAN_FAIL | MM_PHYSICAL_ALLOCATE_COMMIT_NOW | MM_PHYSICAL_ALLOCATE_ZEROED, + adminQueuePages, (4096 + K_PAGE_SIZE - 1) / K_PAGE_SIZE); + + if (!adminQueuePhysicalAddress) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not allocate %d pages of contiguous physical memory for admin queues.\n", adminQueuePages); + return; + } + + uintptr_t adminSubmissionQueuePhysicalAddress = adminQueuePhysicalAddress; + uintptr_t adminCompletionQueuePhysicalAddress = adminQueuePhysicalAddress + ((adminSubmissionQueueBytes + K_PAGE_SIZE - 1) & ~(K_PAGE_SIZE - 1)); + + WR_REGISTER_ASQ(adminSubmissionQueuePhysicalAddress); + WR_REGISTER_ACQ(adminCompletionQueuePhysicalAddress); + + adminSubmissionQueue = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), adminSubmissionQueuePhysicalAddress, adminSubmissionQueueBytes, ES_FLAGS_DEFAULT); + adminCompletionQueue = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), adminCompletionQueuePhysicalAddress, adminCompletionQueueBytes, ES_FLAGS_DEFAULT); + + if (!adminSubmissionQueue || !adminCompletionQueue) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not map admin queues.\n"); + return; + } + + KernelLog(LOG_INFO, "NVMe", "admin queue configuration", "Configured admin queues to use physical addresses %x and %x with %d entries each.\n", + adminSubmissionQueuePhysicalAddress, adminCompletionQueuePhysicalAddress, ADMIN_QUEUE_ENTRY_COUNT); + + // Start the controller. + + WR_REGISTER_CC(RD_REGISTER_CC() | (1 << 0)); + + { + KTimeout timeout(readyTransitionTimeout); + + while (!timeout.Hit()) { + uint32_t status = RD_REGISTER_CSTS(); + + if (status & (1 << 1)) { + KernelLog(LOG_ERROR, "NVMe", "fatal error", "Fatal error while enabling controller.\n"); + return; + } else if (status & (1 << 0)) { + break; + } + } + + if (timeout.Hit()) { KernelLog(LOG_ERROR, "NVMe", "reset timeout", "Timeout during reset sequence (3).\n"); return; } + } + + // Enable IRQs for the admin queue, and register our interrupt handler. + + if (!pci->EnableSingleInterrupt([] (uintptr_t, void *context) { return ((NVMeController *) context)->HandleIRQ(); }, this, "NVMe")) { + KernelLog(LOG_ERROR, "NVMe", "IRQ registration failure", "Could not register IRQ %d.\n", pci->interruptLine); + return; + } + + WR_REGISTER_INTMC(1 << 0); + + // Identify controller. + + uintptr_t identifyDataPhysicalAddress = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_CAN_FAIL | MM_PHYSICAL_ALLOCATE_COMMIT_NOW | MM_PHYSICAL_ALLOCATE_ZEROED, + (4096 * 2 + K_PAGE_SIZE - 1) / K_PAGE_SIZE); + + if (!identifyDataPhysicalAddress) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not allocate physical memory for receiving identify data.\n"); + return; + } + + uint8_t *identifyData = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), identifyDataPhysicalAddress, 4096 * 2, ES_FLAGS_DEFAULT); + + if (!identifyData) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not map memory for receiving identify data.\n"); + return; + } + + { + uint32_t command[16] = {}; + command[0] = 0x06; // Identify opcode. + command[6] = identifyDataPhysicalAddress & 0xFFFFFFFF; + command[7] = (identifyDataPhysicalAddress >> 32) & 0xFFFFFFFF; + command[10] = 0x01; // Identify controller. + + if (!IssueAdminCommand(command, nullptr)) { + KernelLog(LOG_ERROR, "NVMe", "identify controller failure", "The identify controller admin command failed.\n"); + return; + } + + maximumDataTransferBytes = identifyData[77] ? (1 << (12 + identifyData[77] + (((capabilities >> 48) & 0xF)))) : 0; + rtd3EntryLatencyUs = *(uint32_t *) (identifyData + 88); + maximumOutstandingCommands = *(uint16_t *) (identifyData + 514); + + if (rtd3EntryLatencyUs > 250 * 1000) { + rtd3EntryLatencyUs = 250 * 1000; // Maximum shutdown delay: 250ms. + } + + if (identifyData[111] > 0x01) { + KernelLog(LOG_ERROR, "NVMe", "unsupported controller type", "Controller type %X is not supported. Only IO controllers are currently supported.\n", + identifyData[111]); + return; + } + + KernelLog(LOG_INFO, "NVMe", "controller identify data", "Controller identify reported the following information: " + "serial number - '%s', model number - '%s', firmware revision - '%s', " + "maximum data transfer - %D, RTD3 entry latency - %dus, maximum outstanding commands - %d.\n", + 20, identifyData + 4, 40, identifyData + 24, 8, identifyData + 64, + maximumDataTransferBytes, rtd3EntryLatencyUs, maximumOutstandingCommands); + + if (maximumDataTransferBytes == 0 || maximumDataTransferBytes >= 2097152) { + maximumDataTransferBytes = 2097152; + } + } + + // Reset the software progress marker. + + { + // TODO How to check if this feature is supported? + uint32_t command[16] = {}; + command[0] = 0x09; // Set features opcode. + command[10] = 0x80; // Software progress marker feature. + command[11] = 0x00; // Reset to 0. + IssueAdminCommand(command, nullptr); // Ignore errors. + } + + // Create IO completion queue. + + { + uint64_t bytes = IO_QUEUE_ENTRY_COUNT * COMPLETION_QUEUE_ENTRY_BYTES; + uint64_t pages = (bytes + K_PAGE_SIZE - 1) / K_PAGE_SIZE; + uintptr_t physicalAddress = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_CAN_FAIL | MM_PHYSICAL_ALLOCATE_COMMIT_NOW | MM_PHYSICAL_ALLOCATE_ZEROED, pages); + + if (!physicalAddress) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not allocate IO completion queue memory.\n"); + return; + } + + ioCompletionQueue = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), physicalAddress, bytes, ES_FLAGS_DEFAULT); + + if (!ioCompletionQueue) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not map IO completion queue memory.\n"); + return; + } + + uint32_t command[16] = {}; + command[0] = 0x05; // Create IO completion queue opcode. + command[6] = physicalAddress & 0xFFFFFFFF; + command[7] = (physicalAddress >> 32) & 0xFFFFFFFF; + command[10] = 1 /* identifier */ | ((IO_QUEUE_ENTRY_COUNT - 1) << 16); + command[11] = (1 << 0) /* physically contiguous */ | (1 << 1) /* interrupts enabled */; + + if (!IssueAdminCommand(command, nullptr)) { + KernelLog(LOG_ERROR, "NVMe", "create queue failure", "Could not create the IO completion queue.\n"); + return; + } + } + + // Create IO submission queue. + + { + uint64_t bytes = IO_QUEUE_ENTRY_COUNT * SUBMISSION_QUEUE_ENTRY_BYTES; + uint64_t pages = (bytes + K_PAGE_SIZE - 1) / K_PAGE_SIZE; + uintptr_t physicalAddress = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_CAN_FAIL | MM_PHYSICAL_ALLOCATE_COMMIT_NOW | MM_PHYSICAL_ALLOCATE_ZEROED, pages); + + if (!physicalAddress) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not allocate IO submission queue memory.\n"); + return; + } + + ioSubmissionQueue = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), physicalAddress, bytes, ES_FLAGS_DEFAULT); + + if (!ioSubmissionQueue) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not map IO submission queue memory.\n"); + return; + } + + uint32_t command[16] = {}; + command[0] = 0x01; // Create IO submission queue opcode. + command[6] = physicalAddress & 0xFFFFFFFF; + command[7] = (physicalAddress >> 32) & 0xFFFFFFFF; + command[10] = 1 /* identifier */ | ((IO_QUEUE_ENTRY_COUNT - 1) << 16); + command[11] = (1 << 0) /* physically contiguous */ | (1 << 16) /* completion queue identifier */; + + if (!IssueAdminCommand(command, nullptr)) { + KernelLog(LOG_ERROR, "NVMe", "create queue failure", "Could not create the IO submission queue.\n"); + return; + } + } + + // Allocate physical memory for PRP lists. + + { + for (uintptr_t i = 0; i < IO_QUEUE_ENTRY_COUNT; i++) { + prpListPages[i] = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_CAN_FAIL | MM_PHYSICAL_ALLOCATE_COMMIT_NOW, 1); + + if (!prpListPages[i]) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not allocate physical memory for PRP lists.\n"); + return; + } + } + + prpListVirtual = (uint64_t *) MMMapPhysical(MMGetKernelSpace(), prpListPages[0], K_PAGE_SIZE, ES_FLAGS_DEFAULT); + + if (!prpListVirtual) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not allocate virtual memory to modify PRP lists.\n"); + return; + } + } + + // Identify active namespace IDs. + + uint32_t nsid = 0; + + while (true) { + uint32_t command[16] = {}; + command[0] = 0x06; // Identify opcode. + command[1] = nsid; // List NSIDs greater than the last one we saw. + command[6] = identifyDataPhysicalAddress & 0xFFFFFFFF; + command[7] = (identifyDataPhysicalAddress >> 32) & 0xFFFFFFFF; + command[10] = 0x02; // Identify active namespace IDs. + + if (!IssueAdminCommand(command, nullptr)) { + KernelLog(LOG_ERROR, "NVMe", "identify controller failure", "The identify controller admin command failed.\n"); + return; + } + + for (uintptr_t i = 0; i < 1024; i++) { + nsid = ((uint32_t *) identifyData)[i]; + + if (!nsid) { + goto allNamespacesIdentified; + } + + KernelLog(LOG_INFO, "NVMe", "active namespace ID", "Namespace ID %d is active.\n", nsid); + + // Identify the namespace. + + command[0] = 0x06; // Identify opcode. + command[1] = nsid; + command[6] = (identifyDataPhysicalAddress + 4096) & 0xFFFFFFFF; + command[7] = ((identifyDataPhysicalAddress + 4096) >> 32) & 0xFFFFFFFF; + command[10] = 0x00; // Identify namespace. + + if (!IssueAdminCommand(command, nullptr)) { + KernelLog(LOG_ERROR, "NVMe", "identify namespace failure", "Could not identify namespace %d.\n", nsid); + continue; + } + + uint8_t formattedLBASize = identifyData[4096 + 26]; + uint32_t lbaFormat = *(uint32_t *) (identifyData + 4096 + 128 + 4 * (formattedLBASize & 0xF)); + + if (lbaFormat & 0xFFFF) { + KernelLog(LOG_ERROR, "NVMe", "metadata unsupported", "Namespace %d has %D of metadata per block, which is unsupported.\n", + nsid, lbaFormat & 0xFFFF); + continue; + } + + uint8_t sectorBytesExponent = (lbaFormat >> 16) & 0xFF; + + if (sectorBytesExponent < 9 || sectorBytesExponent > 16) { + KernelLog(LOG_ERROR, "NVMe", "unsupported block size", "Namespace %d uses blocks of size 2^%d bytes, which is unsupported.\n", + nsid, sectorBytesExponent); + continue; + } + + uint64_t sectorBytes = 1 << sectorBytesExponent; + uint64_t capacity = *(uint64_t *) (identifyData + 4096 + 8) * sectorBytes; + + bool readOnly = identifyData[99] & (1 << 0); + + KernelLog(LOG_INFO, "NVMe", "namespace identified", "Identifier namespace %d with sectors of size %D, and a capacity of %D.%z\n", + nsid, sectorBytes, capacity, readOnly ? " The namespace is read-only." : ""); + + NVMeDrive *device = (NVMeDrive *) KDeviceCreate("NVMe namespace", this, sizeof(NVMeDrive)); + + if (!device) { + KernelLog(LOG_ERROR, "NVMe", "allocation failure", "Could not create device for namespace %d.\n", nsid); + goto allNamespacesIdentified; + } + + device->controller = this; + device->nsid = nsid; + + device->sectorSize = sectorBytes; + device->sectorCount = capacity / sectorBytes; + device->maxAccessSectorCount = maximumDataTransferBytes / sectorBytes; + device->readOnly = readOnly; + device->driveType = ES_DRIVE_TYPE_SSD; + + device->access = [] (KBlockDeviceAccessRequest request) { + NVMeDrive *drive = (NVMeDrive *) request.device; + + request.dispatchGroup->Start(); + + if (!drive->controller->Access(drive, request.offset, request.count, request.operation, + request.buffer, request.flags, request.dispatchGroup)) { + request.dispatchGroup->End(false); + } + }; + + FSRegisterBlockDevice(device); + } + } + + allNamespacesIdentified:; +} + +void NVMeController::Shutdown() { + // Delete the IO queues. + + uint32_t command[16] = {}; + command[0] = 0x00; // Delete IO submission queue opcode. + command[10] = 1 /* identifier */; + IssueAdminCommand(command, nullptr); + command[0] = 0x04; // Delete IO completion queue opcode. + IssueAdminCommand(command, nullptr); + + // Inform the controller of shutdown. + + WR_REGISTER_CC(RD_REGISTER_CC() | (1 << 14)); + + // Wait for shutdown processing to complete. + + KTimeout timeout(rtd3EntryLatencyUs / 1000 + 1); + while (!timeout.Hit() && (RD_REGISTER_CSTS() & 12) != 8); +} + +static void DeviceAttach(KDevice *_parent) { + KPCIDevice *parent = (KPCIDevice *) _parent; + + NVMeController *device = (NVMeController *) KDeviceCreate("NVMe controller", parent, sizeof(NVMeController)); + if (!device) return; + device->pci = parent; + + device->shutdown = [] (KDevice *device) { + ((NVMeController *) device)->Shutdown(); + }; + + device->dumpState = [] (KDevice *device) { + ((NVMeController *) device)->DumpState(); + }; + + KernelLog(LOG_INFO, "NVMe", "found controller", "Found NVMe controller at PCI function %d/%d/%d.\n", parent->bus, parent->slot, parent->function); + + // Enable PCI features. + parent->EnableFeatures(K_PCI_FEATURE_INTERRUPTS + | K_PCI_FEATURE_BUSMASTERING_DMA + | K_PCI_FEATURE_MEMORY_SPACE_ACCESS + | K_PCI_FEATURE_BAR_0); + + // Initialise the controller. + device->Initialise(); +}; + +KDriver driverNVMe = { + .attach = DeviceAttach, +}; diff --git a/drivers/pci.cpp b/drivers/pci.cpp new file mode 100644 index 0000000..25a4b44 --- /dev/null +++ b/drivers/pci.cpp @@ -0,0 +1,554 @@ +// TODO Warn on Read/WriteBAR if port IO/memory space access is disabled in the command register. + +#include + +#define PCI_CONFIG (0xCF8) +#define PCI_DATA (0xCFC) + +struct PCIController : KDevice { + inline uint32_t ReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size = 32); + inline void WriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size = 32); + +#define PCI_BUS_DO_NOT_SCAN 0 +#define PCI_BUS_SCAN_NEXT 1 +#define PCI_BUS_SCANNED 2 + uint8_t busScanStates[256]; + + bool foundUSBController; + + void Enumerate(); + void EnumerateFunction(int bus, int device, int function, int *busesToScan); +}; + +const char *classCodeStrings[] = { + "Unknown", + "Mass storage controller", + "Network controller", + "Display controller", + "Multimedia controller", + "Memory controller", + "Bridge controller", + "Simple communication controller", + "Base system peripheral", + "Input device controller", + "Docking station", + "Processor", + "Serial bus controller", + "Wireless controller", + "Intelligent controller", + "Satellite communication controller", + "Encryption controller", + "Signal processing controller", +}; + +const char *subclassCodeStrings1[] = { + "SCSI bus controller", + "IDE controller", + "Floppy disk controller", + "IPI bus controller", + "RAID controller", + "ATA controller", + "Serial ATA", + "Serial attached SCSI", + "Non-volatile memory controller", +}; + +const char *subclassCodeStrings12[] = { + "FireWire (IEEE 1394) controller", + "ACCESS bus", + "SSA", + "USB controller", + "Fibre channel", + "SMBus", + "InfiniBand", + "IPMI interface", + "SERCOS interface (IEC 61491)", + "CANbus", +}; + +const char *progIFStrings12_3[] = { + "UHCI", + "OHCI", + "EHCI", + "XHCI", +}; + +uint8_t KPCIDevice::ReadBAR8(uintptr_t index, uintptr_t offset) { + uint32_t baseAddress = baseAddresses[index]; + uint8_t result; + + if (baseAddress & 1) { + result = ProcessorIn8((baseAddress & ~3) + offset); + } else { + result = *(volatile uint8_t *) (baseAddressesVirtual[index] + offset); + } + + KernelLog(LOG_VERBOSE, "PCI", "read BAR", "ReadBAR8 - %x, %x, %x, %x\n", this, index, offset, result); + return result; +} + +void KPCIDevice::WriteBAR8(uintptr_t index, uintptr_t offset, uint8_t value) { + uint32_t baseAddress = baseAddresses[index]; + KernelLog(LOG_VERBOSE, "PCI", "write BAR", "WriteBAR8 - %x, %x, %x, %x\n", this, index, offset, value); + + if (baseAddress & 1) { + ProcessorOut8((baseAddress & ~3) + offset, value); + } else { + *(volatile uint8_t *) (baseAddressesVirtual[index] + offset) = value; + } +} + +uint16_t KPCIDevice::ReadBAR16(uintptr_t index, uintptr_t offset) { + uint32_t baseAddress = baseAddresses[index]; + uint16_t result; + + if (baseAddress & 1) { + result = ProcessorIn16((baseAddress & ~3) + offset); + } else { + result = *(volatile uint16_t *) (baseAddressesVirtual[index] + offset); + } + + KernelLog(LOG_VERBOSE, "PCI", "read BAR", "ReadBAR16 - %x, %x, %x, %x\n", this, index, offset, result); + return result; +} + +void KPCIDevice::WriteBAR16(uintptr_t index, uintptr_t offset, uint16_t value) { + uint32_t baseAddress = baseAddresses[index]; + KernelLog(LOG_VERBOSE, "PCI", "write BAR", "WriteBAR16 - %x, %x, %x, %x\n", this, index, offset, value); + + if (baseAddress & 1) { + ProcessorOut16((baseAddress & ~3) + offset, value); + } else { + *(volatile uint16_t *) (baseAddressesVirtual[index] + offset) = value; + } +} + +uint32_t KPCIDevice::ReadBAR32(uintptr_t index, uintptr_t offset) { + uint32_t baseAddress = baseAddresses[index]; + uint32_t result; + + if (baseAddress & 1) { + result = ProcessorIn32((baseAddress & ~3) + offset); + } else { + result = *(volatile uint32_t *) (baseAddressesVirtual[index] + offset); + } + + KernelLog(LOG_VERBOSE, "PCI", "read BAR", "ReadBAR32 - %x, %x, %x, %x\n", this, index, offset, result); + return result; +} + +void KPCIDevice::WriteBAR32(uintptr_t index, uintptr_t offset, uint32_t value) { + uint32_t baseAddress = baseAddresses[index]; + KernelLog(LOG_VERBOSE, "PCI", "write BAR", "WriteBAR32 - %x, %x, %x, %x\n", this, index, offset, value); + + if (baseAddress & 1) { + ProcessorOut32((baseAddress & ~3) + offset, value); + } else { + *(volatile uint32_t *) (baseAddressesVirtual[index] + offset) = value; + } +} + +uint64_t KPCIDevice::ReadBAR64(uintptr_t index, uintptr_t offset) { + uint32_t baseAddress = baseAddresses[index]; + uint64_t result; + + if (baseAddress & 1) { + result = (uint64_t) ReadBAR32(index, offset) | ((uint64_t) ReadBAR32(index, offset + 4) << 32); + } else { + result = *(volatile uint64_t *) (baseAddressesVirtual[index] + offset); + } + + KernelLog(LOG_VERBOSE, "PCI", "read BAR", "ReadBAR64 - %x, %x, %x, %x\n", this, index, offset, result); + return result; +} + +void KPCIDevice::WriteBAR64(uintptr_t index, uintptr_t offset, uint64_t value) { + uint32_t baseAddress = baseAddresses[index]; + KernelLog(LOG_VERBOSE, "PCI", "write BAR", "WriteBAR64 - %x, %x, %x, %x\n", this, index, offset, value); + + if (baseAddress & 1) { + WriteBAR32(index, offset, value & 0xFFFFFFFF); + WriteBAR32(index, offset + 4, (value >> 32) & 0xFFFFFFFF); + } else { + *(volatile uint64_t *) (baseAddressesVirtual[index] + offset) = value; + } +} + +// Spinlock since some drivers need to access it in IRQs (e.g. ACPICA). +// Also can't be part of PCIController since PCI is initialised after ACPICA. +static KSpinlock configSpaceSpinlock; + +static PCIController *pci; + +uint32_t KPCIReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size) { + return pci->ReadConfig(bus, device, function, offset, size); +} + +void KPCIWriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size) { + pci->WriteConfig(bus, device, function, offset, value, size); +} + +uint32_t PCIController::ReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size) { + KSpinlockAcquire(&configSpaceSpinlock); + EsDefer(KSpinlockRelease(&configSpaceSpinlock)); + if (offset & 3) KernelPanic("PCIController::ReadConfig - offset is not 4-byte aligned."); + ProcessorOut32(PCI_CONFIG, (uint32_t) (0x80000000 | (bus << 16) | (device << 11) | (function << 8) | offset)); + if (size == 8) return ProcessorIn8(PCI_DATA); + if (size == 16) return ProcessorIn16(PCI_DATA); + if (size == 32) return ProcessorIn32(PCI_DATA); + KernelPanic("PCIController::ReadConfig - Invalid size %d.\n", size); + return 0; +} + +void PCIController::WriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size) { + KSpinlockAcquire(&configSpaceSpinlock); + EsDefer(KSpinlockRelease(&configSpaceSpinlock)); + if (offset & 3) KernelPanic("PCIController::WriteConfig - offset is not 4-byte aligned."); + ProcessorOut32(PCI_CONFIG, (uint32_t) (0x80000000 | (bus << 16) | (device << 11) | (function << 8) | offset)); + if (size == 8) ProcessorOut8(PCI_DATA, value); + else if (size == 16) ProcessorOut16(PCI_DATA, value); + else if (size == 32) ProcessorOut32(PCI_DATA, value); + else KernelPanic("PCIController::WriteConfig - Invalid size %d.\n", size); +} + +void KPCIDevice::WriteConfig8(uintptr_t offset, uint8_t value) { + pci->WriteConfig(bus, slot, function, offset, value, 8); +} + +uint8_t KPCIDevice::ReadConfig8(uintptr_t offset) { + return pci->ReadConfig(bus, slot, function, offset, 8); +} + +void KPCIDevice::WriteConfig16(uintptr_t offset, uint16_t value) { + pci->WriteConfig(bus, slot, function, offset, value, 16); +} + +uint16_t KPCIDevice::ReadConfig16(uintptr_t offset) { + return pci->ReadConfig(bus, slot, function, offset, 16); +} + +void KPCIDevice::WriteConfig32(uintptr_t offset, uint32_t value) { + pci->WriteConfig(bus, slot, function, offset, value, 32); +} + +uint32_t KPCIDevice::ReadConfig32(uintptr_t offset) { + return pci->ReadConfig(bus, slot, function, offset, 32); +} + +bool KPCIDevice::EnableSingleInterrupt(KIRQHandler irqHandler, void *context, const char *cOwnerName) { + if (EnableMSI(irqHandler, context, cOwnerName)) { + return true; + } + + EnableFeatures(K_PCI_FEATURE_INTERRUPTS); + + if (KRegisterIRQ(interruptLine, irqHandler, context, cOwnerName)) { + return true; + } + + return false; +} + +bool KPCIDevice::EnableMSI(KIRQHandler irqHandler, void *context, const char *cOwnerName) { + // Find the MSI capability. + + uint16_t status = ReadConfig32(0x04) >> 16; + + if (~status & (1 << 4)) { + KernelLog(LOG_ERROR, "PCI", "no MSI support", "Device does not support MSI.\n"); + return false; + } + + uint8_t pointer = ReadConfig8(0x34); + uintptr_t index = 0; + + while (pointer && index++ < 0xFF) { + uint32_t dw = ReadConfig32(pointer); + uint8_t nextPointer = (dw >> 8) & 0xFF; + uint8_t id = dw & 0xFF; + + if (id != 5) { + pointer = nextPointer; + continue; + } + + KMSIInformation msi = KRegisterMSI(irqHandler, context, cOwnerName); + + if (!msi.address) { + KernelLog(LOG_ERROR, "PCI", "register MSI failure", "Could not register MSI.\n"); + return false; + } + + uint16_t control = (dw >> 16) & 0xFFFF; + + if (msi.data & ~0xFFFF) { + KUnregisterMSI(msi.tag); + KernelLog(LOG_ERROR, "PCI", "unsupported MSI data", "PCI only supports 16 bits of MSI data. Requested: %x.\n", msi.data); + return false; + } + + if (msi.address & 3) { + KUnregisterMSI(msi.tag); + KernelLog(LOG_ERROR, "PCI", "unsupported MSI address", "PCI requires DWORD alignment of MSI address. Requested: %x.\n", msi.address); + return false; + } + +#ifdef ARCH_64 + if ((msi.address & 0xFFFFFFFF00000000) && (~control & (1 << 7))) { + KUnregisterMSI(msi.tag); + KernelLog(LOG_ERROR, "PCI", "unsupported MSI address", "MSI does not support 64-bit addresses. Requested: %x.\n", msi.address); + return false; + } +#endif + + control = (control & ~(7 << 4) /* don't allow modifying data */) + | (1 << 0 /* enable MSI */); + dw = (dw & 0x0000FFFF) | (control << 16); + + WriteConfig32(pointer + 0, dw); + WriteConfig32(pointer + 4, msi.address & 0xFFFFFFFF); + + if (control & (1 << 7)) { + WriteConfig32(pointer + 8, msi.address >> 32); + WriteConfig16(pointer + 12, (ReadConfig16(pointer + 12) & 0x3800) | msi.data); + if (control & (1 << 8)) WriteConfig32(pointer + 16, 0); + } else { + WriteConfig16(pointer + 8, msi.data); + if (control & (1 << 8)) WriteConfig32(pointer + 12, 0); + } + + return true; + } + + KernelLog(LOG_ERROR, "PCI", "no MSI support", "Device does not support MSI (2).\n"); + return false; +} + +bool KPCIDevice::EnableFeatures(uint64_t features) { + uint32_t config = ReadConfig32(4); + if (features & K_PCI_FEATURE_INTERRUPTS) config &= ~(1 << 10); + if (features & K_PCI_FEATURE_BUSMASTERING_DMA) config |= 1 << 2; + if (features & K_PCI_FEATURE_MEMORY_SPACE_ACCESS) config |= 1 << 1; + if (features & K_PCI_FEATURE_IO_PORT_ACCESS) config |= 1 << 0; + WriteConfig32(4, config); + + if (ReadConfig32(4) != config) { + KernelLog(LOG_ERROR, "PCI", "configuration update", "Could not update the configuration for device %x.\n", this); + return false; + } + + for (int i = 0; i < 6; i++) { + if (~features & (1 << i)) { + continue; + } + + if (baseAddresses[i] & 1) { + continue; // The BAR is an IO port. + } + + bool size64 = baseAddresses[i] & 4; + + if (!(baseAddresses[i] & 8)) { + // TODO Not prefetchable. + } + + uint64_t address, size; + + if (size64) { + WriteConfig32(0x10 + 4 * i, 0xFFFFFFFF); + WriteConfig32(0x10 + 4 * (i + 1), 0xFFFFFFFF); + size = ReadConfig32(0x10 + 4 * i); + size |= (uint64_t) ReadConfig32(0x10 + 4 * (i + 1)) << 32; + WriteConfig32(0x10 + 4 * i, baseAddresses[i]); + WriteConfig32(0x10 + 4 * (i + 1), baseAddresses[i + 1]); + address = baseAddresses[i]; + address |= (uint64_t) baseAddresses[i + 1] << 32; + } else { + WriteConfig32(0x10 + 4 * i, 0xFFFFFFFF); + size = ReadConfig32(0x10 + 4 * i); + size |= (uint64_t) 0xFFFFFFFF << 32; + WriteConfig32(0x10 + 4 * i, baseAddresses[i]); + address = baseAddresses[i]; + } + + if (!size || !address) { + KernelLog(LOG_ERROR, "PCI", "enable device BAR", "Could not enable BAR %d for device %x.\n", i, this); + return false; + } + + size &= ~15; + size = ~size + 1; + address &= ~15; + + // TODO Do we sometimes have to allocate the physical address ourselves..? + + // If the driver wants to allow WC caching later, it can, with MMAllowWriteCombiningCaching. + baseAddressesVirtual[i] = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), address, size, MM_REGION_NOT_CACHEABLE); + baseAddressesPhysical[i] = address; + baseAddressesSizes[i] = size; + + MMCheckUnusable(address, size); + + KernelLog(LOG_INFO, "PCI", "enable device BAR", "BAR %d has address %x and size %x, mapped to %x.\n", + i, address, size, baseAddressesVirtual[i]); + } + + return true; +} + +bool EnumeratePCIDrivers(KInstalledDriver *driver, KDevice *_device) { + KPCIDevice *device = (KPCIDevice *) _device; + + int classCode = -1, subclassCode = -1, progIF = -1; + bool foundAnyDeviceIDs = false, foundMatchingDeviceID = false; + + EsINIState s = {}; + s.buffer = driver->config, s.bytes = driver->configBytes; + + while (EsINIParse(&s)) { + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("classCode"))) classCode = EsIntegerParse(s.value, s.valueBytes); + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("subclassCode"))) subclassCode = EsIntegerParse(s.value, s.valueBytes); + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("progIF"))) progIF = EsIntegerParse(s.value, s.valueBytes); + + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("deviceID"))) { + foundAnyDeviceIDs = true; + + if (device->deviceID == EsIntegerParse(s.value, s.valueBytes)) { + foundMatchingDeviceID = true; + } + } + } + + if (classCode != -1 && device->classCode != classCode) return false; + if (subclassCode != -1 && device->subclassCode != subclassCode) return false; + if (progIF != -1 && device->progIF != progIF) return false; + + return !foundAnyDeviceIDs || foundMatchingDeviceID; +} + +void PCIController::EnumerateFunction(int bus, int device, int function, int *busesToScan) { + uint32_t deviceID = ReadConfig(bus, device, function, 0x00); + if ((deviceID & 0xFFFF) == 0xFFFF) return; + + uint32_t deviceClass = ReadConfig(bus, device, function, 0x08); + uint32_t interruptInformation = ReadConfig(bus, device, function, 0x3C); + + KPCIDevice *pciDevice = (KPCIDevice *) KDeviceCreate("PCI function", this, sizeof(KPCIDevice)); + if (!pciDevice) return; + + pciDevice->classCode = (deviceClass >> 24) & 0xFF; + pciDevice->subclassCode = (deviceClass >> 16) & 0xFF; + pciDevice->progIF = (deviceClass >> 8) & 0xFF; + + pciDevice->bus = bus; + pciDevice->slot = device; + pciDevice->function = function; + + pciDevice->interruptPin = (interruptInformation >> 8) & 0xFF; + pciDevice->interruptLine = (interruptInformation >> 0) & 0xFF; + + pciDevice->deviceID = ReadConfig(bus, device, function, 0); + pciDevice->subsystemID = ReadConfig(bus, device, function, 0x2C); + + for (int i = 0; i < 6; i++) { + pciDevice->baseAddresses[i] = pciDevice->ReadConfig32(0x10 + 4 * i); + } + + const char *classCodeString = pciDevice->classCode < sizeof(classCodeStrings) / sizeof(classCodeStrings[0]) + ? classCodeStrings[pciDevice->classCode] : "Unknown"; + const char *subclassCodeString = + pciDevice->classCode == 1 && pciDevice->subclassCode < sizeof(subclassCodeStrings1) / sizeof(const char *) + ? subclassCodeStrings1 [pciDevice->subclassCode] + : pciDevice->classCode == 12 && pciDevice->subclassCode < sizeof(subclassCodeStrings12) / sizeof(const char *) + ? subclassCodeStrings12[pciDevice->subclassCode] : ""; + const char *progIFString = + pciDevice->classCode == 12 && pciDevice->subclassCode == 3 && pciDevice->progIF / 0x10 < sizeof(progIFStrings12_3) / sizeof(const char *) + ? progIFStrings12_3[pciDevice->progIF / 0x10] : ""; + + KernelLog(LOG_INFO, "PCI", "enumerate device", + "Found PCI device at %d/%d/%d with ID %x. Class code: %X '%z'. Subclass code: %X '%z'. Prog IF: %X '%z'. Interrupt pin: %d. Interrupt line: %d.\n", + bus, device, function, deviceID, + pciDevice->classCode, classCodeString, pciDevice->subclassCode, subclassCodeString, pciDevice->progIF, progIFString, + pciDevice->interruptPin, pciDevice->interruptLine); + + if (pciDevice->classCode == 0x06 && pciDevice->subclassCode == 0x04 /* PCI bridge */) { + uint8_t secondaryBus = (ReadConfig(bus, device, function, 0x18) >> 8) & 0xFF; + + if (busScanStates[secondaryBus] == PCI_BUS_DO_NOT_SCAN) { + KernelLog(LOG_INFO, "PCI", "PCI bridge", "PCI bridge to bus %d.\n", secondaryBus); + *busesToScan = *busesToScan + 1; + busScanStates[secondaryBus] = PCI_BUS_SCAN_NEXT; + } + } + + bool foundDriver = KDeviceAttach(pciDevice, "PCI", EnumeratePCIDrivers); + + if (foundDriver && pciDevice->classCode == 12 && pciDevice->subclassCode == 3) { + // The USB controller is responsible for disabling PS/2 emulation, and calling KPS2SafeToInitialise. + KernelLog(LOG_INFO, "PCI", "found USB", "Found USB controller.\n"); + foundUSBController = true; + } +} + +void PCIController::Enumerate() { + uint32_t baseHeaderType = ReadConfig(0, 0, 0, 0x0C); + int baseBuses = (baseHeaderType & 0x80) ? 8 : 1; + + int busesToScan = 0; + + for (int baseBus = 0; baseBus < baseBuses; baseBus++) { + uint32_t deviceID = ReadConfig(0, 0, baseBus, 0x00); + if ((deviceID & 0xFFFF) == 0xFFFF) continue; + busScanStates[baseBus] = PCI_BUS_SCAN_NEXT; + busesToScan++; + } + + if (!busesToScan) { + KernelPanic("PCIController::Enumerate - No buses found\n"); + } + + while (busesToScan) { + for (int bus = 0; bus < 256; bus++) { + if (busScanStates[bus] != PCI_BUS_SCAN_NEXT) continue; + + KernelLog(LOG_INFO, "PCI", "scan bus", "Scanning bus %d...\n", bus); + + busScanStates[bus] = PCI_BUS_SCANNED; + busesToScan--; + + for (int device = 0; device < 32; device++) { + uint32_t deviceID = ReadConfig(bus, device, 0, 0x00); + if ((deviceID & 0xFFFF) == 0xFFFF) continue; + + uint32_t headerType = (ReadConfig(bus, device, 0, 0x0C) >> 16) & 0xFF; + int functions = (headerType & 0x80) ? 8 : 1; + + for (int function = 0; function < functions; function++) { + EnumerateFunction(bus, device, function, &busesToScan); + } + } + } + } +} + +static void DeviceAttach(KDevice *parent) { + if (pci) { + KernelLog(LOG_ERROR, "PCI", "multiple PCI controllers", "EntryPCI - Attempt to register multiple PCI controllers; ignored.\n"); + return; + } + + pci = (PCIController *) KDeviceCreate("PCI controller", parent, sizeof(PCIController)); + + if (pci) { + pci->Enumerate(); + + if (!pci->foundUSBController) { + KernelLog(LOG_INFO, "PCI", "no USB", "No USB controller found; initialising PS/2...\n"); + KPS2SafeToInitialise(); + } + } +} + +KDriver driverPCI = { + .attach = DeviceAttach, +}; diff --git a/drivers/ps2.cpp b/drivers/ps2.cpp new file mode 100644 index 0000000..cad7ffc --- /dev/null +++ b/drivers/ps2.cpp @@ -0,0 +1,566 @@ +// TODO Scrolling. + +#include + +struct PS2Update { + union { + struct { + volatile int xMovement, yMovement; + volatile unsigned buttons; + }; + + struct { + volatile unsigned scancode; + }; + }; +}; + +struct PS2 { + void Initialise(KDevice *parentDevice); + void EnableDevices(unsigned which); + void DisableDevices(unsigned which); + void FlushOutputBuffer(); + void SendCommand(uint8_t command); + uint8_t ReadByte(KTimeout *timeout); + void WriteByte(KTimeout *timeout, uint8_t value); + bool SetupKeyboard(KTimeout *timeout); + bool SetupMouse(KTimeout *timeout); + bool PollRead(uint8_t *value, bool forMouse); + void WaitInputBuffer(); + + uint8_t mouseType, scancodeSet; + size_t channels; + bool registeredIRQs; + bool initialised; + + volatile uintptr_t lastUpdatesIndex; + PS2Update lastUpdates[16]; + KSpinlock lastUpdatesLock; + KMutex mutex; +}; + +PS2 ps2; + +uint16_t scancodeConversionTable1[] = { + 0, ES_SCANCODE_ESCAPE, ES_SCANCODE_1, ES_SCANCODE_2, ES_SCANCODE_3, ES_SCANCODE_4, ES_SCANCODE_5, ES_SCANCODE_6, + ES_SCANCODE_7, ES_SCANCODE_8, ES_SCANCODE_9, ES_SCANCODE_0, ES_SCANCODE_HYPHEN, ES_SCANCODE_EQUALS, ES_SCANCODE_BACKSPACE, ES_SCANCODE_TAB, + ES_SCANCODE_Q, ES_SCANCODE_W, ES_SCANCODE_E, ES_SCANCODE_R, ES_SCANCODE_T, ES_SCANCODE_Y, ES_SCANCODE_U, ES_SCANCODE_I, + ES_SCANCODE_O, ES_SCANCODE_P, ES_SCANCODE_LEFT_BRACE, ES_SCANCODE_RIGHT_BRACE, ES_SCANCODE_ENTER, ES_SCANCODE_LEFT_CTRL, ES_SCANCODE_A, ES_SCANCODE_S, + ES_SCANCODE_D, ES_SCANCODE_F, ES_SCANCODE_G, ES_SCANCODE_H, ES_SCANCODE_J, ES_SCANCODE_K, ES_SCANCODE_L, ES_SCANCODE_PUNCTUATION_3, + ES_SCANCODE_PUNCTUATION_4, ES_SCANCODE_PUNCTUATION_5, ES_SCANCODE_LEFT_SHIFT, ES_SCANCODE_PUNCTUATION_1, ES_SCANCODE_Z, ES_SCANCODE_X, ES_SCANCODE_C, ES_SCANCODE_V, + ES_SCANCODE_B, ES_SCANCODE_N, ES_SCANCODE_M, ES_SCANCODE_COMMA, ES_SCANCODE_PERIOD, ES_SCANCODE_SLASH, ES_SCANCODE_RIGHT_SHIFT, ES_SCANCODE_NUM_MULTIPLY, + ES_SCANCODE_LEFT_ALT, ES_SCANCODE_SPACE, ES_SCANCODE_CAPS_LOCK, ES_SCANCODE_F1, ES_SCANCODE_F2, ES_SCANCODE_F3, ES_SCANCODE_F4, ES_SCANCODE_F5, + ES_SCANCODE_F6, ES_SCANCODE_F7, ES_SCANCODE_F8, ES_SCANCODE_F9, ES_SCANCODE_F10, ES_SCANCODE_NUM_LOCK, ES_SCANCODE_SCROLL_LOCK, ES_SCANCODE_NUM_7, + ES_SCANCODE_NUM_8, ES_SCANCODE_NUM_9, ES_SCANCODE_NUM_SUBTRACT, ES_SCANCODE_NUM_4, ES_SCANCODE_NUM_5, ES_SCANCODE_NUM_6, ES_SCANCODE_NUM_ADD, ES_SCANCODE_NUM_1, + ES_SCANCODE_NUM_2, ES_SCANCODE_NUM_3, ES_SCANCODE_NUM_0, ES_SCANCODE_NUM_POINT, 0, 0, 0, ES_SCANCODE_F11, + ES_SCANCODE_F12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + ES_SCANCODE_MM_PREVIOUS, 0, 0, 0, 0, 0, 0, 0, + 0, ES_SCANCODE_MM_NEXT, 0, 0, ES_SCANCODE_NUM_ENTER, ES_SCANCODE_RIGHT_CTRL, 0, 0, + ES_SCANCODE_MM_MUTE, ES_SCANCODE_MM_CALC, ES_SCANCODE_MM_PAUSE, 0, ES_SCANCODE_MM_STOP, 0, 0, 0, + 0, 0, ES_SCANCODE_MM_QUIETER, 0, 0, 0, 0, 0, + ES_SCANCODE_MM_LOUDER, 0, ES_SCANCODE_WWW_HOME, 0, 0, ES_SCANCODE_NUM_DIVIDE, 0, 0, + ES_SCANCODE_RIGHT_ALT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, ES_SCANCODE_HOME, + ES_SCANCODE_UP_ARROW, ES_SCANCODE_PAGE_UP, 0, ES_SCANCODE_LEFT_ARROW, 0, ES_SCANCODE_RIGHT_ARROW, 0, ES_SCANCODE_END, + ES_SCANCODE_DOWN_ARROW, ES_SCANCODE_PAGE_DOWN, ES_SCANCODE_INSERT, ES_SCANCODE_DELETE, 0, 0, 0, 0, + 0, 0, 0, ES_SCANCODE_LEFT_FLAG, ES_SCANCODE_RIGHT_FLAG, ES_SCANCODE_CONTEXT_MENU, ES_SCANCODE_ACPI_POWER, ES_SCANCODE_ACPI_SLEEP, + 0, 0, 0, ES_SCANCODE_ACPI_WAKE, 0, ES_SCANCODE_WWW_SEARCH, ES_SCANCODE_WWW_STARRED, ES_SCANCODE_WWW_REFRESH, + ES_SCANCODE_WWW_STOP, ES_SCANCODE_WWW_FORWARD, ES_SCANCODE_WWW_BACK, ES_SCANCODE_MM_FILES, ES_SCANCODE_MM_EMAIL, ES_SCANCODE_MM_SELECT, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +uint16_t scancodeConversionTable2[] = { + 0, ES_SCANCODE_F9, 0, ES_SCANCODE_F5, ES_SCANCODE_F3, ES_SCANCODE_F1, ES_SCANCODE_F2, ES_SCANCODE_F12, + 0, ES_SCANCODE_F10, ES_SCANCODE_F8, ES_SCANCODE_F6, ES_SCANCODE_F4, ES_SCANCODE_TAB, ES_SCANCODE_PUNCTUATION_5, 0, + 0, ES_SCANCODE_LEFT_ALT, ES_SCANCODE_LEFT_SHIFT, 0, ES_SCANCODE_LEFT_CTRL, ES_SCANCODE_Q, ES_SCANCODE_1, 0, + 0, 0, ES_SCANCODE_Z, ES_SCANCODE_S, ES_SCANCODE_A, ES_SCANCODE_W, ES_SCANCODE_2, 0, + 0, ES_SCANCODE_C, ES_SCANCODE_X, ES_SCANCODE_D, ES_SCANCODE_E, ES_SCANCODE_4, ES_SCANCODE_3, 0, + 0, ES_SCANCODE_SPACE, ES_SCANCODE_V, ES_SCANCODE_F, ES_SCANCODE_T, ES_SCANCODE_R, ES_SCANCODE_5, 0, + 0, ES_SCANCODE_N, ES_SCANCODE_B, ES_SCANCODE_H, ES_SCANCODE_G, ES_SCANCODE_Y, ES_SCANCODE_6, 0, + 0, 0, ES_SCANCODE_M, ES_SCANCODE_J, ES_SCANCODE_U, ES_SCANCODE_7, ES_SCANCODE_8, 0, + 0, ES_SCANCODE_COMMA, ES_SCANCODE_K, ES_SCANCODE_I, ES_SCANCODE_O, ES_SCANCODE_0, ES_SCANCODE_9, 0, + 0, ES_SCANCODE_PERIOD, ES_SCANCODE_SLASH, ES_SCANCODE_L, ES_SCANCODE_PUNCTUATION_3, ES_SCANCODE_P, ES_SCANCODE_HYPHEN, 0, + 0, 0, ES_SCANCODE_PUNCTUATION_4, 0, ES_SCANCODE_LEFT_BRACE, ES_SCANCODE_EQUALS, 0, 0, + ES_SCANCODE_CAPS_LOCK, ES_SCANCODE_RIGHT_SHIFT, ES_SCANCODE_ENTER, ES_SCANCODE_RIGHT_BRACE, 0, ES_SCANCODE_PUNCTUATION_1, 0, 0, + 0, 0, 0, 0, 0, 0, ES_SCANCODE_BACKSPACE, 0, + 0, ES_SCANCODE_NUM_1, 0, ES_SCANCODE_NUM_4, ES_SCANCODE_NUM_7, 0, 0, 0, + ES_SCANCODE_NUM_0, ES_SCANCODE_NUM_POINT, ES_SCANCODE_NUM_2, ES_SCANCODE_NUM_5, ES_SCANCODE_NUM_6, ES_SCANCODE_NUM_8, ES_SCANCODE_ESCAPE, ES_SCANCODE_NUM_LOCK, + ES_SCANCODE_F11, ES_SCANCODE_NUM_ADD, ES_SCANCODE_NUM_3, ES_SCANCODE_NUM_SUBTRACT, ES_SCANCODE_NUM_MULTIPLY, ES_SCANCODE_NUM_9, ES_SCANCODE_SCROLL_LOCK, 0, + 0, 0, 0, ES_SCANCODE_F7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, ES_SCANCODE_PAUSE, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + ES_SCANCODE_WWW_SEARCH, ES_SCANCODE_RIGHT_ALT, ES_SCANCODE_PRINT_SCREEN, 0, ES_SCANCODE_RIGHT_CTRL, ES_SCANCODE_MM_PREVIOUS, 0, 0, + ES_SCANCODE_WWW_STARRED, 0, 0, 0, 0, 0, 0, ES_SCANCODE_LEFT_FLAG, + ES_SCANCODE_WWW_REFRESH, ES_SCANCODE_MM_QUIETER, 0, ES_SCANCODE_MM_MUTE, 0, 0, 0, ES_SCANCODE_CONTEXT_MENU, + ES_SCANCODE_WWW_STOP, 0, 0, ES_SCANCODE_MM_CALC, 0, 0, 0, 0, + ES_SCANCODE_WWW_FORWARD, 0, ES_SCANCODE_MM_LOUDER, 0, ES_SCANCODE_MM_PAUSE, 0, 0, ES_SCANCODE_ACPI_POWER, + ES_SCANCODE_WWW_BACK, 0, ES_SCANCODE_WWW_HOME, ES_SCANCODE_MM_STOP, 0, 0, 0, ES_SCANCODE_ACPI_SLEEP, + ES_SCANCODE_MM_FILES, 0, 0, 0, 0, 0, 0, 0, + ES_SCANCODE_MM_EMAIL, 0, ES_SCANCODE_NUM_DIVIDE, 0, 0, ES_SCANCODE_MM_NEXT, 0, 0, + ES_SCANCODE_MM_SELECT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, ES_SCANCODE_NUM_ENTER, 0, 0, 0, ES_SCANCODE_ACPI_WAKE, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, ES_SCANCODE_END, 0, ES_SCANCODE_LEFT_ARROW, ES_SCANCODE_HOME, 0, 0, 0, + ES_SCANCODE_INSERT, ES_SCANCODE_DELETE, ES_SCANCODE_DOWN_ARROW, 0, ES_SCANCODE_RIGHT_ARROW, ES_SCANCODE_UP_ARROW, 0, 0, + 0, 0, ES_SCANCODE_PAGE_DOWN, 0, 0, ES_SCANCODE_PAGE_UP, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +// Status register. +#define PS2_OUTPUT_FULL (1 << 0) +#define PS2_INPUT_FULL (1 << 1) +#define PS2_MOUSE_BYTE (1 << 5) + +// Mouse types. +#define PS2_MOUSE_NORMAL (0) +#define PS2_MOUSE_SCROLL (3) +#define PS2_MOUSE_5_BUTTON (4) + +// Controller commands. +#define PS2_DISABLE_FIRST (0xAD) +#define PS2_ENABLE_FIRST (0xAE) +#define PS2_TEST_FIRST (0xAB) +#define PS2_DISABLE_SECOND (0xA7) +#define PS2_ENABLE_SECOND (0xA8) +#define PS2_WRITE_SECOND (0xD4) +#define PS2_TEST_SECOND (0xA9) +#define PS2_TEST_CONTROLER (0xAA) +#define PS2_READ_CONFIG (0x20) +#define PS2_WRITE_CONFIG (0x60) + +// Controller configuration. +#define PS2_FIRST_IRQ_MASK (1 << 0) +#define PS2_SECOND_IRQ_MASK (1 << 1) +#define PS2_SECOND_CLOCK (1 << 5) +#define PS2_TRANSLATION (1 << 6) + +// IRQs. +#define PS2_FIRST_IRQ (1) +#define PS2_SECOND_IRQ (12) + +// Ports. +#define PS2_PORT_DATA (0x60) +#define PS2_PORT_STATUS (0x64) +#define PS2_PORT_COMMAND (0x64) + +// Keyboard commands. +#define PS2_KEYBOARD_RESET (0xFF) +#define PS2_KEYBOARD_ENABLE (0xF4) +#define PS2_KEYBOARD_DISABLE (0xF5) +#define PS2_KEYBOARD_REPEAT (0xF3) +#define PS2_KEYBOARD_SET_LEDS (0xED) +#define PS2_KEYBOARD_SCANCODE_SET (0xF0) + +// Mouse commands. +#define PS2_MOUSE_RESET (0xFF) +#define PS2_MOUSE_ENABLE (0xF4) +#define PS2_MOUSE_DISABLE (0xF5) +#define PS2_MOUSE_SAMPLE_RATE (0xF3) +#define PS2_MOUSE_READ (0xEB) +#define PS2_MOUSE_RESOLUTION (0xE8) + +void PS2MouseUpdated(EsGeneric _update) { + PS2Update *update = (PS2Update *) _update.p; + KCursorUpdate(update->xMovement, update->yMovement, update->buttons); +} + +void PS2KeyboardUpdated(EsGeneric _update) { + PS2Update *update = (PS2Update *) _update.p; + KernelLog(LOG_VERBOSE, "PS/2", "keyboard update", "Received scancode %x.\n", update->scancode); + KKeyPress(update->scancode); +} + +void PS2::WaitInputBuffer() { + while (ProcessorIn8(PS2_PORT_STATUS) & PS2_INPUT_FULL); +} + +bool PS2::PollRead(uint8_t *value, bool forMouse) { + uint8_t status = ProcessorIn8(PS2_PORT_STATUS); + if (status & PS2_MOUSE_BYTE && !forMouse) return false; + if (!(status & PS2_MOUSE_BYTE) && forMouse) return false; + + if (status & PS2_OUTPUT_FULL) { + *value = ProcessorIn8(PS2_PORT_DATA); + + if (*value == 0xE1 && !forMouse) { + KDebugKeyPressed(); + } + + EsRandomAddEntropy(*value); + return true; + } else { + return false; + } +} + +int PS2ReadKey() { + static uint8_t firstByte = 0, secondByte = 0, thirdByte = 0; + static size_t bytesFound = 0; + + if (bytesFound == 0) { + if (!ps2.PollRead(&firstByte, false)) return 0; + bytesFound++; + if (firstByte != 0xE0 && firstByte != 0xF0) { + goto sequenceFinished; + } else return 0; + } else if (bytesFound == 1) { + if (!ps2.PollRead(&secondByte, false)) return 0; + bytesFound++; + if (secondByte != 0xF0) { + goto sequenceFinished; + } else return 0; + } else if (bytesFound == 2) { + if (!ps2.PollRead(&thirdByte, false)) return 0; + bytesFound++; + goto sequenceFinished; + } + + sequenceFinished: + KernelLog(LOG_VERBOSE, "PS/2", "keyboard data", "Keyboard data: %X%X%X\n", firstByte, secondByte, thirdByte); + + int scancode = 0; + + if (ps2.scancodeSet == 1) { + if (firstByte == 0xE0) { + if (secondByte & 0x80) { + scancode = secondByte | K_SCANCODE_KEY_RELEASED; + } else { + scancode = secondByte | 0x80; + } + } else { + if (firstByte & 0x80) { + scancode = (firstByte & ~0x80) | K_SCANCODE_KEY_RELEASED; + } else { + scancode = firstByte; + } + } + } else if (ps2.scancodeSet == 2) { + if (firstByte == 0xE0) { + if (secondByte == 0xF0) { + scancode = K_SCANCODE_KEY_RELEASED | (1 << 8) | thirdByte; + } else { + scancode = K_SCANCODE_KEY_PRESSED | (1 << 8) | secondByte; + } + } else { + if (firstByte == 0xF0) { + scancode = K_SCANCODE_KEY_RELEASED | (0 << 8) | secondByte; + } else { + scancode = K_SCANCODE_KEY_PRESSED | (0 << 8) | firstByte; + } + } + } + + uint16_t *table = ps2.scancodeSet == 2 ? scancodeConversionTable2 : scancodeConversionTable1; + + firstByte = 0; + secondByte = 0; + thirdByte = 0; + bytesFound = 0; + + return (scancode & (1 << 15)) | table[scancode & ~(1 << 15)]; +} + +int KWaitKey() { + if (!ps2.channels) ProcessorHalt(); + int scancode; + while (!(scancode = PS2ReadKey())); + return scancode; +} + +bool PS2IRQHandler(uintptr_t interruptIndex, void *) { + if (!ps2.channels) return false; + if (ps2.channels == 1 && interruptIndex == 12) return false; + + if (interruptIndex == 12) { + static uint8_t firstByte = 0, secondByte = 0, thirdByte = 0; + static size_t bytesFound = 0; + + if (bytesFound == 0) { + if (!ps2.PollRead(&firstByte, true)) return false; + if (!(firstByte & 8)) return false; + bytesFound++; + return true; + } else if (bytesFound == 1) { + if (!ps2.PollRead(&secondByte, true)) return false; + bytesFound++; + return true; + } else if (bytesFound == 2) { + if (!ps2.PollRead(&thirdByte, true)) return false; + bytesFound++; + } + + KernelLog(LOG_VERBOSE, "PS/2", "mouse data", "Mouse data: %X%X%X\n", firstByte, secondByte, thirdByte); + + KSpinlockAcquire(&ps2.lastUpdatesLock); + PS2Update *update = ps2.lastUpdates + ps2.lastUpdatesIndex; + ps2.lastUpdatesIndex = (ps2.lastUpdatesIndex + 1) % 16; + KSpinlockRelease(&ps2.lastUpdatesLock); + + update->xMovement = secondByte - ((firstByte << 4) & 0x100); + update->yMovement = -(thirdByte - ((firstByte << 3) & 0x100)); + update->buttons = ((firstByte & (1 << 0)) ? K_LEFT_BUTTON : 0) + | ((firstByte & (1 << 1)) ? K_RIGHT_BUTTON : 0) + | ((firstByte & (1 << 2)) ? K_MIDDLE_BUTTON : 0); + + KRegisterAsyncTask(PS2MouseUpdated, update, false); + + firstByte = 0; + secondByte = 0; + thirdByte = 0; + bytesFound = 0; + } else if (interruptIndex == 1) { + KernelLog(LOG_VERBOSE, "PS/2", "keyboard IRQ", "Received keyboard IRQ.\n"); + + int scancode = PS2ReadKey(); + + if (scancode) { + KSpinlockAcquire(&ps2.lastUpdatesLock); + PS2Update *update = ps2.lastUpdates + ps2.lastUpdatesIndex; + ps2.lastUpdatesIndex = (ps2.lastUpdatesIndex + 1) % 16; + KSpinlockRelease(&ps2.lastUpdatesLock); + update->scancode = scancode; + KRegisterAsyncTask(PS2KeyboardUpdated, update, false); + } + } else { + KernelPanic("PS2IRQHandler - Incorrect interrupt index.\n", interruptIndex); + } + + return true; +} + +void PS2::DisableDevices(unsigned which) { + WaitInputBuffer(); + // EsPrint("ps2 first write...\n"); + if (which & 1) ProcessorOut8(PS2_PORT_COMMAND, PS2_DISABLE_FIRST); + // EsPrint("ps2 first write end\n"); + WaitInputBuffer(); + if (which & 2) ProcessorOut8(PS2_PORT_COMMAND, PS2_DISABLE_SECOND); +} + +void PS2::EnableDevices(unsigned which) { + WaitInputBuffer(); + if (which & 1) ProcessorOut8(PS2_PORT_COMMAND, PS2_ENABLE_FIRST); + WaitInputBuffer(); + if (which & 2) ProcessorOut8(PS2_PORT_COMMAND, PS2_ENABLE_SECOND); +} + +void PS2::FlushOutputBuffer() { + while (ProcessorIn8(PS2_PORT_STATUS) & PS2_OUTPUT_FULL) { + ProcessorIn8(PS2_PORT_DATA); + } +} + +void PS2::SendCommand(uint8_t command) { + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, command); +} + +uint8_t PS2::ReadByte(KTimeout *timeout) { + while (!(ProcessorIn8(PS2_PORT_STATUS) & PS2_OUTPUT_FULL) && !timeout->Hit()); + return ProcessorIn8(PS2_PORT_DATA); +} + +void PS2::WriteByte(KTimeout *timeout, uint8_t value) { + while ((ProcessorIn8(PS2_PORT_STATUS) & PS2_INPUT_FULL) && !timeout->Hit()); + if (timeout->Hit()) return; + ProcessorOut8(PS2_PORT_DATA, value); +} + +bool PS2::SetupKeyboard(KTimeout *timeout) { + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, PS2_KEYBOARD_ENABLE); + if (ReadByte(timeout) != 0xFA) return false; + + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, PS2_KEYBOARD_SCANCODE_SET); + if (ReadByte(timeout) != 0xFA) return false; + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, 0); + if (ReadByte(timeout) != 0xFA) return false; + scancodeSet = ReadByte(timeout) & 3; + KernelLog(LOG_INFO, "PS/2", "scancode set", "Keyboard reports it is using scancode set %d.\n", scancodeSet); + + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, PS2_KEYBOARD_REPEAT); + if (ReadByte(timeout) != 0xFA) return false; + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, 0); + if (ReadByte(timeout) != 0xFA) return false; + + return true; +} + +bool PS2::SetupMouse(KTimeout *timeout) { + // TODO Mouse with scroll wheel detection. + + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, PS2_MOUSE_RESET); + if (ReadByte(timeout) != 0xFA) return false; + if (ReadByte(timeout) != 0xAA) return false; + if (ReadByte(timeout) != 0x00) return false; + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, PS2_MOUSE_SAMPLE_RATE); + if (ReadByte(timeout) != 0xFA) return false; + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, 100); + if (ReadByte(timeout) != 0xFA) return false; + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, PS2_MOUSE_RESOLUTION); + if (ReadByte(timeout) != 0xFA) return false; + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, 3); + if (ReadByte(timeout) != 0xFA) return false; + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_DATA, PS2_MOUSE_ENABLE); + if (ReadByte(timeout) != 0xFA) return false; + + return true; +} + +void PS2::Initialise(KDevice *parentDevice) { + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + if (initialised) { + return; + } + + initialised = true; + channels = 0; + + KTimeout timeout(10000); + + FlushOutputBuffer(); + + // TODO PS/2 detection with ACPI. + + DisableDevices(1 | 2); + FlushOutputBuffer(); + + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_READ_CONFIG); + uint8_t configurationByte = ReadByte(&timeout); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_CONFIG); + WriteByte(&timeout, configurationByte & ~(PS2_FIRST_IRQ_MASK | PS2_SECOND_IRQ_MASK | PS2_TRANSLATION)); + if (timeout.Hit()) return; + + SendCommand(PS2_TEST_CONTROLER); + if (ReadByte(&timeout) != 0x55) return; + + bool hasMouse = false; + if (configurationByte & PS2_SECOND_CLOCK) { + EnableDevices(2); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_READ_CONFIG); + configurationByte = ReadByte(&timeout); + if (!(configurationByte & PS2_SECOND_CLOCK)) { + hasMouse = true; + DisableDevices(2); + } + } + + { + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_TEST_FIRST); + uint8_t b = ReadByte(&timeout); + if (b) return; + if (timeout.Hit()) return; + channels = 1; + } + + if (hasMouse) { + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_TEST_SECOND); + if (!ReadByte(&timeout) && !timeout.Hit()) channels = 2; + } + + EnableDevices(1 | 2); + + if (!SetupKeyboard(&timeout) || timeout.Hit()) { + channels = 0; + return; + } + + if (!SetupMouse(&timeout) || timeout.Hit()) { + channels = 1; + } + + { + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_READ_CONFIG); + uint8_t configurationByte = ReadByte(&timeout); + WaitInputBuffer(); + ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_CONFIG); + WriteByte(&timeout, configurationByte | PS2_FIRST_IRQ_MASK | PS2_SECOND_IRQ_MASK); + } + + if (!registeredIRQs) { + KRegisterIRQ(PS2_FIRST_IRQ, PS2IRQHandler, nullptr, "PS2"); + KRegisterIRQ(PS2_SECOND_IRQ, PS2IRQHandler, nullptr, "PS2"); + registeredIRQs = true; + } + + KDevice *controller = KDeviceCreate("PS/2 controller", parentDevice, sizeof(KDevice)); + KDeviceCreate("PS/2 keyboard", controller, sizeof(KDevice)); + if (channels == 2) KDeviceCreate("PS/2 mouse", controller, sizeof(KDevice)); + + KernelLog(LOG_INFO, "PS/2", "controller initialised", "Setup PS/2 controller%z.\n", channels == 2 ? ", with a mouse" : ""); +} + +static void DeviceAttach(KDevice *parentDevice) { + ps2.Initialise(parentDevice); +} + +KDriver driverPS2 = { + .attach = DeviceAttach, +}; diff --git a/drivers/svga.cpp b/drivers/svga.cpp new file mode 100644 index 0000000..16ecbf7 --- /dev/null +++ b/drivers/svga.cpp @@ -0,0 +1,285 @@ +#include +#include + +struct VideoModeInformation { + uint8_t valid : 1, edidValid : 1; + uint8_t bitsPerPixel; + uint16_t widthPixels, heightPixels; + uint16_t bytesPerScanlineLinear; + uint64_t bufferPhysical; + uint8_t edid[128]; +}; + +VideoModeInformation *vbeMode; +uint32_t screenWidth, screenHeight, strideX, strideY; +volatile uint8_t *linearBuffer; + +#if 0 +float colorBlindnessMatrix[3][9] = { + { + // Protanopia. + 0.171, 0.829, 0, + 0.171, 0.829, 0, + -0.005, 0.005, 1, + }, + + { + // Deuteranopia. + 0.330, 0.670, 0, + 0.330, 0.670, 0, + -0.028, 0.028, 1, + }, + + { + // Tritanopia. + 1, 0.127, -0.127, + 0, 0.874, 0.126, + 0, 0.874, 0.126, + }, +}; + +// #define SIMULATE_COLOR_BLINDNESS (1) +#endif + +void UpdateScreen_32_XRGB(K_USER_BUFFER const uint8_t *source, uint32_t sourceWidth, uint32_t sourceHeight, uint32_t sourceStride, + uint32_t destinationX, uint32_t destinationY) { + GraphicsUpdateScreen32(source, sourceWidth, sourceHeight, sourceStride, + destinationX, destinationY, screenWidth, screenHeight, strideY, linearBuffer); +} + +void DebugPutBlock_32_XRGB(uintptr_t x, uintptr_t y, bool toggle) { + GraphicsDebugPutBlock32(x, y, toggle, screenWidth, screenHeight, strideY, linearBuffer); +} + +void DebugClearScreen_32_XRGB() { + GraphicsDebugClearScreen32(screenWidth, screenHeight, strideY, linearBuffer); +} + +void UpdateScreen_24_RGB(K_USER_BUFFER const uint8_t *source, uint32_t sourceWidth, uint32_t sourceHeight, uint32_t sourceStride, + uint32_t destinationX, uint32_t destinationY) { + GraphicsUpdateScreen24(source, sourceWidth, sourceHeight, sourceStride, + destinationX, destinationY, screenWidth, screenHeight, strideY, linearBuffer); +} + +void DebugPutBlock_24_RGB(uintptr_t x, uintptr_t y, bool toggle) { + if (toggle) { + linearBuffer[y * strideY + x * 3 + 0] += 0x4C; + linearBuffer[y * strideY + x * 3 + 1] += 0x4C; + linearBuffer[y * strideY + x * 3 + 2] += 0x4C; + } else { + linearBuffer[y * strideY + x * 3 + 0] = 0xFF; + linearBuffer[y * strideY + x * 3 + 1] = 0xFF; + linearBuffer[y * strideY + x * 3 + 2] = 0xFF; + } + + linearBuffer[(y + 1) * strideY + (x + 1) * 3 + 0] = 0; + linearBuffer[(y + 1) * strideY + (x + 1) * 3 + 1] = 0; + linearBuffer[(y + 1) * strideY + (x + 1) * 3 + 2] = 0; +} + +void DebugClearScreen_24_RGB() { + for (uintptr_t i = 0; i < screenWidth * screenHeight * 3; i += 3) { + linearBuffer[i + 2] = 0x18; + linearBuffer[i + 1] = 0x7E; + linearBuffer[i + 0] = 0xCF; + } +} + +void InitialiseVBE(KDevice *parent) { + if (KGraphicsIsTargetRegistered()) { + return; + } + + vbeMode = (VideoModeInformation *) MMMapPhysical(MMGetKernelSpace(), 0x7000 + GetBootloaderInformationOffset(), + sizeof(VideoModeInformation), ES_FLAGS_DEFAULT); + + if (!vbeMode->valid) { + return; + } + + if (vbeMode->edidValid) { + for (uintptr_t i = 0; i < 128; i++) { + EsPrint("EDID byte %d: %X.\n", i, vbeMode->edid[i]); + } + } + + KGraphicsTarget *target = (KGraphicsTarget *) KDeviceCreate("VBE", parent, sizeof(KGraphicsTarget)); + + linearBuffer = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), vbeMode->bufferPhysical, + vbeMode->bytesPerScanlineLinear * vbeMode->heightPixels, MM_REGION_WRITE_COMBINING); + screenWidth = target->screenWidth = vbeMode->widthPixels; + screenHeight = target->screenHeight = vbeMode->heightPixels; + strideX = vbeMode->bitsPerPixel >> 3; + strideY = vbeMode->bytesPerScanlineLinear; + + if (vbeMode->bitsPerPixel == 32) { + target->updateScreen = UpdateScreen_32_XRGB; + target->debugPutBlock = DebugPutBlock_32_XRGB; + target->debugClearScreen = DebugClearScreen_32_XRGB; + } else { + target->updateScreen = UpdateScreen_24_RGB; + target->debugPutBlock = DebugPutBlock_24_RGB; + target->debugClearScreen = DebugClearScreen_24_RGB; + } + + // TODO Other color modes. + + KRegisterGraphicsTarget(target); +} + +#if 0 + +#define VGA_AC_INDEX 0x3C0 +#define VGA_AC_WRITE 0x3C0 +#define VGA_AC_READ 0x3C1 + +#define VGA_MISC_WRITE 0x3C2 +#define VGA_MISC_READ 0x3CC + +#define VGA_SEQ_INDEX 0x3C4 +#define VGA_SEQ_DATA 0x3C5 + +#define VGA_DAC_READ_INDEX 0x3C7 +#define VGA_DAC_WRITE_INDEX 0x3C8 +#define VGA_DAC_DATA 0x3C9 + +#define VGA_GC_INDEX 0x3CE +#define VGA_GC_DATA 0x3CF + +#define VGA_CRTC_INDEX 0x3D4 +#define VGA_CRTC_DATA 0x3D5 + +#define VGA_INSTAT_READ 0x3DA + +uint8_t vgaMode18[] = { + 0xE3, 0x03, 0x01, 0x08, 0x00, 0x06, 0x5F, 0x4F, + 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x0C, + 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0F, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x01, 0x00, 0x0F, 0x00, 0x00, +}; + +volatile uint8_t *vgaAddress; + +#define VGA_SCREEN_WIDTH (640) +#define VGA_SCREEN_HEIGHT (480) + +uint8_t egaPaletteConverter[4][64] = { + { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, + 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, }, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, + { 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, }, +}; + +void VGAUpdateScreen(uint8_t *_source, uint8_t *modifiedScanlineBitset, KModifiedScanline *modifiedScanlines) { + for (int plane = 0; plane < 4; plane++) { + uint8_t *source = _source; + + ProcessorOut8(VGA_SEQ_INDEX, 2); + ProcessorOut8(VGA_SEQ_DATA, 1 << plane); + + for (uintptr_t y_ = 0; y_ < VGA_SCREEN_HEIGHT / 8; y_++) { + if (modifiedScanlineBitset[y_] == 0) { + source += VGA_SCREEN_WIDTH * 32; + continue; + } + + for (uintptr_t y = 0; y < 8; y++) { + uint8_t *sourceStart = source; + + if ((modifiedScanlineBitset[y_] & (1 << y)) == 0) { + source += VGA_SCREEN_WIDTH * 4; + continue; + } + + KModifiedScanline *scanline = modifiedScanlines + y + (y_ << 3); + + uintptr_t x = scanline->minimumX & ~7; + source += 4 * x; + + while (x < scanline->maximumX) { + uint8_t v = 0; + + for (int i = 7; i >= 0; i--) { + if (egaPaletteConverter[plane][((source[0] >> 6) & 3) | ((source[1] >> 4) & 12) | ((source[2] >> 2) & 48)]) { + v |= 1 << i; + } + + source += 4; + } + + vgaAddress[(y + y_ * 8) * 80 + (x >> 3)] = v; + x += 8; + } + + source = sourceStart + VGA_SCREEN_WIDTH * 4; + } + } + } +} + +void VGAPutBlock(uintptr_t x, uintptr_t y, bool toggle) { + for (int plane = 0; plane < 4; plane++) { + ProcessorOut8(VGA_SEQ_INDEX, 2); + ProcessorOut8(VGA_SEQ_DATA, 1 << plane); + + if (toggle) { + vgaAddress[y * 80 + x / 8] ^= 1 << (7 - (x & 7)); + } else { + vgaAddress[y * 80 + x / 8] |= 1 << (7 - (x & 7)); + } + } +} + +void VGAClearScreen() { + for (int plane = 0; plane < 4; plane++) { + ProcessorOut8(VGA_SEQ_INDEX, 2); + ProcessorOut8(VGA_SEQ_DATA, 1 << plane); + EsMemoryZero((void *) vgaAddress, VGA_SCREEN_WIDTH / 8 * VGA_SCREEN_HEIGHT); + } +} + +void InitialiseVGA(KDevice *parent) { + if (KGraphicsIsTargetRegistered()) { + return; + } + + vgaAddress = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), 0xA0000, 0x10000, MM_REGION_WRITE_COMBINING); + uint8_t *registers = vgaMode18; + ProcessorOut8(VGA_MISC_WRITE, *registers++); + for (int i = 0; i < 5; i++) { ProcessorOut8(VGA_SEQ_INDEX, i); ProcessorOut8(VGA_SEQ_DATA, *registers++); } + ProcessorOut8(VGA_CRTC_INDEX, 0x03); + ProcessorOut8(VGA_CRTC_DATA, ProcessorIn8(VGA_CRTC_DATA) | 0x80); + ProcessorOut8(VGA_CRTC_INDEX, 0x11); + ProcessorOut8(VGA_CRTC_DATA, ProcessorIn8(VGA_CRTC_DATA) & ~0x80); + registers[0x03] |= 0x80; + registers[0x11] &= ~0x80; + for (int i = 0; i < 25; i++) { ProcessorOut8(VGA_CRTC_INDEX, i); ProcessorOut8(VGA_CRTC_DATA, *registers++); } + for (int i = 0; i < 9; i++) { ProcessorOut8(VGA_GC_INDEX, i); ProcessorOut8(VGA_GC_DATA, *registers++); } + for (int i = 0; i < 21; i++) { ProcessorIn8(VGA_INSTAT_READ); ProcessorOut8(VGA_AC_INDEX, i); ProcessorOut8(VGA_AC_WRITE, *registers++); } + ProcessorIn8(VGA_INSTAT_READ); + ProcessorOut8(VGA_AC_INDEX, 0x20); + + KGraphicsTarget *target = (KGraphicsTarget *) KDeviceCreate("VGA", parent, sizeof(KGraphicsTarget)); + target->screenWidth = VGA_SCREEN_WIDTH; + target->screenHeight = VGA_SCREEN_HEIGHT; + target->updateScreen = VGAUpdateScreen; + target->debugPutBlock = VGAPutBlock; + target->debugClearScreen = VGAClearScreen; + target->reducedColors = true; + // TODO Debug callbacks. + KRegisterGraphicsTarget(target); +} + +#endif + +KDriver driverSVGA = { + .attach = InitialiseVBE, +}; diff --git a/drivers/usb.cpp b/drivers/usb.cpp new file mode 100644 index 0000000..ffeeb79 --- /dev/null +++ b/drivers/usb.cpp @@ -0,0 +1,340 @@ +#include + +#define SETUP_FLAG_D2H (0x80) + +#define DESCRIPTOR_DEVICE (1) +#define DESCRIPTOR_CONFIGURATION (2) +#define DESCRIPTOR_STRING (3) +#define DESCRIPTOR_INTERFACE (4) +#define DESCRIPTOR_ENDPOINT (5) + +KUSBDescriptorHeader *KUSBDevice::GetCommonDescriptor(uint8_t type, uintptr_t index) { + uintptr_t position = selectedConfigurationOffset; + + while (position < configurationDescriptorsBytes) { + KUSBDescriptorHeader *header = (KUSBDescriptorHeader *) (configurationDescriptors + position); + + if (header->descriptorType == DESCRIPTOR_INTERFACE || header->descriptorType == DESCRIPTOR_CONFIGURATION) { + return nullptr; + } else if (header->descriptorType == type) { + if (index) { + index--; + } else { + return header; + } + } + + position += header->length; + } + + return nullptr; +} + +struct SynchronousTransfer { + KEvent complete; + size_t *bytesNotTransferred; + bool success; +}; + +void SynchronousTransferCallback(ptrdiff_t bytesNotTransferred, EsGeneric context) { + SynchronousTransfer *transfer = (SynchronousTransfer *) context.p; + + if (bytesNotTransferred != -1) { + if (transfer->bytesNotTransferred) { + transfer->success = true; + *transfer->bytesNotTransferred = bytesNotTransferred; + } else if (!bytesNotTransferred) { + transfer->success = true; + } + } + + KEventSet(&transfer->complete); +} + +bool KUSBDevice::RunTransfer(KUSBEndpointDescriptor *endpoint, void *buffer, size_t bufferBytes, size_t *bytesNotTransferred) { + SynchronousTransfer transfer = {}; + transfer.bytesNotTransferred = bytesNotTransferred; + queueTransfer(this, endpoint, SynchronousTransferCallback, buffer, bufferBytes, &transfer); + KEventWait(&transfer.complete); + return transfer.success; +} + +bool KUSBDevice::GetString(uint8_t index, char *buffer, size_t bufferBytes) { + uint16_t wideBuffer[127]; + + if (!bufferBytes || !index) { + return false; + } + + uint16_t transferred = 0; + + if (!controlTransfer(this, SETUP_FLAG_D2H, 0x06 /* get descriptor */, + ((uint16_t) DESCRIPTOR_STRING << 8) | (uint16_t) index, 0, + wideBuffer, sizeof(wideBuffer), K_ACCESS_READ, &transferred)) { + return false; + } + + if (transferred < 4) { + return false; + } + + size_t inputCharactersRemaining = (*(uint8_t *) wideBuffer) / 2 - 1; + + if ((size_t) (transferred / 2 - 1) < inputCharactersRemaining) { + inputCharactersRemaining = transferred / 2 - 1; + } + + uint16_t *inputPosition = wideBuffer + 1; + uintptr_t bufferPosition = 0; + + while (inputCharactersRemaining) { + uint32_t c = *inputPosition; + inputCharactersRemaining--; + inputPosition++; + + if (c >= 0xD800 && c < 0xDC00 && inputCharactersRemaining) { + uint32_t c2 = *inputPosition; + + if (c2 >= 0xDC00 && c2 < 0xE000) { + inputCharactersRemaining--; + inputPosition++; + + c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; + } + } + + size_t encodedBytes = utf8_encode(c, nullptr); + + if (bufferPosition + encodedBytes < bufferBytes) { + utf8_encode(c, buffer + bufferPosition); + bufferPosition += encodedBytes; + } else { + break; + } + } + + buffer[bufferPosition] = 0; + + return true; +} + +bool USBInterfaceClassCheck(KInstalledDriver *driver, KDevice *device) { + KUSBInterfaceDescriptor *descriptor = &((KUSBDevice *) device)->interfaceDescriptor; + + int classCode = -1, subclassCode = -1, protocol = -1; + + EsINIState s = {}; + s.buffer = driver->config, s.bytes = driver->configBytes; + + while (EsINIParse(&s)) { + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("classCode"))) classCode = EsIntegerParse(s.value, s.valueBytes); + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("subclassCode"))) subclassCode = EsIntegerParse(s.value, s.valueBytes); + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("protocol"))) protocol = EsIntegerParse(s.value, s.valueBytes); + } + + if (classCode == -1 && subclassCode == -1 && protocol == -1) { + return false; + } + + if (classCode != -1 && descriptor->interfaceClass != classCode) return false; + if (subclassCode != -1 && descriptor->interfaceSubclass != subclassCode) return false; + if (protocol != -1 && descriptor->interfaceProtocol != protocol) return false; + + return true; +} + +bool USBProductIDCheck(KInstalledDriver *driver, KDevice *device) { + KUSBDeviceDescriptor *descriptor = &((KUSBDevice *) device)->deviceDescriptor; + + int productID = -1, vendorID = -1, version = -1; + + EsINIState s = {}; + s.buffer = driver->config, s.bytes = driver->configBytes; + + while (EsINIParse(&s)) { + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("productID"))) productID = EsIntegerParse(s.value, s.valueBytes); + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("vendorID"))) vendorID = EsIntegerParse(s.value, s.valueBytes); + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("version"))) version = EsIntegerParse(s.value, s.valueBytes); + } + + if (productID == -1 && vendorID == -1 && version == -1) { + return false; + } + + if (productID != -1 && descriptor->productID != productID) return false; + if (vendorID != -1 && descriptor->vendorID != vendorID) return false; + if (version != -1 && descriptor->deviceVersion != version) return false; + + return true; +} + +void KRegisterUSBDevice(KUSBDevice *device) { + EsDefer(KDeviceCloseHandle(device)); + + bool foundInterfaceDescriptor = false; + + { + // Get the device descriptor. + + uint16_t transferred; + + if (!device->controlTransfer(device, SETUP_FLAG_D2H, 0x06 /* get descriptor */, + (DESCRIPTOR_DEVICE << 8) | 0x00, 0, &device->deviceDescriptor, + sizeof(KUSBDeviceDescriptor), K_ACCESS_READ, &transferred) + || transferred != sizeof(KUSBDeviceDescriptor)) { + return; + } + + if (device->deviceDescriptor.length < sizeof(KUSBDeviceDescriptor) + || device->deviceDescriptor.descriptorType != DESCRIPTOR_DEVICE + || device->deviceDescriptor.configurationCount == 0) { + KernelLog(LOG_ERROR, "USB", "invalid device descriptor", "Device descriptor is invalid or unsupported.\n"); + return; + } + } + + KernelLog(LOG_INFO, "USB", "device identification", "Device has identification %W/%W/%W.\n", + device->deviceDescriptor.vendorID, device->deviceDescriptor.productID, device->deviceDescriptor.deviceVersion); + + { + // Get strings. + + char buffer[256]; + + if (device->GetString(device->deviceDescriptor.manufacturerString, buffer, sizeof(buffer))) { + KernelLog(LOG_INFO, "USB", "device manufacturer", "Device manufacturer string: '%z'.\n", buffer); + } else { + goto skipStrings; + } + + if (device->GetString(device->deviceDescriptor.productString, buffer, sizeof(buffer))) { + KernelLog(LOG_INFO, "USB", "device product", "Device product string: '%z'.\n", buffer); + } else { + goto skipStrings; + } + + if (device->GetString(device->deviceDescriptor.serialNumberString, buffer, sizeof(buffer))) { + KernelLog(LOG_INFO, "USB", "device serial number", "Device serial number string: '%z'.\n", buffer); + } else { + goto skipStrings; + } + + skipStrings:; + } + + { + // Get the configuration descriptor. + + uint16_t transferred; + + if (!device->controlTransfer(device, SETUP_FLAG_D2H, 0x06 /* get descriptor */, + (DESCRIPTOR_CONFIGURATION << 8) | 0x00, 0, &device->configurationDescriptor, + sizeof(KUSBConfigurationDescriptor), K_ACCESS_READ, &transferred) + || transferred != sizeof(KUSBConfigurationDescriptor)) { + return; + } + + if (device->configurationDescriptor.totalLength < sizeof(KUSBConfigurationDescriptor) + || device->configurationDescriptor.descriptorType != DESCRIPTOR_CONFIGURATION + || !device->configurationDescriptor.interfaceCount + || !device->configurationDescriptor.configurationIndex) { + KernelLog(LOG_ERROR, "USB", "invalid configuration descriptor", "Invalid field in configuration descriptor.\n"); + return; + } + } + + { + // Read the rest of the configuration descriptors. + + uint8_t *buffer = (uint8_t *) EsHeapAllocate(device->configurationDescriptor.totalLength, false, K_FIXED); + + if (!buffer) { + KernelLog(LOG_ERROR, "USB", "allocation failure", "Could not allocate buffer to read all configuration descriptors.\n"); + return; + } + + uint16_t transferred; + + if (!device->controlTransfer(device, SETUP_FLAG_D2H, 0x06 /* get descriptor */, + (DESCRIPTOR_CONFIGURATION << 8) | 0x00, 0, buffer, + device->configurationDescriptor.totalLength, K_ACCESS_READ, &transferred) + || transferred != device->configurationDescriptor.totalLength) { + return; + } + + device->configurationDescriptors = buffer; + device->configurationDescriptorsBytes = device->configurationDescriptor.totalLength; + } + + { + // Check the configuration descriptors are valid. + + uintptr_t position = 0; + uintptr_t configurationsSeen = 0; + + while (position < device->configurationDescriptorsBytes) { + if (position >= device->configurationDescriptorsBytes - sizeof(KUSBDescriptorHeader)) { + KernelLog(LOG_ERROR, "USB", "descriptor invalid length", "Remaining %D, too small for descriptor.\n", + device->configurationDescriptorsBytes - position); + return; + } + + KUSBDescriptorHeader *header = (KUSBDescriptorHeader *) (device->configurationDescriptors + position); + + if (header->length < sizeof(KUSBDescriptorHeader) || header->length > device->configurationDescriptorsBytes - position) { + KernelLog(LOG_ERROR, "USB", "descriptor invalid length", "Given length %D, remaining %D.\n", + header->length, device->configurationDescriptorsBytes - position); + return; + } + + if (header->descriptorType == DESCRIPTOR_CONFIGURATION + && header->length >= sizeof(KUSBConfigurationDescriptor)) { + configurationsSeen++; + } + + if (header->descriptorType == DESCRIPTOR_INTERFACE + && header->length >= sizeof(KUSBInterfaceDescriptor) + && !foundInterfaceDescriptor + && configurationsSeen == 1) { + device->interfaceDescriptor = *(KUSBInterfaceDescriptor *) header; + device->selectedConfigurationOffset = position + header->length; + foundInterfaceDescriptor = true; + } + + position += header->length; + } + } + + { + // Look for a driver that matches the vendor/product. + + if (KDeviceAttach(device, "USB", USBProductIDCheck)) { + return; + } + + // Otherwise, pick the default configuration and interface. + + if (!foundInterfaceDescriptor) { + KernelLog(LOG_ERROR, "USB", "no interface descriptor", + "The device does not have any interface descriptors for the default configuration."); + } + + KernelLog(LOG_INFO, "USB", "device interface", "Device has interface %d with identification %X/%X/%X.\n", + device->interfaceDescriptor.interfaceIndex, device->interfaceDescriptor.interfaceClass, + device->interfaceDescriptor.interfaceSubclass, device->interfaceDescriptor.interfaceProtocol); + + if (!device->selectConfigurationAndInterface(device)) { + KernelLog(LOG_ERROR, "USB", "select interface failure", "Could not select configuration and interface for device.\n"); + return; + } + + if (KDeviceAttach(device, "USB", USBInterfaceClassCheck)) { + return; + } + + KernelLog(LOG_ERROR, "USB", "no driver", "No driver could be found for the device.\n"); + // TODO Show an error message to the user. + } +} + +KDriver driverUSB; diff --git a/drivers/usb_bulk.cpp b/drivers/usb_bulk.cpp new file mode 100644 index 0000000..e41d881 --- /dev/null +++ b/drivers/usb_bulk.cpp @@ -0,0 +1,223 @@ +#include + +// TODO STALL handling. +// TODO Resetting the device on error. +// TODO Command timeout. + +struct Device : KDevice { + KUSBDevice *parent; + KUSBEndpointDescriptor *inputEndpoint, *outputEndpoint; + uint8_t maximumLUN; + KMutex mutex; + + void Initialise(); + bool DoTransfer(struct CommandBlock *block, void *buffer); +}; + +struct Drive : KBlockDevice { + Device *device; + uint8_t lun; +}; + +struct CommandBlock { +#define COMMAND_BLOCK_SIGNATURE (0x43425355) + uint32_t signature; + uint32_t tag; // Returned in the corresponding command status. + uint32_t transferBytes; +#define COMMAND_FLAGS_INPUT (0x80) +#define COMMAND_FLAGS_OUTPUT (0x00) + uint8_t flags; + uint8_t lun; + uint8_t commandBytes; + uint8_t command[16]; +} __attribute__((packed)); + +struct CommandStatus { +#define COMMAND_STATUS_SIGNATURE (0x53425355) + uint32_t signature; + uint32_t tag; + uint32_t residue; +#define STATUS_FAILED (1) +#define STATUS_PHASE_ERROR (2) + uint8_t status; +} __attribute__((packed)); + +bool Device::DoTransfer(CommandBlock *block, void *buffer) { + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + block->signature = COMMAND_BLOCK_SIGNATURE; + block->tag = EsRandomU64() & 0xFFFFFFFF; + + KernelLog(LOG_VERBOSE, "USBBulk", "transfer", "Transferring %D to %x, %z, LUN %d, command %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X (%D).\n", + block->transferBytes, buffer, block->flags == COMMAND_FLAGS_INPUT ? "input" : "output", block->lun, + block->command[0], block->command[1], block->command[2], block->command[3], + block->command[4], block->command[5], block->command[6], block->command[7], + block->command[8], block->command[9], block->command[10], block->command[11], + block->command[12], block->command[13], block->command[14], block->command[15], block->commandBytes); + + // Send the command block to the output endpoint. + + if (!parent->RunTransfer(outputEndpoint, block, sizeof(CommandBlock), nullptr)) { + KernelLog(LOG_ERROR, "USBBulk", "send command block error", "Could not send the command block to the device.\n"); + return false; + } + + // Perform the transfer. + + if (!parent->RunTransfer(block->flags == COMMAND_FLAGS_INPUT ? inputEndpoint : outputEndpoint, buffer, block->transferBytes, nullptr)) { + KernelLog(LOG_ERROR, "USBBulk", "transfer error", "Could not transfer with the device.\n"); + return false; + } + + // Read the command status from the input endpoint. + + CommandStatus status = {}; + + if (!parent->RunTransfer(inputEndpoint, &status, sizeof(CommandStatus), nullptr)) { + KernelLog(LOG_ERROR, "USBBulk", "read command status error", "Could not read the command status from the device.\n"); + return false; + } + + if (status.signature != COMMAND_STATUS_SIGNATURE + || status.tag != block->tag + || status.residue + || status.status) { + KernelLog(LOG_ERROR, "USBBulk", "command unsuccessful", "Command status indicates it was unsuccessful: " + "signature: %x, tag: %x (%x), residue: %D, status: %d.\n", + status.signature, status.tag, block->tag, status.residue, status.status); + return false; + } + + return true; +} + +void DriveAccess(KBlockDeviceAccessRequest request) { + Drive *drive = (Drive *) request.device; + + Device *device = drive->device; + request.dispatchGroup->Start(); + + uint32_t offsetSectors = request.offset / drive->sectorSize; + uint32_t countSectors = request.count / drive->sectorSize; + + CommandBlock command = { + .transferBytes = (uint32_t) request.count, + .flags = (uint8_t) (request.operation == K_ACCESS_WRITE ? COMMAND_FLAGS_OUTPUT : COMMAND_FLAGS_INPUT), + .lun = drive->lun, + .commandBytes = 10, + + .command = { + [0] = (uint8_t) (request.operation == K_ACCESS_WRITE ? 0x2A /* WRITE (12) */ : 0x28 /* READ (12) */), + [1] = 0, + [2] = (uint8_t) (offsetSectors >> 0x18), + [3] = (uint8_t) (offsetSectors >> 0x10), + [4] = (uint8_t) (offsetSectors >> 0x08), + [5] = (uint8_t) (offsetSectors >> 0x00), + [6] = 0, + [7] = (uint8_t) (countSectors >> 0x08), + [8] = (uint8_t) (countSectors >> 0x00), + }, + }; + + request.dispatchGroup->End(device->DoTransfer(&command, (void *) KDMABufferGetVirtualAddress(request.buffer))); +} + +void Device::Initialise() { + uint16_t transferred; + + // Find the input and output endpoints. + + for (uintptr_t i = 0; true; i++) { + KUSBEndpointDescriptor *endpoint = (KUSBEndpointDescriptor *) parent->GetCommonDescriptor(0x05 /* endpoint */, i); + + if (!endpoint) { + break; + } else if (endpoint->IsBulk() && endpoint->IsInput() && !inputEndpoint) { + inputEndpoint = endpoint; + } else if (endpoint->IsBulk() && endpoint->IsOutput() && !outputEndpoint) { + outputEndpoint = endpoint; + } + } + + if (!inputEndpoint || !outputEndpoint) { + KernelLog(LOG_ERROR, "USBBulk", "endpoint missing", "Could not find both bulk endpoints.\n"); + return; + } + + // Reset the mass storage device. + + if (!parent->controlTransfer(parent, 0b00100001, 0b11111111, 0, parent->interfaceDescriptor.interfaceIndex, nullptr, 0, K_ACCESS_WRITE, &transferred)) { + KernelLog(LOG_ERROR, "USBBulk", "reset failure", "Could not reset the mass storage device.\n"); + return; + } + + // Get the maximum LUN. + + parent->controlTransfer(parent, 0b10100001, 0b11111110, 0, parent->interfaceDescriptor.interfaceIndex, &maximumLUN, 1, K_ACCESS_READ, &transferred); + KernelLog(LOG_INFO, "USBBulk", "maximum LUN", "Device reports maximum LUN of %d.\n", maximumLUN); + + for (uintptr_t i = 0; i <= maximumLUN; i++) { + // Get the capacity of the LUN. + + CommandBlock command = { + .transferBytes = 8, + .flags = COMMAND_FLAGS_INPUT, + .lun = (uint8_t) i, + .commandBytes = 10, + .command = { [0] = 0x25 /* READ CAPACITY (10) */ }, + }; + + uint8_t capacity[8]; + + if (!DoTransfer(&command, capacity)) { + KernelLog(LOG_ERROR, "USBBulk", "read capacity error", "Could not read the capacity of LUN %d.\n", i); + continue; + } + + uint32_t sectorCount = (((uint32_t) capacity[3] << 0) + ((uint32_t) capacity[2] << 8) + + ((uint32_t) capacity[1] << 16) + ((uint32_t) capacity[0] << 24)) + 1; + uint32_t sectorBytes = ((uint32_t) capacity[7] << 0) + ((uint32_t) capacity[6] << 8) + + ((uint32_t) capacity[5] << 16) + ((uint32_t) capacity[4] << 24); + + KernelLog(LOG_INFO, "USBBulk", "capacity", "LUN %d has capacity of %D (one sector is %D).\n", + i, (uint64_t) sectorCount * sectorBytes, sectorBytes); + + // Register the drive. + + Drive *drive = (Drive *) KDeviceCreate("USB bulk drive", this, sizeof(Drive)); + + if (!drive) { + KernelLog(LOG_ERROR, "USBBulk", "allocation failure", "Could not create drive for LUN %d.\n", i); + break; + } + + drive->device = this; + drive->lun = i; + drive->sectorSize = sectorBytes; + drive->sectorCount = sectorCount; + drive->maxAccessSectorCount = 262144 / sectorBytes; // TODO How to determine this? What does the USB layer support? + drive->readOnly = false; // TODO How to detect this? + drive->access = DriveAccess; + drive->driveType = ES_DRIVE_TYPE_USB_MASS_STORAGE; + + FSRegisterBlockDevice(drive); + } +} + +static void DeviceAttach(KDevice *parent) { + Device *device = (Device *) KDeviceCreate("USB bulk", parent, sizeof(Device)); + + if (!device) { + KernelLog(LOG_ERROR, "USBBulk", "allocation failure", "Could not allocate device structure.\n"); + return; + } + + device->parent = (KUSBDevice *) parent; + device->Initialise(); + KDeviceCloseHandle(device); +} + +KDriver driverUSBBulk = { + .attach = DeviceAttach, +}; diff --git a/drivers/usb_hid.cpp b/drivers/usb_hid.cpp new file mode 100644 index 0000000..806e19d --- /dev/null +++ b/drivers/usb_hid.cpp @@ -0,0 +1,737 @@ +#include + +// TODO Key repeat not working on Qemu. + +struct ReportItem { + uint32_t usage, application, arrayCount; + int32_t logicalMinimum, logicalMaximum; + + uint8_t reportPrefix; + uint8_t bits; + uint8_t group; + +#define REPORT_ITEM_CONSTANT (1 << 0) +#define REPORT_ITEM_RELATIVE (1 << 1) +#define REPORT_ITEM_WRAP (1 << 2) +#define REPORT_ITEM_NON_LINEAR (1 << 3) +#define REPORT_ITEM_SIGNED (1 << 4) +#define REPORT_ITEM_ARRAY (1 << 5) + uint8_t flags; + +#define REPORT_ITEM_INPUT (1) +#define REPORT_ITEM_OUTPUT (2) +#define REPORT_ITEM_FEATURE (3) + uint8_t type; +}; + +struct BitBuffer { + const uint8_t *buffer; + size_t bytes; + uintptr_t index; + + void Discard(size_t count); + uint32_t ReadUnsigned(size_t count); + int32_t ReadSigned(size_t count); +}; + +struct GameController { + uint64_t id; + uint8_t reportPrefix; +}; + +struct HIDDevice : KDevice { + KUSBDevice *device; + + Array reportItems; + bool usesReportPrefixes; + + Array gameControllers; + + KUSBEndpointDescriptor *reportEndpoint; + uint8_t *lastReport; + size_t lastReportBytes; + + void Initialise(); + bool ParseReportDescriptor(const uint8_t *report, size_t reportBytes); + void ReportReceived(BitBuffer *buffer); +}; + +struct HIDDescriptorLink { + uint8_t type; + uint8_t length[2]; +}; + +struct HIDDescriptor : KUSBDescriptorHeader { + uint8_t specification[2]; + uint8_t countryCode; + uint8_t linkCount; + HIDDescriptorLink links[1]; +}; + +struct ReportGlobalState { + int32_t logicalMinimum, logicalMaximum; + uint16_t usagePage; + uint8_t reportSize, reportCount; + uint8_t reportID; +}; + +struct ReportLocalState { +#define USAGE_ARRAY_SIZE (32) + uint32_t usages[USAGE_ARRAY_SIZE]; + uint32_t usageMinimum, usageMaximum; + uint8_t usageCount; + +#define DELIMITER_NONE (0) +#define DELIMITER_FIRST (1) +#define DELIMITER_IGNORE (2) + uint8_t delimiterState; +}; + +struct UsageString { + uint32_t usage; + const char *string; +}; + +#define HID_APPLICATION_MOUSE (0x010002) +#define HID_APPLICATION_JOYSTICK (0x010004) +#define HID_APPLICATION_KEYBOARD (0x010006) +#define HID_USAGE_X_AXIS (0x010030) +#define HID_USAGE_Y_AXIS (0x010031) +#define HID_USAGE_Z_AXIS (0x010032) +#define HID_USAGE_X_ROTATION (0x010033) +#define HID_USAGE_Y_ROTATION (0x010034) +#define HID_USAGE_Z_ROTATION (0x010035) +#define HID_USAGE_HAT_SWITCH (0x010039) +#define HID_USAGE_KEYCODES (0x070000) +#define HID_USAGE_BUTTON_1 (0x090001) +#define HID_USAGE_BUTTON_2 (0x090002) +#define HID_USAGE_BUTTON_3 (0x090003) +#define HID_USAGE_BUTTON_16 (0x090010) + +UsageString usageStrings[] = { + { 0x000000, "padding" }, + + // Generic desktop page. + { 0x010001, "pointer" }, + { 0x010002, "mouse" }, + { 0x010004, "joystick" }, + { 0x010005, "gamepad" }, + { 0x010006, "keyboard" }, + { 0x010007, "keypad" }, + { 0x010008, "multi-axis controller" }, + { 0x010009, "tablet PC system controls" }, + { 0x010030, "X axis" }, + { 0x010031, "Y axis" }, + { 0x010032, "Z axis" }, + { 0x010033, "X rotation" }, + { 0x010034, "Y rotation" }, + { 0x010035, "Z rotation" }, + { 0x010036, "slider" }, + { 0x010037, "dial" }, + { 0x010038, "wheel" }, + { 0x010039, "hat switch" }, + + // Keyboard/keypad page. + { 0x070000, "keycodes" }, + { 0x0700E0, "left ctrl" }, + { 0x0700E1, "left shift" }, + { 0x0700E2, "left alt" }, + { 0x0700E3, "left gui" }, + { 0x0700E4, "right ctrl" }, + { 0x0700E5, "right shift" }, + { 0x0700E6, "right alt" }, + { 0x0700E7, "right gui" }, + + // LED page. + { 0x080001, "num lock" }, + { 0x080002, "caps lock" }, + { 0x080003, "scroll lock" }, + { 0x080004, "compose" }, + { 0x080005, "kana" }, + + // Button page. + { 0x090001, "button 1" }, + { 0x090002, "button 2" }, + { 0x090003, "button 3" }, + { 0x090004, "button 4" }, + { 0x090005, "button 5" }, + { 0x090006, "button 6" }, + { 0x090007, "button 7" }, + { 0x090008, "button 8" }, + { 0x090009, "button 9" }, + { 0x09000A, "button 10" }, + { 0x09000B, "button 11" }, + { 0x09000C, "button 12" }, + { 0x09000D, "button 13" }, + { 0x09000E, "button 14" }, + { 0x09000F, "button 15" }, + { 0x090010, "button 16" }, +}; + +const char *LookupUsageString(uint32_t usage) { + if (usage > 0xFF000000) { + return "vendor-specific"; + } + + for (uintptr_t i = 0; i < sizeof(usageStrings) / sizeof(usageStrings[0]); i++) { + if (usageStrings[i].usage == usage) { + return usageStrings[i].string; + } + } + + EsPrint("unknown usage %x\n", usage); + return "unknown"; +} + +void BitBuffer::Discard(size_t count) { + index += count; +} + +uint32_t BitBuffer::ReadUnsigned(size_t count) { + uint32_t result = 0; + uint32_t bit = 0; + + while (bit != count) { + uintptr_t byte = index >> 3; + + if (byte >= bytes) { + break; + } + + if (buffer[byte] & (1 << (index & 7))) { + result |= 1 << bit; + } + + bit++, index++; + } + + return result; +} + +int32_t BitBuffer::ReadSigned(size_t count) { + if (!count) return 0; + + uint32_t result = ReadUnsigned(count); + + if (result & (1 << (count - 1))) { + for (uintptr_t i = count; i < 32; i++) { + result |= 1 << i; + } + } + + return result; +} + +bool HIDDevice::ParseReportDescriptor(const uint8_t *report, size_t reportBytes) { +#define REPORT_GLOBAL_STACK_SIZE (8) + ReportGlobalState global[REPORT_GLOBAL_STACK_SIZE] = {}; + uintptr_t gIndex = 0; + ReportLocalState local = {}; + uint32_t application = 0; + uint8_t group = 0; + + uintptr_t position = 0; + + while (position < reportBytes) { + uint8_t header = report[position]; + + if (header == 0xFE) { + // Long items, unused. + if (position + 3 > reportBytes) return false; + position += 3 + report[position + 1]; + continue; + } + + uint8_t size = header & 3; + uint8_t type = header & ~3; + position++; + + if (size == 3) size++; + if (position + size > reportBytes) return false; + + uint32_t uData = 0; + int32_t sData = 0; + + for (uintptr_t i = 0; i < size; i++) { + uData |= report[position + i] << (i * 8); + } + + sData = uData; + + if (size && (report[position + size - 1] & 0x80)) { + for (uintptr_t i = size; i < 4; i++) { + sData |= 0xFF << (i * 8); + } + } + + position += size; + + switch (type) { + case 0b00000100: { global[gIndex].usagePage = uData; } break; + case 0b00010100: { global[gIndex].logicalMinimum = sData; } break; + case 0b00100100: { global[gIndex].logicalMaximum = sData; } break; + case 0b01110100: { global[gIndex].reportSize = uData; } break; + case 0b10010100: { global[gIndex].reportCount = uData; } break; + + case 0b10000100: { + global[gIndex].reportID = uData; + if (uData) usesReportPrefixes = true; + } break; + + case 0b10100100: { + if (gIndex + 1 == REPORT_GLOBAL_STACK_SIZE) return false; + gIndex++; + global[gIndex] = global[gIndex - 1]; + } break; + + case 0b10110100: { + if (gIndex == 0) return false; + gIndex--; + } break; + + case 0b00001000: { + if (local.usageCount == USAGE_ARRAY_SIZE) return false; + + if (local.delimiterState != DELIMITER_IGNORE) { + local.usages[local.usageCount++] = uData | (size < 4 ? (global[gIndex].usagePage << 16) : 0); + } + + if (local.delimiterState == DELIMITER_FIRST) local.delimiterState = DELIMITER_IGNORE; + } break; + + case 0b00011000: { local.usageMinimum = uData | (size < 4 ? (global[gIndex].usagePage << 16) : 0); } break; + case 0b00101000: { local.usageMaximum = uData | (size < 4 ? (global[gIndex].usagePage << 16) : 0); } break; + + case 0b10101000: { + if (uData) local.delimiterState = DELIMITER_FIRST; + else local.delimiterState = DELIMITER_NONE; + } break; + + case 0b10100000: { + if (uData == 1) { + if (local.usageCount == 0) return false; + application = local.usages[0]; + group++; + } + } break; + + case 0b10010000: + case 0b10110000: + case 0b10000000: { + for (uintptr_t i = 0; i < global[gIndex].reportCount; i++) { + ReportItem item = { + .application = application, + .logicalMinimum = global[gIndex].logicalMinimum, + .logicalMaximum = global[gIndex].logicalMaximum, + .reportPrefix = global[gIndex].reportID, + .bits = global[gIndex].reportSize, + }; + + if (type == 0b10000000) { + item.type = REPORT_ITEM_INPUT; + } else if (type == 0b10010000) { + item.type = REPORT_ITEM_OUTPUT; + } else if (type == 0b10110000) { + item.type = REPORT_ITEM_FEATURE; + } + + if ( uData & (1 << 0)) item.flags |= REPORT_ITEM_CONSTANT; + if (~uData & (1 << 1)) item.flags |= REPORT_ITEM_ARRAY; + if ( uData & (1 << 2)) item.flags |= REPORT_ITEM_RELATIVE; + if ( uData & (1 << 3)) item.flags |= REPORT_ITEM_WRAP; + if ( uData & (1 << 4)) item.flags |= REPORT_ITEM_NON_LINEAR; + if (item.logicalMinimum < 0 || item.logicalMaximum < 0) item.flags |= REPORT_ITEM_SIGNED; + + if (local.usageCount) { + item.usage = local.usages[i >= local.usageCount ? local.usageCount - 1 : i]; + } else { + item.usage = (i > local.usageMaximum - local.usageMinimum) ? local.usageMaximum : (local.usageMinimum + i); + } + + if (item.flags & REPORT_ITEM_ARRAY) { + item.arrayCount = global[gIndex].reportCount; + } + + if (!reportItems.Add(item)) { + return false; + } + + KernelLog(LOG_INFO, "USBHID", "parsed report item", + "Parsed report item - group: %d, application: '%z', usage: '%z', range: %i->%i, report: %d, bits: %d, " + "flags: %z%z%z%z%z%z, type: %z, array count: %d\n", + group, LookupUsageString(item.application), LookupUsageString(item.usage), + item.logicalMinimum, item.logicalMaximum, + item.reportPrefix, item.bits, + (item.flags & REPORT_ITEM_CONSTANT) ? "constant|" : "", + (item.flags & REPORT_ITEM_RELATIVE) ? "relative|" : "", + (item.flags & REPORT_ITEM_WRAP) ? "wrap|" : "", + (item.flags & REPORT_ITEM_NON_LINEAR) ? "non-linear|" : "", + (item.flags & REPORT_ITEM_ARRAY) ? "array|" : "", + (item.flags & REPORT_ITEM_SIGNED) ? "signed" : "unsigned", + item.type == REPORT_ITEM_INPUT ? "input" : item.type == REPORT_ITEM_OUTPUT ? "output" : "feature", item.arrayCount); + + if (item.application == HID_APPLICATION_KEYBOARD) { + cDebugName = "USB HID keyboard"; + } else if (item.application == HID_APPLICATION_MOUSE) { + cDebugName = "USB HID mouse"; + } else if (item.application == HID_APPLICATION_JOYSTICK) { + cDebugName = "USB HID joystick"; + } + + if (item.flags & REPORT_ITEM_ARRAY) { + break; + } + } + } break; + } + + if ((type & 0b00001100) == 0) { + EsMemoryZero(&local, sizeof(ReportLocalState)); + } + } + + return true; +} + +void ReportReceivedCallback(ptrdiff_t bytesNotTransferred, EsGeneric context) { + HIDDevice *device = (HIDDevice *) context.p; + size_t bytesTransferred = device->reportEndpoint->GetMaximumPacketSize() - bytesNotTransferred; + + if (bytesNotTransferred == -1) { + KernelLog(LOG_ERROR, "USBHID", "report transfer failure", "Report transfer failed.\n"); + bytesTransferred = 0; + } + + BitBuffer buffer = { device->lastReport, bytesTransferred }; + device->ReportReceived(&buffer); +} + +void HIDDevice::ReportReceived(BitBuffer *buffer) { + uint8_t prefix = 0; + + if (usesReportPrefixes) { + prefix = buffer->ReadUnsigned(8); + } + +#ifdef TRACE_REPORTS + EsPrint("-- report (%d) --\n", prefix); +#endif + + bool mouseEvent = false; + int mouseXMovement = 0, mouseYMovement = 0, mouseButtons = 0; + bool keyboardEvent = false; + uint16_t keysDown[32]; + size_t keysDownCount = 0; + bool gameControllerEvent = false; + EsGameControllerState controllerState = {}; + controllerState.directionalPad = 15; + controllerState.analogCount = 2; + + for (uintptr_t i = 0; i < gameControllers.Length(); i++) { + if (gameControllers[i].reportPrefix == prefix) { + controllerState.id = gameControllers[i].id; + } + } + + for (uintptr_t i = 0; i < reportItems.Length(); i++) { + ReportItem *item = &reportItems[i]; + + if (item->type != REPORT_ITEM_INPUT || item->reportPrefix != prefix) { + continue; + } + +#ifdef TRACE_REPORTS + uintptr_t startIndex = buffer->index; + + EsPrint("%d/%z: ", item->group, LookupUsageString(item->usage)); + + size_t count = (item->flags & REPORT_ITEM_ARRAY) ? item->arrayCount : 1; + + for (uintptr_t i = 0; i < count; i++) { + if (item->flags & REPORT_ITEM_SIGNED) { + EsPrint("%i", buffer->ReadSigned(item->bits)); + } else { + EsPrint("%d", buffer->ReadUnsigned(item->bits)); + } + + if (i != count - 1) { + EsPrint(", "); + } + } + + EsPrint("\n"); + + buffer->index = startIndex; +#endif + + if (item->flags & REPORT_ITEM_ARRAY) { + bool handled = false; + + if (item->application == HID_APPLICATION_KEYBOARD) { + if (item->usage == HID_USAGE_KEYCODES) { + for (uintptr_t i = 0; i < item->arrayCount; i++) { + uint32_t scancode = buffer->ReadUnsigned(item->bits); + keyboardEvent = true; + + if (scancode > 0 && scancode < 0x200 && keysDownCount != 32) { + keysDown[keysDownCount++] = scancode; + } + } + } + } + + if (!handled) { + buffer->Discard(item->bits * item->arrayCount); + } + } else { + bool handled = false; + + if (item->application == HID_APPLICATION_MOUSE) { + // TODO Handle unsigned, absolute, and wrapping movements. + + mouseEvent = true; + handled = true; + + if (item->usage == HID_USAGE_X_AXIS) { + mouseXMovement = buffer->ReadSigned(item->bits); + } else if (item->usage == HID_USAGE_Y_AXIS) { + mouseYMovement = buffer->ReadSigned(item->bits); + } else if (item->usage == HID_USAGE_BUTTON_1) { + if (buffer->ReadUnsigned(item->bits)) mouseButtons |= 1 << 0; + } else if (item->usage == HID_USAGE_BUTTON_2) { + if (buffer->ReadUnsigned(item->bits)) mouseButtons |= 1 << 2; + } else if (item->usage == HID_USAGE_BUTTON_3) { + if (buffer->ReadUnsigned(item->bits)) mouseButtons |= 1 << 1; + } else { + handled = false; + } + } else if (item->application == HID_APPLICATION_KEYBOARD) { + handled = true; + + if (item->usage > HID_USAGE_KEYCODES && item->usage < HID_USAGE_KEYCODES + 0x200) { + handled = true; + keyboardEvent = true; + + if (buffer->ReadUnsigned(item->bits) && keysDownCount != 32) { + keysDown[keysDownCount++] = item->usage - HID_USAGE_KEYCODES; + } + } + } else if (item->application == HID_APPLICATION_JOYSTICK) { + handled = true; + + if (item->usage >= HID_USAGE_BUTTON_1 && item->usage <= HID_USAGE_BUTTON_16) { + gameControllerEvent = true; + + if (buffer->ReadUnsigned(item->bits)) { + controllerState.buttons |= 1 << controllerState.buttonCount; + } + + controllerState.buttonCount++; + } else if (item->usage == HID_USAGE_X_AXIS) { + gameControllerEvent = true; + controllerState.analog[0].x = buffer->ReadUnsigned(item->bits) * 0xFF / item->logicalMaximum; + } else if (item->usage == HID_USAGE_Y_AXIS) { + gameControllerEvent = true; + controllerState.analog[0].y = buffer->ReadUnsigned(item->bits) * 0xFF / item->logicalMaximum; + } else if (item->usage == HID_USAGE_Z_AXIS) { + gameControllerEvent = true; + controllerState.analog[0].z = buffer->ReadUnsigned(item->bits) * 0xFF / item->logicalMaximum; + } else if (item->usage == HID_USAGE_X_ROTATION) { + gameControllerEvent = true; + controllerState.analog[1].x = buffer->ReadUnsigned(item->bits) * 0xFF / item->logicalMaximum; + } else if (item->usage == HID_USAGE_Y_ROTATION) { + gameControllerEvent = true; + controllerState.analog[1].y = buffer->ReadUnsigned(item->bits) * 0xFF / item->logicalMaximum; + } else if (item->usage == HID_USAGE_Z_ROTATION) { + gameControllerEvent = true; + controllerState.analog[1].z = buffer->ReadUnsigned(item->bits) * 0xFF / item->logicalMaximum; + } else if (item->usage == HID_USAGE_HAT_SWITCH) { + gameControllerEvent = true; + controllerState.directionalPad = buffer->ReadUnsigned(item->bits); + } else { + handled = false; + } + } + + if (!handled) { + buffer->Discard(item->bits); + } + } + } + + if (mouseEvent) KCursorUpdate(mouseXMovement, mouseYMovement, mouseButtons); + if (keyboardEvent) KKeyboardUpdate(keysDown, keysDownCount); + if (gameControllerEvent) KGameControllerUpdateState(&controllerState); + + if (device->flags & K_DEVICE_REMOVED) { + KDeviceCloseHandle(this); + } else { + if (!device->queueTransfer(device, reportEndpoint, ReportReceivedCallback, + lastReport, reportEndpoint->GetMaximumPacketSize(), this)) { + KernelLog(LOG_ERROR, "USBHID", "setup transfer failure", "Could not setup the interrupt input transfer to receive the next report packet.\n"); + KDeviceCloseHandle(this); + } + } +} + +void HIDDevice::Initialise() { + // Find the HID descriptor. + + HIDDescriptor *hidDescriptor = (HIDDescriptor *) device->GetCommonDescriptor(0x21, 0); + + if (!hidDescriptor) { + KernelLog(LOG_ERROR, "USBHID", "missing descriptor", "Could not find the HID descriptor.\n"); + return; + } else if (hidDescriptor->length < sizeof(HIDDescriptor) || hidDescriptor->linkCount == 0 + || (hidDescriptor->linkCount - 1) * sizeof(HIDDescriptorLink) + sizeof(HIDDescriptor) > hidDescriptor->length) { + KernelLog(LOG_ERROR, "USBHID", "bad descriptor length", "HID descriptor too short (%D) for %d links.\n", + hidDescriptor->length, hidDescriptor->linkCount); + return; + } + + // Get the size of the report descriptor. + + size_t reportBytes = 0; + + for (uintptr_t i = 0; i < hidDescriptor->linkCount; i++) { + if (hidDescriptor->links[i].type == 0x22) { + reportBytes = (size_t) hidDescriptor->links[i].length[0] | ((size_t) hidDescriptor->links[i].length[1] << 8); + } + } + + if (!reportBytes) { + KernelLog(LOG_ERROR, "USBHID", "no report descriptor", "Could not find report descriptor link in HID descriptor.\n"); + return; + } + + // Switch to the report protocol. + + if (!device->controlTransfer(device, 0x21, 0x0B /* set protocol */, 1 /* report protocol */, + device->interfaceDescriptor.interfaceIndex, nullptr, 0, K_ACCESS_WRITE, nullptr)) { + KernelLog(LOG_ERROR, "USBHID", "set protocol failure", "Could not switch to the report protocol.\n"); + return; + } + + // Get the report descriptor and parse it. + + uint8_t *report = (uint8_t *) EsHeapAllocate(reportBytes, false, K_FIXED); + + if (!report) { + KernelLog(LOG_ERROR, "USBHID", "allocation failure", "Could not allocate buffer to store the report descriptor.\n"); + return; + } + + EsDefer(EsHeapFree(report, reportBytes, K_FIXED)); + + uint16_t transferred = 0; + + if (!device->controlTransfer(device, 0x81, 0x06, 0x22 << 8, 0, report, reportBytes, K_ACCESS_READ, &transferred) + || transferred != reportBytes) { + KernelLog(LOG_ERROR, "USBHID", "no report descriptor", "Could not read the report descriptor from the device.\n"); + return; + } + + if (!ParseReportDescriptor(report, reportBytes)) { + KernelLog(LOG_ERROR, "USBHID", "invalid report descriptor", "Could not parse the report descriptor.\n"); + return; + } + + // Set idle. + + if (!device->controlTransfer(device, 0x21, 0x0A /* set idle */, 0 /* infinite duration, apply to all report IDs */, + device->interfaceDescriptor.interfaceIndex, nullptr, 0, K_ACCESS_WRITE, nullptr)) { + KernelLog(LOG_ERROR, "USBHID", "enable idle failure", "Could not enable idle mode on the device.\n"); + return; + } + + // Get the interrupt-in endpoint descriptor. + + KUSBEndpointDescriptor *endpoint = nullptr; + + { + uintptr_t index = 0; + + while (true) { + KUSBEndpointDescriptor *e = (KUSBEndpointDescriptor *) device->GetCommonDescriptor(0x05 /* endpoint */, index++); + + if (!e) { + break; + } else if (e->IsInterrupt() && e->IsInput()) { + endpoint = e; + break; + } + } + } + + lastReport = (uint8_t *) EsHeapAllocate(endpoint->GetMaximumPacketSize(), true, K_FIXED); + + if (!lastReport) { + KernelLog(LOG_ERROR, "USBHID", "allocation failure", "Could not allocate buffer to store received reports.\n"); + return; + } + + // Start receiving interrupt packets. + + reportEndpoint = endpoint; + KDeviceOpenHandle(this); + + if (!device->queueTransfer(device, endpoint, ReportReceivedCallback, lastReport, endpoint->GetMaximumPacketSize(), this)) { + KernelLog(LOG_ERROR, "USBHID", "setup transfer failure", "Could not setup the interrupt input transfer to receive report packets.\n"); + KDeviceCloseHandle(this); + return; + } + + // If this is a game controller, tell the window manager it's been connected. + + { + uint64_t seen = 0; + + for (uintptr_t i = 0; i < reportItems.Length(); i++) { + ReportItem *item = &reportItems[i]; + + if (item->application == HID_APPLICATION_JOYSTICK + && item->reportPrefix < 64 + && (~seen & (1 << item->reportPrefix))) { + seen |= (1 << item->reportPrefix); + + GameController controller = {}; + controller.id = KGameControllerConnect(); + + if (controller.id) { + controller.reportPrefix = item->reportPrefix; + gameControllers.Add(controller); + } + } + } + } +} + +static void DeviceDestroy(KDevice *_device) { + HIDDevice *device = (HIDDevice *) _device; + + for (uintptr_t i = 0; i < device->gameControllers.Length(); i++) { + KGameControllerDisconnect(device->gameControllers[i].id); + } + + device->reportItems.Free(); + device->gameControllers.Free(); + EsHeapFree(device->lastReport, 0, K_FIXED); +} + +static void DeviceAttach(KDevice *parent) { + HIDDevice *device = (HIDDevice *) KDeviceCreate("USB HID", parent, sizeof(HIDDevice)); + + if (!device) { + KernelLog(LOG_ERROR, "USBHID", "allocation failure", "Could not allocate HIDDevice structure.\n"); + return; + } + + device->destroy = DeviceDestroy; + device->device = (KUSBDevice *) parent; + device->Initialise(); + KDeviceCloseHandle(device); +} + +KDriver driverUSBHID = { + .attach = DeviceAttach, +}; diff --git a/drivers/xhci.cpp b/drivers/xhci.cpp new file mode 100644 index 0000000..5f3e881 --- /dev/null +++ b/drivers/xhci.cpp @@ -0,0 +1,1282 @@ +#include + +// TODO Device attach and detach. +// TODO Babble error recovery. + +#define SPEED_LOW (1) +#define SPEED_FULL (2) +#define SPEED_HIGH (3) +#define SPEED_SUPER (4) + +#define COMMAND_RING_ENTRIES (255) +#define EVENT_RING_ENTRIES (252) +#define TRANSFER_RING_ENTRIES (255) +#define INPUT_CONTEXT_BYTES ((contextSize64 ? 64 : 32) * 33) +#define OUTPUT_CONTEXT_BYTES ((contextSize64 ? 64 : 32) * 32) +#define CONTEXT_INDEX(i) ((i) * (contextSize64 ? 16 : 8)) + +// Capability registers: + +#define RD_REGISTER_CAPLENGTH() pci-> ReadBAR32(0, 0x00) // Capability register length and interface version number. +#define WR_REGISTER_CAPLENGTH(x) pci->WriteBAR32(0, 0x00, x) +#define RD_REGISTER_HCSPARAMS1() pci-> ReadBAR32(0, 0x04) // Structural parameters 1. +#define WR_REGISTER_HCSPARAMS1(x) pci->WriteBAR32(0, 0x04, x) +#define RD_REGISTER_HCSPARAMS2() pci-> ReadBAR32(0, 0x08) // Structural parameters 2. +#define WR_REGISTER_HCSPARAMS2(x) pci->WriteBAR32(0, 0x08, x) +#define RD_REGISTER_HCSPARAMS3() pci-> ReadBAR32(0, 0x0C) // Structural parameters 3. +#define WR_REGISTER_HCSPARAMS3(x) pci->WriteBAR32(0, 0x0C, x) +#define RD_REGISTER_HCCPARAMS1() pci-> ReadBAR32(0, 0x10) // Capability parameters 1. +#define WR_REGISTER_HCCPARAMS1(x) pci->WriteBAR32(0, 0x10, x) +#define RD_REGISTER_DBOFF() pci-> ReadBAR32(0, 0x14) // Doorbell offset. +#define WR_REGISTER_DBOFF(x) pci->WriteBAR32(0, 0x14, x) +#define RD_REGISTER_RTSOFF() pci-> ReadBAR32(0, 0x18) // Runtime register space offset. +#define WR_REGISTER_RTSOFF(x) pci->WriteBAR32(0, 0x18, x) +#define RD_REGISTER_HCCPARAMS2() pci-> ReadBAR32(0, 0x1C) // Capability parameters 2. +#define WR_REGISTER_HCCPARAMS2(x) pci->WriteBAR32(0, 0x1C, x) + +// Host controller operational registers: + +#define RD_REGISTER_USBCMD() pci-> ReadBAR32(0, operationalRegistersOffset + 0x00) // USB command. +#define WR_REGISTER_USBCMD(x) pci->WriteBAR32(0, operationalRegistersOffset + 0x00, x) +#define RD_REGISTER_USBSTS() pci-> ReadBAR32(0, operationalRegistersOffset + 0x04) // USB status. +#define WR_REGISTER_USBSTS(x) pci->WriteBAR32(0, operationalRegistersOffset + 0x04, x) +#define RD_REGISTER_PAGESIZE() pci-> ReadBAR32(0, operationalRegistersOffset + 0x08) // Page size. +#define WR_REGISTER_PAGESIZE(x) pci->WriteBAR32(0, operationalRegistersOffset + 0x08, x) +#define RD_REGISTER_DNCTRL() pci-> ReadBAR32(0, operationalRegistersOffset + 0x14) // Device notification control. +#define WR_REGISTER_DNCTRL(x) pci->WriteBAR32(0, operationalRegistersOffset + 0x14, x) +#define RD_REGISTER_CRCR() pci-> ReadBAR64(0, operationalRegistersOffset + 0x18) // Command ring control. +#define WR_REGISTER_CRCR(x) pci->WriteBAR64(0, operationalRegistersOffset + 0x18, x) +#define RD_REGISTER_DCBAAP() pci-> ReadBAR64(0, operationalRegistersOffset + 0x30) // Device context base address array pointer. +#define WR_REGISTER_DCBAAP(x) pci->WriteBAR64(0, operationalRegistersOffset + 0x30, x) +#define RD_REGISTER_CONFIG() pci-> ReadBAR32(0, operationalRegistersOffset + 0x38) // Configure. +#define WR_REGISTER_CONFIG(x) pci->WriteBAR32(0, operationalRegistersOffset + 0x38, x) + +// Port register sets: + +#define RD_REGISTER_PORTSC(n) pci-> ReadBAR32(0, operationalRegistersOffset + 0x400 + (n) * 0x10) // Port status and control. +#define WR_REGISTER_PORTSC(n, x) pci->WriteBAR32(0, operationalRegistersOffset + 0x400 + (n) * 0x10, x) +#define RD_REGISTER_PORTPMSC(n) pci-> ReadBAR32(0, operationalRegistersOffset + 0x404 + (n) * 0x10) // Port port management status and control. +#define WR_REGISTER_PORTPMSC(n, x) pci->WriteBAR32(0, operationalRegistersOffset + 0x404 + (n) * 0x10, x) +#define RD_REGISTER_PORTLI(n) pci-> ReadBAR32(0, operationalRegistersOffset + 0x408 + (n) * 0x10) // Port link info. +#define WR_REGISTER_PORTLI(n, x) pci->WriteBAR32(0, operationalRegistersOffset + 0x408 + (n) * 0x10, x) +#define RD_REGISTER_PORTHLPMC(n) pci-> ReadBAR32(0, operationalRegistersOffset + 0x40C + (n) * 0x10) // Port hardware LPM control. +#define WR_REGISTER_PORTHLPMC(n, x) pci->WriteBAR32(0, operationalRegistersOffset + 0x40C + (n) * 0x10, x) + +// Host controller runtime registers: + +#define RD_REGISTER_MFINDEX() pci-> ReadBAR32(0, runtimeRegistersOffset + 0x00) // Microframe index. +#define WR_REGISTER_MFINDEX(x) pci->WriteBAR32(0, runtimeRegistersOffset + 0x00, x) + +// Interrupter register sets: + +#define RD_REGISTER_IMAN(n) pci-> ReadBAR32(0, runtimeRegistersOffset + 0x20 + (n) * 0x20) // Interrupter management. +#define WR_REGISTER_IMAN(n, x) pci->WriteBAR32(0, runtimeRegistersOffset + 0x20 + (n) * 0x20, x) +#define RD_REGISTER_IMOD(n) pci-> ReadBAR32(0, runtimeRegistersOffset + 0x24 + (n) * 0x20) // Interrupter moderation. +#define WR_REGISTER_IMOD(n, x) pci->WriteBAR32(0, runtimeRegistersOffset + 0x24 + (n) * 0x20, x) +#define RD_REGISTER_ERSTSZ(n) pci-> ReadBAR32(0, runtimeRegistersOffset + 0x28 + (n) * 0x20) // Event ring segment table size. +#define WR_REGISTER_ERSTSZ(n, x) pci->WriteBAR32(0, runtimeRegistersOffset + 0x28 + (n) * 0x20, x) +#define RD_REGISTER_ERSTBA(n) pci-> ReadBAR64(0, runtimeRegistersOffset + 0x30 + (n) * 0x20) // Event ring segment table base address. +#define WR_REGISTER_ERSTBA(n, x) pci->WriteBAR64(0, runtimeRegistersOffset + 0x30 + (n) * 0x20, x) +#define RD_REGISTER_ERDP(n) pci-> ReadBAR64(0, runtimeRegistersOffset + 0x38 + (n) * 0x20) // Event ring dequeue pointer. +#define WR_REGISTER_ERDP(n, x) pci->WriteBAR64(0, runtimeRegistersOffset + 0x38 + (n) * 0x20, x) + +// Doorbell registers: + +#define RD_REGISTER_DOORBELL(n) pci-> ReadBAR32(0, doorbellsOffset + (n) * 0x04) // Doorbell. +#define WR_REGISTER_DOORBELL(n, x) pci->WriteBAR32(0, doorbellsOffset + (n) * 0x04, x) + +struct XHCIDevice : KUSBDevice { + uintptr_t port; +}; + +struct XHCIEndpoint { + uint32_t *data; + uintptr_t physical; + + uint32_t lastStatus; + uint16_t maximumPacketSize; + uint16_t index : 15, phase : 1; + + KUSBTransferCallback callback; + EsGeneric context; + + bool CreateTransferRing(); + + // TODO Detecting when the transfer ring is full. + void AdvanceTransferRingIndex(); +}; + +struct XHCIPort { + bool usb2, statusChangeEvent, enabled; + uint8_t slotType, slotID, speed; + // uintptr_t maximumPacketSize; + + XHCIEndpoint controlEndpoint; + volatile uint32_t *controlTransferResult; + volatile uintptr_t controlTransferLastTRBAddress; + KEvent controlTransferCompleteEvent; + + XHCIEndpoint ioEndpoints[30]; + + uint32_t *outputContext; + uintptr_t outputContextPhysical; + + XHCIDevice *device; + + KMutex mutex; +}; + +struct XHCIController : KDevice { + KPCIDevice *pci; + + uintptr_t operationalRegistersOffset, + extendedCapabilitiesOffset, + doorbellsOffset, + runtimeRegistersOffset; + size_t maximumDeviceSlots, + maximumInterrupters, + maximumPorts, + maximumEventRingSegments; + bool contextSize64; + + uint64_t *deviceContextBaseAddressArray; + + uint32_t *commandRing; + uintptr_t commandRingIndex; + bool commandRingPhase; + volatile uint32_t *commandResult; + KEvent commandCompleteEvent; + + uint32_t *eventRing; + uintptr_t eventRingPhysical; + uintptr_t eventRingIndex; + bool eventRingPhase; + + uint32_t *inputContext; + uintptr_t inputContextPhysical; + + KEvent portStatusChangeEvent; + KSpinlock portResetSpinlock; + + XHCIPort *ports; + + void Initialise(); + void DumpState(); + bool HandleIRQ(); + + void OnPortEnable(uintptr_t port); + void OnPortDisable(uintptr_t port); + + bool RunCommand(uint32_t *dw); + bool AddTransferDescriptors(uintptr_t buffer, size_t length, int operation, XHCIEndpoint *endpoint, + uint32_t trbType, bool interruptOnLast); + + bool ControlTransfer(uintptr_t port, uint8_t flags, uint8_t request, uint16_t value, uint16_t index, + void *buffer, uint16_t length, int operation, uint16_t *transferred, bool alreadyLocked); + bool SelectConfigurationAndInterface(uintptr_t port, KUSBDevice *device); + bool QueueInterruptTransfer(uintptr_t portIndex, uint8_t endpointAddress, KUSBTransferCallback callback, + void *buffer, size_t bufferBytes, EsGeneric context); +}; + +const char *commandCompletionCodes[] = { + "Invalid", + "Success", + "Data buffer error", + "Babble detected error", + "USB transaction error", + "TRB error", + "Stall error", + "Resource error", + "Bandwidth error", + "No slot available error", + "Invalid stream type error", + "Slot not enabled error", + "Endpoint not enabled error", + "Short packet", + "Ring underrun", + "Ring overrun", + "VF event ring full error", + "Parameter error", + "Bandwidth overrun error", + "Context state error", + "No ping response error", + "Event ring full error", + "Incompatible device error", + "Missed service error", + "Command ring stopped", + "Command aborted", + "Stopped", + "Stopped - length invalid", + "Stopped - short packet", + "Max exit latency too large error", + "Reserved", + "Isochronous buffer overrun", + "Event lost error", + "Undefined error", + "Invalid stream ID error", + "Secondary bandwidth error", + "Split transcation error", +}; + +void XHCIController::DumpState() { + EsPrint("xHCI controller state:\n"); + + EsPrint("\t--- Registers ---\n"); + + EsPrint("\t\tCapability register length: %x.\n", RD_REGISTER_CAPLENGTH()); + EsPrint("\t\tStructural parameters 1: %x.\n", RD_REGISTER_HCSPARAMS1()); + EsPrint("\t\tStructural parameters 2: %x.\n", RD_REGISTER_HCSPARAMS2()); + EsPrint("\t\tStructural parameters 3: %x.\n", RD_REGISTER_HCSPARAMS3()); + EsPrint("\t\tCapability parameters 1: %x.\n", RD_REGISTER_HCCPARAMS1()); + EsPrint("\t\tDoorbell offset: %x.\n", RD_REGISTER_DBOFF()); + EsPrint("\t\tRuntime register space offset: %x.\n", RD_REGISTER_RTSOFF()); + EsPrint("\t\tCapability parameters 2: %x.\n", RD_REGISTER_HCCPARAMS2()); + + EsPrint("\t\tUSB command: %x.\n", RD_REGISTER_USBCMD()); + EsPrint("\t\tUSB status: %x.\n", RD_REGISTER_USBSTS()); + EsPrint("\t\tPage size: %x.\n", RD_REGISTER_PAGESIZE()); + EsPrint("\t\tDevice notification control: %x.\n", RD_REGISTER_DNCTRL()); + EsPrint("\t\tCommand ring control: %x.\n", RD_REGISTER_CRCR()); + EsPrint("\t\tDevice context base address array pointer (64-bit): %x.\n", RD_REGISTER_DCBAAP()); + EsPrint("\t\tConfigure: %x.\n", RD_REGISTER_CONFIG()); + + for (uintptr_t i = 0; i < maximumPorts; i++) { + EsPrint("\t\tPort %d:\n", i); + EsPrint("\t\t\tPort status and control: %x.\n", RD_REGISTER_PORTSC(i)); + EsPrint("\t\t\tPort port management status and control: %x.\n", RD_REGISTER_PORTPMSC(i)); + EsPrint("\t\t\tPort link info: %x.\n", RD_REGISTER_PORTLI(i)); + EsPrint("\t\t\tPort hardware LPM control: %x.\n", RD_REGISTER_PORTHLPMC(i)); + } + + for (uintptr_t i = 0; i < maximumInterrupters; i++) { + EsPrint("\t\tInterrupter %d:\n", i); + EsPrint("\t\t\tInterrupter management: %x.\n", RD_REGISTER_IMAN(i)); + EsPrint("\t\t\tInterrupter moderation: %x.\n", RD_REGISTER_IMOD(i)); + EsPrint("\t\t\tEvent ring segment table size: %x.\n", RD_REGISTER_ERSTSZ(i)); + EsPrint("\t\t\tEvent ring segment table base address: %x.\n", RD_REGISTER_ERSTBA(i)); + EsPrint("\t\t\tEvent ring dequeue pointer: %x.\n", RD_REGISTER_ERDP(i)); + } +} + +bool XHCIEndpoint::CreateTransferRing() { + if (!MMPhysicalAllocateAndMap(16 * (TRANSFER_RING_ENTRIES + 1), 16, 0, true, + 0, (uint8_t **) &data, &physical)) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate the transfer ring.\n"); + return false; + } + + index = 0; + phase = 1; + + data[TRANSFER_RING_ENTRIES * 4 + 0] = physical & 0xFFFFFFFF; + data[TRANSFER_RING_ENTRIES * 4 + 1] = (physical >> 32) & 0xFFFFFFFF; + data[TRANSFER_RING_ENTRIES * 4 + 3] = (1 << 1 /* toggle cycle */) | (6 /* link TRB */ << 10); + + return true; +} + +void XHCIEndpoint::AdvanceTransferRingIndex() { + if (phase) { + data[index * 4 + 3] |= 1 << 0; + } + + index++; + + if (index == TRANSFER_RING_ENTRIES) { + // Toggle cycle bit on link TRB. + data[TRANSFER_RING_ENTRIES * 4 + 3] ^= 1 << 0; + index = 0; + phase = phase ? 0 : 1; + } +} + +bool XHCIController::AddTransferDescriptors(uintptr_t buffer, size_t length, int operation, XHCIEndpoint *endpoint, uint32_t trbType, bool interruptOnLast) { + if (this->flags & K_DEVICE_REMOVED) { + return false; + } + + uintptr_t position = 0; + + while (position != length) { + uintptr_t count = K_PAGE_SIZE - ((buffer + position) & (K_PAGE_SIZE - 1)); + bool last = count >= length - position; + if (last) count = length - position; + uintptr_t physical = MMArchTranslateAddress(MMGetKernelSpace(), buffer + position); + physical += (buffer + position) & (K_PAGE_SIZE - 1); + size_t remainingPackets = (length - position + endpoint->maximumPacketSize - 1) / endpoint->maximumPacketSize; + + uint32_t *dw = endpoint->data + endpoint->index * 4; + + dw[0] = (physical >> 0) & 0xFFFFFFFF; + dw[1] = (physical >> 32) & 0xFFFFFFFF; + dw[2] = count | ((last ? 0 : remainingPackets < 31 ? remainingPackets : 31) << 17); + + dw[3] = trbType << 10; + if (operation == K_ACCESS_READ) dw[3] |= 1 << 16 /* input */; + if (last && interruptOnLast) dw[3] |= 1 << 5 /* interrupt on completion */; + if (!last) dw[3] |= 1 << 4 /* chain */; + + endpoint->AdvanceTransferRingIndex(); + position += count; + } + + return true; +} + +bool XHCIController::ControlTransfer(uintptr_t portIndex, uint8_t flags, uint8_t request, uint16_t value, uint16_t index, + void *buffer, uint16_t length, int operation, uint16_t *transferred, bool alreadyLocked) { + XHCIPort *port = ports + portIndex; + + if (!alreadyLocked) KMutexAcquire(&port->mutex); + EsDefer(if (!alreadyLocked) KMutexRelease(&port->mutex)); + if (alreadyLocked) KMutexAssertLocked(&port->mutex); + + if (this->flags & K_DEVICE_REMOVED) { + return false; + } + + KEventReset(&port->controlTransferCompleteEvent); + + uint32_t transferResult[4]; + port->controlTransferResult = transferResult; + + { + uint32_t *dw = port->controlEndpoint.data + port->controlEndpoint.index * 4; + dw[0] = (uint32_t) flags | ((uint32_t) request << 8) | ((uint32_t) value << 16); + dw[1] = (uint32_t) index | ((uint32_t) length << 16); + dw[2] = 8 /* transfer length */; + dw[3] = (1 << 6 /* immediate data */) | (2 /* setup TRB */ << 10); + + if (length) { + dw[3] |= (operation == K_ACCESS_READ ? 3 : 2) << 16; + } + + port->controlEndpoint.AdvanceTransferRingIndex(); + } + + if (!AddTransferDescriptors((uintptr_t) buffer, length, operation, &port->controlEndpoint, 3 /* data TRB */, false)) { + return false; + } + + { + uint32_t *dw = port->controlEndpoint.data + port->controlEndpoint.index * 4; + port->controlTransferLastTRBAddress = port->controlEndpoint.physical + port->controlEndpoint.index * 16; + dw[0] = dw[1] = dw[2] = 0; + dw[3] = (1 << 5 /* interrupt on completion */) | (operation == K_ACCESS_WRITE ? (1 << 16) : 0) | (4 /* status TRB */ << 10); + port->controlEndpoint.AdvanceTransferRingIndex(); + } + + WR_REGISTER_DOORBELL(port->slotID, 1 /* control endpoint */); + + if (!KEventWait(&port->controlTransferCompleteEvent, 1000)) { + // Timeout. + return false; + } + + uint32_t status = transferResult[2]; + uint8_t completionCode = (status >> 24) & 0xFF; + + if (completionCode != 1) { + if (completionCode < sizeof(commandCompletionCodes) / sizeof(commandCompletionCodes[0])) { + KernelLog(LOG_ERROR, "xHCI", "failed control transfer", "Control transfer failed with completion code '%z'.\n", commandCompletionCodes[completionCode]); + } else { + KernelLog(LOG_ERROR, "xHCI", "failed control transfer", "Control transfer failed with unrecognised completion code %d.\n", completionCode); + } + + if ((port->outputContext[CONTEXT_INDEX(1) + 0] & 7) == 2 /* halted */) { + // Reset the endpoint. + + uint32_t dw[4] = {}; + dw[3] = (port->slotID << 24) | (1 /* control endpoint */ << 16) + | (14 /* reset endpoint command */ << 10) | (0 /* reset transfer state */ << 9); + + if (!RunCommand(dw)) { + KernelLog(LOG_ERROR, "xHCI", "reset control endpoint failure", "Could not reset the control endpoint (1).\n"); + // TODO Force detach the device. + return false; + } + + // Reset the dequeue pointer. + + port->controlEndpoint.index = 0; + port->controlEndpoint.phase = 1; + + EsMemoryZero(port->controlEndpoint.data, 16 * (TRANSFER_RING_ENTRIES + 1)); + + dw[0] = (port->controlEndpoint.physical & 0xFFFFFFFF) | (1 << 0 /* phase bit */); + dw[1] = (port->controlEndpoint.physical >> 32) & 0xFFFFFFFF; + dw[2] = 0; + dw[3] = (port->slotID << 24) | (1 /* control endpoint */ << 16) + | (16 /* set TR dequeue pointer command */ << 10); + + if (!RunCommand(dw)) { + KernelLog(LOG_ERROR, "xHCI", "reset control endpoint failure", "Could not reset the control endpoint (2).\n"); + // TODO Force detach the device. + return false; + } + } + + return false; + } + + if (transferred) *transferred = length - (status & 0xFFFFFF); + return true; +} + +bool XHCIController::SelectConfigurationAndInterface(uintptr_t portIndex, KUSBDevice *device) { + XHCIPort *port = ports + portIndex; + + KMutexAcquire(&port->mutex); + EsDefer(KMutexRelease(&port->mutex)); + + if (this->flags & K_DEVICE_REMOVED) { + return false; + } + + // Setup the input context. + + EsMemoryZero(inputContext, INPUT_CONTEXT_BYTES); + + uintptr_t lastIndex = 0; + + for (uintptr_t i = 0; i < device->interfaceDescriptor.endpointCount; i++) { + KUSBEndpointDescriptor *descriptor = (KUSBEndpointDescriptor *) device->GetCommonDescriptor(5 /* endpoint */, i); + + if (!descriptor) { + KernelLog(LOG_ERROR, "xHCI", "endpoint descriptor missing", "Could not find endpoint descriptor %d (%d total).\n", + i, device->interfaceDescriptor.endpointCount); + return false; + } + + KUSBEndpointCompanionDescriptor *companion = nullptr; + KUSBEndpointIsochronousCompanionDescriptor *isochronousCompanion = nullptr; + + if (port->speed == SPEED_SUPER) { + companion = (KUSBEndpointCompanionDescriptor *) ((uint8_t *) descriptor + descriptor->length); + + if (companion->length < sizeof(KUSBEndpointCompanionDescriptor) + || (size_t) ((uint8_t *) companion + companion->length - device->configurationDescriptors) > device->configurationDescriptorsBytes + || companion->descriptorType != 48 /* superspeed endpoint companion */) { + companion = nullptr; + } else if (companion->HasISOCompanion()) { + isochronousCompanion = (KUSBEndpointIsochronousCompanionDescriptor *) ((uint8_t *) companion + companion->length); + + if (isochronousCompanion->length < sizeof(KUSBEndpointCompanionDescriptor) + || (size_t) ((uint8_t *) isochronousCompanion + isochronousCompanion->length - device->configurationDescriptors) + > device->configurationDescriptorsBytes + || isochronousCompanion->descriptorType != 49 /* superspeed isochronous endpoint companion */) { + isochronousCompanion = nullptr; + } + } + } + + if (descriptor->IsControl()) { + // Already enabled. + continue; + } + + uint32_t maximumBurst = companion ? companion->maxBurst : descriptor->IsBulk() ? 0 : ((descriptor->maximumPacketSize & 0x1800) >> 11); + uint32_t maximumPacketSize = descriptor->GetMaximumPacketSize(); + uint32_t maximumESITPayload = descriptor->IsBulk() ? 0 : (companion + ? (isochronousCompanion ? isochronousCompanion->bytesPerInterval : companion->bytesPerInterval) + : (maximumPacketSize * (maximumBurst + 1))); + + uintptr_t index = (descriptor->IsInput() ? 2 : 1) + descriptor->GetAddress() * 2; + inputContext[CONTEXT_INDEX(0) + 1] |= 1 << (index - 1); + if (lastIndex < index - 1) lastIndex = index - 1; + + XHCIEndpoint *endpoint = port->ioEndpoints + index - 3; + + endpoint->maximumPacketSize = maximumPacketSize; + + if (!endpoint->CreateTransferRing()) { + return false; + } + + // See "4.8.2 Endpoint Context Initialization". + inputContext[CONTEXT_INDEX(index) + 0] = 0; + inputContext[CONTEXT_INDEX(index) + 1] = (maximumBurst << 8) | (maximumPacketSize << 16) | (((maximumESITPayload >> 16) & 0xFF) << 24); + inputContext[CONTEXT_INDEX(index) + 2] = (1 << 0 /* phase */) | (endpoint->physical & 0xFFFFFFFF); + inputContext[CONTEXT_INDEX(index) + 3] = ((endpoint->physical >> 32) & 0xFFFFFFFF); + inputContext[CONTEXT_INDEX(index) + 4] = ((maximumESITPayload & 0xFFFF)) << 16; + + if (descriptor->IsInterrupt()) { + inputContext[CONTEXT_INDEX(index) + 1] |= (3 /* error count */ << 1) | ((descriptor->IsInput() ? 7 : 3) << 3 /* endpoint type */); + } else if (descriptor->IsBulk() && (!companion || !companion->GetMaximumStreams())) { + inputContext[CONTEXT_INDEX(index) + 1] |= (3 /* error count */ << 1) | ((descriptor->IsInput() ? 6 : 2) << 3 /* endpoint type */); + } else { + // TODO Isochronous and stream bulk endpoints. + KernelLog(LOG_ERROR, "xHCI", "unsupported endpoint type", "Isochronous and bulk endpoints are currently unsupported.\n"); + return false; + } + } + + inputContext[CONTEXT_INDEX(0) + 1] |= 1 << 0 /* slot context */; + + // See "4.5.2 Slot Context Initialization". + inputContext[CONTEXT_INDEX(1) + 0] = lastIndex << 27; + + // Send the configure endpoint command. + + { + uint32_t dw[4]; + + dw[0] = (inputContextPhysical >> 0) & 0xFFFFFFFF; + dw[1] = (inputContextPhysical >> 32) & 0xFFFFFFFF; + dw[2] = 0; + dw[3] = (port->slotID << 24) | (12 /* configure endpoint command */ << 10); + + if (!RunCommand(dw)) { + KernelLog(LOG_ERROR, "xHCI", "configure endpoint failure", "The configure endpoint command failed.\n"); + return false; + } + } + + // Set the configuration. + + return ControlTransfer(portIndex, 0, 0x09 /* set configuration */, + device->configurationDescriptor.configurationIndex, 0, + nullptr, 0, K_ACCESS_WRITE, nullptr, true /* already locked */); +} + +bool XHCIController::QueueInterruptTransfer(uintptr_t portIndex, uint8_t endpointAddress, KUSBTransferCallback callback, + void *buffer, size_t bufferBytes, EsGeneric context) { + XHCIPort *port = ports + portIndex; + + KMutexAcquire(&port->mutex); + EsDefer(KMutexRelease(&port->mutex)); + + if (this->flags & K_DEVICE_REMOVED) { + return false; + } + + XHCIEndpoint *endpoint = port->ioEndpoints + endpointAddress - 2; + endpoint->callback = callback; + endpoint->context = context; + + if (!AddTransferDescriptors((uintptr_t) buffer, bufferBytes, (endpointAddress & 1) ? K_ACCESS_READ : K_ACCESS_WRITE, + endpoint, 1 /* normal TRB */, true)) { + return false; + } + + WR_REGISTER_DOORBELL(port->slotID, endpointAddress); + return true; +} + +bool XHCIController::HandleIRQ() { + // Clear interrupt status. + + uint32_t usbStatus = RD_REGISTER_USBSTS(); + WR_REGISTER_USBSTS((1 << 3) | (1 << 4)); + + // Check for an interrupt. + + uint32_t status = RD_REGISTER_IMAN(0); + + KernelLog(LOG_VERBOSE, "xHCI", "IRQ", "Received IRQ. USB status: %x. Interrupter status: %x.\n", usbStatus, status); + + // Acknowledge the interrupt. + + WR_REGISTER_IMAN(0, status); + RD_REGISTER_IMAN(0); // Read the value back. + + // Consume events. + + while (true) { + uint32_t dw0 = eventRing[0x10 + 0x04 * eventRingIndex + 0x00]; + uint32_t dw1 = eventRing[0x10 + 0x04 * eventRingIndex + 0x01]; + uint32_t dw2 = eventRing[0x10 + 0x04 * eventRingIndex + 0x02]; + uint32_t dw3 = eventRing[0x10 + 0x04 * eventRingIndex + 0x03]; + + if ((dw3 & (1 << 0)) != eventRingPhase) { + break; + } + + uint32_t type = (dw3 >> 10) & 0x3F; + uint8_t completionCode = (dw2 >> 24) & 0xFF; + + KernelLog(LOG_VERBOSE, "xHCI", "got event", "Received event of type %d with code %d from %x.\n", + type, completionCode, (uintptr_t) dw0 | ((uintptr_t) dw1 << 32)); + + if (type == 32 /* transfer completion event */) { + uint8_t slotID = (dw3 >> 24) & 0xFF; + uint8_t endpointID = (dw3 >> 16) & 0x1F; + + if (endpointID == 1) { + for (uintptr_t i = 0; i < maximumPorts; i++) { + XHCIPort *port = ports + i; + if (port->slotID != slotID) continue; + if (!port->enabled) break; + + if (!port->controlTransferResult) { + KernelLog(LOG_ERROR, "xHCI", "spurious transfer completion event", + "Received an unexpected transfer command completion event on port %d. " + "Contents: %x, %x, %x, %x.\n", i, dw0, dw1, dw2, dw3); + } else { + bool lastTransfer = dw0 == (port->controlTransferLastTRBAddress & 0xFFFFFFFF) + && dw1 == ((port->controlTransferLastTRBAddress >> 32) & 0xFFFFFFFF); + + if (completionCode != 1 || lastTransfer) { + port->controlTransferResult[0] = dw0; + port->controlTransferResult[1] = dw1; + port->controlTransferResult[2] = dw2; + port->controlTransferResult[3] = dw3; + KEventSet(&port->controlTransferCompleteEvent); + } + } + + break; + } + } else if (endpointID >= 2) { + for (uintptr_t i = 0; i < maximumPorts; i++) { + XHCIPort *port = ports + i; + if (port->slotID != slotID) continue; + if (!port->enabled) break; + XHCIEndpoint *endpoint = port->ioEndpoints + endpointID - 2; + endpoint->lastStatus = dw2; + + if (completionCode != 1) { + if (completionCode < sizeof(commandCompletionCodes) / sizeof(commandCompletionCodes[0])) { + KernelLog(LOG_ERROR, "xHCI", "failed transfer", "Transfer failed with completion code '%z' (%x).\n", + commandCompletionCodes[completionCode], dw2); + } else { + KernelLog(LOG_ERROR, "xHCI", "failed transfer", "Transfer failed with unrecognised completion code %d.\n", completionCode); + } + } + + if (endpoint->callback) { + KRegisterAsyncTask([] (EsGeneric argument) { + XHCIEndpoint *endpoint = (XHCIEndpoint *) argument.p; + KUSBTransferCallback callback = endpoint->callback; + endpoint->callback = nullptr; + callback((endpoint->lastStatus >> 24) != 1 ? -1 : endpoint->lastStatus & 0xFFFFFF, endpoint->context); + }, endpoint, true); + } + + break; + } + } + } else if (type == 33 /* command completion event */) { + if (!commandResult) { + KernelLog(LOG_ERROR, "xHCI", "spurious command completion event", + "Received a spurious command completion event (no commands issued since last expected received completion event). " + "Contents: %x, %x, %x, %x.\n", dw0, dw1, dw2, dw3); + } else { + commandResult[0] = dw0; + commandResult[1] = dw1; + commandResult[2] = dw2; + commandResult[3] = dw3; + KEventSet(&commandCompleteEvent); + } + } else if (type == 34 /* port status change event */) { + uintptr_t port = (dw0 >> 24) - 1; + + KSpinlockAcquire(&portResetSpinlock); + + // Acknowledge the status change. + + uint32_t status = RD_REGISTER_PORTSC(port); + uint32_t linkState = (status >> 5) & 0x0F; + WR_REGISTER_PORTSC(port, ((1 << 9) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21) | (1 << 22) | (1 << 23)) & status); + KernelLog(LOG_INFO, "xHCI", "port status change", "Port %d has new status: %x.\n", port, status); + + if (!ports[port].enabled && (status & (1 << 1 /* port enabled */))) { + KernelLog(LOG_INFO, "xHCI", "port enabled", "Port %d has been enabled.\n", port); + ports[port].statusChangeEvent = true; + ports[port].enabled = true; + KEventSet(&portStatusChangeEvent, false, true); + } else if (ports[port].usb2 && (linkState == 7 || linkState == 4) && (~status & (1 << 4))) { + KernelLog(LOG_INFO, "xHCI", "port reset", "Attempting to reset USB 2 port %d... (1)\n", port); + WR_REGISTER_PORTSC(port, (status & (1 << 9)) | (1 << 4)); + } else if (ports[port].enabled && linkState == 5 && (~status & (1 << 0)) && (status & (1 << 17))) { + KernelLog(LOG_INFO, "xHCI", "port detach", "Device detached from port %d.\n", port); + ports[port].statusChangeEvent = true; + ports[port].enabled = false; + KEventSet(&portStatusChangeEvent, false, true); + } + + KSpinlockRelease(&portResetSpinlock); + } + + eventRingIndex++; + + if (eventRingIndex == EVENT_RING_ENTRIES) { + eventRingIndex = 0; + eventRingPhase = !eventRingPhase; + } + } + + WR_REGISTER_ERDP(0, (eventRingPhysical + 0x40 + (eventRingIndex << 4)) | (1 << 3)); + + return true; +} + +bool XHCIController::RunCommand(uint32_t *dw) { + KEventReset(&commandCompleteEvent); + commandResult = dw; + + commandRing[commandRingIndex * 4 + 0] = dw[0]; + commandRing[commandRingIndex * 4 + 1] = dw[1]; + commandRing[commandRingIndex * 4 + 2] = dw[2]; + commandRing[commandRingIndex * 4 + 3] = dw[3] | (commandRingPhase ? (1 << 0) : 0); + + commandRingIndex++; + + if (commandRingIndex == COMMAND_RING_ENTRIES) { + commandRingIndex = 0; + commandRingPhase = !commandRingPhase; + commandRing[COMMAND_RING_ENTRIES * 4 + 3] ^= 1 << 0; // Toggle phase of link TRB. + } + + // TODO Timeout, and command abortion. + WR_REGISTER_DOORBELL(0, 0); + KEventWait(&commandCompleteEvent); + + commandResult = nullptr; + + uint8_t completionCode = dw[2] >> 24; + + if (completionCode != 1) { + if (completionCode < sizeof(commandCompletionCodes) / sizeof(commandCompletionCodes[0])) { + KernelLog(LOG_ERROR, "xHCI", "failed command", "Command failed with completion code '%z'.\n", commandCompletionCodes[completionCode]); + } else { + KernelLog(LOG_ERROR, "xHCI", "failed command", "Command failed with unrecognised completion code %d.\n", completionCode); + } + } + + return completionCode == 1; +} + +static bool SelectConfigurationAndInterfaceWrapper(KUSBDevice *_device) { + XHCIDevice *device = (XHCIDevice *) _device; + XHCIController *controller = (XHCIController *) device->parent; + return controller->SelectConfigurationAndInterface(device->port, device); +} + +static bool QueueTransferWrapper(KUSBDevice *_device, KUSBEndpointDescriptor *endpoint, KUSBTransferCallback callback, + void *buffer, size_t bufferBytes, EsGeneric context) { + XHCIDevice *device = (XHCIDevice *) _device; + XHCIController *controller = (XHCIController *) device->parent; + return controller->QueueInterruptTransfer(device->port, endpoint->GetAddress() * 2 + (endpoint->IsInput() ? 1 : 0), + callback, buffer, bufferBytes, context); +} + +static bool ControlTransferWrapper(KUSBDevice *_device, uint8_t flags, uint8_t request, uint16_t value, uint16_t index, + void *buffer, uint16_t length, int operation, uint16_t *transferred) { + XHCIDevice *device = (XHCIDevice *) _device; + XHCIController *controller = (XHCIController *) device->parent; + KernelLog(LOG_VERBOSE, "xHCI", "control transfer", "Control transfer: %X, %X, %d, %d, %D.\n", flags, request, value, index, length); + bool success = controller->ControlTransfer(device->port, flags, request, value, index, buffer, length, operation, transferred, false); + KernelLog(LOG_VERBOSE, "xHCI", "control transfer complete", "Control transfer complete. Success = %d.\n", success); + return success; +} + +void XHCIController::OnPortEnable(uintptr_t port) { + uint32_t speed = (RD_REGISTER_PORTSC(port) >> 10) & 0xF; + uint32_t maximumPacketSize = speed == SPEED_LOW ? 8 : speed == SPEED_FULL ? 8 : speed == SPEED_HIGH ? 64 : speed == 4 ? SPEED_SUPER : 0; + ports[port].speed = speed; + ports[port].controlEndpoint.maximumPacketSize = maximumPacketSize; + + KernelLog(LOG_INFO, "xHCI", "initialising port", "Port %d is enabled, initialising. Speed: %z.\n", + port, speed == SPEED_LOW ? "low" : speed == SPEED_FULL ? "full" : speed == SPEED_HIGH ? "high" : speed == SPEED_SUPER ? "super" : "unknown"); + + if (!maximumPacketSize) { + KernelLog(LOG_ERROR, "xHCI", "unrecognised device speed", "Unrecognised device speed %d on port %d.\n", speed, port); + return; + } + + // Assign a device slot. + + uint32_t dw[4] = {}; + dw[3] = (9 /* enable slot */ << 10) | (ports[port].slotType << 16); + + if (!RunCommand(dw) || !(dw[3] >> 24)) { + KernelLog(LOG_ERROR, "xHCI", "enable slot error", "Could not enable a slot for the device on port %d.\n", port); + return; + } + + ports[port].slotID = dw[3] >> 24; + + KernelLog(LOG_INFO, "xHCI", "assign device slot", "Port %d assigned device slot %d.\n", port, ports[port].slotID); + + // Allocate the transfer ring. + + if (!ports[port].controlEndpoint.CreateTransferRing()) { + return; + } + + // Setup the input context. + + EsMemoryZero(inputContext, INPUT_CONTEXT_BYTES); + + inputContext[CONTEXT_INDEX(0) + 1] = (1 << 0 /* slot context valid */) | (1 << 1 /* control endpoint context valid */); + + inputContext[CONTEXT_INDEX(1) + 0] = (1 /* 1 context entry */ << 27) | (speed << 20); + inputContext[CONTEXT_INDEX(1) + 1] = (port + 1) << 16; + + // TODO Update this with the maximum packet size from the device descriptor. + // This field is interpreted differently on USB 2/3. + + inputContext[CONTEXT_INDEX(2) + 1] = (3 /* error count */ << 1) | (4 /* control endpoint */ << 3) | (maximumPacketSize << 16); + inputContext[CONTEXT_INDEX(2) + 2] = (ports[port].controlEndpoint.physical & 0xFFFFFFFF) | (1 << 0 /* phase bit */); + inputContext[CONTEXT_INDEX(2) + 3] = (ports[port].controlEndpoint.physical >> 32) & 0xFFFFFFFF; + inputContext[CONTEXT_INDEX(2) + 4] = 8 /* average TRB length */; + + // Allocate the output context. + + if (!MMPhysicalAllocateAndMap(OUTPUT_CONTEXT_BYTES, K_PAGE_SIZE, 0, true, + 0, (uint8_t **) &ports[port].outputContext, &ports[port].outputContextPhysical)) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate the output context for port %d.\n", port); + return; + } + + deviceContextBaseAddressArray[ports[port].slotID] = ports[port].outputContextPhysical; + + // Address the device. + // TODO Full-speed devices need their maximum packet size queried before addressing. + + dw[0] = (inputContextPhysical >> 0) & 0xFFFFFFFF; + dw[1] = (inputContextPhysical >> 32) & 0xFFFFFFFF; + dw[2] = 0; + dw[3] = (ports[port].slotID << 24) | (0 /* send SET_ADDRESS */ << 9) | (11 /* address device command */ << 10); + + if (!RunCommand(dw)) { + KernelLog(LOG_ERROR, "xHCI", "address device error", "Could not address the device on port %d.\n", port); + return; + } + + KernelLog(LOG_INFO, "xHCI", "address device", "Port %d successfully addressed.\n", port); + + // Register the device with USB subsystem. + + XHCIDevice *device = (XHCIDevice *) KDeviceCreate("XHCI device", this, sizeof(XHCIDevice)); + ports[port].device = device; + device->port = port; + device->controlTransfer = ControlTransferWrapper; + device->selectConfigurationAndInterface = SelectConfigurationAndInterfaceWrapper; + device->queueTransfer = QueueTransferWrapper; + KRegisterUSBDevice(device); + + KernelLog(LOG_INFO, "xHCI", "register device", "Port %d registered with USB subsystem.\n", port); +} + +void XHCIController::OnPortDisable(uintptr_t port) { + KMutexAcquire(&ports[port].mutex); + EsDefer(KMutexRelease(&ports[port].mutex)); + + if (ports[port].device) { + KDeviceRemoved(ports[port].device); + ports[port].device = nullptr; + } + + uint32_t dw[4]; + + // Stop endpoints. + + for (uintptr_t i = 0; i < sizeof(ports[port].ioEndpoints) / sizeof(ports[port].ioEndpoints[0]); i++) { + XHCIEndpoint *endpoint = ports[port].ioEndpoints + i; + + if (!endpoint->data) { + continue; + } + + dw[0] = dw[1] = dw[2] = 0; + dw[3] = (15 /* stop endpoint */ << 10) | ((i + 2) << 16) | (ports[port].slotID << 24); + RunCommand(dw); + + MMPhysicalFreeAndUnmap(endpoint->data, endpoint->physical); + endpoint->data = nullptr; + endpoint->physical = 0; + + KUSBTransferCallback callback = endpoint->callback; + endpoint->callback = nullptr; + + if (callback) { + callback(-1, endpoint->context); + } + } + + // Disable slot. + + dw[0] = dw[1] = dw[2] = 0; + dw[3] = (10 /* disable slot */ << 10) | (ports[port].slotID << 24); + RunCommand(dw); + + // Free the output context. + + MMPhysicalFreeAndUnmap(ports[port].outputContext, ports[port].outputContextPhysical); + deviceContextBaseAddressArray[ports[port].slotID] = ports[port].outputContextPhysical; + ports[port].outputContext = nullptr; + ports[port].outputContextPhysical = 0; + + // Free the control endpoint transfer ring. + + MMPhysicalFreeAndUnmap(ports[port].controlEndpoint.data, ports[port].controlEndpoint.physical); + ports[port].controlEndpoint.data = nullptr; + ports[port].controlEndpoint.physical = 0; + + // Zero out remaining fields in the port structure. + + ports[port].slotID = 0; + ports[port].speed = 0; + ports[port].controlTransferResult = nullptr; + ports[port].controlTransferLastTRBAddress = 0; +} + +void XHCIController::Initialise() { + portStatusChangeEvent.autoReset = true; + + // Read capabilities. + + operationalRegistersOffset = RD_REGISTER_CAPLENGTH() & 0xFF; + + if ((RD_REGISTER_CAPLENGTH() & 0xFF000000) == 0) { + KernelLog(LOG_ERROR, "xHCI", "unsupported version", "xHCI controller reports unsupported version number %x.\n", + RD_REGISTER_CAPLENGTH() >> 16); + return; + } + + uint32_t hcsp1 = RD_REGISTER_HCSPARAMS1(); + maximumDeviceSlots = (hcsp1 >> 0) & 0xFF; + maximumInterrupters = (hcsp1 >> 8) & 0x7FF; + maximumPorts = (hcsp1 >> 24) & 0xFF; + + ports = (XHCIPort *) EsHeapAllocate(sizeof(XHCIPort) * maximumPorts, true, K_FIXED); + + if (!ports) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate ports array.\n"); + return; + } + + uint32_t hcsp2 = RD_REGISTER_HCSPARAMS2(); + maximumEventRingSegments = 1 << ((hcsp2 >> 4) & 0xF); + + uint32_t scratchpadBufferCount = ((hcsp2 >> 27) & 0x1F) | (((hcsp2 >> 21) & 0x1F) << 5); + KernelLog(LOG_INFO, "xHCI", "scratchpad buffers", "Controller requests %d scratchpad buffers (HCSP2 = %x).\n", scratchpadBufferCount, hcsp2); + + uint32_t hccp1 = RD_REGISTER_HCCPARAMS1(); + contextSize64 = (hccp1 & (1 << 2)) ? true : false; + extendedCapabilitiesOffset = ((hccp1 >> 16) & 0xFFFF) << 2; + +#ifdef ARCH_64 + if (~hccp1 & (1 << 0)) { + KernelLog(LOG_ERROR, "xHCI", "missing feature", "xHCI controller does not support 64-bit addresses.\n"); + return; + } +#endif + + doorbellsOffset = RD_REGISTER_DBOFF(); + runtimeRegistersOffset = RD_REGISTER_RTSOFF(); + + KernelLog(LOG_INFO, "xHCI", "capabilities", "xHC reports capabilities: maximum ports - %d, maximum interrupts - %d, " + "maximum device slots - %d, maximum event ring segments - %d.\n", + maximumPorts, maximumInterrupters, maximumDeviceSlots, maximumEventRingSegments); + + // Enumerate extended capabilities. + + if (extendedCapabilitiesOffset) { + uintptr_t offset = extendedCapabilitiesOffset; + + for (uintptr_t i = 0; i < 256; i++) { + uint32_t extendedCapability = pci->ReadBAR32(0, offset); + uint8_t id = (extendedCapability >> 0) & 0xFF; + uint8_t next = (extendedCapability >> 8) & 0xFF; + + if (id == 1) { + // Perform BIOS handoff, if necessary. + + if (extendedCapability & (1 << 16)) { + pci->WriteBAR32(0, offset, extendedCapability & (1 << 24)); + + KTimeout timeout(1000); + while (!timeout.Hit() && (pci->ReadBAR32(0, offset) & (1 << 16))); + + if (pci->ReadBAR32(0, offset) & (1 << 16)) { + KernelLog(LOG_ERROR, "xHCI", "BIOS handoff failure", "Could not take control of the xHC from the BIOS.\n"); + return; + } + + uint32_t control = pci->ReadBAR32(0, offset + 4); + + KernelLog(LOG_INFO, "xHCI", "legacy control", "USB legacy control/status register is %x.\n", control); + + // Disable SMIs. + control &= ~((1 << 0) | (1 << 4) | (1 << 13) | (1 << 14) | (1 << 15)); + + // Clear RsvdZ bits. + control &= ~((1 << 21) | (1 << 22) | (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26) | (1 << 27) | (1 << 28)); + + // Acknowledge any status bits. + control |= (1 << 29) | (1 << 30) | (1 << 31); + + KernelLog(LOG_INFO, "xHCI", "legacy control", "Writing legacy control/status %x.\n", control); + + pci->WriteBAR32(0, offset + 4, control); + } + } else if (id == 2) { + uint32_t nameString = pci->ReadBAR32(0, offset + 4); + uint32_t portRange = pci->ReadBAR32(0, offset + 8); + uintptr_t portOffset = (portRange & 0xFF) - 1; + size_t portCount = (portRange >> 8) & 0xFF; + uint32_t slotType = pci->ReadBAR32(0, offset + 12) & 0x1F; + + KernelLog(LOG_INFO, "xHCI", "protocol enumerated", + "Controller supports protocol on ports %d->%d with version %d.%d (%s) and slot type %d.\n", + portOffset, portOffset + portCount - 1, + extendedCapability >> 24, (extendedCapability >> 16) & 0xFF, 4, &nameString, slotType); + + for (uintptr_t i = portOffset; i < portOffset + portCount; i++) { + ports[i].usb2 = (extendedCapability >> 24) == 2; + ports[i].slotType = slotType; + } + } + + if (next) { + offset += next << 2; + } else { + break; + } + } + } + + // Check page size is supported. + + if (~RD_REGISTER_PAGESIZE() & (1 << (K_PAGE_BITS - 12))) { + KernelLog(LOG_ERROR, "xHCI", "page size not supported", "xHC does not support native page size of %x; supported mask is %x.\n", + K_PAGE_SIZE, RD_REGISTER_PAGESIZE()); + return; + } + + // Stop the controller. + + KernelLog(LOG_INFO, "xHCI", "stop controller", "Stopping the controller...\n"); + + WR_REGISTER_USBCMD(RD_REGISTER_USBCMD() & ~(1 << 0)); + + { + KTimeout timeout(20); + while (!timeout.Hit() && (~RD_REGISTER_USBSTS() & (1 << 0))); + + if ((~RD_REGISTER_USBSTS() & (1 << 0))) { + KernelLog(LOG_ERROR, "xHCI", "stop failure", "Could not stop the xHC to perform a reset.\n"); + return; + } + } + + // Reset the controller. + + KernelLog(LOG_INFO, "xHCI", "reset controller", "Resetting the controller...\n"); + + WR_REGISTER_USBCMD(RD_REGISTER_USBCMD() | (1 << 1)); + + { + KTimeout timeout(100); + while (!timeout.Hit() && (RD_REGISTER_USBCMD() & (1 << 1))); + + if (RD_REGISTER_USBCMD() & (1 << 1)) { + KernelLog(LOG_ERROR, "xHCI", "reset failure", "Could not reset the xHC within 100ms.\n"); + return; + } + } + + KernelLog(LOG_INFO, "xHCI", "reset controller", "Controller successfully reset.\n"); + +#ifdef ARCH_X86_COMMON + // Any PS/2 emulation should have been disabled, so its controller is safe to initialise. + KPS2SafeToInitialise(); +#endif + + // Allocate the input context. + + if (!MMPhysicalAllocateAndMap(INPUT_CONTEXT_BYTES, K_PAGE_SIZE, 0, true, + 0, (uint8_t **) &inputContext, &inputContextPhysical)) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate the input context.\n"); + return; + } + + // Allocate the device context base address array. + + uintptr_t deviceContextBaseAddressArrayPhysical; + + if (!MMPhysicalAllocateAndMap(256 * 8, 64, 0, true, + 0, (uint8_t **) &deviceContextBaseAddressArray, &deviceContextBaseAddressArrayPhysical)) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate the device context base address array.\n"); + return; + } + + WR_REGISTER_DCBAAP(deviceContextBaseAddressArrayPhysical); + + // Allocate the command ring. + + uintptr_t commandRingPhysical; + + if (!MMPhysicalAllocateAndMap(16 * COMMAND_RING_ENTRIES, 64, 0, true, + 0, (uint8_t **) &commandRing, &commandRingPhysical)) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate the command ring.\n"); + return; + } + + if (RD_REGISTER_CRCR() & (1 << 3)) { + KernelLog(LOG_ERROR, "xHCI", "command ring running", "Command ring running while controller stopped.\n"); + return; + } + + KernelLog(LOG_INFO, "xHCI", "command ring allocation", "Allocated command ring at physical address %x.\n", commandRingPhysical); + + WR_REGISTER_CRCR(commandRingPhysical | 1); + + commandRing[COMMAND_RING_ENTRIES * 4 + 0] = commandRingPhysical & 0xFFFFFFFF; + commandRing[COMMAND_RING_ENTRIES * 4 + 1] = (commandRingPhysical >> 32) & 0xFFFFFFFF; + commandRing[COMMAND_RING_ENTRIES * 4 + 3] = (1 << 1 /* toggle cycle */) | (6 /* link TRB */ << 10); + + commandRingPhase = true; + + // Allocate the event ring. + + if (!MMPhysicalAllocateAndMap(64 + 16 * EVENT_RING_ENTRIES, 64, 0, true, + 0, (uint8_t **) &eventRing, &eventRingPhysical)) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate the command ring.\n"); + return; + } + + eventRing[0] = ((eventRingPhysical + 0x40) >> 0) & 0xFFFFFFFF; + eventRing[1] = ((eventRingPhysical + 0x40) >> 32) & 0xFFFFFFFF; + eventRing[2] = EVENT_RING_ENTRIES; + eventRing[3] = 0; + eventRingPhase = true; + + WR_REGISTER_ERDP(0, (eventRingPhysical + 0x40) | (1 << 3)); + WR_REGISTER_ERSTSZ(0, (RD_REGISTER_ERSTSZ(0) & 0xFFFF0000) | 1); + WR_REGISTER_ERSTBA(0, (RD_REGISTER_ERSTBA(0) & 0x3F) | eventRingPhysical); + + // Setup the CONFIG register. + + WR_REGISTER_CONFIG((RD_REGISTER_CONFIG() & 0xFFFFFC00) | maximumDeviceSlots); + + // Register the interrupt handler and enable interrupts. + + KIRQHandler handler = [] (uintptr_t, void *context) { return ((XHCIController *) context)->HandleIRQ(); }; + + if (!pci->EnableSingleInterrupt(handler, this, "xHCI")) { + KernelLog(LOG_ERROR, "xHCI", "IRQ registration failure", "Could not register interrupt handler.\n"); + return; + } + + WR_REGISTER_IMOD(0, 4000 /* in 250ns increments */); // Interrupts should be sent at most every millisecond. + WR_REGISTER_IMAN(0, RD_REGISTER_IMAN(0) | (1 << 1)); + WR_REGISTER_USBCMD(RD_REGISTER_USBCMD() | (1 << 2)); + + // Allocate scratchpad buffers. + + if (scratchpadBufferCount) { + uint64_t *scratchpadArray; + uintptr_t scratchpadArrayPhysical; + + if (!MMPhysicalAllocateAndMap(scratchpadBufferCount * sizeof(uint64_t), 64, 0, true, + 0, (uint8_t **) &scratchpadArray, &scratchpadArrayPhysical)) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate the scratchpad buffer array.\n"); + return; + } + + for (uintptr_t i = 0; i < scratchpadBufferCount; i++) { + scratchpadArray[i] = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_CAN_FAIL | MM_PHYSICAL_ALLOCATE_COMMIT_NOW | MM_PHYSICAL_ALLOCATE_ZEROED); + + if (!scratchpadArray[i]) { + KernelLog(LOG_ERROR, "xHCI", "allocation failure", "Could not allocate scratchpad buffer %d.\n", i); + return; + } + } + + deviceContextBaseAddressArray[0] = scratchpadArrayPhysical; + } + + // Start the controller! + + KernelLog(LOG_INFO, "xHCI", "start controller", "Starting controller...\n"); + + WR_REGISTER_USBCMD(RD_REGISTER_USBCMD() | (1 << 0)); + + { + KTimeout timeout(20); + while (!timeout.Hit() && (RD_REGISTER_USBSTS() & (1 << 0))); + + if ((RD_REGISTER_USBSTS() & (1 << 0))) { + KernelLog(LOG_ERROR, "xHCI", "start failure", "Could not start the xHC after reset.\n"); + return; + } + } + + KernelLog(LOG_INFO, "xHCI", "start controller", "Controller successfully started.\n"); + + // Reset USB2 ports. + // TODO Will we receive events for connected USB3 ports automatically, or do we need to do something? + + KSpinlockAcquire(&portResetSpinlock); + + for (uintptr_t i = 0; i < maximumPorts; i++) { + uint32_t status = RD_REGISTER_PORTSC(i); + uint32_t linkState = (status >> 5) & 0x0F; + KernelLog(LOG_INFO, "xHCI", "port status", "Port %d (USB %d) has status %x (link state = %d).\n", i, ports[i].usb2 ? 2 : 3, status, linkState); + + if (ports[i].usb2 && (linkState == 7 || linkState == 4) && (~status & (1 << 4))) { + KernelLog(LOG_INFO, "xHCI", "port reset", "Attempting to reset USB 2 port %d... (2)\n", i); + WR_REGISTER_PORTSC(i, (status & (1 << 9)) | (1 << 4)); + } + } + + KSpinlockRelease(&portResetSpinlock); + + // Wait for events to process. + + while (true) { + uintptr_t port = 0; + + for (uintptr_t i = 0; i < maximumPorts; i++) { + if (ports[i].statusChangeEvent) { + port = i; + goto found; + } + } + + KEventWait(&portStatusChangeEvent); + continue; + + found:; + ports[port].statusChangeEvent = false; + + if (ports[port].enabled) { + OnPortEnable(port); + } else { + OnPortDisable(port); + } + } +} + +static void DeviceAttach(KDevice *_parent) { + KPCIDevice *parent = (KPCIDevice *) _parent; + + XHCIController *device = (XHCIController *) KDeviceCreate("XHCI controller", parent, sizeof(XHCIController)); + if (!device) return; + device->pci = parent; + + device->dumpState = [] (KDevice *device) { + ((XHCIController *) device)->DumpState(); + }; + + KernelLog(LOG_INFO, "xHCI", "found controller", "Found XHCI controller at PCI function %d/%d/%d.\n", parent->bus, parent->slot, parent->function); + + // Enable PCI features. + parent->EnableFeatures(K_PCI_FEATURE_INTERRUPTS + | K_PCI_FEATURE_BUSMASTERING_DMA + | K_PCI_FEATURE_MEMORY_SPACE_ACCESS + | K_PCI_FEATURE_BAR_0); + + // Initialise the controller on a new thread. + KThreadCreate("XHCIInitialisation", [] (uintptr_t context) { + ((XHCIController *) context)->Initialise(); + }, (uintptr_t) device); +} + +KDriver driverxHCI = { + .attach = DeviceAttach, +}; diff --git a/kernel/audio.cpp b/kernel/audio.cpp new file mode 100644 index 0000000..e69de29 diff --git a/kernel/cache.cpp b/kernel/cache.cpp new file mode 100644 index 0000000..e4e221b --- /dev/null +++ b/kernel/cache.cpp @@ -0,0 +1,1220 @@ +#ifndef IMPLEMENTATION + +// TODO Implement read ahead in CCSpaceAccess. +// TODO Implement dispatch groups in CCSpaceAccess and CCWriteBehindThread. +// TODO Implement better write back algorithm. + +// TODO Check that active.references in the page frame database is used safely with threading. + +// Describes the physical memory covering a section of a file. + +struct CCCachedSection { + EsFileOffset offset, // The offset into the file. + pageCount; // The number of pages in the section. + volatile size_t mappedRegionsCount; // The number of mapped regions that use this section. + uintptr_t *data; // A list of page frames covering the section. +}; + +struct CCActiveSection { + KEvent loadCompleteEvent, writeCompleteEvent; + LinkedItem listItem; // Either in the LRU list, or the modified list. If accessors > 0, it should not be in a list. + + EsFileOffset offset; + struct CCSpace *cache; + + size_t accessors; + volatile bool loading, writing, modified, flush; + + uint16_t referencedPageCount; + uint8_t referencedPages[CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE / 8]; // If accessors > 0, then pages cannot be dereferenced. + + uint8_t modifiedPages[CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE / 8]; +}; + +struct CCActiveSectionReference { + EsFileOffset offset; // Offset into the file; multiple of CC_ACTIVE_SECTION_SIZE. + uintptr_t index; // Index of the active section. +}; + +struct MMActiveSectionManager { + CCActiveSection *sections; + size_t sectionCount; + uint8_t *baseAddress; + KMutex mutex; + LinkedList lruList; + LinkedList modifiedList; + KEvent modifiedNonEmpty, modifiedNonFull; + Thread *writeBackThread; +}; + +// The callbacks for a CCSpace. + +struct CCSpaceCallbacks { + EsError (*readInto)(CCSpace *fileCache, void *buffer, EsFileOffset offset, EsFileOffset count); + EsError (*writeFrom)(CCSpace *fileCache, const void *buffer, EsFileOffset offset, EsFileOffset count); +}; + +// Describes the physical and virtual memory covering a file. + +struct CCSpace { + // A sorted list of the cached sections in the file. + // Maps offset -> physical address. + KMutex cachedSectionsMutex; + Array cachedSections; + + // A sorted list of the active sections. + // Maps offset -> virtual address. + KMutex activeSectionsMutex; + Array activeSections; + + // Used by CCSpaceFlush. + KEvent writeComplete; + + // Callbacks. + const CCSpaceCallbacks *callbacks; +}; + +void CCInitialise(); + +void CCDereferenceActiveSection(CCActiveSection *section, uintptr_t startingPage = 0); + +bool CCSpaceInitialise(CCSpace *cache); +void CCSpaceDestroy(CCSpace *cache); +void CCSpaceFlush(CCSpace *cache); +void CCSpaceTruncate(CCSpace *cache, EsFileOffset newSize); +bool CCSpaceCover(CCSpace *cache, EsFileOffset insertStart, EsFileOffset insertEnd); +void CCSpaceUncover(CCSpace *cache, EsFileOffset removeStart, EsFileOffset removeEnd); + +#define CC_ACCESS_MAP (1 << 0) +#define CC_ACCESS_READ (1 << 1) +#define CC_ACCESS_WRITE (1 << 2) +#define CC_ACCESS_WRITE_BACK (1 << 3) // Wait for the write to complete before returning. +#define CC_ACCESS_PRECISE (1 << 4) // Do not write back bytes not touched by this write. (Usually modified tracking is to page granularity.) Requires WRITE_BACK. +#define CC_ACCESS_USER_BUFFER_MAPPED (1 << 5) // Set if the user buffer is memory-mapped to mirror this or another cache. + +EsError CCSpaceAccess(CCSpace *cache, K_USER_BUFFER void *buffer, EsFileOffset offset, EsFileOffset count, uint32_t flags, + MMSpace *mapSpace = nullptr, unsigned mapFlags = ES_FLAGS_DEFAULT); + +#else + +CCCachedSection *CCFindCachedSectionContaining(CCSpace *cache, EsFileOffset sectionOffset) { + KMutexAssertLocked(&cache->cachedSectionsMutex); + + if (!cache->cachedSections.Length()) { + return nullptr; + } + + CCCachedSection *cachedSection = nullptr; + + bool found = false; + intptr_t low = 0, high = cache->cachedSections.Length() - 1; + + while (low <= high) { + intptr_t i = low + (high - low) / 2; + cachedSection = &cache->cachedSections[i]; + + if (cachedSection->offset + cachedSection->pageCount * K_PAGE_SIZE <= sectionOffset) { + low = i + 1; + } else if (cachedSection->offset > sectionOffset) { + high = i - 1; + } else { + found = true; + break; + } + } + + return found ? cachedSection : nullptr; +} + +bool CCSpaceCover(CCSpace *cache, EsFileOffset insertStart, EsFileOffset insertEnd) { + KMutexAssertLocked(&cache->cachedSectionsMutex); + + // TODO Test this thoroughly. + // TODO Break up really large sections. (maybe into GBs?) + + insertStart = RoundDown(insertStart, K_PAGE_SIZE); + insertEnd = RoundUp(insertEnd, K_PAGE_SIZE); + EsFileOffset position = insertStart, lastEnd = 0; + CCCachedSection *result = nullptr; + + // EsPrint("New: %d, %d\n", insertStart / K_PAGE_SIZE, insertEnd / K_PAGE_SIZE); + + for (uintptr_t i = 0; i < cache->cachedSections.Length(); i++) { + CCCachedSection *section = &cache->cachedSections[i]; + + EsFileOffset sectionStart = section->offset, + sectionEnd = section->offset + section->pageCount * K_PAGE_SIZE; + + // EsPrint("Existing (%d): %d, %d\n", i, sectionStart / K_PAGE_SIZE, sectionEnd / K_PAGE_SIZE); + + if (insertStart > sectionEnd) continue; + + // If the inserted region starts before this section starts, then we need to make a new section before us. + + if (position < sectionStart) { + CCCachedSection newSection = {}; + newSection.mappedRegionsCount = 0; + newSection.offset = position; + newSection.pageCount = ((insertEnd > sectionStart ? sectionStart : insertEnd) - position) / K_PAGE_SIZE; + + if (newSection.pageCount) { + // EsPrint("\tAdded: %d, %d\n", newSection.offset / K_PAGE_SIZE, newSection.pageCount); + newSection.data = (uintptr_t *) EsHeapAllocate(sizeof(uintptr_t) * newSection.pageCount, true, K_CORE); + + if (!newSection.data) { + goto fail; + } + + if (!cache->cachedSections.Insert(newSection, i)) { + EsHeapFree(newSection.data, sizeof(uintptr_t) * newSection.pageCount, K_CORE); + goto fail; + } + + i++; + } + + } + + position = sectionEnd; + if (position > insertEnd) break; + } + + // Insert the final section if necessary. + + if (position < insertEnd) { + CCCachedSection newSection = {}; + newSection.mappedRegionsCount = 0; + newSection.offset = position; + newSection.pageCount = (insertEnd - position) / K_PAGE_SIZE; + newSection.data = (uintptr_t *) EsHeapAllocate(sizeof(uintptr_t) * newSection.pageCount, true, K_CORE); + // EsPrint("\tAdded (at end): %d, %d\n", newSection.offset / K_PAGE_SIZE, newSection.pageCount); + + if (!newSection.data) { + goto fail; + } + + if (!cache->cachedSections.Add(newSection)) { + EsHeapFree(newSection.data, sizeof(uintptr_t) * newSection.pageCount, K_CORE); + goto fail; + } + } + + for (uintptr_t i = 0; i < cache->cachedSections.Length(); i++) { + CCCachedSection *section = &cache->cachedSections[i]; + + EsFileOffset sectionStart = section->offset, + sectionEnd = section->offset + section->pageCount * K_PAGE_SIZE; + + if (sectionStart < lastEnd) KernelPanic("CCSpaceCover - Overlapping MMCachedSections.\n"); + + // If the inserted region ends after this section starts, + // and starts before this section ends, then it intersects it. + + if (insertEnd > sectionStart && insertStart < sectionEnd) { + section->mappedRegionsCount++; + // EsPrint("+ %x %x %d\n", cache, section->data, section->mappedRegionsCount); + if (result && sectionStart != lastEnd) KernelPanic("CCSpaceCover - Incomplete MMCachedSections.\n"); + if (!result) result = section; + } + + lastEnd = sectionEnd; + } + + return true; + + fail:; + return false; // TODO Remove unused cached sections? +} + +void CCSpaceUncover(CCSpace *cache, EsFileOffset removeStart, EsFileOffset removeEnd) { + KMutexAssertLocked(&cache->cachedSectionsMutex); + + removeStart = RoundDown(removeStart, K_PAGE_SIZE); + removeEnd = RoundUp(removeEnd, K_PAGE_SIZE); + + CCCachedSection *first = CCFindCachedSectionContaining(cache, removeStart); + + if (!first) { + KernelPanic("CCSpaceUncover - Range %x->%x was not covered in cache %x.\n", removeStart, removeEnd, cache); + } + + for (uintptr_t i = first - cache->cachedSections.array; i < cache->cachedSections.Length(); i++) { + CCCachedSection *section = &cache->cachedSections[i]; + + EsFileOffset sectionStart = section->offset, + sectionEnd = section->offset + section->pageCount * K_PAGE_SIZE; + + if (removeEnd > sectionStart && removeStart < sectionEnd) { + if (!section->mappedRegionsCount) KernelPanic("CCSpaceUncover - Section wasn't mapped.\n"); + section->mappedRegionsCount--; + // EsPrint("- %x %x %d\n", cache, section->data, section->mappedRegionsCount); + } else { + break; + } + } +} + +void CCWriteSectionPrepare(CCActiveSection *section) { + KMutexAssertLocked(&activeSectionManager.mutex); + if (!section->modified) KernelPanic("CCWriteSectionPrepare - Unmodified section %x on modified list.\n", section); + if (section->accessors) KernelPanic("CCWriteSectionPrepare - Section %x with accessors on modified list.\n", section); + if (section->writing) KernelPanic("CCWriteSectionPrepare - Section %x already being written.\n", section); + activeSectionManager.modifiedList.Remove(§ion->listItem); + section->writing = true; + section->modified = false; + section->flush = false; + KEventReset(§ion->writeCompleteEvent); + section->accessors = 1; +} + +void CCWriteSection(CCActiveSection *section) { + // Write any modified pages to the backing store. + + uint8_t *sectionBase = activeSectionManager.baseAddress + (section - activeSectionManager.sections) * CC_ACTIVE_SECTION_SIZE; + EsError error = ES_SUCCESS; + + for (uintptr_t i = 0; i < CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE; i++) { + uintptr_t from = i, count = 0; + + while (i != CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE + && (section->modifiedPages[i >> 3] & (1 << (i & 7)))) { + count++, i++; + } + + if (!count) continue; + + error = section->cache->callbacks->writeFrom(section->cache, sectionBase + from * K_PAGE_SIZE, + section->offset + from * K_PAGE_SIZE, count * K_PAGE_SIZE); + + if (error != ES_SUCCESS) { + break; + } + } + + // Return the active section. + + KMutexAcquire(&activeSectionManager.mutex); + + if (!section->accessors) KernelPanic("CCWriteSection - Section %x has no accessors while being written.\n", section); + if (section->modified) KernelPanic("CCWriteSection - Section %x was modified while being written.\n", section); + + section->accessors--; + section->writing = false; + EsMemoryZero(section->modifiedPages, sizeof(section->modifiedPages)); + __sync_synchronize(); + KEventSet(§ion->writeCompleteEvent); + KEventSet(§ion->cache->writeComplete, false, true); + + if (!section->accessors) { + if (section->loading) KernelPanic("CCSpaceAccess - Active section %x with no accessors is loading.", section); + activeSectionManager.lruList.InsertEnd(§ion->listItem); + } + + KMutexRelease(&activeSectionManager.mutex); +} + +void CCSpaceFlush(CCSpace *cache) { + while (true) { + bool complete = true; + + KMutexAcquire(&cache->activeSectionsMutex); + KMutexAcquire(&activeSectionManager.mutex); + + for (uintptr_t i = 0; i < cache->activeSections.Length(); i++) { + CCActiveSection *section = activeSectionManager.sections + cache->activeSections[i].index; + + if (section->cache == cache && section->offset == cache->activeSections[i].offset) { + if (section->writing) { + // The section is being written; wait for it to complete. + complete = false; + } else if (section->modified) { + if (section->accessors) { + // Someone is accessing this section; mark it to be written back once they are done. + section->flush = true; + complete = false; + } else { + // Nobody is accessing the section; we can write it ourselves. + complete = false; + CCWriteSectionPrepare(section); + KMutexRelease(&activeSectionManager.mutex); + KMutexRelease(&cache->activeSectionsMutex); + CCWriteSection(section); + KMutexAcquire(&cache->activeSectionsMutex); + KMutexAcquire(&activeSectionManager.mutex); + } + } + } + + } + + KMutexRelease(&activeSectionManager.mutex); + KMutexRelease(&cache->activeSectionsMutex); + + if (!complete) { + KEventWait(&cache->writeComplete); + } else { + break; + } + } +} + +void CCActiveSectionReturnToLists(CCActiveSection *section, bool writeBack) { + bool waitNonFull = false; + + if (section->flush) { + writeBack = true; + } + + while (true) { + // If modified, wait for the modified list to be below a certain size. + + if (section->modified && waitNonFull) { + KEventWait(&activeSectionManager.modifiedNonFull); + } + + // Decrement the accessors count. + + KMutexAcquire(&activeSectionManager.mutex); + EsDefer(KMutexRelease(&activeSectionManager.mutex)); + + if (!section->accessors) KernelPanic("CCSpaceAccess - Active section %x has no accessors.\n", section); + + if (section->accessors == 1) { + if (section->loading) KernelPanic("CCSpaceAccess - Active section %x with no accessors is loading.", section); + + // If nobody is accessing the section, put it at the end of the LRU list. + + if (section->modified) { + if (activeSectionManager.modifiedList.count > CC_MAX_MODIFIED) { + waitNonFull = true; + continue; + } else if (activeSectionManager.modifiedList.count == CC_MAX_MODIFIED) { + KEventReset(&activeSectionManager.modifiedNonFull); + } + + activeSectionManager.modifiedList.InsertEnd(§ion->listItem); + KEventSet(&activeSectionManager.modifiedNonEmpty, false, true); + } else { + activeSectionManager.lruList.InsertEnd(§ion->listItem); + } + } + + section->accessors--; + + if (writeBack && !section->accessors && section->modified) { + CCWriteSectionPrepare(section); + } else { + writeBack = false; + } + + break; + } + + if (writeBack) { + CCWriteSection(section); + } +} + +void CCSpaceTruncate(CCSpace *cache, size_t newSize) { + // Concurrent calls to CCSpaceAccess must be prevented; + // this only handles concurrent calls to CCWriteSection. + + uintptr_t newSizePages = (newSize + K_PAGE_SIZE - 1) / K_PAGE_SIZE; + bool doneActiveSections = false; + + while (!doneActiveSections) { + bool waitForWritingToComplete = false; + CCActiveSection *section = nullptr; + + KMutexAcquire(&cache->activeSectionsMutex); + KMutexAcquire(&activeSectionManager.mutex); + + if (cache->activeSections.Length()) { + // Get the last active section. + CCActiveSectionReference reference = cache->activeSections.Last(); + section = activeSectionManager.sections + reference.index; + + if (section->cache != cache || section->offset != reference.offset) { + // Remove invalid section. + // TODO This code path has not been tested. + cache->activeSections.SetLength(cache->activeSections.Length() - 1); + section = nullptr; + } else { + if (reference.offset + CC_ACTIVE_SECTION_SIZE <= newSize) { + // We've cleared all the active sections that were past the truncation point. + doneActiveSections = true; + section = nullptr; + } else { + if (section->accessors) { + // We want to remove part/all of this section, but it's being written, + // so we'll wait for that to complete first. + + if (!section->writing) { + KernelPanic("CCSpaceTruncate - Active section %x in space %x has accessors but isn't being written.\n", + section, cache); + } + + waitForWritingToComplete = true; + } else { + section->listItem.RemoveFromList(); + } + + if (section->loading) { + // TODO How will this interact with read-ahead, once implemented? + KernelPanic("CCSpaceTruncate - Active section %x in space %x is in the loading state.\n", + section, cache); + } + + section->accessors++; + + if (section->offset >= newSize) { + cache->activeSections.SetLength(cache->activeSections.Length() - 1); + } + } + + } + } else { + doneActiveSections = true; + } + + KMutexRelease(&activeSectionManager.mutex); + KMutexRelease(&cache->activeSectionsMutex); + + if (section) { + if (waitForWritingToComplete) { + KEventWait(§ion->writeCompleteEvent); + } + + if (section->offset >= newSize) { + // Remove active sections completely past the truncation point. + KMutexAcquire(&cache->cachedSectionsMutex); + CCSpaceUncover(cache, section->offset, section->offset + CC_ACTIVE_SECTION_SIZE); + KMutexRelease(&cache->cachedSectionsMutex); + KMutexAcquire(&activeSectionManager.mutex); + CCDereferenceActiveSection(section); + section->cache = nullptr; + section->accessors = 0; + section->modified = false; // Don't try to write this section back! + activeSectionManager.lruList.InsertStart(§ion->listItem); + KMutexRelease(&activeSectionManager.mutex); + } else { + // Remove part of the active section containing the truncation point. + KMutexAcquire(&activeSectionManager.mutex); + CCDereferenceActiveSection(section, newSizePages - section->offset / K_PAGE_SIZE); + KMutexRelease(&activeSectionManager.mutex); + CCActiveSectionReturnToLists(section, false); + break; + } + } + } + + KMutexAcquire(&cache->cachedSectionsMutex); + + while (cache->cachedSections.Length()) { + CCCachedSection *section = &cache->cachedSections.Last(); + + uintptr_t firstPage = 0; + + if (section->offset / K_PAGE_SIZE < newSizePages) { + firstPage = newSizePages - section->offset / K_PAGE_SIZE; + } + + if (firstPage > section->pageCount) { + // Don't early exit if firstPage = section->pageCount, since there could be a partialPage to clear. + break; + } + + for (uintptr_t i = firstPage; i < section->pageCount; i++) { + KMutexAcquire(&pmm.pageFrameMutex); + + if (section->data[i] & MM_SHARED_ENTRY_PRESENT) { + uintptr_t page = section->data[i] & ~(K_PAGE_SIZE - 1); + + if (pmm.pageFrames[page >> K_PAGE_BITS].state != MMPageFrame::ACTIVE) { + MMPhysicalActivatePages(page >> K_PAGE_BITS, 1, ES_FLAGS_DEFAULT); + } + + // Deallocate physical memory no longer in use. + MMPhysicalFree(page, true, 1); + + section->data[i] = 0; + } + + KMutexRelease(&pmm.pageFrameMutex); + } + + if (firstPage) { + if (newSize & (K_PAGE_SIZE - 1)) { + uintptr_t partialPage = (newSize - section->offset) / K_PAGE_SIZE; + + if (partialPage >= section->pageCount) { + KernelPanic("CCSpaceTruncate - partialPage %x outside range in CCSpace %x with new size %x.\n", + partialPage, cache, newSize); + } + + if (section->data[partialPage] & MM_SHARED_ENTRY_PRESENT) { + // Zero the inaccessible part of the last page still accessible after truncation. + PMZeroPartial(section->data[partialPage] & ~(K_PAGE_SIZE - 1), newSize & (K_PAGE_SIZE - 1), K_PAGE_SIZE); + } + } + + break; + } else { + if (section->mappedRegionsCount) { + KernelPanic("CCSpaceTruncate - Section %x has positive mappedRegionsCount in CCSpace %x.", + section, cache); + } + + EsHeapFree(section->data, sizeof(uintptr_t) * section->pageCount, K_CORE); + cache->cachedSections.SetLength(cache->cachedSections.Length() - 1); + } + } + + KMutexRelease(&cache->cachedSectionsMutex); +} + +void CCSpaceDestroy(CCSpace *cache) { + CCSpaceFlush(cache); + + for (uintptr_t i = 0; i < cache->activeSections.Length(); i++) { + KMutexAcquire(&activeSectionManager.mutex); + + CCActiveSection *section = activeSectionManager.sections + cache->activeSections[i].index; + + if (section->cache == cache && section->offset == cache->activeSections[i].offset) { + CCDereferenceActiveSection(section); + section->cache = nullptr; + + if (section->accessors || section->modified || section->listItem.list != &activeSectionManager.lruList) { + KernelPanic("CCSpaceDestroy - Section %x has invalid state to destroy cache space %x.\n", + section, cache); + } + + section->listItem.RemoveFromList(); + activeSectionManager.lruList.InsertStart(§ion->listItem); + } + + KMutexRelease(&activeSectionManager.mutex); + } + + for (uintptr_t i = 0; i < cache->cachedSections.Length(); i++) { + CCCachedSection *section = &cache->cachedSections[i]; + + for (uintptr_t i = 0; i < section->pageCount; i++) { + KMutexAcquire(&pmm.pageFrameMutex); + + if (section->data[i] & MM_SHARED_ENTRY_PRESENT) { + uintptr_t page = section->data[i] & ~(K_PAGE_SIZE - 1); + + if (pmm.pageFrames[page >> K_PAGE_BITS].state != MMPageFrame::ACTIVE) { + MMPhysicalActivatePages(page >> K_PAGE_BITS, 1, ES_FLAGS_DEFAULT); + } + + MMPhysicalFree(page, true, 1); + } + + KMutexRelease(&pmm.pageFrameMutex); + } + + EsHeapFree(section->data, sizeof(uintptr_t) * section->pageCount, K_CORE); + } + + cache->cachedSections.Free(); + cache->activeSections.Free(); +} + +bool CCSpaceInitialise(CCSpace *cache) { + cache->writeComplete.autoReset = true; + return true; +} + +void CCDereferenceActiveSection(CCActiveSection *section, uintptr_t startingPage) { + KMutexAssertLocked(&activeSectionManager.mutex); + + if (!startingPage) { + MMArchUnmapPages(kernelMMSpace, + (uintptr_t) activeSectionManager.baseAddress + (section - activeSectionManager.sections) * CC_ACTIVE_SECTION_SIZE, + CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE, MM_UNMAP_PAGES_BALANCE_FILE); + EsMemoryZero(section->referencedPages, sizeof(section->referencedPages)); + EsMemoryZero(section->modifiedPages, sizeof(section->modifiedPages)); + section->referencedPageCount = 0; + } else { + MMArchUnmapPages(kernelMMSpace, + (uintptr_t) activeSectionManager.baseAddress + + (section - activeSectionManager.sections) * CC_ACTIVE_SECTION_SIZE + + startingPage * K_PAGE_SIZE, + (CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE - startingPage), MM_UNMAP_PAGES_BALANCE_FILE); + + for (uintptr_t i = startingPage; i < CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE; i++) { + if (section->referencedPages[i >> 3] & (1 << (i & 7))) { + section->referencedPages[i >> 3] &= ~(1 << (i & 7)); + section->modifiedPages[i >> 3] &= ~(1 << (i & 7)); + section->referencedPageCount--; + } + } + } +} + +EsError CCSpaceAccess(CCSpace *cache, K_USER_BUFFER void *_buffer, EsFileOffset offset, EsFileOffset count, uint32_t flags, + MMSpace *mapSpace, unsigned mapFlags) { + // TODO Reading in multiple active sections at the same time - will this give better performance on AHCI/NVMe? + // - Each active section needs to be separately committed. + // TODO Read-ahead. + + // Commit CC_ACTIVE_SECTION_SIZE bytes, since we require an active section to be active at a time. + + if (!MMCommit(CC_ACTIVE_SECTION_SIZE, true)) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + EsDefer(MMDecommit(CC_ACTIVE_SECTION_SIZE, true)); + + K_USER_BUFFER uint8_t *buffer = (uint8_t *) _buffer; + + EsFileOffset firstSection = RoundDown(offset, CC_ACTIVE_SECTION_SIZE), + lastSection = RoundUp(offset + count, CC_ACTIVE_SECTION_SIZE); + + uintptr_t guessedActiveSectionIndex = 0; + + bool writeBack = (flags & CC_ACCESS_WRITE_BACK) && (~flags & CC_ACCESS_PRECISE); + bool preciseWriteBack = (flags & CC_ACCESS_WRITE_BACK) && (flags & CC_ACCESS_PRECISE); + + for (EsFileOffset sectionOffset = firstSection; sectionOffset < lastSection; sectionOffset += CC_ACTIVE_SECTION_SIZE) { + if (MM_AVAILABLE_PAGES() < MM_CRITICAL_AVAILABLE_PAGES_THRESHOLD && !GetCurrentThread()->isPageGenerator) { + KernelLog(LOG_ERROR, "Memory", "waiting for non-critical state", "File cache read on non-generator thread, waiting for more available pages.\n"); + KEventWait(&pmm.availableNotCritical); + } + + EsFileOffset start = sectionOffset < offset ? offset - sectionOffset : 0; + EsFileOffset end = sectionOffset + CC_ACTIVE_SECTION_SIZE > offset + count ? offset + count - sectionOffset : CC_ACTIVE_SECTION_SIZE; + + EsFileOffset pageStart = RoundDown(start, K_PAGE_SIZE) / K_PAGE_SIZE; + EsFileOffset pageEnd = RoundUp(end, K_PAGE_SIZE) / K_PAGE_SIZE; + + // Find the section in the active sections list. + + KMutexAcquire(&cache->activeSectionsMutex); + + bool found = false; + uintptr_t index = 0; + + if (guessedActiveSectionIndex < cache->activeSections.Length() + && cache->activeSections[guessedActiveSectionIndex].offset == sectionOffset) { + index = guessedActiveSectionIndex; + found = true; + } + + if (!found && cache->activeSections.Length()) { + intptr_t low = 0, high = cache->activeSections.Length() - 1; + + while (low <= high) { + intptr_t i = low + (high - low) / 2; + + if (cache->activeSections[i].offset < sectionOffset) { + low = i + 1; + } else if (cache->activeSections[i].offset > sectionOffset) { + high = i - 1; + } else { + index = i; + found = true; + break; + } + } + + if (!found) { + index = low; + if (high + 1 != low) KernelPanic("CCSpaceAccess - Bad binary search.\n"); + } + } + + if (found) { + guessedActiveSectionIndex = index + 1; + } + + KMutexAcquire(&activeSectionManager.mutex); + + CCActiveSection *section; + + // Replace active section in list if it has been used for something else. + + bool replace = false; + + if (found) { + CCActiveSection *section = activeSectionManager.sections + cache->activeSections[index].index; + + if (section->cache != cache || section->offset != sectionOffset) { + replace = true, found = false; + } + } + + if (!found) { + // Allocate a new active section. + + if (!activeSectionManager.lruList.count) { + KMutexRelease(&activeSectionManager.mutex); + KMutexRelease(&cache->activeSectionsMutex); + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + section = activeSectionManager.lruList.firstItem->thisItem; + + // Add it to the file cache's list of active sections. + + CCActiveSectionReference reference = { .offset = sectionOffset, .index = (uintptr_t) (section - activeSectionManager.sections) }; + + if (replace) { + cache->activeSections[index] = reference; + } else { + if (!cache->activeSections.Insert(reference, index)) { + KMutexRelease(&activeSectionManager.mutex); + KMutexRelease(&cache->activeSectionsMutex); + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + } + + if (section->cache) { + // Dereference pages. + + if (section->accessors) { + KernelPanic("CCSpaceAccess - Attempting to dereference active section %x with %d accessors.\n", + section, section->accessors); + } + + CCDereferenceActiveSection(section); + + // Uncover the section's previous contents. + + KMutexAcquire(§ion->cache->cachedSectionsMutex); + CCSpaceUncover(section->cache, section->offset, section->offset + CC_ACTIVE_SECTION_SIZE); + KMutexRelease(§ion->cache->cachedSectionsMutex); + + section->cache = nullptr; + } + + // Make sure there are cached sections covering the region of the active section. + + KMutexAcquire(&cache->cachedSectionsMutex); + + if (!CCSpaceCover(cache, sectionOffset, sectionOffset + CC_ACTIVE_SECTION_SIZE)) { + KMutexRelease(&cache->cachedSectionsMutex); + cache->activeSections.Delete(index); + KMutexRelease(&activeSectionManager.mutex); + KMutexRelease(&cache->activeSectionsMutex); + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + KMutexRelease(&cache->cachedSectionsMutex); + + // Remove it from the LRU list. + + activeSectionManager.lruList.Remove(activeSectionManager.lruList.firstItem); + + // Setup the section. + + if (section->accessors) KernelPanic("CCSpaceAccess - Active section %x in the LRU list had accessors.\n", section); + if (section->loading) KernelPanic("CCSpaceAccess - Active section %x in the LRU list was loading.\n", section); + + section->accessors = 1; + section->offset = sectionOffset; + section->cache = cache; + +#if 0 + { + Node *node = EsContainerOf(Node, file.cache, cache); + EsPrint("active section %d: %s, %x\n", reference.index, node->nameBytes, node->nameBuffer, section->offset); + } +#endif + +#ifdef DEBUG_BUILD + for (uintptr_t i = 1; i < cache->activeSections.Length(); i++) { + if (cache->activeSections[i - 1].offset >= cache->activeSections[i].offset) { + KernelPanic("CCSpaceAccess - Active sections list in cache %x unordered.\n", cache); + } + } +#endif + } else { + // Remove the active section from the LRU/modified list, if present, + // and increment the accessors count. + // Don't bother keeping track of its place in the modified list. + + section = activeSectionManager.sections + cache->activeSections[index].index; + + if (!section->accessors) { + if (section->writing) KernelPanic("CCSpaceAccess - Active section %x in list is being written.\n", section); + section->listItem.RemoveFromList(); + } else if (section->listItem.list) { + KernelPanic("CCSpaceAccess - Active section %x in list had accessors (2).\n", section); + } + + section->accessors++; + } + + KMutexRelease(&activeSectionManager.mutex); + KMutexRelease(&cache->activeSectionsMutex); + + if ((flags & CC_ACCESS_WRITE) && section->writing) { + // If writing, wait for any in progress write-behinds to complete. + // Note that, once this event is set, a new write can't be started until accessors is 0. + + KEventWait(§ion->writeCompleteEvent); + } + + uint8_t *sectionBase = activeSectionManager.baseAddress + (section - activeSectionManager.sections) * CC_ACTIVE_SECTION_SIZE; + + // Check if all the pages are already referenced (and hence loaded and mapped). + + bool allReferenced = true; + + for (uintptr_t i = pageStart; i < pageEnd; i++) { + if (~section->referencedPages[i >> 3] & (1 << (i & 7))) { + allReferenced = false; + break; + } + } + + uint8_t alreadyWritten[CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE / 8] = {}; + + if (allReferenced) { + goto copy; + } + + while (true) { + KMutexAcquire(&cache->cachedSectionsMutex); + + // Find the first cached section covering this active section. + + CCCachedSection *cachedSection = CCFindCachedSectionContaining(cache, sectionOffset); + + if (!cachedSection) { + KernelPanic("CCSpaceAccess - Active section %x not covered.\n", section); + } + + // Find where the requested region is located. + + uintptr_t pagesToSkip = pageStart + (sectionOffset - cachedSection->offset) / K_PAGE_SIZE, + pageInCachedSectionIndex = 0; + + while (pagesToSkip) { + if (pagesToSkip >= cachedSection->pageCount) { + pagesToSkip -= cachedSection->pageCount; + cachedSection++; + } else { + pageInCachedSectionIndex = pagesToSkip; + pagesToSkip = 0; + } + } + + if (pageInCachedSectionIndex >= cachedSection->pageCount + || cachedSection >= cache->cachedSections.array + cache->cachedSections.Length()) { + KernelPanic("CCSpaceAccess - Invalid requested region search result.\n"); + } + + // Reference all loaded pages, and record the ones we need to load. + + uintptr_t *pagesToLoad[CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE]; + uintptr_t loadCount = 0; + + for (uintptr_t i = pageStart; i < pageEnd; i++) { + if (cachedSection == cache->cachedSections.array + cache->cachedSections.Length()) { + KernelPanic("CCSpaceAccess - Not enough cached sections.\n"); + } + + KMutexAcquire(&pmm.pageFrameMutex); + + uintptr_t entry = cachedSection->data[pageInCachedSectionIndex]; + pagesToLoad[i] = nullptr; + + if ((entry & MM_SHARED_ENTRY_PRESENT) && (~section->referencedPages[i >> 3] & (1 << (i & 7)))) { + MMPageFrame *frame = pmm.pageFrames + (entry >> K_PAGE_BITS); + + if (frame->state == MMPageFrame::STANDBY) { + // The page was mapped out from all MMSpaces, and therefore was placed on the standby list. + // Mark the page as active before we map it. + MMPhysicalActivatePages(entry / K_PAGE_SIZE, 1, ES_FLAGS_DEFAULT); + frame->cacheReference = cachedSection->data + pageInCachedSectionIndex; + } else if (!frame->active.references) { + KernelPanic("CCSpaceAccess - Active page frame %x had no references.\n", frame); + } + + frame->active.references++; + + MMArchMapPage(kernelMMSpace, entry & ~(K_PAGE_SIZE - 1), (uintptr_t) sectionBase + i * K_PAGE_SIZE, MM_MAP_PAGE_FRAME_LOCK_ACQUIRED); + __sync_synchronize(); + section->referencedPages[i >> 3] |= 1 << (i & 7); + section->referencedPageCount++; + } else if (~entry & MM_SHARED_ENTRY_PRESENT) { + if (section->referencedPages[i >> 3] & (1 << (i & 7))) { + KernelPanic("CCSpaceAccess - Referenced page was not present.\n"); + } + + pagesToLoad[i] = cachedSection->data + pageInCachedSectionIndex; + loadCount++; + } + + KMutexRelease(&pmm.pageFrameMutex); + + pageInCachedSectionIndex++; + + if (pageInCachedSectionIndex == cachedSection->pageCount) { + pageInCachedSectionIndex = 0; + cachedSection++; + } + } + + if (!loadCount) { + KMutexRelease(&cache->cachedSectionsMutex); + goto copy; + } + + // If another thread is already trying to load pages into the active section, + // then wait for it to complete. + + bool loadCollision = section->loading; + + if (!loadCollision) { + section->loading = true; + KEventReset(§ion->loadCompleteEvent); + } + + KMutexRelease(&cache->cachedSectionsMutex); + + if (loadCollision) { + KEventWait(§ion->loadCompleteEvent); + continue; + } + + // Allocate, reference and map physical pages. + + uintptr_t pageFrames[CC_ACTIVE_SECTION_SIZE / K_PAGE_SIZE]; + + for (uintptr_t i = pageStart; i < pageEnd; i++) { + if (!pagesToLoad[i]) { + continue; + } + + pageFrames[i] = MMPhysicalAllocate(ES_FLAGS_DEFAULT); + + MMPageFrame *frame = pmm.pageFrames + (pageFrames[i] >> K_PAGE_BITS); + frame->active.references = 1; + frame->cacheReference = pagesToLoad[i]; + + MMArchMapPage(kernelMMSpace, pageFrames[i], (uintptr_t) sectionBase + i * K_PAGE_SIZE, ES_FLAGS_DEFAULT); + } + + // Read from the cache's backing store. + + EsError error = ES_SUCCESS; + + if ((flags & CC_ACCESS_WRITE) && (~flags & CC_ACCESS_USER_BUFFER_MAPPED)) { + bool loadedStart = false; + + if (error == ES_SUCCESS && (start & (K_PAGE_SIZE - 1)) && pagesToLoad[pageStart]) { + // Left side of the accessed region is not page aligned, so we need to load in the page. + + error = cache->callbacks->readInto(cache, sectionBase + pageStart * K_PAGE_SIZE, + section->offset + pageStart * K_PAGE_SIZE, K_PAGE_SIZE); + loadedStart = true; + } + + if (error == ES_SUCCESS && (end & (K_PAGE_SIZE - 1)) && !(pageStart == pageEnd - 1 && loadedStart) && pagesToLoad[pageEnd - 1]) { + // Right side of the accessed region is not page aligned, so we need to load in the page. + + error = cache->callbacks->readInto(cache, sectionBase + (pageEnd - 1) * K_PAGE_SIZE, + section->offset + (pageEnd - 1) * K_PAGE_SIZE, K_PAGE_SIZE); + } + + K_USER_BUFFER uint8_t *buffer2 = buffer; + + // Initialise the rest of the contents HERE, before referencing the pages. + // The user buffer cannot be mapped otherwise we could deadlock while reading from it, + // as we have marked the active section in the loading state. + + for (uintptr_t i = pageStart; i < pageEnd; i++) { + uintptr_t left = i == pageStart ? (start & (K_PAGE_SIZE - 1)) : 0; + uintptr_t right = i == pageEnd - 1 ? (end & (K_PAGE_SIZE - 1)) : K_PAGE_SIZE; + if (!right) right = K_PAGE_SIZE; + + if (pagesToLoad[i]) { + EsMemoryCopy(sectionBase + i * K_PAGE_SIZE + left, buffer2, right - left); + alreadyWritten[i >> 3] |= 1 << (i & 7); + } + + buffer2 += right - left; + } + + if (buffer + (end - start) != buffer2) { + KernelPanic("CCSpaceAccess - Incorrect page left/right calculation.\n"); + } + } else { + for (uintptr_t i = pageStart; i < pageEnd; i++) { + uintptr_t from = i, count = 0; + + while (i != pageEnd && pagesToLoad[i]) { + count++, i++; + } + + if (!count) continue; + + error = cache->callbacks->readInto(cache, sectionBase + from * K_PAGE_SIZE, + section->offset + from * K_PAGE_SIZE, count * K_PAGE_SIZE); + + if (error != ES_SUCCESS) { + break; + } + } + } + + if (error != ES_SUCCESS) { + // Free and unmap the pages we allocated if there was an error. + + for (uintptr_t i = pageStart; i < pageEnd; i++) { + if (!pagesToLoad[i]) continue; + MMArchUnmapPages(kernelMMSpace, (uintptr_t) sectionBase + i * K_PAGE_SIZE, 1, ES_FLAGS_DEFAULT); + MMPhysicalFree(pageFrames[i], false, 1); + } + } + + KMutexAcquire(&cache->cachedSectionsMutex); + + // Write the pages to the cached sections, and mark them as referenced. + + if (error == ES_SUCCESS) { + for (uintptr_t i = pageStart; i < pageEnd; i++) { + if (pagesToLoad[i]) { + *pagesToLoad[i] = pageFrames[i] | MM_SHARED_ENTRY_PRESENT; + section->referencedPages[i >> 3] |= 1 << (i & 7); + section->referencedPageCount++; + } + } + } + + // Return active section to normal state, and set the load complete event. + + section->loading = false; + KEventSet(§ion->loadCompleteEvent); + + KMutexRelease(&cache->cachedSectionsMutex); + + if (error != ES_SUCCESS) { + return error; + } + + break; + } + + copy:; + + // Copy into/from the user's buffer. + + if (buffer) { + if (flags & CC_ACCESS_MAP) { + if ((start & (K_PAGE_SIZE - 1)) || (end & (K_PAGE_SIZE - 1)) || ((uintptr_t) buffer & (K_PAGE_SIZE - 1))) { + KernelPanic("CCSpaceAccess - Passed READ_MAP flag, but start/end/buffer misaligned.\n"); + } + + for (uintptr_t i = start; i < end; i += K_PAGE_SIZE) { + uintptr_t physicalAddress = MMArchTranslateAddress(kernelMMSpace, (uintptr_t) sectionBase + i, false); + KMutexAcquire(&pmm.pageFrameMutex); + pmm.pageFrames[physicalAddress / K_PAGE_SIZE].active.references++; + KMutexRelease(&pmm.pageFrameMutex); + MMArchMapPage(mapSpace, physicalAddress, (uintptr_t) buffer, + mapFlags | MM_MAP_PAGE_IGNORE_IF_MAPPED /* since this isn't locked */); + buffer += K_PAGE_SIZE; + } + } else if (flags & CC_ACCESS_READ) { + EsMemoryCopy(buffer, sectionBase + start, end - start); + buffer += end - start; + } else if (flags & CC_ACCESS_WRITE) { + for (uintptr_t i = pageStart; i < pageEnd; i++) { + uintptr_t left = i == pageStart ? (start & (K_PAGE_SIZE - 1)) : 0; + uintptr_t right = i == pageEnd - 1 ? (end & (K_PAGE_SIZE - 1)) : K_PAGE_SIZE; + if (!right) right = K_PAGE_SIZE; + + if (~alreadyWritten[i >> 3] & (1 << (i & 7))) { + EsMemoryCopy(sectionBase + i * K_PAGE_SIZE + left, buffer, right - left); + } + + buffer += right - left; + + if (!preciseWriteBack) { + __sync_fetch_and_or(section->modifiedPages + (i >> 3), 1 << (i & 7)); + } + } + + if (!preciseWriteBack) { + section->modified = true; + } else { + uint8_t *sectionBase = activeSectionManager.baseAddress + (section - activeSectionManager.sections) * CC_ACTIVE_SECTION_SIZE; + EsError error = section->cache->callbacks->writeFrom(section->cache, sectionBase + start, section->offset + start, end - start); + + if (error != ES_SUCCESS) { + CCActiveSectionReturnToLists(section, writeBack); + return error; + } + } + } + } + + CCActiveSectionReturnToLists(section, writeBack); + } + + return ES_SUCCESS; +} + +void CCWriteBehindThread() { + while (true) { + // Wait for an active section to be modified, and have no accessors. + + KEventWait(&activeSectionManager.modifiedNonEmpty); + + if (MM_AVAILABLE_PAGES() > MM_LOW_AVAILABLE_PAGES_THRESHOLD && !scheduler.shutdown) { + // If there are sufficient available pages, wait before we start writing sections. + KEventWait(&pmm.availableLow, CC_WAIT_FOR_WRITE_BEHIND); + } + + while (true) { + // Take a section, and mark it as being written. + + CCActiveSection *section = nullptr; + KMutexAcquire(&activeSectionManager.mutex); + + if (activeSectionManager.modifiedList.count) { + section = activeSectionManager.modifiedList.firstItem->thisItem; + CCWriteSectionPrepare(section); + } + + KEventSet(&activeSectionManager.modifiedNonFull, false, true); + KMutexRelease(&activeSectionManager.mutex); + + if (!section) { + break; + } else { + CCWriteSection(section); + } + } + } +} + +void CCInitialise() { + activeSectionManager.sectionCount = CC_SECTION_BYTES / CC_ACTIVE_SECTION_SIZE; + activeSectionManager.sections = (CCActiveSection *) EsHeapAllocate(activeSectionManager.sectionCount * sizeof(CCActiveSection), true, K_FIXED); + + KMutexAcquire(&kernelMMSpace->reserveMutex); + activeSectionManager.baseAddress = (uint8_t *) MMReserve(kernelMMSpace, activeSectionManager.sectionCount * CC_ACTIVE_SECTION_SIZE, MM_REGION_CACHE)->baseAddress; + KMutexRelease(&kernelMMSpace->reserveMutex); + + for (uintptr_t i = 0; i < activeSectionManager.sectionCount; i++) { + activeSectionManager.sections[i].listItem.thisItem = &activeSectionManager.sections[i]; + activeSectionManager.lruList.InsertEnd(&activeSectionManager.sections[i].listItem); + } + + KernelLog(LOG_INFO, "Memory", "cache initialised", "MMInitialise - Active section manager initialised with a maximum of %d of entries.\n", + activeSectionManager.sectionCount); + + activeSectionManager.modifiedNonEmpty.autoReset = true; + KEventSet(&activeSectionManager.modifiedNonFull); + activeSectionManager.writeBackThread = scheduler.SpawnThread("CCWriteBehind", (uintptr_t) CCWriteBehindThread, 0, ES_FLAGS_DEFAULT); + activeSectionManager.writeBackThread->isPageGenerator = true; +} + +#endif diff --git a/kernel/config.ini b/kernel/config.ini new file mode 100644 index 0000000..dddc149 --- /dev/null +++ b/kernel/config.ini @@ -0,0 +1,146 @@ +[@driver Root] +builtin=1 + +; Subsystems. + +[@driver Networking] +parent=Root +builtin=1 + +[@driver USB] +source=drivers/usb.cpp +parent=Root +builtin=1 + +; Architectures. + +[@driver ACPI] +arch=x86_common +parent=Root +builtin=1 + +; Base devices. + +[@driver PCI] +source=drivers/pci.cpp +arch=x86_common +builtin=1 + +[@driver SVGA] +source=drivers/svga.cpp +arch=x86_common +builtin=1 + +[@driver PS2] +source=drivers/ps2.cpp +arch=x86_common +builtin=1 + +; PCI devices. + +[@driver IDE] +source=drivers/ide.cpp +builtin=1 +arch=x86_common +parent=PCI +classCode=0x01 +subclassCode=0x01 + +[@driver AHCI] +source=drivers/ahci.cpp +builtin=1 +parent=PCI +classCode=0x01 +subclassCode=0x06 + +[@driver NVMe] +source=drivers/nvme.cpp +builtin=1 +parent=PCI +classCode=0x01 +subclassCode=0x08 +progIF=0x02 + +[@driver HDAudio] +name=HDAudio +source=drivers/hda.cpp +builtin=1 +parent=PCI +classCode=0x04 +subclassCode=0x03 + +[@driver xHCI] +source=drivers/xhci.cpp +builtin=1 +parent=PCI +classCode=0x0C +subclassCode=0x03 +progIF=0x30 + +[@driver BGA] +source=drivers/bga.cpp +builtin=1 +parent=PCI +deviceID=0xBEEF80EE +deviceID=0x11111234 + +[@driver I8254x] +source=drivers/i8254x.cpp +builtin=1 +parent=PCI +deviceID=0x100E8086 + +; USB devices. + +[@driver USBHID] +source=drivers/usb_hid.cpp +builtin=1 +parent=USB +classCode=0x03 + +[@driver USBBulk] +source=drivers/usb_bulk.cpp +builtin=1 +parent=USB +classCode=0x08 +subclassCode=0x06 +protocol=0x50 + +; File systems. + +[@driver EssenceFS] +source=drivers/esfs2.cpp +builtin=1 +parent=Files +signature_offset=0x2000 +signature=!EssenceFS2----- + +[@driver FAT] +source=drivers/fat.cpp +builtin=1 +parent=Files +signature_offset=0x26 +signature=) +signature_offset=0x42 +signature=) + +[@driver ISO9660] +source=drivers/iso9660.cpp +builtin=1 +parent=Files +signature_offset=0x8001 +signature=CD001 + +[@driver NTFS] +source=drivers/ntfs.cpp +builtin=1 +parent=Files +signature_offset=3 +signature=NTFS + +[@driver Ext2] +source=drivers/ext2.cpp +builtin=1 +parent=Files +signature_offset=1080 +signature=S diff --git a/kernel/drivers.cpp b/kernel/drivers.cpp new file mode 100644 index 0000000..44fc5e9 --- /dev/null +++ b/kernel/drivers.cpp @@ -0,0 +1,324 @@ +#ifndef IMPLEMENTATION + +struct DeviceAttachData { + KDevice *parentDevice; + KInstalledDriver *installedDriver; +}; + +KDevice *deviceTreeRoot; +KMutex deviceTreeMutex; + +Array delayedDevices; +Array installedDrivers; + +#endif + +#ifdef IMPLEMENTATION + +void *ResolveKernelSymbol(const char *name, size_t nameBytes); + +KDevice *KDeviceCreate(const char *cDebugName, KDevice *parent, size_t bytes) { + if (bytes < sizeof(KDevice)) { + KernelPanic("KDeviceCreate - Device structure size is too small (less than KDevice).\n"); + } + + KDevice *device = (KDevice *) EsHeapAllocate(bytes, true, K_FIXED); + if (!device) return nullptr; + + device->parent = parent; + device->cDebugName = cDebugName; + device->handles = 2; // One handle for the creator, and another closed when the device is removed (by the parent). + + if (parent) { + KMutexAcquire(&deviceTreeMutex); + + if (!parent->children.Add(device)) { + EsHeapFree(device, bytes, K_FIXED); + device = nullptr; + } + + KMutexRelease(&deviceTreeMutex); + return device; + } else { + if (deviceTreeRoot) { + KernelPanic("KDeviceCreate - Root device already created.\n"); + } + + return (deviceTreeRoot = device); + } +} + +void DeviceDestroy(KDevice *device) { + device->children.Free(); + if (device->destroy) device->destroy(device); + EsHeapFree(device, 0, K_FIXED); +} + +void KDeviceDestroy(KDevice *device) { + KMutexAcquire(&deviceTreeMutex); + + device->handles = 0; + + if (device->children.Length()) { + KernelPanic("KDeviceDestroy - Device %x has children.\n", device); + } + + while (!device->handles && !device->children.Length()) { + device->parent->children.FindAndDeleteSwap(device, true /* fail if not found */); + KDevice *parent = device->parent; + DeviceDestroy(device); + device = parent; + } + + KMutexRelease(&deviceTreeMutex); +} + +void KDeviceOpenHandle(KDevice *device) { + KMutexAcquire(&deviceTreeMutex); + if (!device->handles) KernelPanic("KDeviceOpenHandle - Device %s has no handles.\n", device); + device->handles++; + KMutexRelease(&deviceTreeMutex); +} + +void KDeviceCloseHandle(KDevice *device) { + KMutexAcquire(&deviceTreeMutex); + + if (!device->handles) KernelPanic("KDeviceCloseHandle - Device %s has no handles.\n", device); + device->handles--; + + while (!device->handles && !device->children.Length()) { + device->parent->children.FindAndDeleteSwap(device, true /* fail if not found */); + KDevice *parent = device->parent; + DeviceDestroy(device); + device = parent; + } + + KMutexRelease(&deviceTreeMutex); +} + +void DeviceRemovedRecurse(KDevice *device) { + if (device->flags & K_DEVICE_REMOVED) KernelPanic("DeviceRemovedRecurse - Device %x already removed.\n", device); + device->flags |= K_DEVICE_REMOVED; + + for (uintptr_t i = 0; i < device->children.Length(); i++) { + KDevice *child = device->children[i]; + DeviceRemovedRecurse(child); + if (!child->handles) KernelPanic("DeviceRemovedRecurse - Child device %s has no handles.\n", child); + child->handles--; + if (child->handles || child->children.Length()) continue; + device->children.DeleteSwap(i); + DeviceDestroy(child); + i--; + } + + if (device->removed) { + device->removed(device); + } +} + +void KDeviceRemoved(KDevice *device) { + KMutexAcquire(&deviceTreeMutex); + DeviceRemovedRecurse(device); + KMutexRelease(&deviceTreeMutex); + KDeviceCloseHandle(device); +} + +const KDriver *DriverLoad(KInstalledDriver *installedDriver) { + static KMutex mutex = {}; + + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + if (installedDriver->loadedDriver) { + return installedDriver->loadedDriver; + } + + KDriver *driver = nullptr; + + char *driverVariable = nullptr; + size_t driverVariableBytes = 0; + + EsINIState s = {}; + s.buffer = installedDriver->config; + s.bytes = installedDriver->configBytes; + + while (EsINIParse(&s)) { + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("driver"))) { + driverVariable = s.value; + driverVariableBytes = s.valueBytes; + } + } + + char *buffer = (char *) EsHeapAllocate(K_MAX_PATH, true, K_FIXED); + if (!buffer) return nullptr; + EsDefer(EsHeapFree(buffer, K_MAX_PATH, K_FIXED)); + + KModule *module = (KModule *) EsHeapAllocate(sizeof(KModule), true, K_FIXED); + if (!module) return nullptr; + + module->path = buffer; + module->pathBytes = EsStringFormat(buffer, K_MAX_PATH, K_OS_FOLDER "/Modules/%s.ekm", + installedDriver->nameBytes, installedDriver->name); + module->resolveSymbol = ResolveKernelSymbol; + + EsError error = KLoadELFModule(module); + + if (error == ES_SUCCESS) { + KernelLog(LOG_INFO, "Modules", "module loaded", "Successfully loaded module '%s'.\n", + installedDriver->nameBytes, installedDriver->name); + + driver = (KDriver *) KFindSymbol(module, driverVariable, driverVariableBytes); + + if (!driver) { + KernelLog(LOG_ERROR, "Modules", "bad module", "DriverLoad - Could not find driver symbol in module '%s'.\n", + installedDriver->nameBytes, installedDriver->name); + } + } else { + KernelLog(LOG_ERROR, "Modules", "module load failure", "Could not load module '%s' (error = %d).\n", + installedDriver->nameBytes, installedDriver->name, error); + EsHeapFree(module, sizeof(KModule), K_FIXED); + } + + return (installedDriver->loadedDriver = driver); +} + +void DeviceAttach(DeviceAttachData attach) { + TS("DeviceAttach to %s\n", attach.installedDriver->nameBytes, attach.installedDriver->name); + + if (attach.parentDevice) { + KDeviceOpenHandle(attach.parentDevice); + } + + KMutexAcquire(&deviceTreeMutex); + + if (!attach.installedDriver->builtin && !fs.bootFileSystem) { + KernelLog(LOG_INFO, "Modules", "delayed device", "Delaying attach device to driver '%s' until boot file system mounted.\n", + attach.installedDriver->nameBytes, attach.installedDriver->name); + delayedDevices.Add(attach); + KMutexRelease(&deviceTreeMutex); + return; + } + + KernelLog(LOG_INFO, "Modules", "device attach", "Attaching device to driver '%s'.\n", + attach.installedDriver->nameBytes, attach.installedDriver->name); + + const KDriver *driver = DriverLoad(attach.installedDriver); + KMutexRelease(&deviceTreeMutex); + + if (driver && driver->attach) { + driver->attach(attach.parentDevice); + } + + if (attach.parentDevice) { + KDeviceCloseHandle(attach.parentDevice); + } +} + +bool KDeviceAttach(KDevice *parentDevice, const char *cName, KDriverIsImplementorCallback callback) { + size_t nameBytes = EsCStringLength(cName); + + for (uintptr_t i = installedDrivers.Length(); i > 0; i--) { + if (0 == EsStringCompareRaw(cName, nameBytes, installedDrivers[i - 1].parent, installedDrivers[i - 1].parentBytes) + && callback(&installedDrivers[i - 1], parentDevice)) { + DeviceAttach({ .parentDevice = parentDevice, .installedDriver = &installedDrivers[i - 1] }); + return true; + } + } + + return false; +} + +void KDeviceAttachAll(KDevice *parentDevice, const char *cName) { + size_t nameBytes = EsCStringLength(cName); + + for (uintptr_t i = 0; i < installedDrivers.Length(); i++) { + if (0 == EsStringCompareRaw(cName, nameBytes, installedDrivers[i].parent, installedDrivers[i].parentBytes)) { + DeviceAttach({ .parentDevice = parentDevice, .installedDriver = &installedDrivers[i] }); + } + } +} + +bool KDeviceAttachByName(KDevice *parentDevice, const char *cName) { + size_t nameBytes = EsCStringLength(cName); + + for (uintptr_t i = 0; i < installedDrivers.Length(); i++) { + if (0 == EsStringCompareRaw(cName, nameBytes, installedDrivers[i].name, installedDrivers[i].nameBytes)) { + DeviceAttach({ .parentDevice = parentDevice, .installedDriver = &installedDrivers[i] }); + return true; + } + } + + return false; +} + +void DeviceRootAttach(KDevice *parentDevice) { + // Load all the root drivers and create their devices. + + KDeviceAttachAll(KDeviceCreate("root", parentDevice, sizeof(KDevice)), "Root"); + + // Check we have found the drive from which we booted. + // TODO Decide the timeout. + + if (!KEventWait(&fs.foundBootFileSystemEvent, 10000)) { + KernelPanic("DeviceRootAttach - Could not find the boot file system.\n"); + } + + // Load any devices that were waiting for the boot file system to be loaded. + + for (uintptr_t i = 0; i < delayedDevices.Length(); i++) { + DeviceAttach(delayedDevices[i]); + KDeviceCloseHandle(delayedDevices[i].parentDevice); + } + + delayedDevices.Free(); +} + +KDriver driverRoot = { + .attach = DeviceRootAttach, +}; + +void DriversInitialise() { + // Add the builtin drivers to the database. + + for (uintptr_t i = 0; i < sizeof(builtinDrivers) / sizeof(builtinDrivers[0]); i++) { + installedDrivers.Add(builtinDrivers[i]); + } + + // Attach to the root device. + + DeviceAttach({ .parentDevice = nullptr, .installedDriver = &installedDrivers[0] }); +} + +void DriversDumpStateRecurse(KDevice *device) { + if (device->dumpState) { + device->dumpState(device); + } + + for (uintptr_t i = 0; i < device->children.Length(); i++) { + DriversDumpStateRecurse(device->children[i]); + } +} + +void DriversDumpState() { + KMutexAcquire(&deviceTreeMutex); + DriversDumpStateRecurse(deviceTreeRoot); + KMutexRelease(&deviceTreeMutex); +} + +void DriversShutdownRecurse(KDevice *device) { + for (uintptr_t i = 0; i < device->children.Length(); i++) { + DriversShutdownRecurse(device->children[i]); + } + + if (device->shutdown) { + device->shutdown(device); + } +} + +void DriversShutdown() { + KMutexAcquire(&deviceTreeMutex); + DriversShutdownRecurse(deviceTreeRoot); + KMutexRelease(&deviceTreeMutex); +} + +#endif diff --git a/kernel/elf.cpp b/kernel/elf.cpp new file mode 100644 index 0000000..53ef859 --- /dev/null +++ b/kernel/elf.cpp @@ -0,0 +1,422 @@ +// TODO Use a custom executable format? + +#define MEMORY_MAPPED_EXECUTABLES + +#ifndef IMPLEMENTATION + +struct ElfHeader { + uint32_t magicNumber; // 0x7F followed by 'ELF' + uint8_t bits; // 1 = 32 bit, 2 = 64 bit + uint8_t endianness; // 1 = LE, 2 = BE + uint8_t version1; + uint8_t abi; // 0 = System V + uint8_t _unused0[8]; + uint16_t type; // 1 = relocatable, 2 = executable, 3 = shared + uint16_t instructionSet; // 0x03 = x86, 0x28 = ARM, 0x3E = x86-64, 0xB7 = AArch64 + uint32_t version2; + +#ifdef ARCH_32 + uint32_t entry; + uint32_t programHeaderTable; + uint32_t sectionHeaderTable; + uint32_t flags; + uint16_t headerSize; + uint16_t programHeaderEntrySize; + uint16_t programHeaderEntries; + uint16_t sectionHeaderEntrySize; + uint16_t sectionHeaderEntries; + uint16_t sectionNameIndex; +#else + uint64_t entry; + uint64_t programHeaderTable; + uint64_t sectionHeaderTable; + uint32_t flags; + uint16_t headerSize; + uint16_t programHeaderEntrySize; + uint16_t programHeaderEntries; + uint16_t sectionHeaderEntrySize; + uint16_t sectionHeaderEntries; + uint16_t sectionNameIndex; +#endif +}; + +#ifdef ARCH_32 +struct ElfSectionHeader { + uint32_t name; + uint32_t type; + uint32_t flags; + uint32_t address; + uint32_t offset; + uint32_t size; + uint32_t link; + uint32_t info; + uint32_t align; + uint32_t entrySize; +}; + +struct ElfProgramHeader { + uint32_t type; // 0 = unused, 1 = load, 2 = dynamic, 3 = interp, 4 = note + uint32_t fileOffset; + uint32_t virtualAddress; + uint32_t _unused0; + uint32_t dataInFile; + uint32_t segmentSize; + uint32_t flags; // 1 = executable, 2 = writable, 4 = readable + uint32_t alignment; +}; + +struct ElfRelocation { + uint32_t offset; + uint32_t info; + int32_t addend; +}; + +struct ElfSymbol { + uint32_t name, value, size; + uint8_t info, _reserved1; + uint16_t sectionIndex; +}; +#else +struct ElfSectionHeader { + uint32_t name; // Offset into section header->sectionNameIndex. + uint32_t type; // 4 = rela + uint64_t flags; + uint64_t address; + uint64_t offset; + uint64_t size; + uint32_t link; + uint32_t info; + uint64_t align; + uint64_t entrySize; +}; + +struct ElfProgramHeader{ + uint32_t type; // 0 = unused, 1 = load, 2 = dynamic, 3 = interp, 4 = note + uint32_t flags; // 1 = executable, 2 = writable, 4 = readable + uint64_t fileOffset; + uint64_t virtualAddress; + uint64_t _unused0; + uint64_t dataInFile; + uint64_t segmentSize; + uint64_t alignment; +}; + +struct ElfRelocation { + uint64_t offset; + uint64_t info; + int64_t addend; +}; + +struct ElfSymbol { + uint32_t name; + uint8_t info, _reserved1; + uint16_t sectionIndex; + uint64_t value, size; +}; +#endif + +#else + +EsError KLoadELF(KNode *node, KLoadedExecutable *executable) { + Process *thisProcess = GetCurrentThread()->process; + + uintptr_t executableOffset = 0; + size_t fileSize = FSNodeGetTotalSize(node); + + { + BundleHeader header; + size_t bytesRead = FSFileReadSync(node, (uint8_t *) &header, 0, sizeof(BundleHeader), 0); + if (bytesRead != sizeof(BundleHeader)) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + + if (header.signature == BUNDLE_SIGNATURE + && header.fileCount < 0x100000 + && header.fileCount * sizeof(BundleFile) + sizeof(BundleHeader) < fileSize) { + if (!header.mapAddress) { + header.mapAddress = BUNDLE_FILE_MAP_ADDRESS; + } + +#ifdef ARCH_X86_64 + if (header.mapAddress > 0x8000000000000000UL || header.mapAddress < 0x1000 || fileSize > 0x1000000000000UL + || header.mapAddress & (K_PAGE_SIZE - 1)) { + return ES_ERROR_UNSUPPORTED_EXECUTABLE; + } +#else +#error Unimplemented. +#endif + + if (header.version != 1) { + return ES_ERROR_UNSUPPORTED_EXECUTABLE; + } + + // Map the bundle file. + + if (!MMMapFile(thisProcess->vmm, (FSFile *) node, + 0, fileSize, ES_MAP_OBJECT_READ_ONLY, + (uint8_t *) header.mapAddress)) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + // Look for the executable in the bundle. + +#ifdef ARCH_X86_64 + uint64_t name = CalculateCRC64(EsLiteral("Executable (x86_64)")); +#endif + + BundleFile *files = (BundleFile *) ((BundleHeader *) header.mapAddress + 1); + + bool found = false; + + for (uintptr_t i = 0; i < header.fileCount; i++) { + if (files[i].nameCRC64 == name) { + executableOffset = files[i].offset; + found = true; + break; + } + } + + if (executableOffset >= fileSize || !found) { + return ES_ERROR_UNSUPPORTED_EXECUTABLE; + } + } + } + + // EsPrint("executableOffset: %x\n", executableOffset); + + ElfHeader header; + size_t bytesRead = FSFileReadSync(node, (uint8_t *) &header, executableOffset, sizeof(ElfHeader), 0); + if (bytesRead != sizeof(ElfHeader)) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + + size_t programHeaderEntrySize = header.programHeaderEntrySize; + + if (header.magicNumber != 0x464C457F) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + if (header.bits != 2) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + if (header.endianness != 1) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + if (header.abi != 0) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + if (header.type != 2) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + if (header.instructionSet != 0x3E) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + + ElfProgramHeader *programHeaders = (ElfProgramHeader *) EsHeapAllocate(programHeaderEntrySize * header.programHeaderEntries, false, K_PAGED); + EsDefer(EsHeapFree(programHeaders, 0, K_PAGED)); + + bytesRead = FSFileReadSync(node, (uint8_t *) programHeaders, executableOffset + header.programHeaderTable, programHeaderEntrySize * header.programHeaderEntries, 0); + if (bytesRead != programHeaderEntrySize * header.programHeaderEntries) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + + for (uintptr_t i = 0; i < header.programHeaderEntries; i++) { + ElfProgramHeader *header = (ElfProgramHeader *) ((uint8_t *) programHeaders + programHeaderEntrySize * i); + + if (header->type == 1 /* PT_LOAD */) { +#ifdef ARCH_X86_64 + if (header->virtualAddress > 0x8000000000000000UL || header->virtualAddress < 0x1000 || header->segmentSize > 0x1000000000000UL) { + return ES_ERROR_UNSUPPORTED_EXECUTABLE; + } +#else +#error Unimplemented. +#endif + +#if 0 + EsPrint("FileOffset %x VirtualAddress %x SegmentSize %x DataInFile %x\n", + header->fileOffset, header->virtualAddress, header->segmentSize, header->dataInFile); +#endif + + void *success; + +#ifndef MEMORY_MAPPED_EXECUTABLES + success = MMStandardAllocate(thisProcess->vmm, RoundUp(header->segmentSize, K_PAGE_SIZE), ES_FLAGS_DEFAULT, + (uint8_t *) RoundDown(header->virtualAddress, K_PAGE_SIZE)); + + if (success) { + bytesRead = FSFileReadSync(node, (void *) header->virtualAddress, executableOffset + header->fileOffset, header->dataInFile, 0); + if (bytesRead != header->dataInFile) return ES_ERROR_UNSUPPORTED_EXECUTABLE; + } +#else + uintptr_t fileStart = RoundDown(header->virtualAddress, K_PAGE_SIZE); + uintptr_t fileOffset = RoundDown(header->fileOffset, K_PAGE_SIZE); + uintptr_t zeroStart = RoundUp(header->virtualAddress + header->dataInFile, K_PAGE_SIZE); + uintptr_t end = RoundUp(header->virtualAddress + header->segmentSize, K_PAGE_SIZE); + + // TODO This doesn't need to be all COPY_ON_WRITE. + + // EsPrint("MMMapFile - %x, %x, %x, %x\n", fileStart, fileOffset, zeroStart, end); + + success = MMMapFile(thisProcess->vmm, (FSFile *) node, + executableOffset + fileOffset, zeroStart - fileStart, + ES_MAP_OBJECT_COPY_ON_WRITE, + (uint8_t *) fileStart, end - zeroStart); + + if (success) { + uint8_t *from = (uint8_t *) header->virtualAddress + header->dataInFile; + EsMemoryZero(from, (uint8_t *) zeroStart - from); + } +#endif + + if (!success) return ES_ERROR_INSUFFICIENT_RESOURCES; + } else if (header->type == 7 /* PT_TLS */) { + executable->tlsImageStart = header->virtualAddress; + executable->tlsImageBytes = header->dataInFile; + executable->tlsBytes = header->segmentSize; + KernelLog(LOG_INFO, "ELF", "executable TLS", "Executable requests %d bytes of TLS, with %d bytes from the image at %x.\n", + executable->tlsBytes, executable->tlsImageBytes, executable->tlsImageStart); + } + } + + executable->startAddress = header.entry; + return ES_SUCCESS; +} + +uintptr_t KFindSymbol(KModule *module, const char *name, size_t nameBytes) { + uint8_t *buffer = module->buffer; + ElfHeader *header = (ElfHeader *) buffer; + + for (uintptr_t i = 0; i < header->sectionHeaderEntries; i++) { + ElfSectionHeader *section = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * i); + if (section->type != 2 /* SHT_SYMTAB */) continue; + + ElfSectionHeader *strings = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * section->link); + + for (uintptr_t i = 0; i < section->size / sizeof(ElfSymbol); i++) { + ElfSymbol *symbol = (ElfSymbol *) (buffer + section->offset + i * sizeof(ElfSymbol)); + if (!symbol->name) continue; + if (symbol->sectionIndex == 0 /* SHN_UNDEF */ || (symbol->info >> 4) != 1 /* STB_GLOBAL */) continue; + + uint8_t *symbolName = buffer + symbol->name + strings->offset; + + if (0 == EsStringCompareRaw(name, nameBytes, (const char *) symbolName, -1)) { + return symbol->value; + } + } + } + + return 0; +} + +uint8_t *modulesLocation = (uint8_t *) MM_MODULES_START; +KMutex modulesMutex; + +uint8_t *AllocateForModule(size_t size) { + KMutexAssertLocked(&modulesMutex); + if ((uintptr_t) modulesLocation + RoundUp(size, K_PAGE_SIZE) > MM_MODULES_START + MM_MODULES_SIZE) return nullptr; + uint8_t *buffer = (uint8_t *) MMStandardAllocate(kernelMMSpace, size, MM_REGION_FIXED, modulesLocation); + if (!buffer) return nullptr; + modulesLocation += RoundUp(size, K_PAGE_SIZE); + return (uint8_t *) buffer; +} + +EsError KLoadELFModule(KModule *module) { + KMutexAcquire(&modulesMutex); + EsDefer(KMutexRelease(&modulesMutex)); + + uint64_t fileFlags = ES_FILE_READ | ES_NODE_FAIL_IF_NOT_FOUND; + KNodeInformation node = FSNodeOpen(module->path, module->pathBytes, fileFlags); + if (node.error != ES_SUCCESS) return node.error; + + uint8_t *buffer = AllocateForModule(node.node->directoryEntry->totalSize); + module->buffer = buffer; + + { + // TODO Free module buffer on error. + + EsDefer(CloseHandleToObject(node.node, KERNEL_OBJECT_NODE, fileFlags)); + + if (!buffer) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + if (node.node->directoryEntry->totalSize != (size_t) FSFileReadSync(node.node, buffer, 0, node.node->directoryEntry->totalSize, 0)) { + return ES_ERROR_UNKNOWN; + } + } + + ElfHeader *header = (ElfHeader *) buffer; + uint8_t *sectionStringTable = buffer + ((ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * header->sectionNameIndex))->offset; + (void) sectionStringTable; + + for (uintptr_t i = 0; i < header->sectionHeaderEntries; i++) { + ElfSectionHeader *section = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * i); + if (section->type != 8 /* SHT_NOBITS */ || !section->size) continue; + uint8_t *memory = AllocateForModule(section->size); + if (!memory) return ES_ERROR_INSUFFICIENT_RESOURCES; // TODO Free allocations. + section->offset = memory - buffer; + } + + bool unresolvedSymbols = false; + + for (uintptr_t i = 0; i < header->sectionHeaderEntries; i++) { + ElfSectionHeader *section = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * i); + if (section->type != 2 /* SHT_SYMTAB */) continue; + + // EsPrint("%d: '%z' - symbol table\n", i, sectionStringTable + section->name); + ElfSectionHeader *strings = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * section->link); + + for (uintptr_t i = 0; i < section->size / sizeof(ElfSymbol); i++) { + ElfSymbol *symbol = (ElfSymbol *) (buffer + section->offset + i * sizeof(ElfSymbol)); + + uint8_t *name = buffer + symbol->name + strings->offset; + + if (symbol->sectionIndex == 0 /* SHN_UNDEF */) { + if (!symbol->name) continue; + + // TODO Check that EsCStringLength stays within bounds. + void *address = module->resolveSymbol((const char *) name, EsCStringLength((const char *) name)); + + if (!address) { + unresolvedSymbols = true; + } else { + symbol->value = (uintptr_t) address; + } + } else if (symbol->sectionIndex < header->sectionHeaderEntries) { + ElfSectionHeader *section = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * symbol->sectionIndex); + symbol->value += (uintptr_t) buffer + section->offset; + } + + // EsPrint("'%z' -> %x\n", name, symbol->value); + } + } + + if (unresolvedSymbols) { + return ES_ERROR_COULD_NOT_RESOLVE_SYMBOL; + } + + for (uintptr_t i = 0; i < header->sectionHeaderEntries; i++) { + ElfSectionHeader *section = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * i); + if (section->type != 4 /* SHT_RELA */) continue; + + ElfSectionHeader *target = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * section->info); + ElfSectionHeader *symbols = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * section->link); + ElfSectionHeader *strings = (ElfSectionHeader *) (buffer + header->sectionHeaderTable + header->sectionHeaderEntrySize * symbols->link); + (void) strings; + + // EsPrint("%d: '%z' - relocation table (for %x)\n", i, sectionStringTable + section->name, target->offset); + + for (uintptr_t i = 0; i < section->size / sizeof(ElfRelocation); i++) { + ElfRelocation *relocation = (ElfRelocation *) (buffer + section->offset + i * sizeof(ElfRelocation)); + ElfSymbol *symbol = (ElfSymbol *) (buffer + symbols->offset + (relocation->info >> 32) * sizeof(ElfSymbol)); + uintptr_t offset = relocation->offset + target->offset, type = relocation->info & 0xFF; + // EsPrint("\t%d: %z (%x), %d, %x, %x\n", i, buffer + symbol->name + strings->offset, symbol->value, type, offset, relocation->addend); + + uintptr_t result = symbol->value + relocation->addend; + +#ifdef ARCH_X86_64 + if (type == 0) {} + else if (type == 10 /* R_X86_64_32 */) *((uint32_t *) (buffer + offset)) = result; + else if (type == 11 /* R_X86_64_32S */) *((uint32_t *) (buffer + offset)) = result; + else if (type == 1 /* R_X86_64_64 */) *((uint64_t *) (buffer + offset)) = result; + else if (type == 2 /* R_X86_64_PC32 */) *((uint32_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset); + else if (type == 24 /* R_X86_64_PC64 */) *((uint64_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset); + else if (type == 4 /* R_X86_64_PLT32 */) *((uint32_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset); +#endif + else return ES_ERROR_UNSUPPORTED_FEATURE; + } + } + + KGetKernelVersionCallback getVersion = (KGetKernelVersionCallback) KFindSymbol(module, EsLiteral("GetKernelVersion")); + + if (!getVersion || getVersion() != KERNEL_VERSION) { + KernelLog(LOG_ERROR, "Modules", "invalid module kernel version", + "KLoadELFModule - Attempted to load module '%s' for invalid kernel version.\n", module->pathBytes, module->path); + return ES_ERROR_UNSUPPORTED_FEATURE; + } + + return ES_SUCCESS; +} + +#endif diff --git a/kernel/files.cpp b/kernel/files.cpp new file mode 100644 index 0000000..af433a0 --- /dev/null +++ b/kernel/files.cpp @@ -0,0 +1,1916 @@ +// TODO Features: +// - Handling errors creating files (prevent further file system operations). +// - Limiting the size of the directory/node cache. +// +// TODO Permissions: +// - Prevent modifications to directories without write permission. +// - Prevent launching executables without read permission. +// +// TODO Drivers: +// - Parsing GPT partition tables. +// - Get NTFS driver working again. +// +// TODO Allocate nodes/directory entries from arenas? +// TODO Check that the MODIFIED tracking is correct. + +#ifndef IMPLEMENTATION + +#define NODE_MAX_ACCESSORS (16777216) + +// KNode flags: +#define NODE_HAS_EXCLUSIVE_WRITER (1 << 0) +#define NODE_ENUMERATED_ALL_DIRECTORY_ENTRIES (1 << 1) +#define NODE_CREATED_ON_FILE_SYSTEM (1 << 2) +#define NODE_DELETED (1 << 3) +#define NODE_MODIFIED (1 << 4) +#define NODE_IN_CACHE_LIST (1 << 5) // Node has no handles and no directory entries, so it can be freed. + +// Modes for opening a node handle. +#define FS_NODE_OPEN_HANDLE_STANDARD (0) +#define FS_NODE_OPEN_HANDLE_FIRST (1) +#define FS_NODE_OPEN_HANDLE_DIRECTORY_TEMPORARY (2) + +struct FSDirectoryEntry : KNodeMetadata { + MMObjectCacheItem cacheItem; + AVLItem item; // item.key.longKey contains the entry's name. + struct FSDirectory *parent; // The directory containing this entry. + KNode *volatile node; // nullptr if the node hasn't been loaded. + char inlineName[16]; // Store the name of the entry inline if it is small enough. + // Followed by driver data. +}; + +struct FSDirectory : KNode { + AVLTree entries; + size_t entryCount; +}; + +struct FSFile : KNode { + int32_t countWrite /* negative indicates non-shared readers */, blockResize; + EsFileOffset fsFileSize; // Files are lazily resized; this is the size the file system thinks the file is. + EsFileOffset fsZeroAfter; // This is the smallest size the file has reached without telling the file system. + CCSpace cache; + KWriterLock resizeLock; // Take exclusive for resizing or flushing. +}; + +EsError FSNodeOpenHandle(KNode *node, uint32_t flags, uint8_t mode); +void FSNodeCloseHandle(KNode *node, uint32_t flags); +EsError FSNodeDelete(KNode *node); +EsError FSNodeMove(KNode *node, KNode *destination, const char *newName, size_t nameNameBytes); +EsError FSFileResize(KNode *node, EsFileOffset newSizeBytes); +ptrdiff_t FSDirectoryEnumerateChildren(KNode *node, K_USER_BUFFER EsDirectoryChild *buffer, size_t bufferSize); +EsError FSFileControl(KNode *node, uint32_t flags); +bool FSTrimCachedNode(MMObjectCache *); +bool FSTrimCachedDirectoryEntry(MMObjectCache *); + +struct { + KWriterLock fileSystemsLock; + + KFileSystem *bootFileSystem; + KEvent foundBootFileSystemEvent; + + KSpinlock updateNodeHandles; // Also used for node/directory entry cache operations. + + bool shutdown; + + volatile uint64_t totalHandleCount; + volatile uint64_t fileSystemsUnmounting; + KEvent fileSystemUnmounted; +} fs = { + .fileSystemUnmounted = { .autoReset = true }, +}; + +#else + +EsFileOffset FSNodeGetTotalSize(KNode *node) { + return node->directoryEntry->totalSize; +} + +char *FSNodeGetName(KNode *node, size_t *bytes) { + KWriterLockAssertLocked(&node->writerLock); + *bytes = node->directoryEntry->item.key.longKeyBytes; + return (char *) node->directoryEntry->item.key.longKey; +} + +bool FSCheckPathForIllegalCharacters(const char *path, size_t pathBytes) { + // Control ASCII characters are not allowed. + + for (uintptr_t i = 0; i < pathBytes; i++) { + char c = path[i]; + + if ((c >= 0x00 && c < 0x20) || c == 0x7F) { + return false; + } + } + + // Invalid UTF-8 sequences are not allowed. + // Surrogate characters are fine. + // Overlong sequences are fine, except for ASCII characters. + + if (!EsUTF8IsValid(path, pathBytes)) { + return false; + } + + return true; +} + +////////////////////////////////////////// +// Accessing files. +////////////////////////////////////////// + +EsError FSReadIntoCache(CCSpace *fileCache, void *buffer, EsFileOffset offset, EsFileOffset count) { + FSFile *node = EsContainerOf(FSFile, cache, fileCache); + + KWriterLockTake(&node->writerLock, K_LOCK_SHARED); + EsDefer(KWriterLockReturn(&node->writerLock, K_LOCK_SHARED)); + + if (node->flags & NODE_DELETED) { + return ES_ERROR_NODE_DELETED; + } + + if (offset > node->directoryEntry->totalSize) { + KernelPanic("FSReadIntoCache - Read out of bounds in node %x.\n", node); + } + + if (node->fsZeroAfter < offset + count) { + if (offset >= node->fsZeroAfter) { + EsMemoryZero(buffer, count); + } else { + if (~node->flags & NODE_CREATED_ON_FILE_SYSTEM) { + KernelPanic("FSReadIntoCache - Node %x has not been created on the file system.\n", node); + } + + size_t realBytes = node->fsZeroAfter - offset, fakeBytes = count - realBytes; + EsMemoryZero((uint8_t *) buffer + realBytes, fakeBytes); + count = node->fileSystem->read(node, buffer, offset, realBytes); + } + } else { + if (~node->flags & NODE_CREATED_ON_FILE_SYSTEM) { + KernelPanic("FSReadIntoCache - Node %x has not been created on the file system.\n", node); + } + + count = node->fileSystem->read(node, buffer, offset, count); + + if (ES_CHECK_ERROR(count)) { + node->error = count; + } + } + + return ES_CHECK_ERROR(count) ? count : ES_SUCCESS; +} + +EsError FSFileCreateAndResizeOnFileSystem(FSFile *node, EsFileOffset fileSize) { + KWriterLockAssertExclusive(&node->writerLock); + + FSDirectoryEntry *entry = node->directoryEntry; + + if (node->flags & NODE_DELETED) { + return ES_ERROR_NODE_DELETED; + } + + if (~node->flags & NODE_CREATED_ON_FILE_SYSTEM) { + KWriterLockTake(&entry->parent->writerLock, K_LOCK_EXCLUSIVE); + + EsError error = ES_SUCCESS; + + if (~entry->parent->flags & NODE_CREATED_ON_FILE_SYSTEM) { + // TODO Get the node error mark? + error = ES_ERROR_UNKNOWN; + } + + if (error == ES_SUCCESS) { + error = node->fileSystem->create((const char *) entry->item.key.longKey, entry->item.key.longKeyBytes, + ES_NODE_FILE, entry->parent, node, entry + 1); + } + + if (error == ES_SUCCESS) { + __sync_fetch_and_or(&node->flags, NODE_CREATED_ON_FILE_SYSTEM); + } else { + // TODO Mark the node with an error. + } + + KWriterLockReturn(&entry->parent->writerLock, K_LOCK_EXCLUSIVE); + + if (error != ES_SUCCESS) { + return error; + } + } + + if (node->fsFileSize != fileSize || node->fsZeroAfter != fileSize) { + // Resize the file on the file system to match the cache size. + EsError error = ES_ERROR_UNKNOWN; + KWriterLockTake(&entry->parent->writerLock, K_LOCK_EXCLUSIVE); + + if (node->fsZeroAfter != node->fsFileSize) { + // TODO Combined truncate-and-grow file operation. + node->fsFileSize = node->fileSystem->resize(node, node->fsZeroAfter, &error); + } + + // TODO Hint about where to zero upto - since we'll likely be about to write over the sectors! + node->fsFileSize = node->fileSystem->resize(node, fileSize, &error); + KWriterLockReturn(&entry->parent->writerLock, K_LOCK_EXCLUSIVE); + + if (node->fsFileSize != fileSize) { + return ES_ERROR_COULD_NOT_RESIZE_FILE; + } + + node->fsZeroAfter = fileSize; + } + + return ES_SUCCESS; +} + +EsError FSWriteFromCache(CCSpace *fileCache, const void *buffer, EsFileOffset offset, EsFileOffset count) { + FSFile *node = EsContainerOf(FSFile, cache, fileCache); + + KWriterLockTake(&node->writerLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&node->writerLock, K_LOCK_EXCLUSIVE)); + + FSDirectoryEntry *entry = node->directoryEntry; + volatile EsFileOffset fileSize = entry->totalSize; + + EsError error = FSFileCreateAndResizeOnFileSystem(node, fileSize); + + if (error != ES_SUCCESS) { + return error; + } + + if (offset > fileSize) { + KernelPanic("VFSWriteFromCache - Write out of bounds in node %x.\n", node); + } + + if (count > fileSize - offset) { + count = fileSize - offset; + } + + if (node->flags & NODE_DELETED) { + return ES_ERROR_NODE_DELETED; + } + + count = node->fileSystem->write(node, buffer, offset, count); + + if (ES_CHECK_ERROR(count)) { + node->error = count; + } + + return ES_CHECK_ERROR(count) ? count : ES_SUCCESS; +} + +const CCSpaceCallbacks fsFileCacheCallbacks = { + .readInto = FSReadIntoCache, + .writeFrom = FSWriteFromCache, +}; + +ptrdiff_t FSFileReadSync(KNode *node, K_USER_BUFFER void *buffer, EsFileOffset offset, EsFileOffset bytes, uint32_t accessFlags) { + if (fs.shutdown) KernelPanic("FSFileReadSync - Attempting to read from a file after FSShutdown called.\n"); + + FSFile *file = (FSFile *) node; + KWriterLockTake(&file->resizeLock, K_LOCK_SHARED); + EsDefer(KWriterLockReturn(&file->resizeLock, K_LOCK_SHARED)); + + if (offset > file->directoryEntry->totalSize) return ES_ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS; + if (bytes > file->directoryEntry->totalSize - offset) bytes = file->directoryEntry->totalSize - offset; + if (!bytes) return 0; + + EsError error = CCSpaceAccess(&file->cache, buffer, offset, bytes, + CC_ACCESS_READ | ((accessFlags & FS_FILE_ACCESS_USER_BUFFER_MAPPED) ? CC_ACCESS_USER_BUFFER_MAPPED : 0)); + return error == ES_SUCCESS ? bytes : error; +} + +void _FSFileResize(FSFile *file, EsFileOffset newSize) { + KWriterLockAssertExclusive(&file->resizeLock); + + EsFileOffsetDifference delta = newSize - file->directoryEntry->totalSize; + + if (!delta) { + return; + } + + if (delta < 0) { + // Truncate the space first, so that any pending write-backs past this point can complete. + CCSpaceTruncate(&file->cache, newSize); + } + + // No more writes-back can be issued past newSize until the resize lock is returned. Since: + // - CCSpaceTruncate waits for any queued writes past newSize to finish. + // - FSFileWriteSync waits for shared access on the resize lock before it can queue any more writes. + // This means we are safe to possible decrease sizing information. + + if (newSize < file->fsZeroAfter) { + file->fsZeroAfter = newSize; + } + + // Take the move lock before we write to the directoryEntry, + // because FSNodeMove needs to also update ancestors with the file's size when it is moved. + KMutexAcquire(&file->fileSystem->moveMutex); + + // We'll get the filesystem to resize the file during write-back. + file->directoryEntry->totalSize = newSize; + + KNode *ancestor = file->directoryEntry->parent; + + while (ancestor) { + __sync_fetch_and_or(&ancestor->flags, NODE_MODIFIED); + ancestor->directoryEntry->totalSize += delta; + ancestor = ancestor->directoryEntry->parent; + } + + __sync_fetch_and_or(&file->flags, NODE_MODIFIED); + + KMutexRelease(&file->fileSystem->moveMutex); +} + +EsError FSFileResize(KNode *node, EsFileOffset newSize) { + if (fs.shutdown) KernelPanic("FSFileResize - Attempting to resize a file after FSShutdown called.\n"); + + if (newSize > 1UL << 60) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + if (node->directoryEntry->type != ES_NODE_FILE) { + KernelPanic("FSFileResize - Node %x is not a file.\n", node); + } + + FSFile *file = (FSFile *) node; + EsError error = ES_SUCCESS; + KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE); + + if (file->blockResize) { + error = ES_ERROR_FILE_IN_EXCLUSIVE_USE; + } else if (!file->fileSystem->resize) { + error = ES_ERROR_FILE_ON_READ_ONLY_VOLUME; + } else { + _FSFileResize(file, newSize); + } + + KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE); + return error; +} + +ptrdiff_t FSFileWriteSync(KNode *node, K_USER_BUFFER const void *buffer, EsFileOffset offset, EsFileOffset bytes, uint32_t flags) { + if (fs.shutdown) KernelPanic("FSFileWriteSync - Attempting to write to a file after FSShutdown called.\n"); + + if (offset + bytes > node->directoryEntry->totalSize) { + if (ES_SUCCESS != FSFileResize(node, offset + bytes)) { + return ES_ERROR_COULD_NOT_RESIZE_FILE; + } + } + + FSFile *file = (FSFile *) node; + KWriterLockTake(&file->resizeLock, K_LOCK_SHARED); + EsDefer(KWriterLockReturn(&file->resizeLock, K_LOCK_SHARED)); + + if (!file->fileSystem->write) return ES_ERROR_FILE_ON_READ_ONLY_VOLUME; + if (offset > file->directoryEntry->totalSize) return ES_ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS; + if (bytes > file->directoryEntry->totalSize - offset) bytes = file->directoryEntry->totalSize - offset; + if (!bytes) return 0; + + EsError error = CCSpaceAccess(&file->cache, (void *) buffer, offset, bytes, + CC_ACCESS_WRITE | ((flags & FS_FILE_ACCESS_USER_BUFFER_MAPPED) ? CC_ACCESS_USER_BUFFER_MAPPED : 0)); + __sync_fetch_and_or(&file->flags, NODE_MODIFIED); + return error == ES_SUCCESS ? bytes : error; +} + +EsError FSFileControl(KNode *node, uint32_t flags) { + FSFile *file = (FSFile *) node; + + if (flags & ES_FILE_CONTROL_FLUSH) { + KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE)); + + CCSpaceFlush(&file->cache); + + KWriterLockTake(&file->writerLock, K_LOCK_EXCLUSIVE); + EsDefer(KWriterLockReturn(&file->writerLock, K_LOCK_EXCLUSIVE)); + + __sync_fetch_and_and(&file->flags, ~NODE_MODIFIED); + + EsError error = FSFileCreateAndResizeOnFileSystem(file, file->directoryEntry->totalSize); + if (error != ES_SUCCESS) return error; + + if (file->fileSystem->sync) { + // TODO Should we also sync the parent? + FSDirectory *parent = file->directoryEntry->parent; + + if (parent) KWriterLockTake(&parent->writerLock, K_LOCK_EXCLUSIVE); + file->fileSystem->sync(parent, file); + if (parent) KWriterLockReturn(&parent->writerLock, K_LOCK_EXCLUSIVE); + } + + if (file->error != ES_SUCCESS) { + EsError error = file->error; + file->error = ES_SUCCESS; + return error; + } + } + + return ES_SUCCESS; +} + +////////////////////////////////////////// +// Directories. +////////////////////////////////////////// + +EsError FSNodeDelete(KNode *node) { + if (fs.shutdown) KernelPanic("FSNodeDelete - Attempting to delete a file after FSShutdown called.\n"); + + EsError error = ES_SUCCESS; + + FSDirectoryEntry *entry = node->directoryEntry; + FSDirectory *parent = entry->parent; + FSFile *file = entry->type == ES_NODE_FILE ? (FSFile *) node : nullptr; + + if (!parent) return ES_ERROR_FILE_PERMISSION_NOT_GRANTED; + + // Open a handle to the parent, so that if its directory entry count drops to zero after the operation, + // it is put on the node cache list when the handle is closed. + + if (ES_SUCCESS != FSNodeOpenHandle(parent, ES_FLAGS_DEFAULT, FS_NODE_OPEN_HANDLE_DIRECTORY_TEMPORARY)) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + EsDefer(FSNodeCloseHandle(parent, ES_FLAGS_DEFAULT)); + + if (file) { + KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE); + + if (file->blockResize) { + KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE); + return ES_ERROR_FILE_IN_EXCLUSIVE_USE; + } + + _FSFileResize(file, 0); + } + + KWriterLockTake(&node->writerLock, K_LOCK_EXCLUSIVE); + KWriterLockTake(&parent->writerLock, K_LOCK_EXCLUSIVE); + + if (node->flags & NODE_DELETED) { + error = ES_ERROR_NODE_DELETED; + } else if (entry->type == ES_NODE_DIRECTORY && ((FSDirectory *) node)->entryCount) { + error = ES_ERROR_DIRECTORY_NOT_EMPTY; + } else if (!node->fileSystem->remove) { + error = ES_ERROR_FILE_ON_READ_ONLY_VOLUME; + } else if (node->flags & NODE_CREATED_ON_FILE_SYSTEM) { + error = node->fileSystem->remove(parent, node); + } + + if (error == ES_SUCCESS) { + __sync_fetch_and_or(&node->flags, NODE_DELETED); + TreeRemove(&parent->entries, &entry->item); + parent->entryCount--; + } + + __sync_fetch_and_or(&parent->flags, NODE_MODIFIED); + KWriterLockReturn(&parent->writerLock, K_LOCK_EXCLUSIVE); + KWriterLockReturn(&node->writerLock, K_LOCK_EXCLUSIVE); + if (file) KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE); + + return error; +} + +EsError FSNodeMove(KNode *node, KNode *_newParent, const char *newName, size_t newNameBytes) { + if (fs.shutdown) KernelPanic("FSNodeMove - Attempting to move a file after FSShutdown called.\n"); + + if (!FSCheckPathForIllegalCharacters(newName, newNameBytes)) { + return ES_ERROR_ILLEGAL_PATH; + } + + FSDirectoryEntry *entry = node->directoryEntry; + FSDirectory *newParent = (FSDirectory *) _newParent; + FSDirectory *oldParent = entry->parent; + + // Check the move is valid. + + if (newParent->directoryEntry->type != ES_NODE_DIRECTORY) { + return ES_ERROR_TARGET_INVALID_TYPE; + } + + if (!oldParent || oldParent->fileSystem != newParent->fileSystem || oldParent->fileSystem != node->fileSystem) { + return ES_ERROR_VOLUME_MISMATCH; + } + + if (!newNameBytes || newNameBytes > ES_MAX_DIRECTORY_CHILD_NAME_LENGTH) { + return ES_ERROR_INVALID_NAME; + } + + for (uintptr_t i = 0; i < newNameBytes; i++) { + if (newName[i] == '/') { + return ES_ERROR_INVALID_NAME; + } + } + + if (!node->fileSystem->move) { + return ES_ERROR_FILE_ON_READ_ONLY_VOLUME; + } + + // Open a handle to the parent, so that if its directory entry count drops to zero after the operation, + // it is put on the node cache list when the handle is closed. + + if (ES_SUCCESS != FSNodeOpenHandle(oldParent, ES_FLAGS_DEFAULT, FS_NODE_OPEN_HANDLE_DIRECTORY_TEMPORARY)) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + EsDefer(FSNodeCloseHandle(oldParent, ES_FLAGS_DEFAULT)); + + EsError error = ES_SUCCESS; + bool alreadyExists = false; + void *newKeyBuffer = nullptr; + + KWriterLock *locks[] = { &node->writerLock, &oldParent->writerLock, &newParent->writerLock }; + KWriterLockTakeMultiple(locks, oldParent == newParent ? 2 : 3, K_LOCK_EXCLUSIVE); + + KMutexAcquire(&node->fileSystem->moveMutex); + EsDefer(KMutexRelease(&node->fileSystem->moveMutex)); + + KNode *newAncestor = newParent, *oldAncestor; + + while (newAncestor) { + if (newAncestor == node) { + // We are trying to move this node into a folder within itself. + error = ES_ERROR_TARGET_WITHIN_SOURCE; + goto fail; + } + + newAncestor = newAncestor->directoryEntry->parent; + } + + if ((node->flags | newParent->flags) & NODE_DELETED) { + error = ES_ERROR_NODE_DELETED; + goto fail; + } + + // Check a node with the same name doesn't already exist in the new directory. + + alreadyExists = TreeFind(&newParent->entries, MakeLongKey(newName, newNameBytes), TREE_SEARCH_EXACT); + + if (!alreadyExists && (~newParent->flags & NODE_ENUMERATED_ALL_DIRECTORY_ENTRIES)) { + // The entry is not cached; load it from the file system. + node->fileSystem->scan(newName, newNameBytes, newParent); + alreadyExists = TreeFind(&newParent->entries, MakeLongKey(newName, newNameBytes), TREE_SEARCH_EXACT); + } + + if (alreadyExists) { + error = ES_ERROR_FILE_ALREADY_EXISTS; + goto fail; + } + + // Allocate a buffer for the new key before we try to do anything permanent... + + newKeyBuffer = nullptr; + + if (newNameBytes > sizeof(entry->inlineName)) { + newKeyBuffer = EsHeapAllocate(newNameBytes, false, K_FIXED); + + if (!newKeyBuffer) { + error = ES_ERROR_INSUFFICIENT_RESOURCES; + goto fail; + } + } + + // Move the node on the file system, if it has been created. + + if (entry->node && (entry->node->flags & NODE_CREATED_ON_FILE_SYSTEM)) { + error = node->fileSystem->move(oldParent, node, newParent, newName, newNameBytes); + + if (error != ES_SUCCESS) { + goto fail; + } + } + + // Update the node's parent in our cache. + + entry->parent = newParent; + + TreeRemove(&oldParent->entries, &entry->item); + + entry->item.key.longKey = newKeyBuffer ?: entry->inlineName; + EsMemoryCopy(entry->item.key.longKey, newName, newNameBytes); + entry->item.key.longKeyBytes = newNameBytes; + + TreeInsert(&newParent->entries, &entry->item, entry, entry->item.key); + + oldParent->entryCount--; + + if (oldParent->directoryEntry->directoryChildren != ES_DIRECTORY_CHILDREN_UNKNOWN) { + oldParent->directoryEntry->directoryChildren--; + } + + newParent->entryCount++; + + if (newParent->directoryEntry->directoryChildren != ES_DIRECTORY_CHILDREN_UNKNOWN) { + newParent->directoryEntry->directoryChildren++; + } + + // Move the size of the node from the old to the new ancestors. + + oldAncestor = oldParent; + + while (oldAncestor) { + oldAncestor->directoryEntry->totalSize -= entry->totalSize; + oldAncestor = oldAncestor->directoryEntry->parent; + } + + newAncestor = newParent; + + while (newAncestor) { + newAncestor->directoryEntry->totalSize += entry->totalSize; + newAncestor = newAncestor->directoryEntry->parent; + } + + fail:; + + if (error != ES_SUCCESS) { + if (newKeyBuffer) { + EsHeapFree(newKeyBuffer, newNameBytes, K_FIXED); + } + } + + if (oldParent != newParent) { + KWriterLockReturn(&oldParent->writerLock, K_LOCK_EXCLUSIVE); + } + + __sync_fetch_and_or(&node->flags, NODE_MODIFIED); + __sync_fetch_and_or(&newParent->flags, NODE_MODIFIED); + __sync_fetch_and_or(&oldParent->flags, NODE_MODIFIED); + + KWriterLockReturn(&newParent->writerLock, K_LOCK_EXCLUSIVE); + KWriterLockReturn(&node->writerLock, K_LOCK_EXCLUSIVE); + + return error; +} + +void _FSDirectoryEnumerateChildrenVisit(AVLItem *item, K_USER_BUFFER EsDirectoryChild *buffer, size_t bufferSize, uintptr_t *position) { + if (!item || *position == bufferSize) { + return; + } + + FSDirectoryEntry *entry = item->thisItem; + EsDirectoryChild *output = buffer + *position; + *position = *position + 1; + + if (entry->node && (entry->node->flags & NODE_DELETED)) { + KernelPanic("_FSDirectoryEnumerateChildrenVisit - Deleted node %x found in directory tree.\n"); + } + + size_t nameBytes = entry->item.key.longKeyBytes > ES_MAX_DIRECTORY_CHILD_NAME_LENGTH ? ES_MAX_DIRECTORY_CHILD_NAME_LENGTH : entry->item.key.longKeyBytes; + EsMemoryCopy(output->name, entry->item.key.longKey, nameBytes); + output->type = entry->type; + output->fileSize = entry->totalSize; + output->directoryChildren = entry->directoryChildren; + output->nameBytes = nameBytes; + + _FSDirectoryEnumerateChildrenVisit(item->children[0], buffer, bufferSize, position); + _FSDirectoryEnumerateChildrenVisit(item->children[1], buffer, bufferSize, position); +} + +ptrdiff_t FSDirectoryEnumerateChildren(KNode *node, K_USER_BUFFER EsDirectoryChild *buffer, size_t bufferSize) { + // uint64_t start = ProcessorReadTimeStamp(); + + if (node->directoryEntry->type != ES_NODE_DIRECTORY) { + KernelPanic("FSDirectoryEnumerateChildren - Node %x is not a directory.\n", node); + } + + FSDirectory *directory = (FSDirectory *) node; + + // I think it's safe to modify the user's buffer with this lock. + KWriterLockTake(&directory->writerLock, K_LOCK_EXCLUSIVE); + + if (~directory->flags & NODE_ENUMERATED_ALL_DIRECTORY_ENTRIES) { + EsError error = directory->fileSystem->enumerate(directory); + + if (error != ES_SUCCESS) { + KWriterLockReturn(&directory->writerLock, K_LOCK_EXCLUSIVE); + return error; + } + + __sync_fetch_and_or(&directory->flags, NODE_ENUMERATED_ALL_DIRECTORY_ENTRIES); + directory->directoryEntry->directoryChildren = directory->entryCount; + } + + uintptr_t position = 0; + _FSDirectoryEnumerateChildrenVisit(directory->entries.root, buffer, bufferSize, &position); + + KWriterLockReturn(&directory->writerLock, K_LOCK_EXCLUSIVE); + + // uint64_t end = ProcessorReadTimeStamp(); + // EsPrint("FSDirectoryEnumerateChildren took %dmcs for %d items.\n", (end - start) / KGetTimeStampTicksPerUs(), position); + + return position; +} + +void FSNodeFree(KNode *node) { + FSDirectoryEntry *entry = node->directoryEntry; + + if (entry->node != node) { + KernelPanic("FSNodeFree - FSDirectoryEntry node mismatch for node %x.\n", node); + } else if (node->flags & NODE_IN_CACHE_LIST) { + KernelPanic("FSNodeFree - Node %x is in the cache list.\n", node); + } + + if (entry->type == ES_NODE_FILE) { + CCSpaceDestroy(&((FSFile *) node)->cache); + } else if (entry->type == ES_NODE_DIRECTORY) { + if (((FSDirectory *) node)->entries.root) { + KernelPanic("FSNodeFree - Directory %x still had items in its tree.\n", node); + } + } + + if (node->driverNode) { + node->fileSystem->close(node); + } + + // EsPrint("Freeing node with name '%s'...\n", entry->item.key.longKeyBytes, entry->item.key.longKey); + + bool deleted = node->flags & NODE_DELETED; + + KFileSystem *fileSystem = node->fileSystem; + EsHeapFree(node, entry->type == ES_NODE_DIRECTORY ? sizeof(FSDirectory) : sizeof(FSFile), K_FIXED); + + if (!deleted) { + KSpinlockAcquire(&fs.updateNodeHandles); + MMObjectCacheInsert(&fileSystem->cachedDirectoryEntries, &entry->cacheItem); + entry->node = nullptr; + entry->removingNodeFromCache = false; + KSpinlockRelease(&fs.updateNodeHandles); + } else { + // The node has been deleted, and we're about to deallocate the directory entry anyway. + // See FSNodeCloseHandle. + } +} + +void FSNodeScanAndLoadComplete(KNode *node, bool success) { + if (success) { + if (node->flags & NODE_IN_CACHE_LIST) { + KernelPanic("FSNodeScanAndLoadComplete - Node %x is already in the cache list.\n", node); + } else if (node->directoryEntry->type == ES_NODE_DIRECTORY && ((FSDirectory *) node)->entryCount) { + KernelPanic("FSNodeScanAndLoadComplete - Node %x has entries.\n", node); + } + + // The driver just scanned and loaded the node. + // Put it in the cache list; this is similar to what's done in FSNodeCreate. + // This is because we haven't opened any handles to the node yet, + // so for correctness it must be on the cache list. + // However, we do not expect it to be freed (although it would not be a problem if it were), + // since the parent's writer lock should be taken. + MMObjectCacheInsert(&node->fileSystem->cachedNodes, &node->cacheItem); + __sync_fetch_and_or(&node->flags, NODE_IN_CACHE_LIST); + } else { + FSNodeFree(node); + } +} + +void FSDirectoryEntryFree(FSDirectoryEntry *entry) { + if (entry->cacheItem.previous || entry->cacheItem.next) { + KernelPanic("FSDirectoryEntryFree - Entry %x is in cache.\n", entry); +#ifdef TREE_VALIDATE + } else if (entry->item.tree) { + KernelPanic("FSDirectoryEntryFree - Entry %x is in parent's tree.\n", entry); +#endif + } + + // EsPrint("Freeing directory entry with name '%s'...\n", entry->item.key.longKeyBytes, entry->item.key.longKey); + + if (entry->item.key.longKey != entry->inlineName) { + EsHeapFree((void *) entry->item.key.longKey, entry->item.key.longKeyBytes, K_FIXED); + } + + EsHeapFree(entry, 0, K_FIXED); +} + +EsError FSNodeCreate(FSDirectory *parent, const char *name, size_t nameBytes, EsNodeType type) { + KWriterLockAssertExclusive(&parent->writerLock); + KFileSystem *fileSystem = parent->fileSystem; + + if (!fileSystem->create) { + // Read-only file system. + return ES_ERROR_FILE_ON_READ_ONLY_VOLUME; + } + + KNodeMetadata metadata = {}; + metadata.type = type; + + KNode *node; + EsError error = FSDirectoryEntryFound(parent, &metadata, nullptr, name, nameBytes, false, &node); + if (error != ES_SUCCESS) return error; + + if (parent->directoryEntry->directoryChildren != ES_DIRECTORY_CHILDREN_UNKNOWN) { + parent->directoryEntry->directoryChildren++; + } + + __sync_fetch_and_or(&parent->flags, NODE_MODIFIED); + __sync_fetch_and_or(&node->flags, NODE_MODIFIED); + + // Only create directories immediately; files are created in FSWriteFromCache. + + if (type != ES_NODE_FILE) { + error = fileSystem->create(name, nameBytes, type, parent, node, node->directoryEntry + 1); + + if (error == ES_SUCCESS) { + __sync_fetch_and_or(&node->flags, NODE_CREATED_ON_FILE_SYSTEM); + } else { + // TODO Mark the node with an error. + } + } + + // Put the node onto the object cache list. + // Since the parent directory is locked, it should stay around for long enough to be immediately found FSNodeTraverseLayer. + if (node->flags & NODE_IN_CACHE_LIST) KernelPanic("FSNodeCreate - Node %x is already in the cache list.\n", node); + MMObjectCacheInsert(&node->fileSystem->cachedNodes, &node->cacheItem); + __sync_fetch_and_or(&node->flags, NODE_IN_CACHE_LIST); + + return ES_SUCCESS; +} + +EsError FSDirectoryEntryAllocateNode(FSDirectoryEntry *entry, KFileSystem *fileSystem, bool createdOnFileSystem, bool inDirectoryEntryCache) { + { + KSpinlockAcquire(&fs.updateNodeHandles); + EsDefer(KSpinlockRelease(&fs.updateNodeHandles)); + + if (entry->removingThisFromCache) { + if (!inDirectoryEntryCache) { + KernelPanic("FSDirectoryEntryAllocateNode - Entry %x is being removed from the cache, " + "but the caller did not expect it to have ever been in the cache.\n", entry); + } + + return ES_ERROR_DIRECTORY_ENTRY_BEING_REMOVED; + } + + if (inDirectoryEntryCache) { + MMObjectCacheRemove(&fileSystem->cachedDirectoryEntries, &entry->cacheItem); + } + } + + KNode *node = (KNode *) EsHeapAllocate(entry->type == ES_NODE_DIRECTORY ? sizeof(FSDirectory) : sizeof(FSFile), true, K_FIXED); + + if (!node) { + MMObjectCacheInsert(&fileSystem->cachedDirectoryEntries, &entry->cacheItem); + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + if (entry->type == ES_NODE_DIRECTORY) { + FSDirectory *directory = (FSDirectory *) node; + directory->entries.longKeys = true; + + if (!createdOnFileSystem) { + // We just created the directory, so we've definitely got all the entries. + directory->flags |= NODE_ENUMERATED_ALL_DIRECTORY_ENTRIES; + } + } else if (entry->type == ES_NODE_FILE) { + FSFile *file = (FSFile *) node; + file->fsFileSize = entry->totalSize; + file->fsZeroAfter = entry->totalSize; + file->cache.callbacks = &fsFileCacheCallbacks; + + if (!CCSpaceInitialise(&file->cache)) { + MMObjectCacheInsert(&fileSystem->cachedDirectoryEntries, &entry->cacheItem); + EsHeapFree(node, 0, K_FIXED); + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + } + + static uint64_t nextNodeID = 1; + node->id = __sync_fetch_and_add(&nextNodeID, 1); + + // TODO On file systems that support it, use their stable unique ID for the node. + // - What happens with delay-created files? + // - This ID should be unique among all volumes. + // - Maybe this should be a separate ID? + + if (createdOnFileSystem) { + node->flags |= NODE_CREATED_ON_FILE_SYSTEM; + } + + node->directoryEntry = entry; + node->fileSystem = fileSystem; + node->error = ES_SUCCESS; + entry->node = node; + return ES_SUCCESS; +} + +EsError FSDirectoryEntryFound(KNode *_parent, KNodeMetadata *metadata, + const void *driverData, const void *name, size_t nameBytes, + bool update, KNode **node) { + FSDirectory *parent = (FSDirectory *) _parent; + size_t driverDataBytes = parent->fileSystem->directoryEntryDataBytes; + KWriterLockAssertExclusive(&parent->writerLock); + + AVLItem *existingEntry = TreeFind(&parent->entries, MakeLongKey(name, nameBytes), TREE_SEARCH_EXACT); + + if (existingEntry) { + if (!driverData) { + KernelPanic("FSDirectoryEntryFound - Directory entry '%s' in %x already exists, but no driverData is provided.\n", + nameBytes, name, parent); + } + + if (node) { + if (!update) { + if (existingEntry->thisItem->node) { + KernelPanic("FSDirectoryEntryFound - Entry exists and is created on file system.\n"); + } + + EsError error = FSDirectoryEntryAllocateNode(existingEntry->thisItem, parent->fileSystem, true, true); + + if (error != ES_SUCCESS) { + return error; + } + } + + *node = existingEntry->thisItem->node; + } else if (update) { + EsMemoryCopy(existingEntry->thisItem + 1, driverData, driverDataBytes); + } else if (EsMemoryCompare(existingEntry->thisItem + 1, driverData, driverDataBytes)) { + // NOTE This can be caused by a directory containing an entry with the same name multiple times. + KernelLog(LOG_ERROR, "FS", "directory entry driverData changed", "FSDirectoryEntryFound - 'update' is false but driverData has changed.\n"); + } + + return ES_SUCCESS; + } else if (update) { + return ES_ERROR_FILE_DOES_NOT_EXIST; + } + + FSDirectoryEntry *entry = (FSDirectoryEntry *) EsHeapAllocate(sizeof(FSDirectoryEntry) + driverDataBytes, true, K_FIXED); + + if (!entry) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + if (nameBytes > sizeof(entry->inlineName)) { + entry->item.key.longKey = EsHeapAllocate(nameBytes, false, K_FIXED); + + if (!entry->item.key.longKey) { + EsHeapFree(entry, sizeof(FSDirectoryEntry) + driverDataBytes, K_FIXED); + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + } else { + entry->item.key.longKey = entry->inlineName; + } + + EsMemoryCopy(entry->item.key.longKey, name, nameBytes); + entry->item.key.longKeyBytes = nameBytes; + + EsMemoryCopy(entry, metadata, sizeof(KNodeMetadata)); + if (driverData) EsMemoryCopy(entry + 1, driverData, driverDataBytes); + entry->parent = parent; + + TreeInsert(&parent->entries, &entry->item, entry, entry->item.key, AVL_DUPLICATE_KEYS_PANIC); + parent->entryCount++; + + if (node) { + if (!update) { + EsError error = FSDirectoryEntryAllocateNode(entry, parent->fileSystem, driverData, false); + + if (error != ES_SUCCESS) { + return error; + } + } + + *node = entry->node; + } else { + MMObjectCacheInsert(&parent->fileSystem->cachedDirectoryEntries, &entry->cacheItem); + } + + return ES_SUCCESS; +} + +void FSNodeUpdateDriverData(KNode *node, const void *newDriverData) { + KWriterLockAssertExclusive(&node->writerLock); + EsMemoryCopy(node->directoryEntry + 1, newDriverData, node->fileSystem->directoryEntryDataBytes); +} + +void FSNodeSynchronize(KNode *node) { + if (node->directoryEntry->type == ES_NODE_FILE) { + FSFile *file = (FSFile *) node; + CCSpaceFlush(&file->cache); + KWriterLockTake(&node->writerLock, K_LOCK_EXCLUSIVE); + FSFileCreateAndResizeOnFileSystem(file, file->directoryEntry->totalSize); + KWriterLockReturn(&node->writerLock, K_LOCK_EXCLUSIVE); + } + + if (node->flags & NODE_MODIFIED) { + if (node->fileSystem->sync && (node->flags & NODE_CREATED_ON_FILE_SYSTEM /* might be false if create() failed */)) { + FSDirectory *parent = node->directoryEntry->parent; + + if (parent) KWriterLockTake(&parent->writerLock, K_LOCK_EXCLUSIVE); + node->fileSystem->sync(parent, node); + if (parent) KWriterLockReturn(&parent->writerLock, K_LOCK_EXCLUSIVE); + } + } +} + +void FSUnmountFileSystem(uintptr_t argument) { + KFileSystem *fileSystem = (KFileSystem *) argument; + KernelLog(LOG_INFO, "FS", "unmount start", "Unmounting file system %x...\n", fileSystem); + + MMObjectCacheUnregister(&fileSystem->cachedNodes); + MMObjectCacheUnregister(&fileSystem->cachedDirectoryEntries); + + while (fileSystem->cachedNodes.count || fileSystem->cachedDirectoryEntries.count) { + MMObjectCacheFlush(&fileSystem->cachedNodes); + MMObjectCacheFlush(&fileSystem->cachedDirectoryEntries); + } + + if (fileSystem->unmount) { + fileSystem->unmount(fileSystem); + } + + KernelLog(LOG_INFO, "FS", "unmount complete", "Unmounted file system %x.\n", fileSystem); + KDeviceCloseHandle(fileSystem->children[0]); + __sync_fetch_and_sub(&fs.fileSystemsUnmounting, 1); + KEventSet(&fs.fileSystemUnmounted, false, true); +} + +////////////////////////////////////////// +// Opening nodes. +////////////////////////////////////////// + +#define NODE_INCREMENT_HANDLE_COUNT(node) \ + node->handles++; \ + node->fileSystem->totalHandleCount++; \ + fs.totalHandleCount++; + +EsError FSDirectoryEntryOpenHandleToNode(FSDirectoryEntry *directoryEntry) { + KSpinlockAcquire(&fs.updateNodeHandles); + EsDefer(KSpinlockRelease(&fs.updateNodeHandles)); + + if (!directoryEntry->node || directoryEntry->removingNodeFromCache) { + return ES_ERROR_NODE_NOT_LOADED; + } + + if (directoryEntry->node->handles == NODE_MAX_ACCESSORS) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + KNode *node = directoryEntry->node; + + if (!node->handles) { + if (node->directoryEntry->type == ES_NODE_DIRECTORY && ((FSDirectory *) node)->entryCount) { + if (node->flags & NODE_IN_CACHE_LIST) KernelPanic("FSNodeOpenHandle - Directory %x with entries is in the cache list.\n", node); + } else { + if (~node->flags & NODE_IN_CACHE_LIST) KernelPanic("FSNodeOpenHandle - Node %x is not in the cache list.\n", node); + MMObjectCacheRemove(&node->fileSystem->cachedNodes, &node->cacheItem); + __sync_fetch_and_and(&node->flags, ~NODE_IN_CACHE_LIST); + } + } + + NODE_INCREMENT_HANDLE_COUNT(node); + return ES_SUCCESS; +} + +EsError FSNodeOpenHandle(KNode *node, uint32_t flags, uint8_t mode) { + { + // See comment in FSNodeCloseHandle for why we use the spinlock. + KSpinlockAcquire(&fs.updateNodeHandles); + EsDefer(KSpinlockRelease(&fs.updateNodeHandles)); + + if (node->handles && mode == FS_NODE_OPEN_HANDLE_FIRST) { + KernelPanic("FSNodeOpenHandle - Trying to open first handle to %x, but it already has handles.\n", node); + } else if (!node->handles && mode == FS_NODE_OPEN_HANDLE_STANDARD) { + KernelPanic("FSNodeOpenHandle - Trying to open handle to %x, but it has no handles.\n", node); + } + + if (node->handles == NODE_MAX_ACCESSORS) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + if (node->directoryEntry->type == ES_NODE_FILE) { + FSFile *file = (FSFile *) node; + + if (flags & ES_FILE_READ) { + if (file->countWrite > 0) return ES_ERROR_FILE_HAS_WRITERS; + } else if (flags & ES_FILE_WRITE_EXCLUSIVE) { + if (flags & _ES_NODE_FROM_WRITE_EXCLUSIVE) { + if (!file->countWrite || (~file->flags & NODE_HAS_EXCLUSIVE_WRITER)) { + KernelPanic("FSNodeOpenHandle - File %x is invalid state for a handle to have the _ES_NODE_FROM_WRITE_EXCLUSIVE flag.\n", file); + } + } else { + if (file->countWrite) { + return ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE; + } + } + } else if (flags & ES_FILE_WRITE) { + if ((file->flags & NODE_HAS_EXCLUSIVE_WRITER) || file->countWrite < 0) return ES_ERROR_FILE_IN_EXCLUSIVE_USE; + } + + if (flags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE)) { + if (!file->fileSystem->write) { + return ES_ERROR_FILE_ON_READ_ONLY_VOLUME; + } + } + + if (flags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE)) file->countWrite++; + if (flags & ES_FILE_READ) file->countWrite--; + if (flags & ES_FILE_WRITE_EXCLUSIVE) __sync_fetch_and_or(&node->flags, NODE_HAS_EXCLUSIVE_WRITER); + } + + NODE_INCREMENT_HANDLE_COUNT(node); + + // EsPrint("Open handle to %s (%d; %d).\n", node->directoryEntry->item.key.longKeyBytes, + // node->directoryEntry->item.key.longKey, node->handles, fs.totalHandleCount); + } + + if (node->directoryEntry->type == ES_NODE_FILE && (flags & ES_NODE_PREVENT_RESIZE)) { + // Modify blockResize with the resizeLock, to prevent a resize being in progress when blockResize becomes positive. + FSFile *file = (FSFile *) node; + KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE); + file->blockResize++; + KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE); + } + + return ES_SUCCESS; +} + +void FSNodeCloseHandle(KNode *node, uint32_t flags) { + if (node->directoryEntry->type == ES_NODE_FILE && (flags & ES_NODE_PREVENT_RESIZE)) { + FSFile *file = (FSFile *) node; + KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE); + file->blockResize--; + KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE); + } + + // Don't use the node's writer lock for this. + // It'd be unnecessarily require getting exclusive access. + // There's not much to do, so just use a global spinlock. + KSpinlockAcquire(&fs.updateNodeHandles); + + if (node->handles) { + node->handles--; + node->fileSystem->totalHandleCount--; + fs.totalHandleCount--; + + // EsPrint("Close handle to %s (%d; %d).\n", node->directoryEntry->item.key.longKeyBytes, + // node->directoryEntry->item.key.longKey, node->handles, fs.totalHandleCount); + } else { + KernelPanic("FSNodeCloseHandle - Node %x had no handles.\n", node); + } + + if (node->directoryEntry->type == ES_NODE_FILE) { + FSFile *file = (FSFile *) node; + + if ((flags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE))) { + if (file->countWrite <= 0) KernelPanic("FSNodeCloseHandle - Invalid countWrite on node %x.\n", node); + file->countWrite--; + } + + if ((flags & ES_FILE_READ)) { + if (file->countWrite >= 0) KernelPanic("FSNodeCloseHandle - Invalid countWrite on node %x.\n", node); + file->countWrite++; + } + + if ((flags & ES_FILE_WRITE_EXCLUSIVE) && file->countWrite == 0) { + if (~file->flags & NODE_HAS_EXCLUSIVE_WRITER) KernelPanic("FSNodeCloseHandle - Missing exclusive flag on node %x.\n", node); + __sync_fetch_and_and(&node->flags, ~NODE_HAS_EXCLUSIVE_WRITER); + } + } + + bool deleted = (node->flags & NODE_DELETED) && !node->handles; + bool unmounted = !node->fileSystem->totalHandleCount; + bool hasEntries = node->directoryEntry->type == ES_NODE_DIRECTORY && ((FSDirectory *) node)->entryCount; + if (unmounted && node->handles) KernelPanic("FSNodeCloseHandle - File system has no handles but this node %x has handles.\n", node); + KFileSystem *fileSystem = node->fileSystem; + + if (!node->handles && !deleted && !hasEntries) { + if (node->flags & NODE_IN_CACHE_LIST) KernelPanic("FSNodeCloseHandle - Node %x is already in the cache list.\n", node); + MMObjectCacheInsert(&node->fileSystem->cachedNodes, &node->cacheItem); + __sync_fetch_and_or(&node->flags, NODE_IN_CACHE_LIST); + node = nullptr; // The node could be freed at any time after MMObjectCacheInsert. + } + + KSpinlockRelease(&fs.updateNodeHandles); + + if (unmounted && !fileSystem->unmounting) { + // All handles to all nodes in the file system have been closed. + // Spawn a thread to unmount it. + fileSystem->unmounting = true; + __sync_fetch_and_add(&fs.fileSystemsUnmounting, 1); + KThreadCreate("FSUnmount", FSUnmountFileSystem, (uintptr_t) fileSystem); + } + + if (deleted) { + if (!node->directoryEntry->parent) KernelPanic("FSNodeCloseHandle - A root directory %x was deleted.\n", node); + + // The node has been deleted, and no handles remain. + // When it was deleted, it should have been removed from its parent directory, + // both on the file system and in the directory lookup structures. + // So, we are free to deallocate the node. + + FSDirectoryEntry *entry = node->directoryEntry; + FSNodeFree(node); + FSDirectoryEntryFree(entry); + } +} + +EsError FSNodeTraverseLayer(uintptr_t *sectionEnd, + const char *path, size_t pathBytes, bool isFinalPath, + KFileSystem *fileSystem, FSDirectory *directory, + uint32_t flags, KNode **node, bool *createdNode) { + EsError error = ES_SUCCESS; + + *sectionEnd = *sectionEnd + 1; + uintptr_t sectionStart = *sectionEnd; + + while (*sectionEnd != pathBytes && path[*sectionEnd] != '/') { + *sectionEnd = *sectionEnd + 1; + } + + const char *name = path + sectionStart; + size_t nameBytes = *sectionEnd - sectionStart; + AVLKey key = MakeLongKey(name, nameBytes); + FSDirectoryEntry *entry = nullptr; + AVLItem *treeItem = nullptr; + + // First, try to get the cached directory entry with shared access. + + { + KWriterLockTake(&directory->writerLock, K_LOCK_SHARED); + + treeItem = TreeFind(&directory->entries, key, TREE_SEARCH_EXACT); + bool needExclusiveAccess = true; + + if (treeItem) { + error = FSDirectoryEntryOpenHandleToNode(treeItem->thisItem); + + if (error == ES_ERROR_NODE_NOT_LOADED) { + error = ES_SUCCESS; // Proceed to use exclusive access. + } else { + entry = treeItem->thisItem; + needExclusiveAccess = false; + } + } + + KWriterLockReturn(&directory->writerLock, K_LOCK_SHARED); + + if (!needExclusiveAccess) { + goto usedSharedAccess; + } + } + + tryAgain:; + + KWriterLockTake(&directory->writerLock, K_LOCK_EXCLUSIVE); + + treeItem = TreeFind(&directory->entries, key, TREE_SEARCH_EXACT); + + if (!treeItem && (~directory->flags & NODE_ENUMERATED_ALL_DIRECTORY_ENTRIES)) { + // The entry is not cached; load it from the file system. + fileSystem->scan(name, nameBytes, directory); + treeItem = TreeFind(&directory->entries, key, TREE_SEARCH_EXACT); + } + + if (!treeItem) { + // The node does not exist. + + if (flags & _ES_NODE_NO_WRITE_BASE) { + error = ES_ERROR_FILE_PERMISSION_NOT_GRANTED; + goto failed; + } + + if (*sectionEnd == pathBytes && isFinalPath) { + if (~flags & ES_NODE_FAIL_IF_NOT_FOUND) { + error = FSNodeCreate(directory, name, nameBytes, flags & ES_NODE_DIRECTORY); + if (error != ES_SUCCESS) goto failed; + treeItem = TreeFind(&directory->entries, key, TREE_SEARCH_EXACT); + flags &= ~ES_NODE_FAIL_IF_FOUND; + *createdNode = true; + } + + if (!treeItem) { + error = ES_ERROR_FILE_DOES_NOT_EXIST; + goto failed; + } + } else { + if (flags & ES_NODE_CREATE_DIRECTORIES) { + error = FSNodeCreate(directory, name, nameBytes, ES_NODE_DIRECTORY); + if (error != ES_SUCCESS) goto failed; + treeItem = TreeFind(&directory->entries, key, TREE_SEARCH_EXACT); + } + + if (!treeItem) { + error = ES_ERROR_PATH_NOT_TRAVERSABLE; + goto failed; + } + } + } + + entry = treeItem->thisItem; + + if (!entry->node) { + // The node has not be loaded; load it from the file system. + + error = FSDirectoryEntryAllocateNode(entry, fileSystem, true, true); + + if (error == ES_ERROR_DIRECTORY_ENTRY_BEING_REMOVED) { + // The directory entry is being removed. + // Since this will take the directory's writer lock, we shouldn't need an additional synchronisation object. + // Instead we can just yield to wait for a bit, then try again. + // Similar to the strategy for the ES_ERROR_NODE_NOT_LOADED race below. + KWriterLockReturn(&directory->writerLock, K_LOCK_EXCLUSIVE); + KYield(); + goto tryAgain; + } + + if (error != ES_SUCCESS) { + goto failed; + } + + error = fileSystem->load(directory, entry->node, entry, entry + 1); + + if (error != ES_SUCCESS) { + FSNodeFree(entry->node); + goto failed; + } + + if (ES_SUCCESS != FSNodeOpenHandle(entry->node, 0, FS_NODE_OPEN_HANDLE_FIRST)) { + KernelPanic("FSNodeTraverseLayer - FSNodeOpenHandle failed while opening first handle for %x.\n", entry->node); + } + } else { + error = FSDirectoryEntryOpenHandleToNode(entry); + + if (error == ES_ERROR_NODE_NOT_LOADED) { + // The node is being removed, or was just removed. + // The main bottleneck in removing a node from the cache is CCSpaceFlush. + // Since this will take the directory's writer lock, we shouldn't need an additional synchronisation object. + // Instead we can just yield to wait for a bit, then try again. + KWriterLockReturn(&directory->writerLock, K_LOCK_EXCLUSIVE); + KYield(); + goto tryAgain; + } + } + + failed:; + KWriterLockReturn(&directory->writerLock, K_LOCK_EXCLUSIVE); + usedSharedAccess:; + FSNodeCloseHandle(directory, 0); + + if (error != ES_SUCCESS) { + return error; + } + + if (*sectionEnd != pathBytes || !isFinalPath) { + if (entry->node->directoryEntry->type != ES_NODE_DIRECTORY) { + FSNodeCloseHandle(directory, 0); + return ES_ERROR_PATH_NOT_TRAVERSABLE; + } + } + + *node = entry->node; + return ES_SUCCESS; +} + +KNodeInformation FSNodeOpen(const char *path, size_t pathBytes, uint32_t flags, KNode *baseDirectory) { + if ((1 << (flags & 0xF)) & ~(0x117)) { + // You should only pass one access flag! (or none) + return { ES_ERROR_FILE_PERMISSION_NOT_GRANTED }; + } + + if (fs.shutdown) return { ES_ERROR_PATH_NOT_TRAVERSABLE }; + if (pathBytes && path[pathBytes - 1] == '/') pathBytes--; + + if (!FSCheckPathForIllegalCharacters(path, pathBytes)) { + return { ES_ERROR_ILLEGAL_PATH }; + } + + KFileSystem *fileSystem = nullptr; + FSDirectory *directory = nullptr; + EsError error = ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME; + + KWriterLockTake(&fs.fileSystemsLock, K_LOCK_SHARED); + + if (!baseDirectory) { + fileSystem = fs.bootFileSystem; + directory = fileSystem ? (FSDirectory *) fileSystem->rootDirectory : nullptr; + } else { + fileSystem = baseDirectory->fileSystem; + directory = (FSDirectory *) baseDirectory; + + if (directory->directoryEntry->type != ES_NODE_DIRECTORY) { + KernelPanic("FSNodeOpen - Base directory %x was not a directory.\n", directory); + } + } + + KWriterLockReturn(&fs.fileSystemsLock, K_LOCK_SHARED); + + KNode *node = pathBytes ? nullptr : directory; + + error = FSNodeOpenHandle(directory, 0, FS_NODE_OPEN_HANDLE_STANDARD); + if (error != ES_SUCCESS) return { error }; + + bool createdNode = false; + + for (uintptr_t sectionEnd = 0; sectionEnd < pathBytes; ) { + error = FSNodeTraverseLayer(§ionEnd, path, pathBytes, true, fileSystem, directory, flags, &node, &createdNode); + if (error != ES_SUCCESS) return { error }; + if (sectionEnd != pathBytes) directory = (FSDirectory *) node; + } + + if (node->directoryEntry->type != ES_NODE_DIRECTORY && (flags & ES_NODE_DIRECTORY)) { + return { ES_ERROR_INCORRECT_NODE_TYPE }; + } + + if ((flags & ES_NODE_FAIL_IF_FOUND) && !createdNode) { + error = ES_ERROR_FILE_ALREADY_EXISTS; + } else { + error = FSNodeOpenHandle(node, flags, FS_NODE_OPEN_HANDLE_STANDARD); + } + + FSNodeCloseHandle(node, 0); + if (error != ES_SUCCESS) node = nullptr; + return { error, node }; +} + +bool FSTrimCachedDirectoryEntry(MMObjectCache *cache) { + FSDirectoryEntry *entry = nullptr; + + KSpinlockAcquire(&fs.updateNodeHandles); + + MMObjectCacheItem *item = MMObjectCacheRemoveLRU(cache); + + if (item) { + entry = EsContainerOf(FSDirectoryEntry, cacheItem, item); + entry->removingThisFromCache = true; + } + + KSpinlockRelease(&fs.updateNodeHandles); + + if (entry) { + if (!entry->parent) { + // This is the root of the file system. + FSDirectoryEntryFree(entry); + } else if (ES_SUCCESS == FSNodeOpenHandle(entry->parent, ES_FLAGS_DEFAULT, FS_NODE_OPEN_HANDLE_DIRECTORY_TEMPORARY)) { + KWriterLockTake(&entry->parent->writerLock, K_LOCK_EXCLUSIVE); + TreeRemove(&entry->parent->entries, &entry->item); + entry->parent->entryCount--; + __sync_fetch_and_and(&entry->parent->flags, ~NODE_ENUMERATED_ALL_DIRECTORY_ENTRIES); + KWriterLockReturn(&entry->parent->writerLock, K_LOCK_EXCLUSIVE); + FSNodeCloseHandle(entry->parent, ES_FLAGS_DEFAULT); // This will put the parent in the node cache if needed. + FSDirectoryEntryFree(entry); + } else { + // A very rare case where the parent directory had so many handles open that a temporary handle couldn't be opened. + // Put it back in the cache, and hopefully next time we try to get rid of it there won't be 16 million handles open on the parent. + // TODO Test this branch! + KSpinlockAcquire(&fs.updateNodeHandles); + entry->removingThisFromCache = false; + MMObjectCacheInsert(cache, &entry->cacheItem); + KSpinlockRelease(&fs.updateNodeHandles); + } + } + + return entry != nullptr; +} + +bool FSTrimCachedNode(MMObjectCache *cache) { + KNode *node = nullptr; + + KSpinlockAcquire(&fs.updateNodeHandles); + + MMObjectCacheItem *item = MMObjectCacheRemoveLRU(cache); + + if (item) { + node = EsContainerOf(KNode, cacheItem, item); + __sync_fetch_and_and(&node->flags, ~NODE_IN_CACHE_LIST); + node->directoryEntry->removingNodeFromCache = true; + } + + KSpinlockRelease(&fs.updateNodeHandles); + + if (node) { + FSNodeSynchronize(node); + FSNodeFree(node); + } + + return node != nullptr; +} + +////////////////////////////////////////// +// DMA transfer buffers. +////////////////////////////////////////// + +struct KDMABuffer { + uintptr_t virtualAddress; + size_t totalByteCount; + uintptr_t offsetBytes; +}; + +uintptr_t KDMABufferGetVirtualAddress(KDMABuffer *buffer) { + return buffer->virtualAddress; +} + +size_t KDMABufferGetTotalByteCount(KDMABuffer *buffer) { + return buffer->totalByteCount; +} + +bool KDMABufferIsComplete(KDMABuffer *buffer) { + return buffer->offsetBytes == buffer->totalByteCount; +} + +KDMASegment KDMABufferNextSegment(KDMABuffer *buffer, bool peek) { + if (buffer->offsetBytes >= buffer->totalByteCount || !buffer->virtualAddress) { + KernelPanic("KDMABufferNextSegment - Invalid state in buffer %x.\n", buffer); + } + + size_t transferByteCount = K_PAGE_SIZE; + uintptr_t virtualAddress = buffer->virtualAddress + buffer->offsetBytes; + uintptr_t physicalAddress = MMArchTranslateAddress(MMGetKernelSpace(), virtualAddress); + uintptr_t offsetIntoPage = virtualAddress & (K_PAGE_SIZE - 1); + + if (!physicalAddress) { + KernelPanic("KDMABufferNextSegment - Page in buffer %x unmapped.\n", buffer); + } + + if (offsetIntoPage) { + transferByteCount = K_PAGE_SIZE - offsetIntoPage; + physicalAddress += offsetIntoPage; + } + + if (transferByteCount > buffer->totalByteCount - buffer->offsetBytes) { + transferByteCount = buffer->totalByteCount - buffer->offsetBytes; + } + + bool isLast = buffer->offsetBytes + transferByteCount == buffer->totalByteCount; + if (!peek) buffer->offsetBytes += transferByteCount; + return { physicalAddress, transferByteCount, isLast }; +} + +////////////////////////////////////////// +// Block devices. +////////////////////////////////////////// + +bool FSBlockDeviceAccess(KBlockDeviceAccessRequest request) { + KBlockDevice *device = request.device; + + if (!request.count) { + return true; + } + + if (device->readOnly && request.operation == K_ACCESS_WRITE) { + KernelPanic("FSBlockDeviceAccess - Drive %x is read-only.\n", device); + } + + if (request.offset / device->sectorSize > device->sectorCount + || (request.offset + request.count) / device->sectorSize > device->sectorCount) { + KernelPanic("FSBlockDeviceAccess - Access out of bounds on drive %x.\n", device); + } + + if ((request.offset % device->sectorSize) || (request.count % device->sectorSize)) { + KernelPanic("FSBlockDeviceAccess - Misaligned access.\n"); + } + + KDMABuffer buffer = *request.buffer; + + if (buffer.virtualAddress & 3) { + KernelPanic("FSBlockDeviceAccess - Buffer must be DWORD aligned.\n"); + } + + KWorkGroup fakeDispatchGroup = {}; + + if (!request.dispatchGroup) { + fakeDispatchGroup.Initialise(); + request.dispatchGroup = &fakeDispatchGroup; + } + + KBlockDeviceAccessRequest r = {}; + r.device = request.device; + r.buffer = &buffer; + r.flags = request.flags; + r.dispatchGroup = request.dispatchGroup; + r.operation = request.operation; + r.offset = request.offset; + + while (request.count) { + r.count = device->maxAccessSectorCount * device->sectorSize; + if (r.count > request.count) r.count = request.count; + buffer.offsetBytes = 0; + buffer.totalByteCount = r.count; + r.count = r.count; + device->access(r); + r.offset += r.count; + buffer.virtualAddress += r.count; + request.count -= r.count; + } + + if (request.dispatchGroup == &fakeDispatchGroup) { + return fakeDispatchGroup.Wait(); + } else { + return true; + } +} + +EsError FSReadIntoBlockCache(CCSpace *fileCache, void *buffer, EsFileOffset offset, EsFileOffset count) { + KFileSystem *fileSystem = (KFileSystem *) fileCache - 1; + return fileSystem->Access(offset, count, K_ACCESS_READ, buffer, ES_FLAGS_DEFAULT, nullptr) ? ES_SUCCESS : ES_ERROR_DRIVE_CONTROLLER_REPORTED; +} + +EsError FSWriteFromBlockCache(CCSpace *fileCache, const void *buffer, EsFileOffset offset, EsFileOffset count) { + KFileSystem *fileSystem = (KFileSystem *) fileCache - 1; + return fileSystem->Access(offset, count, K_ACCESS_WRITE, (void *) buffer, ES_FLAGS_DEFAULT, nullptr) ? ES_SUCCESS : ES_ERROR_DRIVE_CONTROLLER_REPORTED; +} + +const CCSpaceCallbacks fsBlockCacheCallbacks = { + .readInto = FSReadIntoBlockCache, + .writeFrom = FSWriteFromBlockCache, +}; + +bool KFileSystem::Access(EsFileOffset offset, size_t count, int operation, void *buffer, uint32_t flags, KWorkGroup *dispatchGroup) { + if (this->flags & K_DEVICE_REMOVED) { + if (dispatchGroup) { + dispatchGroup->Start(); + dispatchGroup->End(false); + } + + return false; + } + + bool blockDeviceCachedEnabled = true; + + if (blockDeviceCachedEnabled && (flags & BLOCK_ACCESS_CACHED)) { + if (dispatchGroup) { + dispatchGroup->Start(); + } + + // TODO Use the dispatch group. + + // We use the CC_ACCESS_PRECISE flag for file systems that have a block size less than the page size. + // Otherwise, we might end up trashing file blocks (which aren't kept in the block device cache). + + EsError result = CCSpaceAccess((CCSpace *) (this + 1), buffer, offset, count, + operation == K_ACCESS_READ ? CC_ACCESS_READ : (CC_ACCESS_WRITE | CC_ACCESS_WRITE_BACK | CC_ACCESS_PRECISE)); + + if (dispatchGroup) { + dispatchGroup->End(result == ES_SUCCESS); + } + + return result == ES_SUCCESS; + } else { + KDMABuffer dmaBuffer = { (uintptr_t) buffer, count }; + KBlockDeviceAccessRequest request = {}; + request.device = block; + request.offset = offset; + request.count = count; + request.operation = operation; + request.buffer = &dmaBuffer; + request.flags = flags; + request.dispatchGroup = dispatchGroup; + return FSBlockDeviceAccess(request); + } +} + +////////////////////////////////////////// +// Partition devices. +////////////////////////////////////////// + +struct PartitionDevice : KBlockDevice { + EsFileOffset sectorOffset; +}; + +void FSPartitionDeviceAccess(KBlockDeviceAccessRequest request) { + PartitionDevice *_device = (PartitionDevice *) request.device; + request.device = (KBlockDevice *) _device->parent; + request.offset += _device->sectorOffset * _device->sectorSize; + FSBlockDeviceAccess(request); +} + +void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, unsigned flags, const char *cName) { + PartitionDevice *child = (PartitionDevice *) KDeviceCreate(cName, parent, sizeof(PartitionDevice)); + if (!child) return; + + child->parent = parent; + child->sectorSize = parent->sectorSize; + child->maxAccessSectorCount = parent->maxAccessSectorCount; + child->sectorOffset = offset; + child->sectorCount = sectorCount; + child->noMBR = flags & FS_PARTITION_DEVICE_NO_MBR ? true : false; + child->readOnly = parent->readOnly; + child->access = FSPartitionDeviceAccess; + child->cModel = cName; + child->nestLevel = parent->nestLevel + 1; + child->driveType = parent->driveType; + + FSRegisterBlockDevice(child); +} + +////////////////////////////////////////// +// File system and partition table detection. +////////////////////////////////////////// + +bool FSSignatureCheck(KInstalledDriver *driver, KDevice *device) { + uint8_t *block = ((KFileSystem *) device)->block->information; + + EsINIState s = {}; + s.buffer = driver->config; + s.bytes = driver->configBytes; + + int64_t offset = -1; + + while (EsINIParse(&s)) { + if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("signature_offset"))) { + offset = EsIntegerParse(s.value, s.valueBytes); + } else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("signature"))) { + if (offset >= K_SIGNATURE_BLOCK_SIZE || offset >= K_SIGNATURE_BLOCK_SIZE - (int64_t) s.valueBytes || offset < 0) { + KernelPanic("FSSignatureCheck - Filesystem '%s' has invalid signature detection information.\n", driver->nameBytes, driver->name); + } + + if (0 == EsMemoryCompare(block + offset, s.value, s.valueBytes)) { + return true; + } + } + } + + return false; +} + +bool FSCheckMBR(KBlockDevice *device) { + if (device->information[510] != 0x55 || device->information[511] != 0xAA) { + return false; + } + + KernelLog(LOG_INFO, "FS", "probing MBR", "First sector on device looks like an MBR...\n"); + + uint32_t offsets[4], counts[4]; + bool present[4] = {}; + + for (uintptr_t i = 0; i < 4; i++) { + if (!device->information[4 + 0x1BE + i * 0x10]) { + continue; + } + + offsets[i] = + ((uint32_t) device->information[0x1BE + i * 0x10 + 8 ] << 0 ) + + ((uint32_t) device->information[0x1BE + i * 0x10 + 9 ] << 8 ) + + ((uint32_t) device->information[0x1BE + i * 0x10 + 10] << 16) + + ((uint32_t) device->information[0x1BE + i * 0x10 + 11] << 24); + counts[i] = + ((uint32_t) device->information[0x1BE + i * 0x10 + 12] << 0 ) + + ((uint32_t) device->information[0x1BE + i * 0x10 + 13] << 8 ) + + ((uint32_t) device->information[0x1BE + i * 0x10 + 14] << 16) + + ((uint32_t) device->information[0x1BE + i * 0x10 + 15] << 24); + present[i] = true; + + if (offsets[i] > device->sectorCount || counts[i] > device->sectorCount - offsets[i] || counts[i] < 32) { + KernelLog(LOG_INFO, "FS", "invalid MBR", "Partition %d has offset %d and count %d, which is invalid. Ignoring the rest of the MBR...\n", + i, offsets[i], counts[i]); + return false; + } + } + + for (uintptr_t i = 0; i < 4; i++) { + if (present[i]) { + KernelLog(LOG_INFO, "FS", "MBR partition", "Found MBR partition %d with offset %d and count %d.\n", + i, offsets[i], counts[i]); + FSPartitionDeviceCreate(device, offsets[i], counts[i], FS_PARTITION_DEVICE_NO_MBR, "MBR partition"); + } + } + + return true; +} + +void FSDetectFileSystem(KBlockDevice *device) { + KernelLog(LOG_INFO, "FS", "detect file system", "Detecting file system on block device '%z'.\n", device->cModel); + + if (device->nestLevel > 4) { + KernelLog(LOG_ERROR, "FS", "file system nest limit", "Reached file system nest limit (4), ignoring device.\n"); + } + + uint64_t sectorsToRead = (K_SIGNATURE_BLOCK_SIZE + device->sectorSize - 1) / device->sectorSize; + + if (sectorsToRead > device->sectorCount) { + KernelLog(LOG_ERROR, "FS", "drive too small", "The drive must be at least %D (K_SIGNATURE_BLOCK_SIZE).\n", K_SIGNATURE_BLOCK_SIZE); + return; + } + + uint8_t *information = (uint8_t *) EsHeapAllocate(sectorsToRead * device->sectorSize, false, K_FIXED); + device->information = information; + + KDMABuffer dmaBuffer = { (uintptr_t) information }; + KBlockDeviceAccessRequest request = {}; + request.device = device; + request.count = sectorsToRead * device->sectorSize; + request.operation = K_ACCESS_READ; + request.buffer = &dmaBuffer; + + if (!FSBlockDeviceAccess(request)) { + // We could not access the block device. + KernelLog(LOG_ERROR, "FS", "detect fileSystem read failure", "The signature block could not be read on block device %x.\n", device); + } else { + if (!device->noMBR && FSCheckMBR(device)) { + // Found an MBR. + } else { + FSDirectoryEntry *rootEntry = nullptr; + KFileSystem *fileSystem = nullptr; + CCSpace *cache = nullptr; + + rootEntry = (FSDirectoryEntry *) EsHeapAllocate(sizeof(FSDirectoryEntry), true, K_FIXED); + if (!rootEntry) goto error; + + rootEntry->type = ES_NODE_DIRECTORY; + if (ES_SUCCESS != FSDirectoryEntryAllocateNode(rootEntry, nullptr, true, false)) goto error; + + fileSystem = (KFileSystem *) KDeviceCreate("file system", device, sizeof(KFileSystem) + sizeof(CCSpace)); + if (!fileSystem) goto error; + + fileSystem->rootDirectory = rootEntry->node; + fileSystem->rootDirectory->fileSystem = fileSystem; + fileSystem->block = device; + cache = (CCSpace *) (fileSystem + 1); + if (!CCSpaceInitialise(cache)) goto error; + + cache->callbacks = &fsBlockCacheCallbacks; + KDeviceAttach(fileSystem, "Files", FSSignatureCheck); + KDeviceCloseHandle(fileSystem); + goto success; + + error:; + if (fileSystem) KDeviceDestroy(fileSystem); + if (rootEntry && rootEntry->node) FSNodeFree(rootEntry->node); + if (rootEntry) EsHeapFree(rootEntry, sizeof(FSDirectoryEntry), K_FIXED); + success:; + } + } + + EsHeapFree(information, sectorsToRead * device->sectorSize, K_FIXED); + KDeviceCloseHandle(device); +} + +////////////////////////////////////////// +// Device management. +////////////////////////////////////////// + +void FSRegisterBootFileSystem(KFileSystem *fileSystem, EsUniqueIdentifier identifier) { + if (!EsMemoryCompare(&identifier, &installationID, sizeof(EsUniqueIdentifier))) { + KWriterLockTake(&fs.fileSystemsLock, K_LOCK_EXCLUSIVE); + + if (!fs.bootFileSystem) { + fs.bootFileSystem = fileSystem; + KEventSet(&fs.foundBootFileSystemEvent); + fileSystem->isBootFileSystem = true; + FSNodeOpenHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT, FS_NODE_OPEN_HANDLE_FIRST); + } else { + KernelLog(LOG_ERROR, "FS", "duplicate boot file system", "Found multiple boot file systems; the first registered will be used.\n"); + } + + KWriterLockReturn(&fs.fileSystemsLock, K_LOCK_EXCLUSIVE); + } + + FSRegisterFileSystem(fileSystem); +} + +void FSFileSystemDeviceRemoved(KDevice *device) { + KFileSystem *fileSystem = (KFileSystem *) device; + EsMessage m; + EsMemoryZero(&m, sizeof(EsMessage)); + m.type = ES_MSG_UNREGISTER_FILE_SYSTEM; + m.unregisterFileSystem.id = fileSystem->id; + desktopProcess->messageQueue.SendMessage(nullptr, &m); +} + +void FSRegisterFileSystem(KFileSystem *fileSystem) { + if (fileSystem->children.Length() != 1) { + KernelPanic("FSRegisterFileSystem - File system %x does not have a child device.\n", fileSystem); + } + + static volatile uint64_t id = 1; + fileSystem->id = __sync_fetch_and_add(&id, 1); + + fileSystem->removed = FSFileSystemDeviceRemoved; + + MMObjectCacheRegister(&fileSystem->cachedDirectoryEntries, FSTrimCachedDirectoryEntry, + sizeof(FSDirectoryEntry) + 16 /* approximate average name bytes */ + fileSystem->directoryEntryDataBytes); + MMObjectCacheRegister(&fileSystem->cachedNodes, FSTrimCachedNode, + sizeof(FSFile) + fileSystem->nodeDataBytes); + fileSystem->rootDirectory->directoryEntry->directoryChildren = fileSystem->rootDirectoryInitialChildren; + FSNodeOpenHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT, fileSystem->isBootFileSystem ? FS_NODE_OPEN_HANDLE_STANDARD : FS_NODE_OPEN_HANDLE_FIRST); + + EsMessage m; + EsMemoryZero(&m, sizeof(EsMessage)); + m.type = ES_MSG_REGISTER_FILE_SYSTEM; + m.registerFileSystem.rootDirectory = desktopProcess->handleTable.OpenHandle(fileSystem->rootDirectory, _ES_NODE_DIRECTORY_WRITE, KERNEL_OBJECT_NODE); + m.registerFileSystem.isBootFileSystem = fileSystem->isBootFileSystem; + desktopProcess->messageQueue.SendMessage(nullptr, &m); +} + +void FSRegisterBlockDevice(KBlockDevice *device) { +#ifdef SERIAL_STARTUP + FSDetectFileSystem(device); +#else + KThreadCreate("FSDetect", [] (uintptr_t context) { + FSDetectFileSystem((KBlockDevice *) context); + }, (uintptr_t) device); +#endif +} + +void FSShutdown() { + // A file system is unmounted when the last open handle to its nodes is closed. + // When a file system is registered, a handle is opened to its root directory and given to Desktop. + // Therefore, when the Desktop process is terminated, that handle is closed. + // However, we additionally have a handle open to the boot file system, which we need to close. + // Then, we wait for all file system unmounting threads to complete. + + // By this point there should be one open handle to the root directory, + // and any handles temporarily opened by object cache trimming threads. + // (FSTrimCachedDirectoryEntry opens a handle on the parent directory.) + + fs.shutdown = true; + CloseHandleToObject(fs.bootFileSystem->rootDirectory, KERNEL_OBJECT_NODE); + while (fs.fileSystemsUnmounting) KEventWait(&fs.fileSystemUnmounted); + if (fs.totalHandleCount) KernelPanic("FSShutdown - Expected no open handles, got %d.\n", fs.totalHandleCount); +} + +#endif diff --git a/kernel/graphics.cpp b/kernel/graphics.cpp new file mode 100644 index 0000000..ac92262 --- /dev/null +++ b/kernel/graphics.cpp @@ -0,0 +1,562 @@ +#ifndef IMPLEMENTATION + +struct Surface : EsPaintTarget { + bool Resize(size_t newResX, size_t newResY, uint32_t clearColor = 0, bool copyOldBits = false); + void Copy(Surface *source, EsPoint destinationPoint, EsRectangle sourceRegion, bool addToModifiedRegion); + void Draw(Surface *source, EsRectangle destinationRegion, int sourceX, int sourceY, uint16_t alpha); + void BlendWindow(Surface *source, EsPoint destinationPoint, EsRectangle sourceRegion, int material, uint8_t alpha, EsRectangle materialRegion); + void Blur(EsRectangle region, EsRectangle clip); + void SetBits(K_USER_BUFFER const void *bits, uintptr_t stride, EsRectangle region); + void Scroll(EsRectangle region, ptrdiff_t delta, bool vertical); + + EsRectangle modifiedRegion; +}; + +struct Graphics { + KGraphicsTarget *target; + size_t width, height; + Surface frameBuffer; + bool debuggerActive; + size_t totalSurfaceBytes; +}; + +void GraphicsUpdateScreen(K_USER_BUFFER void *bits = nullptr, EsRectangle *bounds = nullptr, uintptr_t stride = 0); + +Graphics graphics; + +#else + +void GraphicsUpdateScreen(K_USER_BUFFER void *bits, EsRectangle *bounds, uintptr_t bitsStride) { + KMutexAssertLocked(&windowManager.mutex); + + if (windowManager.resizeWindow && windowManager.resizeStartTimeStampMs + RESIZE_FLICKER_TIMEOUT_MS > KGetTimeInMs() + && !windowManager.inspectorWindowCount /* HACK see note in the SET_BITS syscall */) { + return; + } + + if (bounds && (Width(*bounds) <= 0 || Height(*bounds) <= 0)) { + return; + } + + int cursorX = windowManager.cursorX + windowManager.cursorImageOffsetX - (bounds ? bounds->l : 0); + int cursorY = windowManager.cursorY + windowManager.cursorImageOffsetY - (bounds ? bounds->t : 0); + + Surface *sourceSurface; + Surface _sourceSurface; + EsRectangle _bounds; + + if (bits) { + sourceSurface = &_sourceSurface; + EsMemoryZero(sourceSurface, sizeof(Surface)); + sourceSurface->bits = bits; + sourceSurface->width = Width(*bounds); + sourceSurface->height = Height(*bounds); + sourceSurface->stride = bitsStride; + } else { + sourceSurface = &graphics.frameBuffer; + _bounds = ES_RECT_4(0, sourceSurface->width, 0, sourceSurface->height); + bounds = &_bounds; + } + + EsRectangle cursorBounds = ES_RECT_4(cursorX, cursorX + windowManager.cursorSwap.width, cursorY, cursorY + windowManager.cursorSwap.height); + EsRectangleClip(ES_RECT_4(0, Width(*bounds), 0, Height(*bounds)), cursorBounds, &cursorBounds); + + windowManager.cursorSwap.Copy(sourceSurface, ES_POINT(0, 0), cursorBounds, true); + windowManager.changedCursorImage = false; + + int cursorImageWidth = windowManager.cursorSurface.width, cursorImageHeight = windowManager.cursorSurface.height; + sourceSurface->Draw(&windowManager.cursorSurface, ES_RECT_4(cursorX, cursorX + cursorImageWidth, cursorY, cursorY + cursorImageHeight), 0, 0, + windowManager.cursorXOR ? ES_DRAW_BITMAP_XOR : 0xFF); + + if (bits) { + graphics.target->updateScreen((K_USER_BUFFER const uint8_t *) bits, + sourceSurface->width, sourceSurface->height, + sourceSurface->stride, bounds->l, bounds->t); + } else { + if (Width(sourceSurface->modifiedRegion) > 0 && Height(sourceSurface->modifiedRegion) > 0) { + uint8_t *bits = (uint8_t *) sourceSurface->bits + + sourceSurface->modifiedRegion.l * 4 + + sourceSurface->modifiedRegion.t * sourceSurface->stride; + graphics.target->updateScreen(bits, Width(sourceSurface->modifiedRegion), Height(sourceSurface->modifiedRegion), + sourceSurface->width * 4, sourceSurface->modifiedRegion.l, sourceSurface->modifiedRegion.t); + sourceSurface->modifiedRegion = { (int32_t) graphics.width, 0, (int32_t) graphics.height, 0 }; + } + } + + sourceSurface->Copy(&windowManager.cursorSwap, ES_POINT(cursorBounds.l, cursorBounds.t), ES_RECT_4(0, Width(cursorBounds), 0, Height(cursorBounds)), true); +} + +bool KGraphicsIsTargetRegistered() { + return graphics.target ? true : false; +} + +void KRegisterGraphicsTarget(KGraphicsTarget *target) { + // TODO Locking. + if (graphics.target) return; + + graphics.target = target; + + graphics.width = target->screenWidth; + graphics.height = target->screenHeight; + + graphics.frameBuffer.Resize(graphics.width, graphics.height); + + windowManager.Initialise(); + + EsMessage m; + EsMemoryZero(&m, sizeof(EsMessage)); + m.type = ES_MSG_SET_SCREEN_RESOLUTION; + desktopProcess->messageQueue.SendMessage(nullptr, &m); +} + +bool Surface::Resize(size_t newResX, size_t newResY, uint32_t clearColor, bool copyOldBits) { + // Check the surface is within our working size limits. + if (!newResX || !newResY || newResX >= 32767 || newResY >= 32767) { + return false; + } + + if (width == newResX && height == newResY) { + return true; + } + + uint8_t *newBits = (uint8_t *) EsHeapAllocate(newResX * newResY * 4, !copyOldBits, K_PAGED); + + if (!newBits) { + return false; + } + + int oldWidth = width, oldHeight = height, oldStride = stride; + void *oldBits = bits; + + width = newResX, height = newResY, bits = newBits; + stride = newResX * 4; + + EsPainter painter; + painter.clip = ES_RECT_4(0, width, 0, height); + painter.target = this; + + if (copyOldBits) { + EsDrawBitmap(&painter, ES_RECT_4(0, oldWidth, 0, oldHeight), (uint32_t *) oldBits, oldStride, ES_DRAW_BITMAP_OPAQUE); + + if (clearColor) { + EsDrawBlock(&painter, ES_RECT_4(oldWidth, width, 0, height), clearColor); + EsDrawBlock(&painter, ES_RECT_4(0, oldWidth, oldHeight, height), clearColor); + } else { + EsDrawClear(&painter, ES_RECT_4(oldWidth, width, 0, height)); + EsDrawClear(&painter, ES_RECT_4(0, oldWidth, oldHeight, height)); + } + } + + EsHeapFree(oldBits, 0, K_PAGED); + + __sync_fetch_and_add(&graphics.totalSurfaceBytes, newResX * newResY * 4 - oldWidth * oldHeight * 4); + + return true; +} + +void Surface::Copy(Surface *source, EsPoint destinationPoint, EsRectangle sourceRegion, bool addToModifiedRegion) { + EsRectangle destinationRegion = ES_RECT_4(destinationPoint.x, destinationPoint.x + Width(sourceRegion), + destinationPoint.y, destinationPoint.y + Height(sourceRegion)); + + if (addToModifiedRegion) { + modifiedRegion = EsRectangleBounding(destinationRegion, modifiedRegion); + EsRectangleClip(modifiedRegion, ES_RECT_4(0, width, 0, height), &modifiedRegion); + } + + EsPainter painter; + painter.clip = ES_RECT_4(0, width, 0, height); + painter.target = this; + uint8_t *sourceBits = (uint8_t *) source->bits + source->stride * sourceRegion.t + 4 * sourceRegion.l; + EsDrawBitmap(&painter, destinationRegion, (uint32_t *) sourceBits, source->stride, ES_DRAW_BITMAP_OPAQUE); +} + +void Surface::SetBits(K_USER_BUFFER const void *_bits, uintptr_t sourceStride, EsRectangle bounds) { + if (Width(bounds) < 0 || Height(bounds) < 0 || bounds.l < 0 || bounds.t < 0 || bounds.r > (int32_t) width || bounds.b > (int32_t) height) { + KernelPanic("Surface::SetBits - Invalid bounds %R for surface %x.\n", bounds, this); + } + + if (Width(bounds) == 0 || Height(bounds) == 0) { + return; + } + + modifiedRegion = EsRectangleBounding(bounds, modifiedRegion); + + uint32_t *rowStart = (uint32_t *) bits + bounds.l + bounds.t * stride / 4; + K_USER_BUFFER const uint32_t *sourceRowStart = (K_USER_BUFFER const uint32_t *) _bits; + + for (uintptr_t i = bounds.t; i < (uintptr_t) bounds.b; i++, rowStart += stride / 4, sourceRowStart += sourceStride / 4) { + size_t count = Width(bounds); + uint32_t *destination = rowStart; + K_USER_BUFFER const uint32_t *bits = sourceRowStart; + + do { + *destination = *bits; + destination++, bits++, count--; + } while (count); + } +} + +void Surface::Scroll(EsRectangle region, ptrdiff_t delta, bool vertical) { + if (vertical) { + if (delta > 0) { + for (intptr_t i = region.t; i < region.b; i++) { + for (intptr_t j = region.l; j < region.r; j++) { + ((uint32_t *) bits)[j + (i - delta) * stride / 4] = ((uint32_t *) bits)[j + i * stride / 4]; + } + } + } else { + for (intptr_t i = region.b - 1; i >= region.t; i--) { + for (intptr_t j = region.l; j < region.r; j++) { + ((uint32_t *) bits)[j + (i - delta) * stride / 4] = ((uint32_t *) bits)[j + i * stride / 4]; + } + } + } + } else { + if (delta > 0) { + for (intptr_t i = region.t; i < region.b; i++) { + for (intptr_t j = region.l; j < region.r; j++) { + ((uint32_t *) bits)[j - delta + i * stride / 4] = ((uint32_t *) bits)[j + i * stride / 4]; + } + } + } else { + // TODO. + } + } +} + +#define C0(p) ((p & 0x000000FF) >> 0x00) +#define C1(p) ((p & 0x0000FF00) >> 0x08) +#define C2(p) ((p & 0x00FF0000) >> 0x10) +#define C3(p) ((p & 0xFF000000) >> 0x18) + +__attribute__((optimize("-O2"))) +void BlurRegionOfImage(uint32_t *image, int width, int height, int stride, uint16_t *kernel, uintptr_t repeat) { + if (width <= 3 || height <= 3) { + return; + } + + for (int y = 0; y < height; y++) { + for (uintptr_t i = 0; i < repeat; i++) { + uint32_t *start = image + stride * y; + uint32_t a = start[0], b = start[0], c = start[0], d = start[0], e = start[1], f = start[2], g = 0; + uint32_t *u = start, *v = start + 3; + + for (int i = 0; i < width; i++, u++, v++) { + if (i + 3 < width) g = *v; + *u = (((C0(a) * kernel[0] + C0(b) * kernel[1] + C0(c) * kernel[2] + C0(d) * kernel[3] + C0(e) + * kernel[4] + C0(f) * kernel[5] + C0(g) * kernel[6]) >> 8) << 0x00) + + (((C1(a) * kernel[0] + C1(b) * kernel[1] + C1(c) * kernel[2] + C1(d) * kernel[3] + C1(e) + * kernel[4] + C1(f) * kernel[5] + C1(g) * kernel[6]) >> 8) << 0x08) + + (((C2(a) * kernel[0] + C2(b) * kernel[1] + C2(c) * kernel[2] + C2(d) * kernel[3] + C2(e) + * kernel[4] + C2(f) * kernel[5] + C2(g) * kernel[6]) >> 8) << 0x10) + + (C3(d) << 0x18); + a = b, b = c, c = d, d = e, e = f, f = g; + } + } + } + + for (int x = 0; x < width; x++) { + for (uintptr_t i = 0; i < repeat; i++) { + uint32_t *start = image + x; + uint32_t a = start[0], b = start[0], c = start[0], d = start[0], e = start[stride], f = start[stride * 2], g = 0; + uint32_t *u = start, *v = start + 3 * stride; + + for (int i = 0; i < height; i++, u += stride, v += stride) { + if (i + 3 < height) g = *v; + *u = (((C0(a) * kernel[0] + C0(b) * kernel[1] + C0(c) * kernel[2] + C0(d) * kernel[3] + C0(e) + * kernel[4] + C0(f) * kernel[5] + C0(g) * kernel[6]) >> 8) << 0x00) + + (((C1(a) * kernel[0] + C1(b) * kernel[1] + C1(c) * kernel[2] + C1(d) * kernel[3] + C1(e) + * kernel[4] + C1(f) * kernel[5] + C1(g) * kernel[6]) >> 8) << 0x08) + + (((C2(a) * kernel[0] + C2(b) * kernel[1] + C2(c) * kernel[2] + C2(d) * kernel[3] + C2(e) + * kernel[4] + C2(f) * kernel[5] + C2(g) * kernel[6]) >> 8) << 0x10) + + (C3(d) << 0x18); + a = b, b = c, c = d, d = e, e = f, f = g; + } + } + } +} + +__attribute__((optimize("-O2"))) +void BlurRegionOfImage(uint32_t *image, int width, int height, int stride, uintptr_t repeat) { + if (width <= 3 || height <= 3) { + return; + } + + for (uintptr_t i = 0; i < repeat; i++) { + uint32_t *start = image; + + for (int y = 0; y < height; y++) { + uint32_t a = start[0], b = start[0], c = start[0], d = start[0], e = start[1], f = start[2], g = 0; + uint32_t *u = start, *v = start + 3; + + for (int i = 0; i < width; i++, u++, v++) { + if (i + 3 < width) g = *v; + *u = (((C0(a) * 0x07 + C0(b) * 0x1A + C0(c) * 0x38 + C0(d) * 0x49 + C0(e) * 0x38 + C0(f) * 0x1A + C0(g) * 0x07) >> 8) << 0x00) + + (((C1(a) * 0x07 + C1(b) * 0x1A + C1(c) * 0x38 + C1(d) * 0x49 + C1(e) * 0x38 + C1(f) * 0x1A + C1(g) * 0x07) >> 8) << 0x08) + + (((C2(a) * 0x07 + C2(b) * 0x1A + C2(c) * 0x38 + C2(d) * 0x49 + C2(e) * 0x38 + C2(f) * 0x1A + C2(g) * 0x07) >> 8) << 0x10) + + (C3(d) << 0x18); + a = b, b = c, c = d, d = e, e = f, f = g; + } + + start += stride; + } + + start = image; + + for (int x = 0; x < width; x++) { + uint32_t a = start[0], b = start[0], c = start[0], d = start[0], e = start[stride], f = start[stride * 2], g = 0; + uint32_t *u = start, *v = start + 3 * stride; + + for (int i = 0; i < height; i++, u += stride, v += stride) { + if (i + 3 < height) g = *v; + *u = (((C0(a) * 0x07 + C0(b) * 0x1A + C0(c) * 0x38 + C0(d) * 0x49 + C0(e) * 0x38 + C0(f) * 0x1A + C0(g) * 0x07) >> 8) << 0x00) + + (((C1(a) * 0x07 + C1(b) * 0x1A + C1(c) * 0x38 + C1(d) * 0x49 + C1(e) * 0x38 + C1(f) * 0x1A + C1(g) * 0x07) >> 8) << 0x08) + + (((C2(a) * 0x07 + C2(b) * 0x1A + C2(c) * 0x38 + C2(d) * 0x49 + C2(e) * 0x38 + C2(f) * 0x1A + C2(g) * 0x07) >> 8) << 0x10) + + (C3(d) << 0x18); + a = b, b = c, c = d, d = e, e = f, f = g; + } + + start++; + } + } +} + +void Surface::Blur(EsRectangle region, EsRectangle clip) { +#if 1 + if (!EsRectangleClip(region, ES_RECT_4(0, width, 0, height), ®ion)) { + return; + } + + if (!EsRectangleClip(region, clip, ®ion)) { + return; + } + + BlurRegionOfImage((uint32_t *) ((uint8_t *) bits + region.l * 4 + region.t * stride), Width(region), Height(region), width, 1); +#else + EsPainter painter; + painter.clip = ES_RECT_4(0, width, 0, height); + painter.target = this; + EsDrawInvert(&painter, EsRectangleIntersection(region, clip)); +#endif +} + +__attribute__((optimize("-O2"))) +void Surface::BlendWindow(Surface *source, EsPoint destinationPoint, EsRectangle sourceRegion, int material, uint8_t alpha, EsRectangle materialRegion) { + if (destinationPoint.x < 0) { sourceRegion.l -= destinationPoint.x; destinationPoint.x = 0; } + if (destinationPoint.y < 0) { sourceRegion.t -= destinationPoint.y; destinationPoint.y = 0; } + if (destinationPoint.x + sourceRegion.r - sourceRegion.l >= (int) width) sourceRegion.r -= destinationPoint.x + sourceRegion.r - sourceRegion.l - width; + if (destinationPoint.y + sourceRegion.b - sourceRegion.t >= (int) height) sourceRegion.b -= destinationPoint.y + sourceRegion.b - sourceRegion.t - height; + if (sourceRegion.r > (int) source->width) sourceRegion.r = source->width; + if (sourceRegion.b > (int) source->height) sourceRegion.b = source->height; + if (sourceRegion.r <= sourceRegion.l) return; + if (sourceRegion.b <= sourceRegion.t) return; + if (sourceRegion.l < 0) return; + if (sourceRegion.t < 0) return; + + EsRectangle destinationRegion = ES_RECT_4(destinationPoint.x, destinationPoint.x + Width(sourceRegion), + destinationPoint.y, destinationPoint.y + Height(sourceRegion)); + modifiedRegion = EsRectangleBounding(destinationRegion, modifiedRegion); + + if (material == BLEND_WINDOW_MATERIAL_GLASS || material == BLEND_WINDOW_MATERIAL_LIGHT_BLUR) { + int repeat = material == BLEND_WINDOW_MATERIAL_GLASS ? 3 : 1; + +#ifndef SIMPLE_GRAPHICS + if (alpha == 0xFF) { + BlurRegionOfImage((uint32_t *) bits + materialRegion.l + materialRegion.t * width, + Width(materialRegion), Height(materialRegion), width, repeat); + } else { + uint16_t kernel[] = { 0x07, 0x1A, 0x38, 0, 0x38, 0x1A, 0x07 }; + uint16_t sum = 0; + + for (uintptr_t i = 0; i < 7; i++) { + kernel[i] = kernel[i] * alpha / 0xFF; + sum += kernel[i]; + } + + kernel[3] = 0xFF - sum; + + BlurRegionOfImage((uint32_t *) bits + materialRegion.l + materialRegion.t * width, + Width(materialRegion), Height(materialRegion), width, kernel, repeat); + } +#else + (void) materialRegion; + (void) alpha; +#endif + } + + intptr_t y = sourceRegion.t; + + uint8_t *destinationPixel = (uint8_t *) bits + destinationPoint.y * stride + destinationPoint.x * 4; + uint8_t *sourcePixel = (uint8_t *) source->bits + sourceRegion.t * source->stride + sourceRegion.l * 4; + +#ifndef SIMPLE_GRAPHICS + __m128i constantAlphaMask = _mm_set1_epi32(0xFF000000); + __m128i constantAlpha = _mm_set1_epi32(alpha); + __m128i constant255 = _mm_set1_epi32(0xFF); +#endif + + while (y < sourceRegion.b) { + size_t countX = sourceRegion.r - sourceRegion.l; + + uint8_t *a = destinationPixel, *b = sourcePixel; + + while (countX >= 4) { + __m128i sourceValue = _mm_loadu_si128((__m128i *) sourcePixel); + +#ifndef SIMPLE_GRAPHICS + __m128i destinationValue = _mm_loadu_si128((__m128i *) destinationPixel); + + if (alpha != 0xFF) { + sourceValue = _mm_or_si128(_mm_andnot_si128(constantAlphaMask, sourceValue), + _mm_and_si128(_mm_slli_epi32(_mm_mullo_epi16(_mm_srli_epi32(sourceValue, 24), constantAlpha), 16), constantAlphaMask)); + } + + __m128i alpha = _mm_srli_epi32(sourceValue, 24); + + __m128i red = _mm_mullo_epi16(_mm_and_si128(_mm_srli_epi32(sourceValue, 0), constant255), alpha); + __m128i green = _mm_mullo_epi16(_mm_and_si128(_mm_srli_epi32(sourceValue, 8), constant255), alpha); + __m128i blue = _mm_mullo_epi16(_mm_and_si128(_mm_srli_epi32(sourceValue, 16), constant255), alpha); + + alpha = _mm_sub_epi32(constant255, alpha); + + red = _mm_srli_epi32(_mm_add_epi32(red, _mm_mullo_epi16(_mm_and_si128(_mm_srli_epi32(destinationValue, 0), constant255), alpha)), 8); + green = _mm_srli_epi32(_mm_add_epi32(green, _mm_mullo_epi16(_mm_and_si128(_mm_srli_epi32(destinationValue, 8), constant255), alpha)), 8); + blue = _mm_srli_epi32(_mm_add_epi32(blue, _mm_mullo_epi16(_mm_and_si128(_mm_srli_epi32(destinationValue, 16), constant255), alpha)), 8); + + sourceValue = _mm_or_si128(_mm_slli_epi32(red, 0), _mm_or_si128(_mm_slli_epi32(green, 8), _mm_slli_epi32(blue, 16))); +#endif + + _mm_storeu_si128((__m128i *) destinationPixel, sourceValue); + + destinationPixel += 16; + sourcePixel += 16; + countX -= 4; + } + + while (countX >= 1) { + uint32_t modified = *(uint32_t *) sourcePixel; +#ifndef SIMPLE_GRAPHICS + uint32_t original = *(uint32_t *) destinationPixel; + if (alpha != 0xFF) modified = (modified & 0xFFFFFF) | (((((modified & 0xFF000000) >> 24) * alpha) << 16) & 0xFF000000); + uint32_t m1 = (modified & 0xFF000000) >> 24; + uint32_t m2 = 255 - m1; + uint32_t r2 = m2 * (original & 0x00FF00FF); + uint32_t g2 = m2 * (original & 0x0000FF00); + uint32_t r1 = m1 * (modified & 0x00FF00FF); + uint32_t g1 = m1 * (modified & 0x0000FF00); + uint32_t result = (0x0000FF00 & ((g1 + g2) >> 8)) | (0x00FF00FF & ((r1 + r2) >> 8)); +#else + uint32_t result = modified; +#endif + + *(uint32_t *) destinationPixel = result; + + destinationPixel += 4; + sourcePixel += 4; + countX -= 1; + } + + y++; + destinationPixel = a + stride; + sourcePixel = b + source->stride; + } +} + +void Surface::Draw(Surface *source, EsRectangle destinationRegion, int sourceX, int sourceY, uint16_t alpha) { + modifiedRegion = EsRectangleBounding(destinationRegion, modifiedRegion); + EsRectangleClip(modifiedRegion, ES_RECT_4(0, width, 0, height), &modifiedRegion); + EsPainter painter; + painter.clip = ES_RECT_4(0, width, 0, height); + painter.target = this; + uint8_t *sourceBits = (uint8_t *) source->bits + source->stride * sourceY + 4 * sourceX; + EsDrawBitmap(&painter, destinationRegion, (uint32_t *) sourceBits, source->stride, alpha); +} + +void GraphicsUpdateScreen32(K_USER_BUFFER const uint8_t *_source, uint32_t sourceWidth, uint32_t sourceHeight, uint32_t sourceStride, + uint32_t destinationX, uint32_t destinationY, + uint32_t screenWidth, uint32_t screenHeight, uint32_t stride, volatile uint8_t *pixel) { + uint32_t *destinationRowStart = (uint32_t *) (pixel + destinationX * 4 + destinationY * stride); + const uint32_t *sourceRowStart = (const uint32_t *) _source; + + if (destinationX > screenWidth || sourceWidth > screenWidth - destinationX + || destinationY > screenHeight || sourceHeight > screenHeight - destinationY) { + KernelPanic("GraphicsUpdateScreen32 - Update region outside graphics target bounds.\n"); + } + + for (uintptr_t y = 0; y < sourceHeight; y++, destinationRowStart += stride / 4, sourceRowStart += sourceStride / 4) { + uint32_t *destination = destinationRowStart; + const uint32_t *source = sourceRowStart; + + for (uintptr_t x = 0; x < sourceWidth; x++) { + *destination = *source; + destination++, source++; + } + } +} + +void GraphicsUpdateScreen24(K_USER_BUFFER const uint8_t *_source, uint32_t sourceWidth, uint32_t sourceHeight, uint32_t sourceStride, + uint32_t destinationX, uint32_t destinationY, + uint32_t screenWidth, uint32_t screenHeight, uint32_t stride, volatile uint8_t *pixel) { + uint8_t *destinationRowStart = (uint8_t *) (pixel + destinationX * 3 + destinationY * stride); + const uint8_t *sourceRowStart = _source; + + if (destinationX > screenWidth || sourceWidth > screenWidth - destinationX + || destinationY > screenHeight || sourceHeight > screenHeight - destinationY) { + KernelPanic("GraphicsUpdateScreen32 - Update region outside graphics target bounds.\n"); + } + + for (uintptr_t y = 0; y < sourceHeight; y++, destinationRowStart += stride, sourceRowStart += sourceStride) { + uint8_t *destination = destinationRowStart; + const uint8_t *source = sourceRowStart; + + for (uintptr_t x = 0; x < sourceWidth; x++) { + *destination++ = *source++; + *destination++ = *source++; + *destination++ = *source++; + source++; + } + } +} + +void GraphicsDebugPutBlock32(uintptr_t x, uintptr_t y, bool toggle, + unsigned screenWidth, unsigned screenHeight, unsigned stride, volatile uint8_t *linearBuffer) { + (void) screenWidth; + (void) screenHeight; + + if (toggle) { + linearBuffer[y * stride + x * 4 + 0] += 0x4C; + linearBuffer[y * stride + x * 4 + 1] += 0x4C; + linearBuffer[y * stride + x * 4 + 2] += 0x4C; + } else { + linearBuffer[y * stride + x * 4 + 0] = 0xFF; + linearBuffer[y * stride + x * 4 + 1] = 0xFF; + linearBuffer[y * stride + x * 4 + 2] = 0xFF; + } + + linearBuffer[(y + 1) * stride + (x + 1) * 4 + 0] = 0; + linearBuffer[(y + 1) * stride + (x + 1) * 4 + 1] = 0; + linearBuffer[(y + 1) * stride + (x + 1) * 4 + 2] = 0; +} + +void GraphicsDebugClearScreen32(unsigned screenWidth, unsigned screenHeight, unsigned stride, volatile uint8_t *linearBuffer) { + for (uintptr_t i = 0; i < screenHeight; i++) { + for (uintptr_t j = 0; j < screenWidth * 4; j += 4) { + if (graphics.debuggerActive) { + linearBuffer[i * stride + j + 2] = 0x18; + linearBuffer[i * stride + j + 1] = 0x7E; + linearBuffer[i * stride + j + 0] = 0xCF; + } else { + linearBuffer[i * stride + j + 2] >>= 1; + linearBuffer[i * stride + j + 1] >>= 1; + linearBuffer[i * stride + j + 0] >>= 1; + } + } + } +} + +#undef C0 +#undef C1 +#undef C2 +#undef C3 + +#endif diff --git a/kernel/kernel.h b/kernel/kernel.h new file mode 100644 index 0000000..e3e879c --- /dev/null +++ b/kernel/kernel.h @@ -0,0 +1,194 @@ +#ifndef IMPLEMENTATION + +#define K_IN_CORE_KERNEL +#define K_PRIVATE +#include "module.h" + +////////////////////////////////// + +// TODO Determine the best values for these constants. + +// Wait 1 second before running the write behind thread. (Ignored if MM_AVAILABLE_PAGES() is below the low threshold.) +#define CC_WAIT_FOR_WRITE_BEHIND (1000) + +// Describes the virtual memory covering a section of a file. +#define CC_ACTIVE_SECTION_SIZE ((EsFileOffset) 262144) + +// Maximum number of active sections on the modified list. If exceeded, writers will wait for it to drop before retrying. +#define CC_MAX_MODIFIED (33554432 / CC_ACTIVE_SECTION_SIZE) + +// The size of the kernel's address space used for mapping active sections. +#if defined(ARCH_32) +#define CC_SECTION_BYTES (ClampIntptr(0, 64L * 1024 * 1024, pmm.commitFixedLimit * K_PAGE_SIZE / 4)) +#elif defined(ARCH_64) +#define CC_SECTION_BYTES (ClampIntptr(0, 1024L * 1024 * 1024, pmm.commitFixedLimit * K_PAGE_SIZE / 4)) +#endif + +// When we reach a critical number of pages, FIXED allocations start failing, +// and page faults are blocked, unless you are on a page generating thread (the modified page writer or the balancer). +#define MM_CRITICAL_AVAILABLE_PAGES_THRESHOLD (1048576 / K_PAGE_SIZE) + +// The number of pages at which balancing starts. +#define MM_LOW_AVAILABLE_PAGES_THRESHOLD (16777216 / K_PAGE_SIZE) + +// The number of pages past MM_LOW_AVAILABLE_PAGES_THRESHOLD to aim for when balancing. +#define MM_PAGES_TO_FIND_BALANCE (4194304 / K_PAGE_SIZE) + +// The number of pages in the zero list before signaling the page zeroing thread. +#define MM_ZERO_PAGE_THRESHOLD (16) + +// The amount of commit reserved specifically for page generating threads. +#define MM_CRITICAL_REMAINING_COMMIT_THRESHOLD (1048576 / K_PAGE_SIZE) + +// The number of objects that are trimmed from a MMObjectCache at a time. +#define MM_OBJECT_CACHE_TRIM_GROUP_COUNT (1024) + +// The current target maximum size for the object caches. (This uses the approximate sizes of objects.) +// We want to keep a reasonable amount of commit available at all times, +// since when the kernel is allocating memory it might not be able to wait for the caches to be trimmed without deadlock. +// So, try to keep the commit quota used by the object caches at most half the available space. +#define MM_NON_CACHE_MEMORY_PAGES() (pmm.commitFixed + pmm.commitPageable - pmm.approximateTotalObjectCacheBytes / K_PAGE_SIZE) +#define MM_OBJECT_CACHE_PAGES_MAXIMUM() ((pmm.commitLimit - MM_NON_CACHE_MEMORY_PAGES()) / 2) + +#define PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES (16) +#define POOL_CACHE_COUNT (16) + +////////////////////////////////// + +#include + +#define EsAssertionFailure(file, line) KernelPanic("%z:%d - EsAssertionFailure called.\n", file, line) + +#ifdef ARCH_X86_64 +#include "x86_64.cpp" +#endif + +struct AsyncTask { + KAsyncTaskCallback callback; + void *argument; + struct MMSpace *addressSpace; +}; + +struct CPULocalStorage { + // Must be the first fields; used in __cyg_profile_func_enter. + uintptr_t kernelFunctionCallCount; + + struct Thread *currentThread, + *idleThread, + *asyncTaskThread; + + struct InterruptContext *panicContext; + + bool irqSwitchThread, schedulerReady, inIRQ; + + unsigned processorID; + size_t spinlockCount; + + ArchCPU *archCPU; + + // TODO Have separate interrupt task threads and system worker threads (with no task limit). +#define MAX_ASYNC_TASKS (256) + volatile AsyncTask asyncTasks[MAX_ASYNC_TASKS]; + volatile uint8_t asyncTasksRead, asyncTasksWrite; +}; + +////////////////////////////////// + +void KernelInitialise(); +void KernelShutdown(uintptr_t action); + +void ArchInitialise(); +void ArchShutdown(uintptr_t action); + +extern "C" void ArchResetCPU(); +extern "C" void ArchSpeakerBeep(); +extern "C" void ArchNextTimer(size_t ms); // Receive a TIMER_INTERRUPT in ms ms. +InterruptContext *ArchInitialiseThread(uintptr_t kernelStack, uintptr_t kernelStackSize, struct Thread *thread, + uintptr_t startAddress, uintptr_t argument1, uintptr_t argument2, + bool userland, uintptr_t stack, uintptr_t userStackSize); + +uint64_t timeStampTicksPerMs; + +EsUniqueIdentifier installationID; // The identifier of this OS installation, given to us by the bootloader. +struct Process *desktopProcess; + +KSpinlock ipiLock; + +////////////////////////////////// + +#endif + +#include +#include +#include + +#include "memory.cpp" + +#ifndef IMPLEMENTATION +#include +#include +#else +#include +#endif + +#include "objects.cpp" +#include "syscall.cpp" +#include "scheduler.cpp" +#include "synchronisation.cpp" +#include "drivers.cpp" +#include "elf.cpp" +#include "graphics.cpp" +#include "cache.cpp" +#include "files.cpp" +#include "windows.cpp" +#include "networking.cpp" + +#ifdef ENABLE_POSIX_SUBSYSTEM +#include "posix.cpp" +#endif + +#include "terminal.cpp" + +#ifdef IMPLEMENTATION + +////////////////////////////////// + +extern "C" uint64_t KGetTimeInMs() { + if (!timeStampTicksPerMs) return 0; + return scheduler.timeMs; +} + +uint64_t KGetTimeStampTicksPerMs() { + return timeStampTicksPerMs; +} + +uint64_t KGetTimeStampTicksPerUs() { + return timeStampTicksPerMs / 1000; +} + +bool KInIRQ() { + return GetLocalStorage()->inIRQ; +} + +bool KBootedFromEFI() { + extern uint32_t bootloaderID; + return bootloaderID == 2; +} + +void KSwitchThreadAfterIRQ() { + GetLocalStorage()->irqSwitchThread = true; +} + +EsUniqueIdentifier KGetBootIdentifier() { + return installationID; +} + +////////////////////////////////// + +#ifdef ARCH_X86_64 +#include "x86_64.h" +#include +#include "x86_64.cpp" +#endif + +#endif diff --git a/kernel/main.cpp b/kernel/main.cpp new file mode 100644 index 0000000..6a0f265 --- /dev/null +++ b/kernel/main.cpp @@ -0,0 +1,29 @@ +// TODO Prevent Meltdown/Spectre exploits. +// TODO Kernel debugger. +// TODO Passing data to userspace - zeroing padding bits of structures. +// TODO Remove file extensions? +// TODO Thread-local variables for native applications (already working under the POSIX subsystem). + +#include "kernel.h" +#define IMPLEMENTATION +#include "kernel.h" + +extern "C" void KernelMain() { + scheduler.SpawnProcess(PROCESS_KERNEL); // Spawn the kernel process. + ArchInitialise(); // Start processors and initialise CPULocalStorage. + scheduler.started = true; // Start the pre-emptive scheduler. + // Continues in KernelInitialise. +} + +void KernelInitialise() { + desktopProcess = scheduler.SpawnProcess(PROCESS_DESKTOP); // Spawn the desktop process. + DriversInitialise(); // Load the root device. + desktopProcess->Start(EsLiteral(K_DESKTOP_EXECUTABLE)); // Start the desktop process. +} + +void KernelShutdown(uintptr_t action) { + scheduler.Shutdown(); // Kill user processes. + FSShutdown(); // Flush file cache and unmount filesystems. + DriversShutdown(); // Inform drivers of shutdown. + ArchShutdown(action); // Power off or restart the computer. +} diff --git a/kernel/memory.cpp b/kernel/memory.cpp new file mode 100644 index 0000000..c155410 --- /dev/null +++ b/kernel/memory.cpp @@ -0,0 +1,2305 @@ +// TODO Soft page faults. +// TODO Paging file. +// TODO Large pages. +// TODO Locking memory. +// TODO No execute permissions. +// TODO NUMA? +// TODO Cache coloring. + +#define GUARD_PAGES + +#ifndef IMPLEMENTATION + +// A contiguous range of addresses in an MMSpace. + +struct MMRegion { + uintptr_t baseAddress; + size_t pageCount; + uint32_t flags; + + struct { + union { + struct { + uintptr_t offset; + } physical; + + struct { + struct MMSharedRegion *region; + uintptr_t offset; + } shared; + + struct { + struct FSFile *node; + EsFileOffset offset; + size_t zeroedBytes; + uint64_t fileHandleFlags; + } file; + + struct { + RangeSet commit; // TODO Currently guarded by MMSpace::reserveMutex, maybe give it its own mutex? + size_t commitPageCount; + MMRegion *guardBefore, *guardAfter; + } normal; + }; + + KWriterLock pin; // Take SHARED when using the region in a system call. Take EXCLUSIVE to free the region. + KMutex mapMutex; // Access the page tables for a specific region, e.g. to atomically check if a mapping exists and if not, create it. + } data; + + union { + struct { + AVLItem itemBase; + + union { + AVLItem itemSize; + LinkedItem itemNonGuard; + }; + }; + + struct { + bool used; + } core; + }; +}; + +// A virtual address space. +// One per process. + +struct MMSpace { + VIRTUAL_ADDRESS_SPACE_DATA(); // Architecture specific data. + + AVLTree // Key = + freeRegionsBase, // Base address + freeRegionsSize, // Page count + usedRegions; // Base address + LinkedList usedRegionsNonGuard; + + KMutex reserveMutex; // Acquire to Access the region trees. + + bool user; // Regions in the space may be accessed from userspace. + uint64_t commit; // An *approximate* commit in pages. TODO Better memory usage tracking. +}; + +// A physical page of memory. + +struct MMPageFrame { + volatile enum : uint8_t { + // Frames that can't be used. + UNUSABLE, // Not connected to RAM. + BAD, // Connected to RAM with errors. TODO + + // Frames that aren't referenced. + ZEROED, // Cleared with zeros. + FREE, // Contains whatever data is had when it was freed. + + // Frames that are referenced by an invalid [shared] page mapping. + // In shared regions, each invalid page mapping points to the shared page mapping. + // This means only one variable must be updated to reuse the frame. + STANDBY, // Data has been written to page file or backing file. + + // Frames that are referenced by one or more valid page mappings. + ACTIVE, + } state; + + volatile uint8_t flags; + + // The reference to this frame in a CCCachedSection. + volatile uintptr_t *cacheReference; + + union { + struct { + // For STANDBY, MODIFIED, UPDATED, ZEROED and FREE. + // The frame's position in a list. + volatile uintptr_t next, *previous; + } list; + + struct { + // For ACTIVE. + // For file pages, this tracks how many valid page table entries point to this frame. + volatile uintptr_t references; + } active; + }; +}; + +// A shared memory region. + +struct MMSharedRegion { + size_t sizeBytes; + volatile size_t handles; + KMutex mutex; + LinkedItem namedItem; + char cName[ES_SHARED_MEMORY_NAME_MAX_LENGTH + 1]; + void *data; +}; + +// An object pool, for fast allocation and deallocation of objects of constant size. +// (There is no guarantee that the objects will be contiguous in memory.) + +struct Pool { + void *Add(size_t elementSize); // Aligned to the size of a pointer. + void Remove(void *element); + + size_t elementSize; + void *cache[POOL_CACHE_COUNT]; + size_t cacheEntries; + KMutex mutex; +}; + +// Physical memory manager state. + +struct PMM { + MMPageFrame *pageFrames; + + uintptr_t firstFreePage; + uintptr_t firstZeroedPage; + uintptr_t firstStandbyPage, lastStandbyPage; + Bitset freeOrZeroedPageBitset; // Used for allocating large pages. + + uintptr_t countZeroedPages, countFreePages, countStandbyPages, countActivePages; + +#define MM_REMAINING_COMMIT() (pmm.commitLimit - pmm.commitPageable - pmm.commitFixed) + int64_t commitFixed, commitPageable, + commitFixedLimit, commitLimit; + + // Acquire to: + KMutex commitMutex, // (Un)commit pages. + pageFrameMutex; // Allocate or free pages. + + KMutex pmManipulationLock; + KSpinlock pmManipulationProcessorLock; + void *pmManipulationRegion; + + Thread *zeroPageThread, *balanceThread; + KEvent zeroPageEvent; + + LinkedList objectCacheList; + KMutex objectCacheListMutex; + + // Events for when the number of available pages is low. +#define MM_AVAILABLE_PAGES() (pmm.countZeroedPages + pmm.countFreePages + pmm.countStandbyPages) + KEvent availableCritical, availableLow; + KEvent availableNotCritical; + + // Event for when the object cache should be trimmed. +#define MM_OBJECT_CACHE_SHOULD_TRIM() (pmm.approximateTotalObjectCacheBytes / K_PAGE_SIZE > MM_OBJECT_CACHE_PAGES_MAXIMUM()) + uintptr_t approximateTotalObjectCacheBytes; + KEvent trimObjectCaches; + + // These variables will be cleared if the object they point to is removed. + // See MMUnreserve and Scheduler::RemoveProcess. + Process *nextProcessToBalance; + MMRegion *nextRegionToBalance; + uintptr_t balanceResumePosition; +}; + +// See MMPhysicalAllocate. +alignas(K_PAGE_SIZE) uint8_t earlyZeroBuffer[K_PAGE_SIZE]; + +// Memory spaces. +// kernelMMSpace - Whence the kernel allocates memory. +// coreMMSpace - Whence other memory managers allocate memory. + +extern MMSpace _kernelMMSpace, _coreMMSpace; +#define kernelMMSpace (&_kernelMMSpace) +#define coreMMSpace (&_coreMMSpace) + +// Constants. + +// MMArchMapPage. +#define MM_MAP_PAGE_NOT_CACHEABLE (1 << 0) +#define MM_MAP_PAGE_USER (1 << 1) +#define MM_MAP_PAGE_OVERWRITE (1 << 2) +#define MM_MAP_PAGE_COMMIT_TABLES_NOW (1 << 3) +#define MM_MAP_PAGE_READ_ONLY (1 << 4) +#define MM_MAP_PAGE_COPIED (1 << 5) +#define MM_MAP_PAGE_NO_NEW_TABLES (1 << 6) +#define MM_MAP_PAGE_FRAME_LOCK_ACQUIRED (1 << 7) +#define MM_MAP_PAGE_WRITE_COMBINING (1 << 8) +#define MM_MAP_PAGE_IGNORE_IF_MAPPED (1 << 9) + +// MMArchUnmapPages. +#define MM_UNMAP_PAGES_FREE (1 << 0) +#define MM_UNMAP_PAGES_FREE_COPIED (1 << 1) +#define MM_UNMAP_PAGES_BALANCE_FILE (1 << 2) + +// MMPhysicalAllocate. +// --> Moved to module.h. + +// MMHandlePageFault. +#define MM_HANDLE_PAGE_FAULT_WRITE (1 << 0) +#define MM_HANDLE_PAGE_FAULT_LOCK_ACQUIRED (1 << 1) +#define MM_HANDLE_PAGE_FAULT_FOR_SUPERVISOR (1 << 2) + +// MMStandardAllocate - flags passed through into MMReserve. +// --> Moved to module.h. + +// MMReserve - region types. +#define MM_REGION_PHYSICAL (0x0100) // The region is mapped to device memory. +#define MM_REGION_NORMAL (0x0200) // A normal region. +#define MM_REGION_SHARED (0x0400) // The region's contents is shared via a MMSharedRegion. +#define MM_REGION_GUARD (0x0800) // A guard region, to make sure we don't accidentally go into other regions. +#define MM_REGION_CACHE (0x1000) // Used for the file cache. +#define MM_REGION_FILE (0x2000) // A mapped file. + +#define MM_SHARED_ENTRY_PRESENT (1) + +// Architecture-dependent functions. + +void MMArchMapPage(MMSpace *space, uintptr_t physicalAddress, uintptr_t virtualAddress, unsigned flags); +void MMArchUnmapPages(MMSpace *space, uintptr_t virtualAddressStart, uintptr_t pageCount, unsigned flags, size_t unmapMaximum = 0, uintptr_t *resumePosition = nullptr); +void MMArchInvalidatePages(uintptr_t virtualAddressStart, uintptr_t pageCount); +bool MMArchHandlePageFault(uintptr_t address, uint32_t flags); +uintptr_t MMArchTranslateAddress(MMSpace *space, uintptr_t virtualAddress, bool writeAccess); +void MMArchInitialiseVAS(); +bool MMArchInitialiseUserSpace(MMSpace *space); +bool MMArchCommitPageTables(MMSpace *space, MMRegion *region); +bool MMArchMakePageWritable(MMSpace *space, uintptr_t virtualAddress); +void MMFreeVAS(MMSpace *space); +void MMFinalizeVAS(MMSpace *space); + +// Forward declarations. + +bool MMHandlePageFault(MMSpace *space, uintptr_t address, unsigned flags); +bool MMUnmapFilePage(uintptr_t frameNumber, bool justLoaded = false); // Returns true if the page became inactive. + +// Public memory manager functions. + +void *MMMapPhysical(MMSpace *space, uintptr_t address, size_t bytes, uint64_t caching); +void *MMStandardAllocate(MMSpace *space, size_t bytes, uint32_t flags, void *baseAddress, bool commitAll); +bool MMFree(MMSpace *space, void *address, size_t expectedSize, bool userOnly); +MMRegion *MMReserve(MMSpace *space, size_t bytes, unsigned flags, uintptr_t forcedAddress = 0, bool generateGuardPages = false); +bool MMCommit(uint64_t bytes, bool fixed); +void MMDecommit(uint64_t bytes, bool fixed); +bool MMCommitRange(MMSpace *space, MMRegion *region, uintptr_t offset, size_t pages); +bool MMDecommitRange(MMSpace *space, MMRegion *region, uintptr_t offset, size_t pages); +uintptr_t MMPhysicalAllocate(unsigned flags, uintptr_t count, uintptr_t align, uintptr_t below); +void MMInitialise(); +MMSharedRegion *MMSharedCreateRegion(size_t sizeBytes, bool fixed, uintptr_t below); +MMSharedRegion *MMSharedOpenRegion(const char *name, size_t nameBytes, + size_t fallbackSizeBytes /* If the region doesn't exist, the size it should be created with. If 0, it'll fail. */, uint64_t flags); +MMRegion *MMFindAndPinRegion(MMSpace *space, uintptr_t address, uintptr_t size); +void MMUnpinRegion(MMSpace *space, MMRegion *region); +void MMSpaceDestroy(MMSpace *space); +bool MMSpaceInitialise(MMSpace *space); +void MMPhysicalFree(uintptr_t page, bool mutexAlreadyAcquired, size_t count); +void MMUnreserve(MMSpace *space, MMRegion *remove, bool unmapPages, bool guardRegion = false); +MMRegion *MMFindRegion(MMSpace *space, uintptr_t address); +void *MMMapFile(MMSpace *space, struct FSFile *node, EsFileOffset offset, size_t bytes, + int protection, void *baseAddress, size_t zeroedBytes = 0, uint32_t additionalFlags = ES_FLAGS_DEFAULT); + +// Physical memory information from the bootloader. + +struct PhysicalMemoryRegion { + uint64_t baseAddress; + + // The memory map the BIOS provides gives the information in pages. + uint64_t pageCount; +}; + +extern PhysicalMemoryRegion *physicalMemoryRegions; +extern size_t physicalMemoryRegionsCount; +extern size_t physicalMemoryRegionsPagesCount; +extern size_t physicalMemoryOriginalPagesCount; +extern size_t physicalMemoryRegionsIndex; +extern uintptr_t physicalMemoryHighest; + +// Physical memory manipulation. + +void PMZero(uintptr_t *pages, size_t pageCount, + bool contiguous /* True if `pages[0]` contains the base address and all other are contiguous, false if `pages` contains an array of physical addresses. */); +void PMZeroPartial(uintptr_t page, uintptr_t start, uintptr_t end); +void PMCheckZeroed(uintptr_t page); +void PMCopy(uintptr_t page, void *source, size_t pageCount); + +#endif + +#ifdef IMPLEMENTATION + +// Globals. + +MMSpace _kernelMMSpace, _coreMMSpace; +PMM pmm; +MMActiveSectionManager activeSectionManager; + +MMRegion *mmCoreRegions = (MMRegion *) MM_CORE_REGIONS_START; +size_t mmCoreRegionCount, mmCoreRegionArrayCommit; + +LinkedList mmNamedSharedRegions; +KMutex mmNamedSharedRegionsMutex; + +// Code! + +void MMUpdateAvailablePageCount(bool increase) { + if (MM_AVAILABLE_PAGES() >= MM_CRITICAL_AVAILABLE_PAGES_THRESHOLD) { + KEventSet(&pmm.availableNotCritical, false, true); + KEventReset(&pmm.availableCritical); + } else { + KEventReset(&pmm.availableNotCritical); + KEventSet(&pmm.availableCritical, false, true); + + if (!increase) { + KernelLog(LOG_ERROR, "Memory", "critical page limit hit", + "Critical number of available pages remain: %d (%dKB).\n", MM_AVAILABLE_PAGES(), MM_AVAILABLE_PAGES() * K_PAGE_SIZE / 1024); + } + } + + if (MM_AVAILABLE_PAGES() >= MM_LOW_AVAILABLE_PAGES_THRESHOLD) { + KEventReset(&pmm.availableLow); + } else { + KEventSet(&pmm.availableLow, false, true); + } +} + +void MMPhysicalInsertZeroedPage(uintptr_t page) { + if (GetCurrentThread() != pmm.zeroPageThread) { + KernelPanic("MMPhysicalInsertZeroedPage - Inserting a zeroed page not on the MMZeroPageThread.\n"); + } + + MMPageFrame *frame = pmm.pageFrames + page; + frame->state = MMPageFrame::ZEROED; + + { + frame->list.next = pmm.firstZeroedPage; + frame->list.previous = &pmm.firstZeroedPage; + if (pmm.firstZeroedPage) pmm.pageFrames[pmm.firstZeroedPage].list.previous = &frame->list.next; + pmm.firstZeroedPage = page; + } + + pmm.countZeroedPages++; + pmm.freeOrZeroedPageBitset.Put(page); + + MMUpdateAvailablePageCount(true); +} + +void MMPhysicalInsertFreePage(uintptr_t page) { + MMPageFrame *frame = pmm.pageFrames + page; + frame->state = MMPageFrame::FREE; + + { + frame->list.next = pmm.firstFreePage; + frame->list.previous = &pmm.firstFreePage; + if (pmm.firstFreePage) pmm.pageFrames[pmm.firstFreePage].list.previous = &frame->list.next; + pmm.firstFreePage = page; + } + + pmm.freeOrZeroedPageBitset.Put(page); + pmm.countFreePages++; + + if (pmm.countFreePages > MM_ZERO_PAGE_THRESHOLD) { + KEventSet(&pmm.zeroPageEvent, false, true); + } + + MMUpdateAvailablePageCount(true); +} + +void MMPhysicalActivatePages(uintptr_t pages, uintptr_t count, unsigned flags) { + (void) flags; + + KMutexAssertLocked(&pmm.pageFrameMutex); + + for (uintptr_t i = 0; i < count; i++) { + MMPageFrame *frame = pmm.pageFrames + pages + i; + + if (frame->state == MMPageFrame::FREE) { + pmm.countFreePages--; + } else if (frame->state == MMPageFrame::ZEROED) { + pmm.countZeroedPages--; + } else if (frame->state == MMPageFrame::STANDBY) { + pmm.countStandbyPages--; + + if (pmm.lastStandbyPage == pages + i) { + if (frame->list.previous == &pmm.firstStandbyPage) { + // There are no more pages in the list. + pmm.lastStandbyPage = 0; + } else { + pmm.lastStandbyPage = ((uintptr_t) frame->list.previous - (uintptr_t) pmm.pageFrames) / sizeof(MMPageFrame); + } + } + } else { + KernelPanic("MMPhysicalActivatePages - Corrupt page frame database (4).\n"); + } + + // Unlink the frame from its list. + *frame->list.previous = frame->list.next; + if (frame->list.next) pmm.pageFrames[frame->list.next].list.previous = frame->list.previous; + + EsMemoryZero(frame, sizeof(MMPageFrame)); + frame->state = MMPageFrame::ACTIVE; + } + + pmm.countActivePages += count; + MMUpdateAvailablePageCount(false); +} + +uintptr_t MMPhysicalAllocate(unsigned flags, uintptr_t count, uintptr_t align, uintptr_t below) { + bool mutexAlreadyAcquired = flags & MM_PHYSICAL_ALLOCATE_LOCK_ACQUIRED; + if (!mutexAlreadyAcquired) KMutexAcquire(&pmm.pageFrameMutex); + else KMutexAssertLocked(&pmm.pageFrameMutex); + EsDefer(if (!mutexAlreadyAcquired) KMutexRelease(&pmm.pageFrameMutex);); + + intptr_t commitNow = count * K_PAGE_SIZE; + + if (flags & MM_PHYSICAL_ALLOCATE_COMMIT_NOW) { + if (!MMCommit(commitNow, true)) return 0; + } else commitNow = 0; + + bool simple = count == 1 && align == 1 && below == 0; + + if (physicalMemoryRegionsPagesCount) { + // Early page allocation before the page frame database is initialised. + + if (!simple) { + KernelPanic("MMPhysicalAllocate - Non-simple allocation before initialisation of the page frame database.\n"); + } + + uintptr_t i = physicalMemoryRegionsIndex; + + while (!physicalMemoryRegions[i].pageCount) { + i++; + + if (i == physicalMemoryRegionsCount) { + KernelPanic("MMPhysicalAllocate - Expected more pages in physical regions.\n"); + } + } + + PhysicalMemoryRegion *region = physicalMemoryRegions + i; + uintptr_t returnValue = region->baseAddress; + + region->baseAddress += K_PAGE_SIZE; + region->pageCount--; + physicalMemoryRegionsPagesCount--; + physicalMemoryRegionsIndex = i; + + if (flags & MM_PHYSICAL_ALLOCATE_ZEROED) { + // TODO Hack! + MMArchMapPage(coreMMSpace, returnValue, (uintptr_t) earlyZeroBuffer, + MM_MAP_PAGE_OVERWRITE | MM_MAP_PAGE_NO_NEW_TABLES | MM_MAP_PAGE_FRAME_LOCK_ACQUIRED); + EsMemoryZero(earlyZeroBuffer, K_PAGE_SIZE); + } + + return returnValue; + } else if (!simple) { + // Slow path. + // TODO Use standby pages. + + uintptr_t pages = pmm.freeOrZeroedPageBitset.Get(count, align, below); + if (pages == (uintptr_t) -1) goto fail; + MMPhysicalActivatePages(pages, count, flags); + uintptr_t address = pages << K_PAGE_BITS; + if (flags & MM_PHYSICAL_ALLOCATE_ZEROED) PMZero(&address, count, true); + return address; + } else { + uintptr_t page = 0; + bool notZeroed = false; + + if (!page) page = pmm.firstZeroedPage; + if (!page) page = pmm.firstFreePage, notZeroed = true; + if (!page) page = pmm.lastStandbyPage, notZeroed = true; + if (!page) goto fail; + + MMPageFrame *frame = pmm.pageFrames + page; + + if (frame->state == MMPageFrame::ACTIVE) { + KernelPanic("MMPhysicalAllocate - Corrupt page frame database (2).\n"); + } + + if (frame->state == MMPageFrame::STANDBY) { + // EsPrint("Clear RT %x\n", frame); + + if (*frame->cacheReference != ((page << K_PAGE_BITS) | MM_SHARED_ENTRY_PRESENT)) { + KernelPanic("MMPhysicalAllocate - Corrupt shared reference back pointer in frame %x.\n", frame); + } + + // Clear the entry in the CCCachedSection that referenced this standby frame. + *frame->cacheReference = 0; + + // TODO If the CCCachedSection is empty, remove it from its CCSpace. + } else { + pmm.freeOrZeroedPageBitset.Take(page); + } + + MMPhysicalActivatePages(page, 1, flags); + + // EsPrint("PAGE FRAME ALLOCATE: %x\n", page << K_PAGE_BITS); + + uintptr_t address = page << K_PAGE_BITS; + if (notZeroed && (flags & MM_PHYSICAL_ALLOCATE_ZEROED)) PMZero(&address, 1, false); + // if (!notZeroed) PMCheckZeroed(address); + return address; + } + + fail:; + + if (!(flags & MM_PHYSICAL_ALLOCATE_CAN_FAIL)) { + EsPrint("Out of memory. Committed %d/%d fixed and %d pageable out of a maximum %d.\n", pmm.commitFixed, pmm.commitFixedLimit, pmm.commitPageable, pmm.commitLimit); + KernelPanic("MMPhysicalAllocate - Out of memory.\n"); + } + + MMDecommit(commitNow, true); + return 0; +} + +void MMPhysicalFree(uintptr_t page, bool mutexAlreadyAcquired, size_t count) { + if (!page) KernelPanic("MMPhysicalFree - Invalid page.\n"); + if (mutexAlreadyAcquired) KMutexAssertLocked(&pmm.pageFrameMutex); + else KMutexAcquire(&pmm.pageFrameMutex); + if (physicalMemoryRegionsPagesCount) KernelPanic("MMPhysicalFree - PMM not yet initialised.\n"); + + page >>= K_PAGE_BITS; + + for (uintptr_t i = 0; i < count; i++, page++) { + MMPageFrame *frame = pmm.pageFrames + page; + + if (frame->state == MMPageFrame::FREE) { + KernelPanic("MMPhysicalFree - Attempting to free a FREE page.\n"); + } + + if (pmm.commitFixedLimit) { + pmm.countActivePages--; + } + + MMPhysicalInsertFreePage(page); + } + + if (!mutexAlreadyAcquired) KMutexRelease(&pmm.pageFrameMutex); +} + +void MMCheckUnusable(uintptr_t physicalStart, size_t bytes) { + for (uintptr_t i = physicalStart / K_PAGE_SIZE; i < (physicalStart + bytes + K_PAGE_SIZE - 1) / K_PAGE_SIZE + && i < physicalMemoryHighest / K_PAGE_SIZE; i++) { + if (pmm.pageFrames[i].state != MMPageFrame::UNUSABLE) { + KernelPanic("MMCheckUnusable - Page frame at address %x should be unusable.\n", i * K_PAGE_SIZE); + } + } +} + +MMRegion *MMFindRegion(MMSpace *space, uintptr_t address) { + KMutexAssertLocked(&space->reserveMutex); + + if (space == coreMMSpace) { + for (uintptr_t i = 0; i < mmCoreRegionCount; i++) { + MMRegion *region = mmCoreRegions + i; + + if (region->core.used && region->baseAddress <= address + && region->baseAddress + region->pageCount * K_PAGE_SIZE > address) { + return region; + } + } + } else { + AVLItem *item = TreeFind(&space->usedRegions, MakeShortKey(address), TREE_SEARCH_LARGEST_BELOW_OR_EQUAL); + if (!item) return nullptr; + + MMRegion *region = item->thisItem; + if (region->baseAddress > address) KernelPanic("MMFindRegion - Broken usedRegions tree.\n"); + if (region->baseAddress + region->pageCount * K_PAGE_SIZE <= address) return nullptr; + return region; + } + + return nullptr; +} + +uintptr_t MMSharedLookupPage(MMSharedRegion *region, uintptr_t pageIndex) { + KMutexAcquire(®ion->mutex); + if (pageIndex >= region->sizeBytes >> K_PAGE_BITS) KernelPanic("MMSharedLookupPage - Page %d out of range in region %x.\n", pageIndex, region); + uintptr_t entry = ((uintptr_t *) region->data)[pageIndex]; + KMutexRelease(®ion->mutex); + return entry; +} + +bool MMHandlePageFault(MMSpace *space, uintptr_t address, unsigned faultFlags) { + // EsPrint("HandlePageFault: %x/%x/%x\n", space, address, faultFlags); + + address &= ~(K_PAGE_SIZE - 1); + + bool lockAcquired = faultFlags & MM_HANDLE_PAGE_FAULT_LOCK_ACQUIRED; + MMRegion *region; + + if (!lockAcquired && MM_AVAILABLE_PAGES() < MM_CRITICAL_AVAILABLE_PAGES_THRESHOLD && GetCurrentThread() && !GetCurrentThread()->isPageGenerator) { + KernelLog(LOG_ERROR, "Memory", "waiting for non-critical state", "Page fault on non-generator thread, waiting for more available pages.\n"); + KEventWait(&pmm.availableNotCritical); + } + + { + if (!lockAcquired) KMutexAcquire(&space->reserveMutex); + else KMutexAssertLocked(&space->reserveMutex); + EsDefer(if (!lockAcquired) KMutexRelease(&space->reserveMutex)); + + // Find the region, and pin it (so it can't be freed). + region = MMFindRegion(space, address); + if (!region) return false; + if (!KWriterLockTake(®ion->data.pin, K_LOCK_SHARED, true /* poll */)) return false; + } + + EsDefer(KWriterLockReturn(®ion->data.pin, K_LOCK_SHARED)); + KMutexAcquire(®ion->data.mapMutex); + EsDefer(KMutexRelease(®ion->data.mapMutex)); + + if (MMArchTranslateAddress(space, address, faultFlags & MM_HANDLE_PAGE_FAULT_WRITE)) { + // Spurious page fault. + return true; + } + + bool copyOnWrite = false, markModified = false; + + if (faultFlags & MM_HANDLE_PAGE_FAULT_WRITE) { + if (region->flags & MM_REGION_COPY_ON_WRITE) { + // This is copy-on-write page that needs to be copied. + copyOnWrite = true; + } else if (region->flags & MM_REGION_READ_ONLY) { + // The page was read-only. + KernelLog(LOG_ERROR, "Memory", "read only page fault", "MMHandlePageFault - Page was read only.\n"); + return false; + } else { + // We mapped the page as read-only so we could track whether it has been written to. + // It has now been written to. + markModified = true; + } + } + + uintptr_t offsetIntoRegion = address - region->baseAddress; + uint64_t needZeroPages = 0; + bool zeroPage = true; + + if (space->user) { + needZeroPages = MM_PHYSICAL_ALLOCATE_ZEROED; + zeroPage = false; + } + + unsigned flags = ES_FLAGS_DEFAULT; + + if (space->user) flags |= MM_MAP_PAGE_USER; + if (region->flags & MM_REGION_NOT_CACHEABLE) flags |= MM_MAP_PAGE_NOT_CACHEABLE; + if (region->flags & MM_REGION_WRITE_COMBINING) flags |= MM_MAP_PAGE_WRITE_COMBINING; + if (!markModified && !(region->flags & MM_REGION_FIXED) && (region->flags & MM_REGION_FILE)) flags |= MM_MAP_PAGE_READ_ONLY; + + if (region->flags & MM_REGION_PHYSICAL) { + MMArchMapPage(space, region->data.physical.offset + address - region->baseAddress, address, flags); + return true; + } else if (region->flags & MM_REGION_SHARED) { + MMSharedRegion *sharedRegion = region->data.shared.region; + + if (!sharedRegion->handles) { + KernelPanic("MMHandlePageFault - Shared region has no handles.\n"); + } + + KMutexAcquire(&sharedRegion->mutex); + + uintptr_t offset = address - region->baseAddress + region->data.shared.offset; + + if (offset >= sharedRegion->sizeBytes) { + KMutexRelease(&sharedRegion->mutex); + KernelLog(LOG_ERROR, "Memory", "outside shared size", "MMHandlePageFault - Attempting to access shared memory past end of region.\n"); + return false; + } + + uintptr_t *entry = (uintptr_t *) sharedRegion->data + (offset / K_PAGE_SIZE); + + if (*entry & MM_SHARED_ENTRY_PRESENT) zeroPage = false; + else *entry = MMPhysicalAllocate(needZeroPages) | MM_SHARED_ENTRY_PRESENT; + + MMArchMapPage(space, *entry & ~(K_PAGE_SIZE - 1), address, flags); + if (zeroPage) EsMemoryZero((void *) address, K_PAGE_SIZE); + KMutexRelease(&sharedRegion->mutex); + return true; + } else if (region->flags & MM_REGION_FILE) { + if (address >= region->baseAddress + (region->pageCount << K_PAGE_BITS) - region->data.file.zeroedBytes) { + // EsPrint("%x:%d\n", address, needZeroPages); + MMArchMapPage(space, MMPhysicalAllocate(needZeroPages), address, (flags & ~MM_MAP_PAGE_READ_ONLY) | MM_MAP_PAGE_COPIED); + if (zeroPage) EsMemoryZero((void *) address, K_PAGE_SIZE); + return true; + } + + if (copyOnWrite) { + doCopyOnWrite:; + uintptr_t existingTranslation = MMArchTranslateAddress(space, address); + + if (existingTranslation) { + // We need to use PMCopy, because as soon as the page is mapped for the user, + // other threads can access it. + uintptr_t page = MMPhysicalAllocate(ES_FLAGS_DEFAULT); + PMCopy(page, (void *) address, 1); + MMArchUnmapPages(space, address, 1, MM_UNMAP_PAGES_BALANCE_FILE); + MMArchMapPage(space, page, address, (flags & ~MM_MAP_PAGE_READ_ONLY) | MM_MAP_PAGE_COPIED); + return true; + } else { + // EsPrint("Write to unmapped, %x.\n", address); + } + } + + KMutexRelease(®ion->data.mapMutex); + + size_t pagesToRead = 16; + + if (region->pageCount - (offsetIntoRegion + region->data.file.zeroedBytes) / K_PAGE_SIZE < pagesToRead) { + pagesToRead = region->pageCount - (offsetIntoRegion + region->data.file.zeroedBytes) / K_PAGE_SIZE; + } + + EsError error = CCSpaceAccess(®ion->data.file.node->cache, (void *) address, + offsetIntoRegion + region->data.file.offset, pagesToRead * K_PAGE_SIZE, + CC_ACCESS_MAP, space, flags); + + KMutexAcquire(®ion->data.mapMutex); + + if (error != ES_SUCCESS) { + KernelLog(LOG_ERROR, "Memory", "mapped file read error", "MMHandlePageFault - Could not read from file %x. Error: %d.\n", + region->data.file.node, error); + return false; + } + + if (copyOnWrite) { + goto doCopyOnWrite; + } + + return true; + } else if (region->flags & MM_REGION_NORMAL) { + if (!(region->flags & MM_REGION_NO_COMMIT_TRACKING)) { + if (!region->data.normal.commit.Contains(offsetIntoRegion >> K_PAGE_BITS)) { + KernelLog(LOG_ERROR, "Memory", "outside commit range", "MMHandlePageFault - Attempting to access uncommitted memory in reserved region.\n"); + return false; + } + } + + MMArchMapPage(space, MMPhysicalAllocate(needZeroPages), address, flags); + if (zeroPage) EsMemoryZero((void *) address, K_PAGE_SIZE); + return true; + } else if (region->flags & MM_REGION_GUARD) { + KernelLog(LOG_ERROR, "Memory", "guard page hit", "MMHandlePageFault - Guard page hit!\n"); + return false; + } else { + KernelLog(LOG_ERROR, "Memory", "cannot fault in region", "MMHandlePageFault - Unsupported region type (flags: %x).\n", region->flags); + return false; + } +} + +MMRegion *MMReserve(MMSpace *space, size_t bytes, unsigned flags, uintptr_t forcedAddress, bool generateGuardPages) { + MMRegion *outputRegion = nullptr; + size_t pagesNeeded = ((bytes + K_PAGE_SIZE - 1) & ~(K_PAGE_SIZE - 1)) / K_PAGE_SIZE; + + if (!pagesNeeded) return nullptr; + + KMutexAssertLocked(&space->reserveMutex); + + if (space == coreMMSpace) { + if (mmCoreRegionCount == MM_CORE_REGIONS_COUNT) { + return nullptr; + } + + if (forcedAddress) { + KernelPanic("MMReserve - Using a forced address in coreMMSpace.\n"); + } + + { + uintptr_t newRegionCount = mmCoreRegionCount + 1; + uintptr_t commitPagesNeeded = newRegionCount * sizeof(MMRegion) / K_PAGE_SIZE + 1; + + while (mmCoreRegionArrayCommit < commitPagesNeeded) { + if (!MMCommit(K_PAGE_SIZE, true)) return nullptr; + mmCoreRegionArrayCommit++; + } + } + + for (uintptr_t i = 0; i < mmCoreRegionCount; i++) { + MMRegion *region = mmCoreRegions + i; + + if (!region->core.used && region->pageCount >= pagesNeeded) { + if (region->pageCount > pagesNeeded) { + MMRegion *split = mmCoreRegions + mmCoreRegionCount++; + EsMemoryCopy(split, region, sizeof(MMRegion)); + split->baseAddress += pagesNeeded * K_PAGE_SIZE; + split->pageCount -= pagesNeeded; + } + + region->core.used = true; + region->pageCount = pagesNeeded; + + region->flags = flags; + EsMemoryZero(®ion->data, sizeof(region->data)); + outputRegion = region; + goto done; + } + } + } else if (forcedAddress) { + AVLItem *item; + + // EsPrint("reserve forced: %x\n", forcedAddress); + + // Check for a collision. + item = TreeFind(&space->usedRegions, MakeShortKey(forcedAddress), TREE_SEARCH_EXACT); + if (item) return nullptr; + item = TreeFind(&space->usedRegions, MakeShortKey(forcedAddress), TREE_SEARCH_SMALLEST_ABOVE_OR_EQUAL); + if (item && item->thisItem->baseAddress < forcedAddress + pagesNeeded * K_PAGE_SIZE) return nullptr; + item = TreeFind(&space->usedRegions, MakeShortKey(forcedAddress + pagesNeeded * K_PAGE_SIZE - 1), TREE_SEARCH_LARGEST_BELOW_OR_EQUAL); + if (item && item->thisItem->baseAddress + item->thisItem->pageCount * K_PAGE_SIZE > forcedAddress) return nullptr; + item = TreeFind(&space->freeRegionsBase, MakeShortKey(forcedAddress), TREE_SEARCH_EXACT); + if (item) return nullptr; + item = TreeFind(&space->freeRegionsBase, MakeShortKey(forcedAddress), TREE_SEARCH_SMALLEST_ABOVE_OR_EQUAL); + if (item && item->thisItem->baseAddress < forcedAddress + pagesNeeded * K_PAGE_SIZE) return nullptr; + item = TreeFind(&space->freeRegionsBase, MakeShortKey(forcedAddress + pagesNeeded * K_PAGE_SIZE - 1), TREE_SEARCH_LARGEST_BELOW_OR_EQUAL); + if (item && item->thisItem->baseAddress + item->thisItem->pageCount * K_PAGE_SIZE > forcedAddress) return nullptr; + + // EsPrint("(no collisions)\n"); + + MMRegion *region = (MMRegion *) EsHeapAllocate(sizeof(MMRegion), true, K_CORE); + region->baseAddress = forcedAddress; + region->pageCount = pagesNeeded; + region->flags = flags; + TreeInsert(&space->usedRegions, ®ion->itemBase, region, MakeShortKey(region->baseAddress)); + + EsMemoryZero(®ion->data, sizeof(region->data)); + outputRegion = region; + } else { +#ifdef GUARD_PAGES + size_t guardPagesNeeded = generateGuardPages ? 2 : 0; +#else + size_t guardPagesNeeded = 0; +#endif + + AVLItem *item = TreeFind(&space->freeRegionsSize, MakeShortKey(pagesNeeded + guardPagesNeeded), TREE_SEARCH_SMALLEST_ABOVE_OR_EQUAL); + + if (!item) { + goto done; + } + + MMRegion *region = item->thisItem; + TreeRemove(&space->freeRegionsBase, ®ion->itemBase); + TreeRemove(&space->freeRegionsSize, ®ion->itemSize); + + if (region->pageCount > pagesNeeded + guardPagesNeeded) { + MMRegion *split = (MMRegion *) EsHeapAllocate(sizeof(MMRegion), true, K_CORE); + EsMemoryCopy(split, region, sizeof(MMRegion)); + + split->baseAddress += (pagesNeeded + guardPagesNeeded) * K_PAGE_SIZE; + split->pageCount -= (pagesNeeded + guardPagesNeeded); + + TreeInsert(&space->freeRegionsBase, &split->itemBase, split, MakeShortKey(split->baseAddress)); + TreeInsert(&space->freeRegionsSize, &split->itemSize, split, MakeShortKey(split->pageCount), AVL_DUPLICATE_KEYS_ALLOW); + } + + EsMemoryZero(®ion->data, sizeof(region->data)); + + region->pageCount = pagesNeeded; + region->flags = flags; + + if (guardPagesNeeded) { + MMRegion *guardBefore = (MMRegion *) EsHeapAllocate(sizeof(MMRegion), true, K_CORE); + MMRegion *guardAfter = (MMRegion *) EsHeapAllocate(sizeof(MMRegion), true, K_CORE); + + EsMemoryCopy(guardBefore, region, sizeof(MMRegion)); + EsMemoryCopy(guardAfter, region, sizeof(MMRegion)); + + guardAfter->baseAddress += K_PAGE_SIZE * (pagesNeeded + 1); + guardBefore->pageCount = guardAfter->pageCount = 1; + guardBefore->flags = guardAfter->flags = MM_REGION_GUARD; + + region->baseAddress += K_PAGE_SIZE; + region->data.normal.guardBefore = guardBefore; + region->data.normal.guardAfter = guardAfter; + + EsMemoryZero(&guardBefore->itemNonGuard, sizeof(guardBefore->itemNonGuard)); + EsMemoryZero(&guardAfter->itemNonGuard, sizeof(guardAfter->itemNonGuard)); + + TreeInsert(&space->usedRegions, &guardBefore->itemBase, guardBefore, MakeShortKey(guardBefore->baseAddress)); + TreeInsert(&space->usedRegions, &guardAfter ->itemBase, guardAfter, MakeShortKey(guardAfter->baseAddress)); + +#if 0 + EsPrint("Guarded region: %x->%x/%x->%x/%x->%x\n", guardBefore->baseAddress, guardBefore->pageCount * K_PAGE_SIZE + guardBefore->baseAddress, + region->baseAddress, region->pageCount * K_PAGE_SIZE + region->baseAddress, + guardAfter->baseAddress, guardAfter->pageCount * K_PAGE_SIZE + guardAfter->baseAddress); +#endif + } + + TreeInsert(&space->usedRegions, ®ion->itemBase, region, MakeShortKey(region->baseAddress)); + + outputRegion = region; + goto done; + } + + done:; + // EsPrint("reserve: %x -> %x\n", address, (uintptr_t) address + pagesNeeded * K_PAGE_SIZE); + + if (outputRegion) { + // We've now got an address range for the region. + // So we should commit the page tables that will be needed to map it. + + if (!MMArchCommitPageTables(space, outputRegion)) { + // We couldn't commit the leading page tables. + // So we'll have to unreserve the region. + MMUnreserve(space, outputRegion, false); + return nullptr; + } + + if (space != coreMMSpace) { + EsMemoryZero(&outputRegion->itemNonGuard, sizeof(outputRegion->itemNonGuard)); + outputRegion->itemNonGuard.thisItem = outputRegion; + space->usedRegionsNonGuard.InsertEnd(&outputRegion->itemNonGuard); + } + } + + // EsPrint("Reserve: %x->%x\n", outputRegion->baseAddress, outputRegion->pageCount * K_PAGE_SIZE + outputRegion->baseAddress); + return outputRegion; +} + +void MMUnreserve(MMSpace *space, MMRegion *remove, bool unmapPages, bool guardRegion) { + // EsPrint("unreserve: %x, %x, %d, %d\n", remove->baseAddress, remove->flags, unmapPages, guardRegion); + // EsDefer(EsPrint("unreserve complete\n");); + + KMutexAssertLocked(&space->reserveMutex); + + if (pmm.nextRegionToBalance == remove) { + // If the balance thread paused while balancing this region, + // switch to the next region. + pmm.nextRegionToBalance = remove->itemNonGuard.nextItem ? remove->itemNonGuard.nextItem->thisItem : nullptr; + pmm.balanceResumePosition = 0; + } + + if (!remove) { + KernelPanic("MMUnreserve - Region to remove was null.\n"); + } + + if (remove->flags & MM_REGION_NORMAL) { + if (remove->data.normal.guardBefore) MMUnreserve(space, remove->data.normal.guardBefore, false, true); + if (remove->data.normal.guardAfter) MMUnreserve(space, remove->data.normal.guardAfter, false, true); + } else if ((remove->flags & MM_REGION_GUARD) && !guardRegion) { + // You can't free a guard region! + // TODO Error. + KernelLog(LOG_ERROR, "Memory", "attempt to unreserve guard page", "MMUnreserve - Attempting to unreserve a guard page.\n"); + return; + } + + if (remove->itemNonGuard.list && !guardRegion) { + // EsPrint("Remove item non guard...\n"); + remove->itemNonGuard.RemoveFromList(); + // EsPrint("Removed.\n"); + } + + if (unmapPages) { + MMArchUnmapPages(space, remove->baseAddress, + remove->pageCount, ES_FLAGS_DEFAULT); + } + + if (space == coreMMSpace) { + remove->core.used = false; + + intptr_t remove1 = -1, remove2 = -1; + + for (uintptr_t i = 0; i < mmCoreRegionCount && (remove1 != -1 || remove2 != 1); i++) { + MMRegion *r = mmCoreRegions + i; + + if (r->core.used) continue; + if (r == remove) continue; + + if (r->baseAddress == remove->baseAddress + (remove->pageCount << K_PAGE_BITS)) { + remove->pageCount += r->pageCount; + remove1 = i; + } else if (remove->baseAddress == r->baseAddress + (r->pageCount << K_PAGE_BITS)) { + remove->pageCount += r->pageCount; + remove->baseAddress = r->baseAddress; + remove2 = i; + } + } + + if (remove1 != -1) { + mmCoreRegions[remove1] = mmCoreRegions[--mmCoreRegionCount]; + if ((uintptr_t) remove2 == mmCoreRegionCount) remove2 = remove1; + } + + if (remove2 != -1) { + mmCoreRegions[remove2] = mmCoreRegions[--mmCoreRegionCount]; + } + } else { + TreeRemove(&space->usedRegions, &remove->itemBase); + uintptr_t address = remove->baseAddress; + + { + AVLItem *before = TreeFind(&space->freeRegionsBase, MakeShortKey(address), TREE_SEARCH_LARGEST_BELOW_OR_EQUAL); + + if (before && before->thisItem->baseAddress + before->thisItem->pageCount * K_PAGE_SIZE == remove->baseAddress) { + remove->baseAddress = before->thisItem->baseAddress; + remove->pageCount += before->thisItem->pageCount; + TreeRemove(&space->freeRegionsBase, before); + TreeRemove(&space->freeRegionsSize, &before->thisItem->itemSize); + EsHeapFree(before->thisItem, sizeof(MMRegion), K_CORE); + } + } + + { + AVLItem *after = TreeFind(&space->freeRegionsBase, MakeShortKey(address), TREE_SEARCH_SMALLEST_ABOVE_OR_EQUAL); + + if (after && remove->baseAddress + remove->pageCount * K_PAGE_SIZE == after->thisItem->baseAddress) { + remove->pageCount += after->thisItem->pageCount; + TreeRemove(&space->freeRegionsBase, after); + TreeRemove(&space->freeRegionsSize, &after->thisItem->itemSize); + EsHeapFree(after->thisItem, sizeof(MMRegion), K_CORE); + } + } + + TreeInsert(&space->freeRegionsBase, &remove->itemBase, remove, MakeShortKey(remove->baseAddress)); + TreeInsert(&space->freeRegionsSize, &remove->itemSize, remove, MakeShortKey(remove->pageCount), AVL_DUPLICATE_KEYS_ALLOW); + } +} + +void *MMMapFile(MMSpace *space, FSFile *node, EsFileOffset offset, size_t bytes, int protection, void *baseAddress, size_t zeroedBytes, uint32_t additionalFlags) { + if (protection != ES_MAP_OBJECT_READ_ONLY && protection != ES_MAP_OBJECT_COPY_ON_WRITE) { + return nullptr; + } + + if (node->directoryEntry->type != ES_NODE_FILE) { + return nullptr; + } + + MMRegion *region = nullptr; + uint64_t fileHandleFlags = ES_NODE_PREVENT_RESIZE + | (protection == ES_MAP_OBJECT_READ_WRITE ? ES_FILE_WRITE : ES_FILE_READ_SHARED); + bool decommit = false; + + // Register a handle to the node. + // If this successes, past this point we file cannot be resized. + + if (!OpenHandleToObject(node, KERNEL_OBJECT_NODE, fileHandleFlags)) { + return nullptr; + } + + // Acquire the file's cache mutex before the space's reserve mutex, + // so that we can handle page faults without locking the reserve mutex. + + KMutexAcquire(&node->cache.cachedSectionsMutex); + EsDefer(KMutexRelease(&node->cache.cachedSectionsMutex)); + KMutexAcquire(&space->reserveMutex); + EsDefer(KMutexRelease(&space->reserveMutex)); + + // Check the parameters. + + uintptr_t offsetIntoPage = offset & (K_PAGE_SIZE - 1); + + if (node->directoryEntry->totalSize <= offset) { + goto fail; + } + + if (offsetIntoPage) bytes += offset & (K_PAGE_SIZE - 1); + + // Reserve the region. + + region = MMReserve(space, bytes + zeroedBytes, MM_REGION_FILE | additionalFlags + | ((protection == ES_MAP_OBJECT_READ_ONLY || protection == ES_MAP_OBJECT_COPY_ON_WRITE) ? MM_REGION_READ_ONLY : 0) + | (protection == ES_MAP_OBJECT_COPY_ON_WRITE ? MM_REGION_COPY_ON_WRITE : 0), + baseAddress ? (uintptr_t) baseAddress - offsetIntoPage : 0); + + if (!region) { + goto fail; + } + + // Commit copy on write regions. + + if (protection == ES_MAP_OBJECT_COPY_ON_WRITE) { + if (!MMCommit(bytes + zeroedBytes, false)) { + goto fail; + } + + decommit = true; + } + + // Initialise data. + + region->data.file.node = node; + region->data.file.offset = offset - offsetIntoPage; + region->data.file.zeroedBytes = zeroedBytes; + region->data.file.fileHandleFlags = fileHandleFlags; + + // Make sure the region is covered by MMCachedSections in the file. + // (This is why we needed the file's cache mutex.) + // We'll allocate in coreMMSpace as needed. + + if (!CCSpaceCover(&node->cache, region->data.file.offset, region->data.file.offset + bytes)) { + goto fail; + } + + return (uint8_t *) region->baseAddress + offsetIntoPage; + + fail:; + if (region) MMUnreserve(space, region, false /* No pages have been mapped. */); + if (decommit) MMDecommit(bytes + zeroedBytes, false); + CloseHandleToObject(node, KERNEL_OBJECT_NODE, fileHandleFlags); + return nullptr; +} + +void *MMMapShared(MMSpace *space, MMSharedRegion *sharedRegion, uintptr_t offset, size_t bytes, uint32_t additionalFlags, void *baseAddress) { + MMRegion *region; + OpenHandleToObject(sharedRegion, KERNEL_OBJECT_SHMEM); + + KMutexAcquire(&space->reserveMutex); + EsDefer(KMutexRelease(&space->reserveMutex)); + + if (offset & (K_PAGE_SIZE - 1)) bytes += offset & (K_PAGE_SIZE - 1); + if (sharedRegion->sizeBytes <= offset) goto fail; + if (sharedRegion->sizeBytes < offset + bytes) goto fail; + + region = MMReserve(space, bytes, MM_REGION_SHARED | additionalFlags, (uintptr_t) baseAddress); + if (!region) goto fail; + + if (!(region->flags & MM_REGION_SHARED)) KernelPanic("MMMapShared - Cannot commit into non-shared region.\n"); + if (region->data.shared.region) KernelPanic("MMMapShared - A shared region has already been bound.\n"); + + region->data.shared.region = sharedRegion; + region->data.shared.offset = offset & ~(K_PAGE_SIZE - 1); + + return (uint8_t *) region->baseAddress + (offset & (K_PAGE_SIZE - 1)); + + fail:; + CloseHandleToObject(sharedRegion, KERNEL_OBJECT_SHMEM); + return nullptr; +} + +void MMDecommit(uint64_t bytes, bool fixed) { + // EsPrint("De-Commit %d %d\n", bytes, fixed); + + if (bytes & (K_PAGE_SIZE - 1)) KernelPanic("MMDecommit - Expected multiple of K_PAGE_SIZE bytes.\n"); + int64_t pagesNeeded = bytes / K_PAGE_SIZE; + + KMutexAcquire(&pmm.commitMutex); + EsDefer(KMutexRelease(&pmm.commitMutex)); + + if (fixed) { + if (pmm.commitFixed < pagesNeeded) KernelPanic("MMDecommit - Decommitted too many pages.\n"); + pmm.commitFixed -= pagesNeeded; + } else { + if (pmm.commitPageable < pagesNeeded) KernelPanic("MMDecommit - Decommitted too many pages.\n"); + pmm.commitPageable -= pagesNeeded; + } + + KernelLog(LOG_VERBOSE, "Memory", "decommit", "Decommit %D%z. Now at %D.\n", bytes, fixed ? ", fixed" : "", (pmm.commitFixed + pmm.commitPageable) << K_PAGE_BITS); +} + +bool MMCommit(uint64_t bytes, bool fixed) { + if (bytes & (K_PAGE_SIZE - 1)) KernelPanic("MMCommit - Expected multiple of K_PAGE_SIZE bytes.\n"); + int64_t pagesNeeded = bytes / K_PAGE_SIZE; + + KMutexAcquire(&pmm.commitMutex); + EsDefer(KMutexRelease(&pmm.commitMutex)); + + if (pmm.commitLimit) { + if (fixed) { + if (pagesNeeded > pmm.commitFixedLimit - pmm.commitFixed) { + KernelLog(LOG_ERROR, "Memory", "failed fixed commit", "Failed fixed commit %d pages (currently %d/%d).\n", + pagesNeeded, pmm.commitFixed, pmm.commitFixedLimit); + return false; + } + + if (MM_AVAILABLE_PAGES() - pagesNeeded < MM_CRITICAL_AVAILABLE_PAGES_THRESHOLD && !GetCurrentThread()->isPageGenerator) { + KernelLog(LOG_ERROR, "Memory", "failed fixed commit", + "Failed fixed commit %d as the available pages (%d, %d, %d) would cross the critical threshold, %d.\n.", + pagesNeeded, pmm.countZeroedPages, pmm.countFreePages, pmm.countStandbyPages, MM_CRITICAL_AVAILABLE_PAGES_THRESHOLD); + return false; + } + + pmm.commitFixed += pagesNeeded; + } else { + if (pagesNeeded > MM_REMAINING_COMMIT() - (intptr_t) (GetCurrentThread()->isPageGenerator ? 0 : MM_CRITICAL_REMAINING_COMMIT_THRESHOLD)) { + KernelLog(LOG_ERROR, "Memory", "failed pageable commit", + "Failed pageable commit %d pages (currently %d/%d).\n", + pagesNeeded, pmm.commitPageable + pmm.commitFixed, pmm.commitLimit); + return false; + } + + pmm.commitPageable += pagesNeeded; + } + + if (MM_OBJECT_CACHE_SHOULD_TRIM()) { + KEventSet(&pmm.trimObjectCaches, false, true); + } + } else { + // We haven't started tracking commit counts yet. + } + + KernelLog(LOG_VERBOSE, "Memory", "commit", "Commit %D%z. Now at %D.\n", bytes, fixed ? ", fixed" : "", (pmm.commitFixed + pmm.commitPageable) << K_PAGE_BITS); + + return true; +} + +bool MMCommitRange(MMSpace *space, MMRegion *region, uintptr_t pageOffset, size_t pageCount) { + KMutexAssertLocked(&space->reserveMutex); + + if (region->flags & MM_REGION_NO_COMMIT_TRACKING) { + KernelPanic("MMCommitRange - Region does not support commit tracking.\n"); + } + + if (pageOffset >= region->pageCount || pageCount > region->pageCount - pageOffset) { + KernelPanic("MMCommitRange - Invalid region offset and page count.\n"); + } + + if (~region->flags & MM_REGION_NORMAL) { + KernelPanic("MMCommitRange - Cannot commit into non-normal region.\n"); + } + + intptr_t delta = 0; + region->data.normal.commit.Set(pageOffset, pageOffset + pageCount, &delta, false); + + if (delta < 0) { + KernelPanic("MMCommitRange - Invalid delta calculation adding %x, %x to %x.\n", pageOffset, pageCount, region); + } + + if (delta == 0) { + return true; + } + + { + if (!MMCommit(delta * K_PAGE_SIZE, region->flags & MM_REGION_FIXED)) { + return false; + } + + region->data.normal.commitPageCount += delta; + space->commit += delta; + + if (region->data.normal.commitPageCount > region->pageCount) { + KernelPanic("MMCommitRange - Invalid delta calculation increases region %x commit past page count.\n", region); + } + } + + if (!region->data.normal.commit.Set(pageOffset, pageOffset + pageCount, nullptr, true)) { + MMDecommit(delta * K_PAGE_SIZE, region->flags & MM_REGION_FIXED); + region->data.normal.commitPageCount -= delta; + space->commit -= delta; + return false; + } + + if (region->flags & MM_REGION_FIXED) { + for (uintptr_t i = pageOffset; i < pageOffset + pageCount; i++) { + // TODO Don't call into MMHandlePageFault. I don't like MM_HANDLE_PAGE_FAULT_LOCK_ACQUIRED. + + if (!MMHandlePageFault(space, region->baseAddress + i * K_PAGE_SIZE, MM_HANDLE_PAGE_FAULT_LOCK_ACQUIRED)) { + KernelPanic("MMCommitRange - Unable to fix pages.\n"); + } + } + } + + return true; +} + +bool MMDecommitRange(MMSpace *space, MMRegion *region, uintptr_t pageOffset, size_t pageCount) { + KMutexAssertLocked(&space->reserveMutex); + + if (region->flags & MM_REGION_NO_COMMIT_TRACKING) { + KernelPanic("MMDecommitRange - Region does not support commit tracking.\n"); + } + + if (pageOffset >= region->pageCount || pageCount > region->pageCount - pageOffset) { + KernelPanic("MMDecommitRange - Invalid region offset and page count.\n"); + } + + if (~region->flags & MM_REGION_NORMAL) { + KernelPanic("MMDecommitRange - Cannot decommit from non-normal region.\n"); + } + + intptr_t delta = 0; + + if (!region->data.normal.commit.Clear(pageOffset, pageOffset + pageCount, &delta, true)) { + return false; + } + + if (delta > 0) { + KernelPanic("MMDecommitRange - Invalid delta calculation removing %x, %x from %x.\n", pageOffset, pageCount, region); + } + + delta = -delta; + + if (region->data.normal.commitPageCount < (size_t) delta) { + KernelPanic("MMDecommitRange - Invalid delta calculation decreases region %x commit below zero.\n", region); + } + + // EsPrint("\tdecommit = %x\n", pagesRemoved); + + MMDecommit(delta * K_PAGE_SIZE, region->flags & MM_REGION_FIXED); + space->commit -= delta; + region->data.normal.commitPageCount -= delta; + MMArchUnmapPages(space, region->baseAddress + pageOffset * K_PAGE_SIZE, pageCount, MM_UNMAP_PAGES_FREE); + + return true; +} + +void MMAllowWriteCombiningCaching(MMSpace *space, void *virtualAddress) { + if (!space) space = kernelMMSpace; + + KMutexAcquire(&space->reserveMutex); + + MMRegion *region = MMFindRegion(space, (uintptr_t) virtualAddress); + + if (!(region->flags & MM_REGION_NOT_CACHEABLE)) { + KernelPanic("MMAllowWriteCombiningCaching - Region was cachable.\n"); + } + + region->flags &= ~MM_REGION_NOT_CACHEABLE; + region->flags |= MM_REGION_WRITE_COMBINING; + MMArchUnmapPages(space, region->baseAddress, region->pageCount, ES_FLAGS_DEFAULT); + + KMutexRelease(&space->reserveMutex); + + for (uintptr_t i = 0; i < region->pageCount; i++) { + MMHandlePageFault(space, region->baseAddress + i * K_PAGE_SIZE, ES_FLAGS_DEFAULT); + } +} + +size_t MMGetRegionPageCount(MMSpace *space, void *address) { + if (!space) space = kernelMMSpace; + + KMutexAcquire(&space->reserveMutex); + EsDefer(KMutexRelease(&space->reserveMutex)); + + MMRegion *region = MMFindRegion(space, (uintptr_t) address); + return region->pageCount; +} + +void *MMMapPhysical(MMSpace *space, uintptr_t offset, size_t bytes, uint64_t caching) { + if (!space) space = kernelMMSpace; + + uintptr_t offset2 = offset & (K_PAGE_SIZE - 1); + offset -= offset2; + if (offset2) bytes += K_PAGE_SIZE; + + MMRegion *region; + + { + KMutexAcquire(&space->reserveMutex); + EsDefer(KMutexRelease(&space->reserveMutex)); + + region = MMReserve(space, bytes, MM_REGION_PHYSICAL | MM_REGION_FIXED | caching); + if (!region) return nullptr; + + region->data.physical.offset = offset; + } + + for (uintptr_t i = 0; i < region->pageCount; i++) { + MMHandlePageFault(space, region->baseAddress + i * K_PAGE_SIZE, ES_FLAGS_DEFAULT); + } + + return (uint8_t *) region->baseAddress + offset2; +} + +bool MMSharedResizeRegion(MMSharedRegion *region, size_t sizeBytes) { + KMutexAcquire(®ion->mutex); + EsDefer(KMutexRelease(®ion->mutex)); + + sizeBytes = (sizeBytes + K_PAGE_SIZE - 1) & ~(K_PAGE_SIZE - 1); + + size_t pages = sizeBytes / K_PAGE_SIZE; + size_t oldPages = region->sizeBytes / K_PAGE_SIZE; + void *oldData = region->data; + + void *newData = EsHeapAllocate(pages * sizeof(void *), true, K_CORE); + + if (!newData && pages) { + return false; + } + + if (oldPages > pages) { + MMDecommit(K_PAGE_SIZE * (oldPages - pages), true); + } else if (pages > oldPages) { + if (!MMCommit(K_PAGE_SIZE * (pages - oldPages), true)) { + EsHeapFree(newData, pages * sizeof(void *), K_CORE); + return false; + } + } + + region->sizeBytes = sizeBytes; + region->data = newData; + + // The old shared memory region was empty. + if (!oldData) return true; + + if (oldPages > pages) { + for (uintptr_t i = pages; i < oldPages; i++) { + uintptr_t *addresses = (uintptr_t *) oldData; + uintptr_t address = addresses[i]; + if (address & MM_SHARED_ENTRY_PRESENT) MMPhysicalFree(address); + } + } + + uintptr_t copy = oldPages > pages ? pages : oldPages; + EsMemoryCopy(region->data, oldData, sizeof(void *) * copy); + EsHeapFree(oldData, oldPages * sizeof(void *), K_CORE); + + return true; +} + +MMSharedRegion *MMSharedOpenRegion(const char *name, size_t nameBytes, size_t fallbackSizeBytes, uint64_t flags) { + if (nameBytes > ES_SHARED_MEMORY_NAME_MAX_LENGTH) return nullptr; + + KMutexAcquire(&mmNamedSharedRegionsMutex); + EsDefer(KMutexRelease(&mmNamedSharedRegionsMutex)); + + LinkedItem *item = mmNamedSharedRegions.firstItem; + + while (item) { + MMSharedRegion *region = item->thisItem; + + if (EsCStringLength(region->cName) == nameBytes && 0 == EsMemoryCompare(region->cName, name, nameBytes)) { + if (flags & ES_MEMORY_OPEN_FAIL_IF_FOUND) return nullptr; + OpenHandleToObject(region, KERNEL_OBJECT_SHMEM); + return region; + } + + item = item->nextItem; + } + + if (flags & ES_MEMORY_OPEN_FAIL_IF_NOT_FOUND) return nullptr; + + MMSharedRegion *region = MMSharedCreateRegion(fallbackSizeBytes); + if (!region) return nullptr; + EsMemoryCopy(region->cName, name, nameBytes); + + region->namedItem.thisItem = region; + mmNamedSharedRegions.InsertEnd(®ion->namedItem); + + return region; +} + +MMSharedRegion *MMSharedCreateRegion(size_t sizeBytes, bool fixed, uintptr_t below) { + if (!sizeBytes) return nullptr; + + MMSharedRegion *region = (MMSharedRegion *) EsHeapAllocate(sizeof(MMSharedRegion), true, K_CORE); + if (!region) return nullptr; + region->handles = 1; + + if (!MMSharedResizeRegion(region, sizeBytes)) { + EsHeapFree(region, 0, K_CORE); + return nullptr; + } + + if (fixed) { + for (uintptr_t i = 0; i < region->sizeBytes >> K_PAGE_BITS; i++) { + ((uintptr_t *) region->data)[i] = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_ZEROED, 1, 1, below) | MM_SHARED_ENTRY_PRESENT; + } + } + + return region; +} + +void MMSharedDestroyRegion(MMSharedRegion *region) { + MMSharedResizeRegion(region, 0); // TODO Check leaks. + EsHeapFree(region, 0, K_CORE); +} + +void *MMStandardAllocate(MMSpace *space, size_t bytes, unsigned flags, void *baseAddress, bool commitAll) { + if (!space) space = kernelMMSpace; + + KMutexAcquire(&space->reserveMutex); + EsDefer(KMutexRelease(&space->reserveMutex)); + + MMRegion *region = MMReserve(space, bytes, flags | MM_REGION_NORMAL, (uintptr_t) baseAddress, true); + if (!region) return nullptr; + + if (commitAll) { + if (!MMCommitRange(space, region, 0, region->pageCount)) { + MMUnreserve(space, region, false /* No pages have been mapped. */); + return nullptr; + } + } + + return (void *) region->baseAddress; +} + +bool MMFree(MMSpace *space, void *address, size_t expectedSize, bool userOnly) { + if (!space) space = kernelMMSpace; + + MMSharedRegion *sharedRegionToFree = nullptr; + FSFile *nodeToFree = nullptr; + uint64_t fileHandleFlags = 0; + + { + KMutexAcquire(&space->reserveMutex); + EsDefer(KMutexRelease(&space->reserveMutex)); + + MMRegion *region = MMFindRegion(space, (uintptr_t) address); + + if (!region) { + return false; + } + + if (userOnly && (~region->flags & MM_REGION_USER)) { + KernelLog(LOG_ERROR, "Memory", "attempt to free non-user region", + "MMFree - A user process is attempting to free a region %x that is not marked with MM_REGION_USER.\n", region); + return false; + } + + if (!KWriterLockTake(®ion->data.pin, K_LOCK_EXCLUSIVE, true /* poll */)) { + KernelLog(LOG_ERROR, "Memory", "attempt to free in use region", + "MMFree - Attempting to free a region %x that is currently in by a system call.\n", region); + return false; + } + + if (region->baseAddress != (uintptr_t) address && (~region->flags & MM_REGION_PHYSICAL /* physical region bases are not page aligned */)) { + KernelLog(LOG_ERROR, "Memory", "incorrect base address", "MMFree - Passed the address %x to free region %x, which has baseAddress of %x.\n", + address, region, region->baseAddress); + return false; + } + + if (expectedSize && (expectedSize + K_PAGE_SIZE - 1) / K_PAGE_SIZE != region->pageCount) { + KernelLog(LOG_ERROR, "Memory", "incorrect free size", "MMFree - The region page count is %d, but the expected free size is %d.\n", + region->pageCount, (expectedSize + K_PAGE_SIZE - 1) / K_PAGE_SIZE); + return false; + } + + bool unmapPages = true; + + if (region->flags & MM_REGION_NORMAL) { + if (!MMDecommitRange(space, region, 0, region->pageCount)) { + KernelPanic("MMFree - Could not decommit entire region %x (should not fail).\n", region); + } + + if (region->data.normal.commitPageCount) { + KernelPanic("MMFree - After decommiting range covering the entire region (%x), some pages were still commited.\n", region); + } + + region->data.normal.commit.ranges.Free(); + unmapPages = false; + } else if (region->flags & MM_REGION_SHARED) { + sharedRegionToFree = region->data.shared.region; + } else if (region->flags & MM_REGION_FILE) { + MMArchUnmapPages(space, region->baseAddress, + region->pageCount, MM_UNMAP_PAGES_FREE_COPIED | MM_UNMAP_PAGES_BALANCE_FILE); + unmapPages = false; + + FSFile *node = region->data.file.node; + EsFileOffset removeStart = RoundDown(region->data.file.offset, K_PAGE_SIZE); + EsFileOffset removeEnd = RoundUp(removeStart + (region->pageCount << K_PAGE_BITS) - region->data.file.zeroedBytes, K_PAGE_SIZE); + nodeToFree = node; + fileHandleFlags = region->data.file.fileHandleFlags; + + KMutexAcquire(&node->cache.cachedSectionsMutex); + CCSpaceUncover(&node->cache, removeStart, removeEnd); + KMutexRelease(&node->cache.cachedSectionsMutex); + + if (region->flags & MM_REGION_COPY_ON_WRITE) { + MMDecommit(region->pageCount << K_PAGE_BITS, false); + } + } else if (region->flags & MM_REGION_PHYSICAL) { + } else if (region->flags & MM_REGION_GUARD) { + KernelLog(LOG_ERROR, "Memory", "attempt to free guard region", "MMFree - Attempting to free a guard region!\n"); + return false; + } else { + KernelPanic("MMFree - Unsupported region type.\n"); + } + + MMUnreserve(space, region, unmapPages); + } + + if (sharedRegionToFree) CloseHandleToObject(sharedRegionToFree, KERNEL_OBJECT_SHMEM); + if (nodeToFree && fileHandleFlags) CloseHandleToObject(nodeToFree, KERNEL_OBJECT_NODE, fileHandleFlags); + + return true; +} + +bool MMSpaceInitialise(MMSpace *space) { + // EsPrint("... Committed %d/%d fixed and %d pageable out of a maximum %d.\n", pmm.commitFixed, pmm.commitFixedLimit, pmm.commitPageable, pmm.commitLimit); + + space->user = true; + + MMRegion *region = (MMRegion *) EsHeapAllocate(sizeof(MMRegion), true, K_CORE); + + if (!region) { + return false; + } + + if (!MMArchInitialiseUserSpace(space)) { + EsHeapFree(region, sizeof(MMRegion), K_CORE); + return false; + } + + region->baseAddress = MM_USER_SPACE_START; + region->pageCount = MM_USER_SPACE_SIZE / K_PAGE_SIZE; + TreeInsert(&space->freeRegionsBase, ®ion->itemBase, region, MakeShortKey(region->baseAddress)); + TreeInsert(&space->freeRegionsSize, ®ion->itemSize, region, MakeShortKey(region->pageCount), AVL_DUPLICATE_KEYS_ALLOW); + + return true; +} + +void MMSpaceDestroy(MMSpace *space) { + LinkedItem *item = space->usedRegionsNonGuard.firstItem; + + while (item) { + MMRegion *region = item->thisItem; + item = item->nextItem; + MMFree(space, (void *) region->baseAddress); + } + + while (true) { + AVLItem *item = TreeFind(&space->freeRegionsBase, MakeShortKey(0), TREE_SEARCH_SMALLEST_ABOVE_OR_EQUAL); + if (!item) break; + TreeRemove(&space->freeRegionsBase, &item->thisItem->itemBase); + TreeRemove(&space->freeRegionsSize, &item->thisItem->itemSize); + EsHeapFree(item->thisItem, sizeof(MMRegion), K_CORE); + } + + MMFreeVAS(space); +} + +bool MMUnmapFilePage(uintptr_t frameNumber, bool justLoaded) { + KMutexAssertLocked(&pmm.pageFrameMutex); + + MMPageFrame *frame = pmm.pageFrames + frameNumber; + + if (!justLoaded) { + if (frame->state != MMPageFrame::ACTIVE || !frame->active.references) { + KernelPanic("MMUnmapFilePage - Corrupt page frame database (%d/%x).\n", frameNumber, frame); + } + + // Decrease the reference count. + frame->active.references--; + } + + if (!frame->active.references) { + // If there are no more references, then the frame can be moved to the standby or modified list. + + // EsPrint("Unmap file page: %x\n", frameNumber << K_PAGE_BITS); + + { + frame->state = MMPageFrame::STANDBY; + pmm.countStandbyPages++; + + if (*frame->cacheReference != ((frameNumber << K_PAGE_BITS) | MM_SHARED_ENTRY_PRESENT)) { + KernelPanic("MMUnmapFilePage - Corrupt shared reference back pointer in frame %x.\n", frame); + } + + frame->list.next = pmm.firstStandbyPage; + frame->list.previous = &pmm.firstStandbyPage; + if (pmm.firstStandbyPage) pmm.pageFrames[pmm.firstStandbyPage].list.previous = &frame->list.next; + if (!pmm.lastStandbyPage) pmm.lastStandbyPage = frameNumber; + pmm.firstStandbyPage = frameNumber; + + MMUpdateAvailablePageCount(true); + } + + pmm.countActivePages--; + return true; + } + + return false; +} + +void MMBalanceThread() { + size_t targetAvailablePages = 0; + + while (true) { + if (MM_AVAILABLE_PAGES() >= targetAvailablePages) { + // Wait for there to be a low number of available pages. + KEventWait(&pmm.availableLow); + targetAvailablePages = MM_LOW_AVAILABLE_PAGES_THRESHOLD + MM_PAGES_TO_FIND_BALANCE; + } + + // EsPrint("--> Balance!\n"); + + // Find a process to balance. + + KSpinlockAcquire(&scheduler.lock); + + Process *process = nullptr; + + while (true) { + if (pmm.nextProcessToBalance) { + process = pmm.nextProcessToBalance; + } else { + process = scheduler.allProcesses.firstItem->thisItem; + } + + pmm.nextProcessToBalance = process->allItem.nextItem ? process->allItem.nextItem->thisItem : nullptr; + + if (process->handles) { + process->handles++; + break; + } + } + + KSpinlockRelease(&scheduler.lock); + + // For every memory region... + + MMSpace *space = process->vmm; + GetCurrentThread()->SetAddressSpace(space); + KMutexAcquire(&space->reserveMutex); + LinkedItem *item = pmm.nextRegionToBalance ? &pmm.nextRegionToBalance->itemNonGuard : space->usedRegionsNonGuard.firstItem; + + while (item && MM_AVAILABLE_PAGES() < targetAvailablePages) { + MMRegion *region = item->thisItem; + + // EsPrint("process = %x, region = %x, offset = %x\n", process, region, pmm.balanceResumePosition); + + KMutexAcquire(®ion->data.mapMutex); + + bool canResume = false; + + if (region->flags & MM_REGION_FILE) { + canResume = true; + MMArchUnmapPages(space, + region->baseAddress, region->pageCount, + MM_UNMAP_PAGES_BALANCE_FILE, + targetAvailablePages - MM_AVAILABLE_PAGES(), &pmm.balanceResumePosition); + } else if (region->flags & MM_REGION_CACHE) { + // TODO Trim the cache's active sections and cached sections lists. + + KMutexAcquire(&activeSectionManager.mutex); + + LinkedItem *item = activeSectionManager.lruList.firstItem; + + while (item && MM_AVAILABLE_PAGES() < targetAvailablePages) { + CCActiveSection *section = item->thisItem; + if (section->cache && section->referencedPageCount) CCDereferenceActiveSection(section); + item = item->nextItem; + } + + KMutexRelease(&activeSectionManager.mutex); + } + + KMutexRelease(®ion->data.mapMutex); + + if (MM_AVAILABLE_PAGES() >= targetAvailablePages && canResume) { + // We have enough to pause. + break; + } + + item = item->nextItem; + pmm.balanceResumePosition = 0; + } + + if (item) { + // Continue with this region next time. + pmm.nextRegionToBalance = item->thisItem; + pmm.nextProcessToBalance = process; + // EsPrint("will resume at %x\n", pmm.balanceResumePosition); + } else { + // Go to the next process. + pmm.nextRegionToBalance = nullptr; + pmm.balanceResumePosition = 0; + } + + KMutexRelease(&space->reserveMutex); + GetCurrentThread()->SetAddressSpace(nullptr); + CloseHandleToObject(process, KERNEL_OBJECT_PROCESS); + } +} + +void MMZeroPageThread() { + while (true) { + KEventWait(&pmm.zeroPageEvent); + KEventWait(&pmm.availableNotCritical); + + bool done = false; + + while (!done) { + uintptr_t pages[PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES]; + int i = 0; + + { + KMutexAcquire(&pmm.pageFrameMutex); + EsDefer(KMutexRelease(&pmm.pageFrameMutex)); + + for (; i < PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES; i++) { + if (pmm.firstFreePage) { + pages[i] = pmm.firstFreePage; + MMPhysicalActivatePages(pages[i], 1, ES_FLAGS_DEFAULT); + } else { + done = true; + break; + } + + MMPageFrame *frame = pmm.pageFrames + pages[i]; + frame->state = MMPageFrame::ACTIVE; + pmm.freeOrZeroedPageBitset.Take(pages[i]); + } + } + + for (int j = 0; j < i; j++) pages[j] <<= K_PAGE_BITS; + if (i) PMZero(pages, i, false); + + { + KMutexAcquire(&pmm.pageFrameMutex); + pmm.countActivePages -= i; + while (i--) MMPhysicalInsertZeroedPage(pages[i] >> K_PAGE_BITS); + KMutexRelease(&pmm.pageFrameMutex); + } + } + } +} + +#if 0 +void PMCheckZeroed(uintptr_t page) { + pmm.pmManipulationLock.Acquire(); + + { + MMSpace *vas = coreMMSpace; + void *region = pmm.pmManipulationRegion; + + vas->data.mapMutex.Acquire(); + MMArchMapPage(vas, page, (uintptr_t) region, MM_MAP_PAGE_OVERWRITE); + vas->data.mapMutex.Release(); + + pmm.pmManipulationProcessorLock.Acquire(); + ProcessorInvalidatePage((uintptr_t) region); + + for (uintptr_t i = 0; i < K_PAGE_SIZE; i++) { + if (((uint8_t *) region)[i]) { + KernelPanic("PMCheckZeroed - Supposedly zeroed page %x was not zeroed.\n", page); + } + } + + pmm.pmManipulationProcessorLock.Release(); + } + + pmm.pmManipulationLock.Release(); +} +#endif + +void PMZeroPartial(uintptr_t page, uintptr_t start, uintptr_t end) { + KMutexAcquire(&pmm.pmManipulationLock); + MMSpace *vas = coreMMSpace; + void *region = pmm.pmManipulationRegion; + MMArchMapPage(vas, page, (uintptr_t) region, MM_MAP_PAGE_OVERWRITE | MM_MAP_PAGE_NO_NEW_TABLES); + KSpinlockAcquire(&pmm.pmManipulationProcessorLock); + ProcessorInvalidatePage((uintptr_t) region); + EsMemoryZero((uint8_t *) region + start, end - start); + KSpinlockRelease(&pmm.pmManipulationProcessorLock); + KMutexRelease(&pmm.pmManipulationLock); +} + +void PMZero(uintptr_t *pages, size_t pageCount, bool contiguous) { + KMutexAcquire(&pmm.pmManipulationLock); + + repeat:; + size_t doCount = pageCount > PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES ? PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES : pageCount; + pageCount -= doCount; + + { + MMSpace *vas = coreMMSpace; + void *region = pmm.pmManipulationRegion; + + for (uintptr_t i = 0; i < doCount; i++) { + MMArchMapPage(vas, contiguous ? pages[0] + (i << K_PAGE_BITS) : pages[i], + (uintptr_t) region + K_PAGE_SIZE * i, MM_MAP_PAGE_OVERWRITE | MM_MAP_PAGE_NO_NEW_TABLES); + } + + KSpinlockAcquire(&pmm.pmManipulationProcessorLock); + + for (uintptr_t i = 0; i < doCount; i++) { + ProcessorInvalidatePage((uintptr_t) region + i * K_PAGE_SIZE); + } + + EsMemoryZero(region, doCount * K_PAGE_SIZE); + + KSpinlockRelease(&pmm.pmManipulationProcessorLock); + } + + if (pageCount) { + if (!contiguous) pages += PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES; + goto repeat; + } + + // if (pageNumbers) EsPrint("w%d\n", pmm.pmManipulationLock.blockedThreads.count); + KMutexRelease(&pmm.pmManipulationLock); +} + +void PMCopy(uintptr_t page, void *_source, size_t pageCount) { + uint8_t *source = (uint8_t *) _source; + KMutexAcquire(&pmm.pmManipulationLock); + + repeat:; + size_t doCount = pageCount > PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES ? PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES : pageCount; + pageCount -= doCount; + + { + MMSpace *vas = coreMMSpace; + void *region = pmm.pmManipulationRegion; + + for (uintptr_t i = 0; i < doCount; i++) { + MMArchMapPage(vas, page + K_PAGE_SIZE * i, (uintptr_t) region + K_PAGE_SIZE * i, MM_MAP_PAGE_OVERWRITE | MM_MAP_PAGE_NO_NEW_TABLES); + } + + KSpinlockAcquire(&pmm.pmManipulationProcessorLock); + + for (uintptr_t i = 0; i < doCount; i++) { + ProcessorInvalidatePage((uintptr_t) region + i * K_PAGE_SIZE); + } + + EsMemoryCopy(region, source, doCount * K_PAGE_SIZE); + + KSpinlockRelease(&pmm.pmManipulationProcessorLock); + } + + if (pageCount) { + page += PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES * K_PAGE_SIZE; + source += PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES * K_PAGE_SIZE; + goto repeat; + } + + KMutexRelease(&pmm.pmManipulationLock); +} + +void PMRead(uintptr_t page, void *_source, size_t pageCount) { + uint8_t *source = (uint8_t *) _source; + KMutexAcquire(&pmm.pmManipulationLock); + + repeat:; + size_t doCount = pageCount > PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES ? PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES : pageCount; + pageCount -= doCount; + + { + MMSpace *vas = coreMMSpace; + void *region = pmm.pmManipulationRegion; + + for (uintptr_t i = 0; i < doCount; i++) { + MMArchMapPage(vas, page + K_PAGE_SIZE * i, (uintptr_t) region + K_PAGE_SIZE * i, MM_MAP_PAGE_OVERWRITE | MM_MAP_PAGE_NO_NEW_TABLES); + } + + KSpinlockAcquire(&pmm.pmManipulationProcessorLock); + + for (uintptr_t i = 0; i < doCount; i++) { + ProcessorInvalidatePage((uintptr_t) region + i * K_PAGE_SIZE); + } + + EsMemoryCopy(source, region, doCount * K_PAGE_SIZE); + + KSpinlockRelease(&pmm.pmManipulationProcessorLock); + } + + if (pageCount) { + page += PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES * K_PAGE_SIZE; + source += PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES * K_PAGE_SIZE; + goto repeat; + } + + KMutexRelease(&pmm.pmManipulationLock); +} + +void *Pool::Add(size_t _elementSize) { + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + if (elementSize && _elementSize != elementSize) KernelPanic("Pool::Add - Pool element size mismatch.\n"); + elementSize = _elementSize; + + void *address; + +#if 1 + if (cacheEntries) { + address = cache[--cacheEntries]; + EsMemoryZero(address, elementSize); + } else { + address = EsHeapAllocate(elementSize, true, K_FIXED); + } +#else + address = EsHeapAllocate(elementSize, true); +#endif + + return address; +} + +void Pool::Remove(void *address) { + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + if (!address) return; + +#if 1 + if (cacheEntries == POOL_CACHE_COUNT) { + EsHeapFree(address, elementSize, K_FIXED); + } else { + cache[cacheEntries++] = address; + } +#else + EsHeapFree(address, elementSize); +#endif +} + +MMRegion *MMFindAndPinRegion(MMSpace *space, uintptr_t address, uintptr_t size) { + if (address + size < address) { + return nullptr; + } + + KMutexAcquire(&space->reserveMutex); + EsDefer(KMutexRelease(&space->reserveMutex)); + + MMRegion *region = MMFindRegion(space, address); + + if (!region) { + return nullptr; + } + + if (region->baseAddress > address) { + return nullptr; + } + + if (region->baseAddress + region->pageCount * K_PAGE_SIZE < address + size) { + return nullptr; + } + + if (!KWriterLockTake(®ion->data.pin, K_LOCK_SHARED, true /* poll */)) { + return nullptr; + } + + return region; +} + +void MMUnpinRegion(MMSpace *space, MMRegion *region) { + KMutexAcquire(&space->reserveMutex); + KWriterLockReturn(®ion->data.pin, K_LOCK_SHARED); + KMutexRelease(&space->reserveMutex); +} + +bool MMPhysicalAllocateAndMap(size_t sizeBytes, size_t alignmentBytes, size_t maximumBits, bool zeroed, + uint64_t caching, uint8_t **_virtualAddress, uintptr_t *_physicalAddress) { + if (!sizeBytes) sizeBytes = 1; + if (!alignmentBytes) alignmentBytes = 1; + + bool noBelow = false; + +#ifdef ARCH_32 + if (!maximumBits || maximumBits >= 32) noBelow = true; +#endif + +#ifdef ARCH_64 + if (!maximumBits || maximumBits >= 64) noBelow = true; +#endif + + uintptr_t sizePages = (sizeBytes + K_PAGE_SIZE - 1) >> K_PAGE_BITS; + + uintptr_t physicalAddress = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_CAN_FAIL | MM_PHYSICAL_ALLOCATE_COMMIT_NOW, + sizePages, (alignmentBytes + K_PAGE_SIZE - 1) >> K_PAGE_BITS, + noBelow ? 0 : ((size_t) 1 << maximumBits)); + + if (!physicalAddress) { + return false; + } + + void *virtualAddress = MMMapPhysical(kernelMMSpace, physicalAddress, sizeBytes, caching); + + if (!virtualAddress) { + MMPhysicalFree(physicalAddress, false, sizePages); + return false; + } + + if (zeroed) { + EsMemoryZero(virtualAddress, sizeBytes); + } + + *_virtualAddress = (uint8_t *) virtualAddress; + *_physicalAddress = physicalAddress; + return true; +} + +void MMPhysicalFreeAndUnmap(void *virtualAddress, uintptr_t physicalAddress) { + KMutexAcquire(&kernelMMSpace->reserveMutex); + MMRegion *region = MMFindRegion(kernelMMSpace, (uintptr_t) virtualAddress); + + if (!region || (~region->flags & MM_REGION_PHYSICAL) || region->data.physical.offset != physicalAddress) { + KernelPanic("MMPhysicalFreeAndUnmap - Virtual address %x did not point to a region of physical memory mapping %x.\n", virtualAddress, physicalAddress); + } + + size_t pageCount = region->pageCount; + MMUnreserve(kernelMMSpace, region, true); + KMutexRelease(&kernelMMSpace->reserveMutex); + + MMPhysicalFree(physicalAddress, false, pageCount); +} + +MMSpace *MMGetKernelSpace() { + return kernelMMSpace; +} + +MMSpace *MMGetCurrentProcessSpace() { + return GetCurrentThread()->process->vmm; +} + +void MMArchRemap(MMSpace *space, const void *virtualAddress, uintptr_t newPhysicalAddress) { + if (ProcessorAreInterruptsEnabled()) { + KernelPanic("MMArchRemap - Cannot remap address with interrupts enabled (does not invalidate the page on other processors).\n"); + } + + MMArchMapPage(space, newPhysicalAddress, (uintptr_t) virtualAddress, MM_MAP_PAGE_OVERWRITE | MM_MAP_PAGE_NO_NEW_TABLES); +} + +void MMObjectCacheInsert(MMObjectCache *cache, MMObjectCacheItem *item) { + KSpinlockAcquire(&cache->lock); + cache->items.Insert(item, false /* end */); + cache->count++; + __sync_fetch_and_add(&pmm.approximateTotalObjectCacheBytes, cache->averageObjectBytes); + + if (MM_OBJECT_CACHE_SHOULD_TRIM()) { + KEventSet(&pmm.trimObjectCaches, false, true); + } + + KSpinlockRelease(&cache->lock); +} + +void MMObjectCacheRemove(MMObjectCache *cache, MMObjectCacheItem *item, bool alreadyLocked) { + if (!alreadyLocked) KSpinlockAcquire(&cache->lock); + else KSpinlockAssertLocked(&cache->lock); + item->Remove(); + cache->count--; + __sync_fetch_and_sub(&pmm.approximateTotalObjectCacheBytes, cache->averageObjectBytes); + + if (!alreadyLocked) KSpinlockRelease(&cache->lock); +} + +MMObjectCacheItem *MMObjectCacheRemoveLRU(MMObjectCache *cache) { + MMObjectCacheItem *item = nullptr; + KSpinlockAcquire(&cache->lock); + + if (cache->count) { + item = cache->items.first; + MMObjectCacheRemove(cache, item, true); + } + + KSpinlockRelease(&cache->lock); + return item; +} + +void MMObjectCacheRegister(MMObjectCache *cache, bool (*trim)(MMObjectCache *), size_t averageObjectBytes) { + KMutexAcquire(&pmm.objectCacheListMutex); + cache->trim = trim; + cache->averageObjectBytes = averageObjectBytes; + cache->item.thisItem = cache; + pmm.objectCacheList.InsertEnd(&cache->item); + KMutexRelease(&pmm.objectCacheListMutex); +} + +void MMObjectCacheUnregister(MMObjectCache *cache) { + KMutexAcquire(&pmm.objectCacheListMutex); + pmm.objectCacheList.Remove(&cache->item); + KMutexRelease(&pmm.objectCacheListMutex); + + // Wait for any trim threads still using the cache to finish. + KWriterLockTake(&cache->trimLock, K_LOCK_EXCLUSIVE); + KWriterLockReturn(&cache->trimLock, K_LOCK_EXCLUSIVE); +} + +void MMObjectCacheFlush(MMObjectCache *cache) { + if (cache->item.list) KernelPanic("MMObjectCacheFlush - Cache %x must be unregistered before flushing.\n", cache); + + // Wait for any trim threads still using the cache to finish. + KWriterLockTake(&cache->trimLock, K_LOCK_EXCLUSIVE); + + // Trim the cache until it is empty. + // The trim callback is allowed to increase cache->count, + // but nobody else should be increasing it once it has been unregistered. + while (cache->count) cache->trim(cache); + + // Return the trim lock. + KWriterLockReturn(&cache->trimLock, K_LOCK_EXCLUSIVE); +} + +void MMObjectCacheTrimThread() { + MMObjectCache *cache = nullptr; + + while (true) { + while (!MM_OBJECT_CACHE_SHOULD_TRIM()) { + KEventReset(&pmm.trimObjectCaches); + KEventWait(&pmm.trimObjectCaches); + } + + KMutexAcquire(&pmm.objectCacheListMutex); + + // TODO Is there a faster way to find the next cache? + // This needs to work with multiple producers and consumers. + // And I don't want to put the caches in an array, because then registering a cache could fail. + + MMObjectCache *previousCache = cache; + cache = nullptr; + + LinkedItem *item = pmm.objectCacheList.firstItem; + + while (item) { + if (item->thisItem == previousCache && item->nextItem) { + cache = item->nextItem->thisItem; + break; + } + + item = item->nextItem; + } + + if (!cache && pmm.objectCacheList.firstItem) { + cache = pmm.objectCacheList.firstItem->thisItem; + } + + if (cache) { + KWriterLockTake(&cache->trimLock, K_LOCK_SHARED); + } + + KMutexRelease(&pmm.objectCacheListMutex); + + if (!cache) { + continue; + } + + for (uintptr_t i = 0; i < MM_OBJECT_CACHE_TRIM_GROUP_COUNT; i++) { + if (!cache->trim(cache)) { + break; + } + } + + KWriterLockReturn(&cache->trimLock, K_LOCK_SHARED); + } +} + +void MMInitialise() { + { + // Initialise coreMMSpace. + + MMArchInitialiseVAS(); + mmCoreRegions[0].baseAddress = MM_CORE_SPACE_START; + mmCoreRegions[0].pageCount = MM_CORE_SPACE_SIZE / K_PAGE_SIZE; + mmCoreRegions[0].core.used = false; + mmCoreRegionCount = 1; + } + + { + // Initialise kernelMMSpace. + + KMutexAcquire(&coreMMSpace->reserveMutex); + kernelMMSpace->data.l1Commit = (uint8_t *) MMReserve(coreMMSpace, L1_COMMIT_SIZE_BYTES, MM_REGION_NORMAL | MM_REGION_NO_COMMIT_TRACKING | MM_REGION_FIXED)->baseAddress; + KMutexRelease(&coreMMSpace->reserveMutex); + + MMRegion *region = (MMRegion *) EsHeapAllocate(sizeof(MMRegion), true, K_CORE); + region->baseAddress = MM_KERNEL_SPACE_START; + region->pageCount = MM_KERNEL_SPACE_SIZE / K_PAGE_SIZE; + TreeInsert(&kernelMMSpace->freeRegionsBase, ®ion->itemBase, region, MakeShortKey(region->baseAddress)); + TreeInsert(&kernelMMSpace->freeRegionsSize, ®ion->itemSize, region, MakeShortKey(region->pageCount), AVL_DUPLICATE_KEYS_ALLOW); + } + + { + // Initialise physical memory management. + + KMutexAcquire(&kernelMMSpace->reserveMutex); + pmm.pmManipulationRegion = (void *) MMReserve(kernelMMSpace, PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES * K_PAGE_SIZE, ES_FLAGS_DEFAULT)->baseAddress; + KMutexRelease(&kernelMMSpace->reserveMutex); + + physicalMemoryHighest += K_PAGE_SIZE << 3; + pmm.pageFrames = (MMPageFrame *) MMStandardAllocate(kernelMMSpace, (physicalMemoryHighest >> K_PAGE_BITS) * sizeof(MMPageFrame), MM_REGION_FIXED); + pmm.freeOrZeroedPageBitset.Initialise(physicalMemoryHighest >> K_PAGE_BITS, true); + + uint64_t commitLimit = 0; + + while (physicalMemoryRegionsPagesCount) { + // TODO This loop is a bit slow... + MMPhysicalInsertFreePage(MMPhysicalAllocate(ES_FLAGS_DEFAULT) >> K_PAGE_BITS); + commitLimit++; + } + + pmm.commitLimit = pmm.commitFixedLimit = commitLimit; + KernelLog(LOG_INFO, "Memory", "pmm initialised", "MMInitialise - PMM initialised with a fixed commit limit of %d pages.\n", pmm.commitLimit); + } + + { + // Initialise file cache. + + CCInitialise(); + } + + { + // Thread initialisation. + + pmm.zeroPageEvent.autoReset = true; + MMCommit(PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES * K_PAGE_SIZE, true); + pmm.zeroPageThread = scheduler.SpawnThread("MMZero", (uintptr_t) MMZeroPageThread, 0, SPAWN_THREAD_LOW_PRIORITY); + pmm.balanceThread = scheduler.SpawnThread("MMBalance", (uintptr_t) MMBalanceThread, 0, ES_FLAGS_DEFAULT); + pmm.balanceThread->isPageGenerator = true; + scheduler.SpawnThread("MMObjTrim", (uintptr_t) MMObjectCacheTrimThread, 0, ES_FLAGS_DEFAULT); + } +} + +#endif diff --git a/kernel/module.h b/kernel/module.h new file mode 100644 index 0000000..1638970 --- /dev/null +++ b/kernel/module.h @@ -0,0 +1,1014 @@ +// TODO Include more functions and definitions. +// TODO Add K- prefix to more identifiers. + +#define KERNEL + +#ifndef K_PRIVATE +#define K_PRIVATE private: +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#define alloca __builtin_alloca + +#define KERNEL_VERSION (1) +typedef uint64_t (*KGetKernelVersionCallback)(); +#ifdef KERNEL_MODULE +extern "C" uint64_t GetKernelVersion() { return KERNEL_VERSION; } +#endif + +// --------------------------------------------------------------------------------------------------------------- +// API header. +// --------------------------------------------------------------------------------------------------------------- + +#define ES_DIRECT_API +#define ES_FORWARD(x) x +#define ES_EXTERN_FORWARD ES_EXTERN_C +#include + +// TODO stb's behaviour with null termination is non-standard. +extern "C" int EsCRTsprintf(char *buffer, const char *format, ...); +extern "C" int EsCRTsnprintf(char *buffer, size_t bufferSize, const char *format, ...); +extern "C" int EsCRTvsnprintf(char *buffer, size_t bufferSize, const char *format, va_list arguments); + +// --------------------------------------------------------------------------------------------------------------- +// Global defines. +// --------------------------------------------------------------------------------------------------------------- + +#define K_VERSION (0x010000) +#define K_USER_BUFFER // Used to mark pointers that (might) point to non-kernel memory. +#define K_MAX_PROCESSORS (256) // See cpu_local_storage_size in x86_64.s. +#define K_MAX_PATH (4096) +#define K_ACCESS_IMPLEMENTATION_DEFINED (2) + +// --------------------------------------------------------------------------------------------------------------- +// Heap allocations. +// --------------------------------------------------------------------------------------------------------------- + +struct EsHeap; + +extern EsHeap heapCore; +extern EsHeap heapFixed; + +#define K_CORE (&heapCore) +#define K_FIXED (&heapFixed) +#define K_PAGED (&heapFixed) + +void *EsHeapAllocate(size_t size, bool zeroMemory, EsHeap *kernelHeap); +void EsHeapFree(void *address, size_t expectedSize, EsHeap *kernelHeap); + +// --------------------------------------------------------------------------------------------------------------- +// Debug output. +// --------------------------------------------------------------------------------------------------------------- + +enum KLogLevel { + LOG_VERBOSE, + LOG_INFO, + LOG_ERROR, +}; + +void KernelLog(KLogLevel level, const char *subsystem, const char *event, const char *format, ...); +void KernelPanic(const char *format, ...); +void EsPrint(const char *format, ...); + +#define EsPanic KernelPanic + +// --------------------------------------------------------------------------------------------------------------- +// IRQs. +// --------------------------------------------------------------------------------------------------------------- + +typedef bool (*KIRQHandler)(uintptr_t interruptIndex /* tag for MSI */, void *context); + +// Interrupts are active high and level triggered, unless overridden by the ACPI MADT table. +bool KRegisterIRQ(uintptr_t interruptIndex, KIRQHandler handler, void *context, const char *cOwnerName); + +struct KMSIInformation { + // Both fields are zeroed if the MSI could not be registered. + uintptr_t address; + uintptr_t data; + uintptr_t tag; +}; + +KMSIInformation KRegisterMSI(KIRQHandler handler, void *context, const char *cOwnerName); +void KUnregisterMSI(uintptr_t tag); + +// --------------------------------------------------------------------------------------------------------------- +// Async tasks. +// --------------------------------------------------------------------------------------------------------------- + +// Async tasks are executed on the same processor that registered it. +// They can be registered with interrupts disabled (e.g. in IRQ handlers). +// They are executed in the order they were registered. +// They can acquire mutexes, but cannot perform IO. + +typedef void (*KAsyncTaskCallback)(EsGeneric argument); +void KRegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, bool needed = true); + +// --------------------------------------------------------------------------------------------------------------- +// Common data types, algorithms and things. +// --------------------------------------------------------------------------------------------------------------- + +#ifndef K_IN_CORE_KERNEL +#define SHARED_DEFINITIONS_ONLY +#endif + +#include +#include +#include +#include + +#ifdef K_IN_CORE_KERNEL +#define SHARED_COMMON_WANT_ALL +#include +#endif + +// --------------------------------------------------------------------------------------------------------------- +// Processor instruction wrappers. +// --------------------------------------------------------------------------------------------------------------- + +extern "C" struct CPULocalStorage *GetLocalStorage(); +extern "C" struct Thread *GetCurrentThread(); + +extern "C" void ProcessorDisableInterrupts(); +extern "C" void ProcessorEnableInterrupts(); +extern "C" bool ProcessorAreInterruptsEnabled(); +extern "C" void ProcessorHalt(); +extern "C" void ProcessorIdle(); +extern "C" void ProcessorOut8(uint16_t port, uint8_t value); +extern "C" uint8_t ProcessorIn8(uint16_t port); +extern "C" void ProcessorOut16(uint16_t port, uint16_t value); +extern "C" uint16_t ProcessorIn16(uint16_t port); +extern "C" void ProcessorOut32(uint16_t port, uint32_t value); +extern "C" uint32_t ProcessorIn32(uint16_t port); +extern "C" void ProcessorInvalidatePage(uintptr_t virtualAddress); +extern "C" void ProcessorInvalidateAllPages(); +extern "C" void ProcessorAPStartup(); +extern "C" void ProcessorMagicBreakpoint(...); +extern "C" void ProcessorBreakpointHelper(...); +extern "C" void ProcessorSetLocalStorage(struct CPULocalStorage *cls); +extern "C" void ProcessorSetThreadStorage(uintptr_t tls); +extern "C" size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi = false, int processorID = -1); // Returns the number of processors the IPI was *not* sent to. +extern "C" void ProcessorDebugOutputByte(uint8_t byte); +extern "C" void ProcessorFakeTimerInterrupt(); +extern "C" uint64_t ProcessorReadTimeStamp(); +extern "C" void DoContextSwitch(struct InterruptContext *context, + uintptr_t virtualAddressSpace, uintptr_t threadKernelStack, struct Thread *newThread); +extern "C" void ProcessorSetAddressSpace(uintptr_t virtualAddressSpaceIdentifier); +extern "C" uintptr_t ProcessorGetAddressSpace(); +extern "C" void ProcessorFlushCodeCache(); +extern "C" void ProcessorFlushCache(); + +#ifdef ARCH_X86_64 +extern "C" uintptr_t ProcessorGetRSP(); +extern "C" uintptr_t ProcessorGetRBP(); +extern "C" uint64_t ProcessorReadMXCSR(); +#endif + +// --------------------------------------------------------------------------------------------------------------- +// Kernel core. +// --------------------------------------------------------------------------------------------------------------- + +extern "C" uint64_t KGetTimeInMs(); // Scheduler time. + +bool KCopyToUser(K_USER_BUFFER void *destination, const void *source, size_t bytes); +bool KCopyFromUser(void *destination, K_USER_BUFFER const void *source, size_t bytes); + +void *KGetRSDP(); +size_t KGetCPUCount(); +CPULocalStorage *KGetCPULocal(uintptr_t index); +uint64_t KCPUCurrentID(); +uint64_t KGetTimeStampTicksPerMs(); +uint64_t KGetTimeStampTicksPerUs(); + +bool KBootedFromEFI(); +bool KInIRQ(); +void KSwitchThreadAfterIRQ(); + +void KDebugKeyPressed(); +int KWaitKey(); + +#ifdef ARCH_X86_COMMON +void KPS2SafeToInitialise(); +#endif + +EsUniqueIdentifier KGetBootIdentifier(); + +struct KTimeout { + uint64_t end; + inline KTimeout(int ms) { end = KGetTimeInMs() + ms; } + inline bool Hit() { return KGetTimeInMs() >= end; } +}; + +enum KernelObjectType : uint32_t { + COULD_NOT_RESOLVE_HANDLE = 0x00000000, + KERNEL_OBJECT_NONE = 0x80000000, + + KERNEL_OBJECT_PROCESS = 0x00000001, // A process. + KERNEL_OBJECT_THREAD = 0x00000002, // A thread. + KERNEL_OBJECT_WINDOW = 0x00000004, // A window. + KERNEL_OBJECT_SHMEM = 0x00000008, // A region of shared memory. + KERNEL_OBJECT_NODE = 0x00000010, // A file system node (file or directory). + KERNEL_OBJECT_EVENT = 0x00000020, // A synchronisation event. + KERNEL_OBJECT_CONSTANT_BUFFER = 0x00000040, // A buffer of unmodifiable data stored in the kernel's address space. +#ifdef ENABLE_POSIX_SUBSYSTEM + KERNEL_OBJECT_POSIX_FD = 0x00000100, // A POSIX file descriptor, used in the POSIX subsystem. +#endif + KERNEL_OBJECT_PIPE = 0x00000200, // A pipe through which data can be sent between processes, blocking when full or empty. + KERNEL_OBJECT_EMBEDDED_WINDOW = 0x00000400, // An embedded window object, referencing its container Window. + KERNEL_OBJECT_DIRECTORY_MONITOR = 0x00000100, // Monitors a directory, sending messages to the owner process. + KERNEL_OBJECT_EVENT_SINK = 0x00002000, // An event sink. Events can be forwarded to it, allowing waiting on many objects. + KERNEL_OBJECT_CONNECTION = 0x00004000, // A network connection. +}; + +void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0); +bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0, bool maybeHasNoHandles = false); + +// --------------------------------------------------------------------------------------------------------------- +// Module loading. +// --------------------------------------------------------------------------------------------------------------- + +#define KModuleResolveSymbolCallback (const char *name, size_t nameBytes) +typedef void *(*KModuleResolveSymbolCallbackFunction) KModuleResolveSymbolCallback; + +struct KModule { + const char *path; + size_t pathBytes; + KModuleResolveSymbolCallbackFunction resolveSymbol; + + uint8_t *buffer; +}; + +struct KLoadedExecutable { + uintptr_t startAddress; + + uintptr_t tlsImageStart; + uintptr_t tlsImageBytes; + uintptr_t tlsBytes; // All bytes after the image are to be zeroed. +}; + +EsError KLoadELF(struct KNode *node, KLoadedExecutable *executable); +EsError KLoadELFModule(KModule *module); +uintptr_t KFindSymbol(KModule *module, const char *name, size_t nameBytes); + +// --------------------------------------------------------------------------------------------------------------- +// Synchronisation primitives. +// --------------------------------------------------------------------------------------------------------------- + +struct KSpinlock { // Mutual exclusion. CPU-owned. Disables interrupts. The only synchronisation primitive that can be acquired with interrupts disabled. + K_PRIVATE + volatile uint8_t state, ownerCPU; + volatile bool interruptsEnabled; +#ifdef DEBUG_BUILD + struct Thread *volatile owner; + volatile uintptr_t acquireAddress, releaseAddress; +#endif +}; + +void KSpinlockAcquire(KSpinlock *spinlock); +void KSpinlockRelease(KSpinlock *spinlock, bool force = false); +void KSpinlockAssertLocked(KSpinlock *spinlock); + +struct KMutex { // Mutual exclusion. Thread-owned. + K_PRIVATE + struct Thread *volatile owner; +#ifdef DEBUG_BUILD + uintptr_t acquireAddress, releaseAddress, id; +#endif + LinkedList blockedThreads; +}; + +#ifdef DEBUG_BUILD +bool _KMutexAcquire(KMutex *mutex, const char *cMutexString, const char *cFile, int line); +void _KMutexRelease(KMutex *mutex, const char *cMutexString, const char *cFile, int line); +#define KMutexAcquire(mutex) _KMutexAcquire(mutex, #mutex, __FILE__, __LINE__) +#define KMutexRelease(mutex) _KMutexRelease(mutex, #mutex, __FILE__, __LINE__) +#else +bool KMutexAcquire(KMutex *mutex); +void KMutexRelease(KMutex *mutex); +#endif +void KMutexAssertLocked(KMutex *mutex); + +struct KEvent { // Waiting and notifying. Can wait on multiple at once. Can be set and reset with interrupts disabled. + volatile bool autoReset; // This should be first field in the structure, + // so that the type of KEvent can be easily declared with {autoReset}. + volatile uintptr_t state; + + K_PRIVATE + + LinkedList blockedThreads; + volatile size_t handles; + struct EventSinkTable *sinkTable; +}; + +bool KEventSet(KEvent *event, bool schedulerAlreadyLocked = false, bool maybeAlreadySet = false); +void KEventReset(KEvent *event); +bool KEventPoll(KEvent *event); // TODO Remove this! Currently it is only used by KAudioFillBuffersFromMixer. +bool KEventWait(KEvent *event, uint64_t timeoutMs = ES_WAIT_NO_TIMEOUT); // See KWaitEvents to wait for multiple events. Returns false if the wait timed out. + +struct KWriterLock { // One writer or many readers. + K_PRIVATE + LinkedList blockedThreads; + volatile int64_t state; // -1: exclusive; >0: shared owners. +#ifdef DEBUG_BUILD + volatile Thread *exclusiveOwner; +#endif +}; + +#define K_LOCK_EXCLUSIVE (true) +#define K_LOCK_SHARED (false) +bool KWriterLockTake(KWriterLock *lock, bool write, bool poll = false); +void KWriterLockReturn(KWriterLock *lock, bool write); +void KWriterLockConvertExclusiveToShared(KWriterLock *lock); +void KWriterLockAssertExclusive(KWriterLock *lock); +void KWriterLockAssertShared(KWriterLock *lock); +void KWriterLockAssertLocked(KWriterLock *lock); + +struct KSemaphore { // Exclusion with a multiple units. + KEvent available; + volatile uintptr_t units; + + K_PRIVATE + + KMutex mutex; // TODO Make this a spinlock? + uintptr_t _custom; + uintptr_t lastTaken; +}; + +bool KSemaphoreTake(KSemaphore *semaphore, uintptr_t units = 1, uintptr_t timeoutMs = ES_WAIT_NO_TIMEOUT); +void KSemaphoreReturn(KSemaphore *semaphore, uintptr_t units = 1); +bool KSemaphorePoll(KSemaphore *semaphore); +void KSemaphoreSet(KSemaphore *semaphore, uintptr_t units = 1); + +struct KTimer { + KEvent event; + K_PRIVATE + LinkedItem item; + uint64_t triggerTimeMs; + KAsyncTaskCallback callback; + EsGeneric argument; +}; + +void KTimerSet(KTimer *timer, uint64_t triggerInMs, KAsyncTaskCallback callback = nullptr, EsGeneric argument = 0); +void KTimerRemove(KTimer *timer); // Timers with callbacks cannot be removed (it'd race with async task delivery). + +// --------------------------------------------------------------------------------------------------------------- +// Window manager. +// --------------------------------------------------------------------------------------------------------------- + +void KCursorUpdate(int xMovement, int yMovement, unsigned buttons); +void KKeyboardUpdate(uint16_t *keysDown, size_t keysDownCount); +void KKeyPress(unsigned scancode); + +uint64_t KGameControllerConnect(); +void KGameControllerDisconnect(uint64_t id); +void KGameControllerUpdateState(EsGameControllerState *state); + +#define K_SCANCODE_KEY_RELEASED (1 << 15) +#define K_SCANCODE_KEY_PRESSED (0 << 15) + +#define K_LEFT_BUTTON (1) +#define K_MIDDLE_BUTTON (2) +#define K_RIGHT_BUTTON (4) + +// --------------------------------------------------------------------------------------------------------------- +// Memory manager. +// --------------------------------------------------------------------------------------------------------------- + +#ifdef ARCH_X86_64 +#define K_PAGE_BITS (12) +#define K_PAGE_SIZE ((uintptr_t) 1 << K_PAGE_BITS) +#define K_USER_ADDRESS_SPACE_START (0x0000000000000000ULL) +#define K_USER_ADDRESS_SPACE_END (0x0000800000000000ULL) +#define K_KERNEL_ADDRESS_SPACE_START (0xFFFF800000000000ULL) +#define K_KERNEL_ADDRESS_SPACE_END (0xFFFFFFFFFFFFFFFFULL) +#define K_STACK_GROWS_DOWN +#endif + +struct MMSpace; +MMSpace *MMGetKernelSpace(); +MMSpace *MMGetCurrentProcessSpace(); + +#define MM_REGION_FIXED (0x01) // A region where all the physical pages are allocated up-front, and cannot be removed from the working set. +#define MM_REGION_NOT_CACHEABLE (0x02) // Do not cache the pages in the region. +#define MM_REGION_NO_COMMIT_TRACKING (0x04) // Page committing is manually tracked. +#define MM_REGION_READ_ONLY (0x08) // Generate page faults when written to. +#define MM_REGION_COPY_ON_WRITE (0x10) // Copy on write. +#define MM_REGION_WRITE_COMBINING (0x20) // Write combining caching is enabled. Incompatible with MM_REGION_NOT_CACHEABLE. +#define MM_REGION_EXECUTABLE (0x40) +#define MM_REGION_USER (0x80) // The application created it, and is therefore allowed to modify it. +// Limited by region type flags. + +void *MMMapPhysical(MMSpace *space, uintptr_t address, size_t bytes, uint64_t caching); +void *MMStandardAllocate(MMSpace *space, size_t bytes, uint32_t flags, void *baseAddress = nullptr, bool commitAll = true); +bool MMFree(MMSpace *space, void *address, size_t expectedSize = 0, bool userOnly = false); +void MMAllowWriteCombiningCaching(MMSpace *space, void *virtualAddress); +size_t MMGetRegionPageCount(MMSpace *space, void *virtualAddress); + +uint64_t MMNumberOfUsablePhysicalPages(); + +// Returns 0 if not mapped. Rounds address down to nearest page. +uintptr_t MMArchTranslateAddress(MMSpace *space, uintptr_t virtualAddress, bool writeAccess = false /* if true, return 0 if address not writable */); + +// Must be done with interrupts disabled; does not invalidate the page on other processors. +void MMArchRemap(MMSpace *space, const void *virtualAddress, uintptr_t newPhysicalAddress); + +#define MM_PHYSICAL_ALLOCATE_CAN_FAIL (1 << 0) // Don't panic if the allocation fails. +#define MM_PHYSICAL_ALLOCATE_COMMIT_NOW (1 << 1) // Commit (fixed) the allocated pages. +#define MM_PHYSICAL_ALLOCATE_ZEROED (1 << 2) // Zero the pages. +#define MM_PHYSICAL_ALLOCATE_LOCK_ACQUIRED (1 << 3) // The page frame mutex is already acquired. + +uintptr_t /* Returns physical address of first page, or 0 if none were available. */ MMPhysicalAllocate(unsigned flags, + uintptr_t count = 1 /* Number of contiguous pages to allocate. */, + uintptr_t align = 1 /* Alignment, in pages. */, + uintptr_t below = 0 /* Upper limit of physical address, in pages. E.g. for 32-bit pages only, pass (0x100000000 >> K_PAGE_BITS). */); +void MMPhysicalFree(uintptr_t page /* Physical address. */, + bool mutexAlreadyAcquired = false /* Internal use. Pass false. */, + size_t count = 1 /* Number of consecutive pages to free. */); + +bool MMPhysicalAllocateAndMap(size_t sizeBytes, size_t alignmentBytes, size_t maximumBits, bool zeroed, + uint64_t caching, uint8_t **virtualAddress, uintptr_t *physicalAddress); +void MMPhysicalFreeAndUnmap(void *virtualAddress, uintptr_t physicalAddress); + +#define MM_SHARED_ENTRY_PRESENT (1) +struct MMSharedRegion; +MMSharedRegion *MMSharedCreateRegion(size_t sizeBytes, bool fixed = false, uintptr_t below = 0 /* See fixed = true, passed to MMPhysicalAllocate. */); +uintptr_t MMSharedLookupPage(MMSharedRegion *region, uintptr_t pageIndex); +void *MMMapShared(MMSpace *space, MMSharedRegion *sharedRegion, uintptr_t offset, size_t bytes, uint32_t additionalFlags = ES_FLAGS_DEFAULT, void *baseAddresses = nullptr); + +// Check that the range of physical memory is unusable. +// Panics on failure. +void MMCheckUnusable(uintptr_t physicalStart, size_t bytes); + +#include + +typedef SimpleList MMObjectCacheItem; + +struct MMObjectCache { + K_PRIVATE + KSpinlock lock; // Used instead of a mutex to keep accesses to the list lightweight. + SimpleList items; + size_t count; + bool (*trim)(MMObjectCache *cache); // Return true if an object was trimmed. + KWriterLock trimLock; // Open in shared access to trim the cache. + LinkedItem item; + size_t averageObjectBytes; +}; + +void MMObjectCacheInsert(MMObjectCache *cache, MMObjectCacheItem *item); +void MMObjectCacheRemove(MMObjectCache *cache, MMObjectCacheItem *item, bool alreadyLocked = false); +MMObjectCacheItem *MMObjectCacheRemoveLRU(MMObjectCache *cache); +void MMObjectCacheRegister(MMObjectCache *cache, bool (*trimCallback)(MMObjectCache *), size_t averageObjectBytes); +void MMObjectCacheUnregister(MMObjectCache *cache); +void MMObjectCacheFlush(MMObjectCache *cache); + +// --------------------------------------------------------------------------------------------------------------- +// Scheduler. +// --------------------------------------------------------------------------------------------------------------- + +uint64_t KProcessCurrentID(); +uint64_t KThreadCurrentID(); + +bool KThreadCreate(const char *cName, void (*startAddress)(uintptr_t), uintptr_t argument = 0); +extern "C" void KThreadTerminate(); // Terminates the current thread. Kernel threads can only be terminated by themselves. +void KYield(); + +uintptr_t KWaitEvents(KEvent **events, size_t count); + +struct KWorkGroup { + inline void Initialise() { + remaining = 1; + success = 1; + KEventReset(&event); + } + + inline bool Wait() { + if (__sync_fetch_and_sub(&remaining, 1) != 1) { + KEventWait(&event); + } + + if (remaining) { + KernelPanic("KWorkGroup::Wait - Expected remaining operations to be 0 after event set.\n"); + } + + return success ? true : false; + } + + inline void Start() { + if (__sync_fetch_and_add(&remaining, 1) == 0) { + KernelPanic("KWorkGroup::Start - Could not start operation on completed dispatch group.\n"); + } + } + + inline void End(bool _success) { + if (!_success) { + success = false; + __sync_synchronize(); + } + + if (__sync_fetch_and_sub(&remaining, 1) == 1) { + KEventSet(&event); + } + } + + K_PRIVATE + + volatile uintptr_t remaining; + volatile uintptr_t success; + KEvent event; +}; + +// --------------------------------------------------------------------------------------------------------------- +// Device management. +// --------------------------------------------------------------------------------------------------------------- + +struct KInstalledDriver { + char *name; // The name of the driver. + size_t nameBytes; + char *parent; // The name of the parent driver. + size_t parentBytes; + char *config; // The driver's configuration, taken from kernel/config.ini. + size_t configBytes; + bool builtin; // True if the driver is builtin to the kernel executable. + struct KDriver *loadedDriver; // The corresponding driver, if it has been loaded. +}; + +struct KDevice { + const char *cDebugName; + + KDevice *parent; // The parent device. + Array children; // Child devices. + +#define K_DEVICE_REMOVED (1 << 0) + uint8_t flags; + + uint32_t handles; + + // These callbacks are called with the deviceTreeMutex locked. + void (*shutdown)(KDevice *device); // Called when the computer is about to shutdown. Optional. + void (*dumpState)(KDevice *device); // Dump the entire state of the device for debugging. Optional. + void (*removed)(KDevice *device); // Called when the device is removed. Called after the children are informed. Optional. + void (*destroy)(KDevice *device); // Called just before the device is destroyed. +}; + +struct KDriver { + // Called when a new device the driver implements is attached. + // You should pass this the parent device to `KDeviceCreate`. + // The parent device pointer cannot be used after the function returns. + void (*attach)(KDevice *parent); +}; + +typedef bool KDriverIsImplementorCallback(KInstalledDriver *driver, KDevice *device); // Return true if the child driver implements the device. + +// Searches for a driver that implements the device. Loads the driver if necessary (possibly asynchronously), and calls `attach`. +// Returns true if a matching driver was found; a maximum of one driver will be called. +// Example usage: +// - A bus driver finds a function with a connected device. +// - It creates a device for that function with KDeviceCreate, and sets the parent to the bus controller device. +// - It calls KDeviceAttach on the function device. +// - A suitable driver is found, which creates a device with that as its parent. +bool KDeviceAttach(KDevice *parentDevice, const char *cParentDriver /* match the parent field in the config */, KDriverIsImplementorCallback callback); + +// Similar to KDeviceAttach, except it calls `attach` for every driver that matches the parent field. +void KDeviceAttachAll(KDevice *parentDevice, const char *cParentDriver); + +// Similar to KDeviceAttach, except it calls `attach` only for the driver matching the provided name. Returns true if the driver was found. +bool KDeviceAttachByName(KDevice *parentDevice, const char *cName); + +KDevice *KDeviceCreate(const char *cDebugName, KDevice *parent, size_t bytes /* must be at least the size of a KDevice */); +void KDeviceOpenHandle(KDevice *device); +void KDeviceDestroy(KDevice *device); // Call if initialisation of the device failed. Otherwise use KDeviceCloseHandle. +void KDeviceCloseHandle(KDevice *device); // The device creator is responsible for one handle after the creating it. The device is destroyed once all handles are closed. +void KDeviceRemoved(KDevice *device); // Call when a child device is removed. Must be called only once! + +#include + +// --------------------------------------------------------------------------------------------------------------- +// Direct memory access. +// --------------------------------------------------------------------------------------------------------------- + +struct KDMASegment { + uintptr_t physicalAddress; + size_t byteCount; + bool isLast; +}; + +struct KDMABuffer; +uintptr_t KDMABufferGetVirtualAddress(KDMABuffer *buffer); // TODO Temporary. +size_t KDMABufferGetTotalByteCount(KDMABuffer *buffer); +KDMASegment KDMABufferNextSegment(KDMABuffer *buffer, bool peek = false); +bool KDMABufferIsComplete(KDMABuffer *buffer); // Returns true if the end of the transfer buffer has been reached. + +// --------------------------------------------------------------------------------------------------------------- +// Block devices. +// --------------------------------------------------------------------------------------------------------------- + +#define K_ACCESS_READ (0) +#define K_ACCESS_WRITE (1) + +struct KBlockDeviceAccessRequest { + struct KBlockDevice *device; + EsFileOffset offset; + size_t count; + int operation; + KDMABuffer *buffer; + uint64_t flags; + KWorkGroup *dispatchGroup; +}; + +typedef void (*KDeviceAccessCallbackFunction)(KBlockDeviceAccessRequest request); + +struct KBlockDevice : KDevice { + KDeviceAccessCallbackFunction access; // Don't call directly; see KFileSystem::Access. + size_t sectorSize, maxAccessSectorCount; + EsFileOffset sectorCount; + bool noMBR; // Set to `true` if this device cannot contain a MBR. + bool readOnly; + uint8_t nestLevel; + uint8_t driveType; + const char *cModel; + + K_PRIVATE + + uint8_t *information; // Signature block. Only valid during fileSystem detection. +}; + +#define FS_PARTITION_DEVICE_NO_MBR (1 << 0) +void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, unsigned flags, const char *cName); + +// --------------------------------------------------------------------------------------------------------------- +// PCI. +// --------------------------------------------------------------------------------------------------------------- + +struct KPCIDevice : KDevice { + void WriteBAR8(uintptr_t index, uintptr_t offset, uint8_t value); + uint8_t ReadBAR8(uintptr_t index, uintptr_t offset); + void WriteBAR16(uintptr_t index, uintptr_t offset, uint16_t value); + uint16_t ReadBAR16(uintptr_t index, uintptr_t offset); + void WriteBAR32(uintptr_t index, uintptr_t offset, uint32_t value); + uint32_t ReadBAR32(uintptr_t index, uintptr_t offset); + void WriteBAR64(uintptr_t index, uintptr_t offset, uint64_t value); + uint64_t ReadBAR64(uintptr_t index, uintptr_t offset); + + void WriteConfig8(uintptr_t offset, uint8_t value); + uint8_t ReadConfig8(uintptr_t offset); + void WriteConfig16(uintptr_t offset, uint16_t value); + uint16_t ReadConfig16(uintptr_t offset); + void WriteConfig32(uintptr_t offset, uint32_t value); + uint32_t ReadConfig32(uintptr_t offset); + +#define K_PCI_FEATURE_BAR_0 (1 << 0) +#define K_PCI_FEATURE_BAR_1 (1 << 1) +#define K_PCI_FEATURE_BAR_2 (1 << 2) +#define K_PCI_FEATURE_BAR_3 (1 << 3) +#define K_PCI_FEATURE_BAR_4 (1 << 4) +#define K_PCI_FEATURE_BAR_5 (1 << 5) +#define K_PCI_FEATURE_INTERRUPTS (1 << 8) +#define K_PCI_FEATURE_BUSMASTERING_DMA (1 << 9) +#define K_PCI_FEATURE_MEMORY_SPACE_ACCESS (1 << 10) +#define K_PCI_FEATURE_IO_PORT_ACCESS (1 << 11) + bool EnableFeatures(uint64_t features); + bool EnableSingleInterrupt(KIRQHandler irqHandler, void *context, const char *cOwnerName); + + uint32_t deviceID, subsystemID, domain; + uint8_t classCode, subclassCode, progIF; + uint8_t bus, slot, function; + uint8_t interruptPin, interruptLine; + + uint8_t *baseAddressesVirtual[6]; + uintptr_t baseAddressesPhysical[6]; + size_t baseAddressesSizes[6]; + + uint32_t baseAddresses[6]; + + K_PRIVATE + bool EnableMSI(KIRQHandler irqHandler, void *context, const char *cOwnerName); +}; + +uint32_t KPCIReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size = 32); +void KPCIWriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size = 32); + +// --------------------------------------------------------------------------------------------------------------- +// USB. +// --------------------------------------------------------------------------------------------------------------- + +struct KUSBDescriptorHeader { + uint8_t length; + uint8_t descriptorType; +} __attribute__((packed)); + +struct KUSBConfigurationDescriptor : KUSBDescriptorHeader { + uint16_t totalLength; + uint8_t interfaceCount; + uint8_t configurationIndex; + uint8_t configurationString; + uint8_t attributes; + uint8_t maximumPower; +} __attribute__((packed)); + +struct KUSBInterfaceDescriptor : KUSBDescriptorHeader { + uint8_t interfaceIndex; + uint8_t alternateSetting; + uint8_t endpointCount; + uint8_t interfaceClass; + uint8_t interfaceSubclass; + uint8_t interfaceProtocol; + uint8_t interfaceString; +} __attribute__((packed)); + +struct KUSBDeviceDescriptor : KUSBDescriptorHeader { + uint16_t specificationVersion; + uint8_t deviceClass; + uint8_t deviceSubclass; + uint8_t deviceProtocol; + uint8_t maximumPacketSize; + uint16_t vendorID; + uint16_t productID; + uint16_t deviceVersion; + uint8_t manufacturerString; + uint8_t productString; + uint8_t serialNumberString; + uint8_t configurationCount; +} __attribute__((packed)); + +struct KUSBEndpointCompanionDescriptor : KUSBDescriptorHeader { + uint8_t maxBurst; + uint8_t attributes; + uint16_t bytesPerInterval; + + inline uint8_t GetMaximumStreams() { return attributes & 0x1F; } + inline bool HasISOCompanion() { return attributes & (1 << 7); } +} __attribute__((packed)); + +struct KUSBEndpointIsochronousCompanionDescriptor : KUSBDescriptorHeader { + uint16_t reserved; + uint32_t bytesPerInterval; +} __attribute__((packed)); + +struct KUSBEndpointDescriptor : KUSBDescriptorHeader { + uint8_t address; + uint8_t attributes; + uint16_t maximumPacketSize; + uint8_t pollInterval; + + inline bool IsControl() { return (attributes & 3) == 0; } + inline bool IsIsochronous() { return (attributes & 3) == 1; } + inline bool IsBulk() { return (attributes & 3) == 2; } + inline bool IsInterrupt() { return (attributes & 3) == 3; } + inline bool IsInput() { return (address & 0x80); } + inline bool IsOutput() { return !(address & 0x80); } + inline uint8_t GetAddress() { return address & 0x0F; } + inline uint16_t GetMaximumPacketSize() { return maximumPacketSize & 0x7FF; } +} __attribute__((packed)); + +typedef void (*KUSBTransferCallback)(ptrdiff_t bytesNotTransferred /* -1 if error */, EsGeneric context); + +struct KUSBDevice : KDevice { + bool GetString(uint8_t index, char *buffer, size_t bufferBytes); + KUSBDescriptorHeader *GetCommonDescriptor(uint8_t type, uintptr_t index); + bool RunTransfer(KUSBEndpointDescriptor *endpoint, void *buffer, size_t bufferBytes, size_t *bytesNotTransferred /* if null, fails if positive */); + + // Callbacks provided by the host controller: + // NOTE These do not provide mutual exclusion; you must ensure this manually. + bool (*controlTransfer)(KUSBDevice *device, uint8_t flags, uint8_t request, uint16_t value, uint16_t index, + void *buffer, uint16_t length, int operation /* K_ACCESS_READ/WRITE */, uint16_t *transferred); + bool (*queueTransfer)(KUSBDevice *device, KUSBEndpointDescriptor *endpoint, KUSBTransferCallback callback, + void *buffer, size_t bufferBytes, EsGeneric context); + bool (*selectConfigurationAndInterface)(KUSBDevice *device); + + uint8_t *configurationDescriptors; + size_t configurationDescriptorsBytes; + uintptr_t selectedConfigurationOffset; + + KUSBDeviceDescriptor deviceDescriptor; + KUSBConfigurationDescriptor configurationDescriptor; + KUSBInterfaceDescriptor interfaceDescriptor; +}; + +void KRegisterUSBDevice(KUSBDevice *device); // Takes ownership of the device's main handle. + +// --------------------------------------------------------------------------------------------------------------- +// File systems. +// --------------------------------------------------------------------------------------------------------------- + +struct KNodeMetadata { + // Metadata stored in the node's directory entry. + EsNodeType type; + bool removingNodeFromCache, removingThisFromCache; + EsFileOffset totalSize; + EsFileOffsetDifference directoryChildren; // ES_DIRECTORY_CHILDREN_UNKNOWN if not supported by the file system. +}; + +struct KNode { + void *driverNode; + + K_PRIVATE + + volatile size_t handles; + struct FSDirectoryEntry *directoryEntry; + struct KFileSystem *fileSystem; + uint64_t id; + KWriterLock writerLock; // Acquire before the parent's. + EsError error; + volatile uint32_t flags; + MMObjectCacheItem cacheItem; +}; + +struct KFileSystem : KDevice { + KBlockDevice *block; // Gives the sector size and count. + + KNode *rootDirectory; + + // Only use this for file system metadata that isn't cached in a Node. + // This must be used consistently, i.e. if you ever read a region cached, then you must always write that region cached, and vice versa. +#define BLOCK_ACCESS_CACHED (1) + // Access the block device. Returns true on success. + // Offset and count must be sector aligned. Buffer must be DWORD aligned. + // TODO Make this return EsError. + bool Access(EsFileOffset offset, size_t count, int operation, void *buffer, uint32_t flags, KWorkGroup *dispatchGroup = nullptr); + + // Fill these fields in before registering the file system: + + void *driverData; + + char name[64]; + size_t nameBytes; + + size_t directoryEntryDataBytes; // The size of the driverData passed to FSDirectoryEntryFound and received in the load callback. + size_t nodeDataBytes; // The average bytes allocated by the driver per node (used for managing cache sizes). + + EsFileOffsetDifference rootDirectoryInitialChildren; + EsFileOffset spaceTotal, spaceUsed; + + size_t (*read) (KNode *node, void *buffer, EsFileOffset offset, EsFileOffset count); + size_t (*write) (KNode *node, const void *buffer, EsFileOffset offset, EsFileOffset count); + void (*sync) (KNode *directory, KNode *node); // TODO Error reporting? + EsError (*scan) (const char *name, size_t nameLength, KNode *directory); // Add the entry with FSDirectoryEntryFound. + EsError (*load) (KNode *directory, KNode *node, KNodeMetadata *metadata /* for if you need to update it */, + const void *entryData /* driverData passed to FSDirectoryEntryFound */); + EsFileOffset (*resize) (KNode *file, EsFileOffset newSize, EsError *error); + EsError (*create) (const char *name, size_t nameLength, EsNodeType type, KNode *parent, KNode *node, void *driverData); + EsError (*enumerate) (KNode *directory); // Add the entries with FSDirectoryEntryFound. + EsError (*remove) (KNode *directory, KNode *file); + EsError (*move) (KNode *oldDirectory, KNode *file, KNode *newDirectory, const char *newName, size_t newNameLength); + void (*close) (KNode *node); + void (*unmount) (KFileSystem *fileSystem); + + // TODO Normalizing file names, for case-insensitive filesystems. + // void * (*normalize) (const char *name, size_t nameLength, size_t *resultLength); + + // Internals. + + KMutex moveMutex; + bool isBootFileSystem, unmounting; + volatile uint64_t totalHandleCount; + uint64_t id; + + MMObjectCache cachedDirectoryEntries, // Directory entries without a loaded node. + cachedNodes; // Nodes with no handles or directory entries. +}; + +EsError FSDirectoryEntryFound(KNode *parentDirectory, KNodeMetadata *metadata /* ignored if the entry is already cached */, + const void *driverData /* if update is false and the entry is already cached, this must match the previous driverData */, + const void *name, size_t nameBytes, + bool update /* set to true if you don't want to insert an new entry if it isn't already cached; returns ES_SUCCESS or ES_ERROR_FILE_DOES_NOT_EXIST only */, + KNode **node = nullptr /* set if scanning to immediately load; call FSNodeScanAndLoadComplete afterwards */); + +// Call if you are scanning and used immediate load with FSDirectoryEntryFound. +void FSNodeScanAndLoadComplete(KNode *node, bool success); + +// Equivalent to FSDirectoryEntryFound with update set to true, +// but lets you pass an arbitrary KNode instead of a [directory, file name] pair. +void FSNodeUpdateDriverData(KNode *node, const void *newDriverData); + +// All these functions take ownership of the device's main handle. +void FSRegisterBlockDevice(KBlockDevice *blockDevice); +void FSRegisterFileSystem(KFileSystem *fileSystem); +void FSRegisterBootFileSystem(KFileSystem *fileSystem, EsUniqueIdentifier identifier); + +#define K_SIGNATURE_BLOCK_SIZE (65536) + +struct KNodeInformation { + EsError error; + KNode *node; +}; + +KNodeInformation FSNodeOpen(const char *path, size_t pathBytes, uint32_t flags, KNode *baseDirectory = nullptr); + +EsFileOffset FSNodeGetTotalSize(KNode *node); + +char *FSNodeGetName(KNode *node, size_t *bytes); // For debugging use only. + +// Do not pass memory-mapped buffers. +#define FS_FILE_ACCESS_USER_BUFFER_MAPPED (1 << 0) +ptrdiff_t FSFileReadSync(KNode *node, K_USER_BUFFER void *buffer, EsFileOffset offset, EsFileOffset bytes, uint32_t flags); +ptrdiff_t FSFileWriteSync(KNode *node, const K_USER_BUFFER void *buffer, EsFileOffset offset, EsFileOffset bytes, uint32_t flags); + +// --------------------------------------------------------------------------------------------------------------- +// Graphics. +// --------------------------------------------------------------------------------------------------------------- + +struct KGraphicsTarget : KDevice { + size_t screenWidth, screenHeight; + bool reducedColors; // Set to true if using less than 15 bit color. + + void (*updateScreen)(K_USER_BUFFER const uint8_t *source, uint32_t sourceWidth, uint32_t sourceHeight, uint32_t sourceStride, + uint32_t destinationX, uint32_t destinationY); + void (*debugPutBlock)(uintptr_t x, uintptr_t y, bool toggle); + void (*debugClearScreen)(); +}; + +// TODO Locking for these functions? +void KRegisterGraphicsTarget(KGraphicsTarget *target); +bool KGraphicsIsTargetRegistered(); + +// Shared implementation of updating the screen for targets that use 32-bit linear buffers. +void GraphicsUpdateScreen32(K_USER_BUFFER const uint8_t *source, uint32_t sourceWidth, uint32_t sourceHeight, uint32_t sourceStride, + uint32_t destinationX, uint32_t destinationY, + uint32_t width, uint32_t height, uint32_t stride, volatile uint8_t *pixel); +void GraphicsUpdateScreen24(K_USER_BUFFER const uint8_t *_source, uint32_t sourceWidth, uint32_t sourceHeight, uint32_t sourceStride, + uint32_t destinationX, uint32_t destinationY, + uint32_t width, uint32_t height, uint32_t stride, volatile uint8_t *pixel); +void GraphicsDebugPutBlock32(uintptr_t x, uintptr_t y, bool toggle, + unsigned screenWidth, unsigned screenHeight, unsigned stride, volatile uint8_t *linearBuffer); +void GraphicsDebugClearScreen32(unsigned screenWidth, unsigned screenHeight, unsigned stride, volatile uint8_t *linearBuffer); + +// --------------------------------------------------------------------------------------------------------------- +// Networking. +// --------------------------------------------------------------------------------------------------------------- + +struct KIPAddress { + uint8_t d[4]; +}; + +struct KMACAddress { + uint8_t d[6]; +}; + +struct NetTask { + void (*callback)(NetTask *task, void *receivedData); + struct NetInterface *interface; + uint16_t index; + int16_t error; + uint8_t step; + bool completed; +}; + +struct NetAddressSetupTask : NetTask { + uint32_t dhcpTransactionID; + bool changedState; +}; + +struct NetInterface : KDevice { + KIPAddress ipAddress; + + // Set by driver before registering: + + bool (*transmit)(NetInterface *self, void *dataVirtual, uintptr_t dataPhysical, size_t dataBytes); + + union { + KMACAddress macAddress; + uint64_t macAddress64; + }; + + // Internals: + + K_PRIVATE + + SimpleList item; + NetAddressSetupTask addressSetupTask; + + Array arpTable; + Array arpRequests; + KWriterLock arpTableLock; + + // Changing the connection status and cancelling packets requires exclusive access. + // NetTaskBegin and NetInterfaceReceive (and hence all NetTask callbacks) run with shared access. + KWriterLock connectionLock; + + bool connected, hasIP; + uint16_t ipIdentification; + KIPAddress serverIdentifier; + KIPAddress dnsServerIP; + KIPAddress routerIP; +}; + +enum NetPacketType { + NET_PACKET_ETHERNET, +}; + +void NetTransmitBufferReturn(void *data); // Once a driver is finished with a transmit buffer, it should return it here. If the driver returns false from the transmit callback, then the driver must *not* return the buffer. + +void NetTaskBegin(NetTask *task); +void NetTaskComplete(NetTask *task, EsError error); + +void KRegisterNetInterface(NetInterface *interface); +void NetInterfaceReceive(NetInterface *interface, const uint8_t *data, size_t dataBytes, NetPacketType packetType); // NOTE Currently this can be only called on one thread for each NetInterface. (This restriction will hopefully be removed soon.) +void NetInterfaceSetConnected(NetInterface *interface, bool connected); // NOTE This shouldn't be called by more than one thread. +void NetInterfaceShutdown(NetInterface *interface); // NOTE This doesn't do any disconnecting/cancelling of tasks. Currently it only sends a DHCP request to release the IP address, and is expected to be called at the final stages of system shutdown. diff --git a/kernel/networking.cpp b/kernel/networking.cpp new file mode 100644 index 0000000..91feac7 --- /dev/null +++ b/kernel/networking.cpp @@ -0,0 +1,2167 @@ +// TODO Event-based API for userland. + +// TODO Locking: In NetTCPReceive, lock on getting task so it can't be destroyed by NetConnectionDestroy. + +// TODO Limiting the size of the ARP table; LRU. +// TODO Sending ARP requests not working in VBox. + +// TODO Domain name resolve button doesn't work in the test program. +// TODO Resolved domain name cache. + +// TODO UDP and TCP: checking packets are received from the correct NetInterface, MAC and IP. +// TODO UDP and TCP: checking source port matches expected value on received packets. +// TODO UDP and TCP (and possibly others): lock in the NetTask callback when processing a received packet, +// to allow for a NetInterface to have multiple dispatcher threads. +// TODO TCP: merging ACK responses. +// TODO TCP: high performance extensions. +// TODO TCP: reducing duplication of non-reply code. + +// TODO Cancelling tasks after losing connection; retrying tasks; timeout tasks. +// TODO Retrying the NetAddressSetupTask if it completes with error. + +// TODO Handling more ICMP messages. +// TODO Sending ICMP messages on certain bad packets. +// TODO IPv6. + +// TODO Check receive buffer is treated as empty when read pointer == write pointer. + +// TODO Make most log messages LOG_VERBOSE. + +#ifndef IMPLEMENTATION + +struct EthernetHeader { + KMACAddress destinationMAC; + KMACAddress sourceMAC; + uint16_t type; +} __attribute__((packed)); + +#define ETHERNET_HEADER(ethernet, _type, _destinationMAC) \ + if (ethernet) { \ + ethernet->destinationMAC = _destinationMAC; \ + ethernet->sourceMAC = interface->macAddress; \ + ethernet->type = SwapBigEndian16(_type); \ + } + +#define ETHERNET_TYPE_IPV4 (0x0800) +#define ETHERNET_TYPE_ARP (0x0806) + +struct IPHeader { + uint8_t versionAndLength; + uint8_t serviceType; + uint16_t totalLength; + uint16_t identification; + uint16_t flagsAndFragmentOffset; + uint8_t timeToLive; + uint8_t protocol; + uint16_t headerChecksum; + KIPAddress sourceAddress; + KIPAddress destinationAddress; + + uint16_t CalculateHeaderChecksum() const { + const uint8_t *in = (const uint8_t *) this; + uint32_t sum = 0; + + for (uintptr_t i = 0; i < 20; i += 2) { + if (i == 10) continue; + sum += ((uint16_t) in[i] << 8) + (uint16_t) in[i + 1]; + } + + while (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + + return SwapBigEndian16(~sum); + } +} __attribute__((packed)); + +#define IP_HEADER(ip, _destinationAddress, _protocol) \ + if (ip) { \ + ip->versionAndLength = (4 << 4) | (5 << 0); /* We're using IPv4 with a 5 DWORD header. */ \ + ip->identification = ByteSwap16(++interface->ipIdentification); \ + ip->timeToLive = 64; /* Live for at most 64 seconds. */ \ + ip->protocol = _protocol; \ + ip->sourceAddress = interface->ipAddress; \ + ip->destinationAddress = _destinationAddress; \ + } + +#define IP_PROTOCOL_ICMP (1) +#define IP_PROTOCOL_TCP (6) +#define IP_PROTOCOL_UDP (17) + +struct UDPHeader { + uint16_t sourcePort; + uint16_t destinationPort; + uint16_t length; + uint16_t checksum; + + uint16_t CalculateChecksum() const { + const IPHeader *ipHeader = (const IPHeader *) this - 1; + + struct { + KIPAddress sourceAddress; + KIPAddress destinationAddress; + uint8_t zero; + uint8_t protocol; + uint16_t udpLength; + } pseudoHeader = { + .sourceAddress = ipHeader->sourceAddress, + .destinationAddress = ipHeader->destinationAddress, + .zero = 0, + .protocol = ipHeader->protocol, + .udpLength = length, + }; + + const uint8_t *in = (const uint8_t *) this; + const uint8_t *in2 = (const uint8_t *) &pseudoHeader; + const uint8_t *data = (const uint8_t *) (this + 1); + + uint32_t sum = 0; + + for (uintptr_t i = 0; i < 8; i += 2) { + if (i == 6) continue; + sum += ((uint16_t) in[i] << 8) + (uint16_t) in[i + 1]; + } + + for (uintptr_t i = 0; i < 12; i += 2) { + sum += ((uint16_t) in2[i] << 8) + (uint16_t) in2[i + 1]; + } + + uintptr_t dataBytes = ByteSwap16(length) - 8; + + for (uintptr_t i = 0; i < dataBytes; i += 2) { + if (i + 1 == dataBytes) { + sum += (uint16_t) data[i] << 8; + } else { + sum += ((uint16_t) data[i] << 8) + (uint16_t) data[i + 1]; + } + } + + while (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + + return (sum == 0xFFFF) ? 0xFFFF : SwapBigEndian16(~sum); + } +} __attribute__((packed)); + +#define UDP_HEADER(udp, _sourcePort, _destinationPort) \ + if (udp) { \ + udp->sourcePort = SwapBigEndian16(_sourcePort); \ + udp->destinationPort = SwapBigEndian16(_destinationPort); \ + } + +#define UDP_PORT_BASE (49152) + +struct TCPHeader { + uint16_t sourcePort; + uint16_t destinationPort; + uint32_t sequenceNumber; + uint32_t ackNumber; + uint16_t flags; + uint16_t window; + uint16_t checksum; + uint16_t urgentPointer; + + uint16_t CalculateChecksum(uint16_t length) const { + const IPHeader *ipHeader = (const IPHeader *) this - 1; + + struct { + KIPAddress sourceAddress; + KIPAddress destinationAddress; + uint8_t zero; + uint8_t protocol; + uint16_t tcpLength; + } pseudoHeader = { + .sourceAddress = ipHeader->sourceAddress, + .destinationAddress = ipHeader->destinationAddress, + .zero = 0, + .protocol = ipHeader->protocol, + .tcpLength = ByteSwap16(length), + }; + + const uint8_t *in = (const uint8_t *) this; + const uint8_t *in2 = (const uint8_t *) &pseudoHeader; + + uint32_t sum = 0; + + for (uintptr_t i = 0; i < length; i += 2) { + if (i == 16) { + // Checksum field; skip. + } else if (i + 1 == length) { + sum += (uint16_t) in[i] << 8; + } else { + sum += ((uint16_t) in[i] << 8) + (uint16_t) in[i + 1]; + } + } + + for (uintptr_t i = 0; i < 12; i += 2) { + sum += ((uint16_t) in2[i] << 8) + (uint16_t) in2[i + 1]; + } + + while (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + + return SwapBigEndian16(~sum); + } +} __attribute__((packed)); + +struct TCPReceivedData { + uint16_t flags; + uint16_t segmentLength; + uint32_t ackNumber; + uint32_t sequenceNumber; + + const EthernetHeader *ethernet; + const IPHeader *ip; + const TCPHeader *tcp; + const void *segment; +}; + +// NOTE Keep these in order! +// We've sent a packet asking to start a connection. We're expecting the server to ACK it with a matching request. +#define TCP_STEP_SYN_SENT (1) +// We've received a packet asking to start a connection. We've sent a matching request back. We're waiting for that to be ACK'd. +#define TCP_STEP_SYN_RECEIVED (2) +// We're in normal data communication. +#define TCP_STEP_ESTABLISHED (3) +// Closing steps: +#define TCP_STEP_FIN_WAIT_1 (4) +#define TCP_STEP_FIN_WAIT_2 (5) +#define TCP_STEP_CLOSE_WAIT (6) +#define TCP_STEP_CLOSING (7) +#define TCP_STEP_LAST_ACK (8) + +#define TCP_FIN (1 << 0) +#define TCP_SYN (1 << 1) +#define TCP_RST (1 << 2) +#define TCP_PSH (1 << 3) +#define TCP_ACK (1 << 4) + +#define TCP_PORT_BASE (49152) + +#define TCP_PREPARE_REPLY(_data1, _data1Bytes, _data2, _data2Bytes) \ + EthernetHeader *ethernetReply = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); \ + ETHERNET_HEADER(ethernetReply, ETHERNET_TYPE_IPV4, data->ethernet->sourceMAC); \ + IPHeader *ipReply = (IPHeader *) buffer.Write(nullptr, sizeof(IPHeader)); \ + IP_HEADER(ipReply, data->ip->sourceAddress, IP_PROTOCOL_TCP); \ + TCPHeader *tcpReply = (TCPHeader *) buffer.Write(nullptr, sizeof(TCPHeader)); \ + buffer.Write(_data1, _data1Bytes); \ + buffer.Write(_data2, _data2Bytes); \ + \ + if (buffer.error) { \ + KernelPanic("TCP_PREPARE_REPLY - Network interface buffer size too small.\n"); \ + } \ + \ + ipReply->totalLength = ByteSwap16(buffer.position - sizeof(*ethernetReply)); \ + ipReply->flagsAndFragmentOffset = SwapBigEndian16(1 << 14 /* do not fragment */); \ + ipReply->headerChecksum = ipReply->CalculateHeaderChecksum(); \ + \ + tcpReply->sourcePort = data->tcp->destinationPort; \ + tcpReply->destinationPort = data->tcp->sourcePort; + +#define TCP_PREPARE_REPLY_2(_data1, _data1Bytes, _data2, _data2Bytes, _flags, _headerDWORDs) \ + TCP_PREPARE_REPLY(_data1, _data1Bytes, _data2, _data2Bytes); \ + tcpReply->flags = SwapBigEndian16((_flags) | ((_headerDWORDs) << 12 /* header is 5 DWORDs */)); \ + tcpReply->sequenceNumber = SwapBigEndian32(task->sendNext); \ + tcpReply->ackNumber = SwapBigEndian32(task->receiveNext); \ + tcpReply->window = SwapBigEndian16(task->receiveWindow); \ + +#define TCP_MAKE_STANDARD_REPLY(_flags) \ + { \ + EsBuffer buffer = NetTransmitBufferGet(); \ + if (buffer.error) { NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); return; } \ + TCP_PREPARE_REPLY_2(nullptr, 0, nullptr, 0, _flags, 5); \ + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); \ + } + +struct DHCPHeader { + uint8_t opCode; + uint8_t hardwareAddressType; + uint8_t hardwareAddressLength; + uint8_t hops; + uint32_t transactionID; + uint16_t seconds; + uint16_t flags; + KIPAddress clientIPAddress; + KIPAddress yourIPAddress; + KIPAddress nextServerIPAddress; + KIPAddress relayAgentIPAddress; + uint8_t clientHardwareAddress[16]; + uint8_t serverHostName[64]; + uint8_t bootFileName[128]; + uint8_t optionsMagic[4]; +} __attribute__((packed)); + +#define DHCP_HEADER(dhcp, _opCode) \ + if (dhcp) { \ + dhcp->opCode = _opCode; \ + dhcp->hardwareAddressType = 1; /* Ethernet. */ \ + dhcp->hardwareAddressLength = 6; \ + dhcp->transactionID = (uint32_t) EsRandomU64(); \ + EsMemoryCopy(&dhcp->clientHardwareAddress, &interface->macAddress, sizeof(KMACAddress)); \ + dhcp->optionsMagic[0] = 99; /* Magic cookie. */ \ + dhcp->optionsMagic[1] = 130; \ + dhcp->optionsMagic[2] = 83; \ + dhcp->optionsMagic[3] = 99; \ + } + +#define DHCP_START() \ + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); \ + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_IPV4, broadcastMAC); \ + IPHeader *ip = (IPHeader *) buffer.Write(nullptr, sizeof(IPHeader)); \ + IP_HEADER(ip, broadcastIP, IP_PROTOCOL_UDP); \ + UDPHeader *udp = (UDPHeader *) buffer.Write(nullptr, sizeof(UDPHeader)); \ + UDP_HEADER(udp, 68, 67); \ + DHCPHeader *dhcp = (DHCPHeader *) buffer.Write(nullptr, sizeof(DHCPHeader)); \ + DHCP_HEADER(dhcp, DHCP_BOOTREQUEST); + +#define DHCP_END() \ + if (!buffer.error) { \ + ip->totalLength = ByteSwap16(buffer.position - sizeof(*ethernet)); \ + udp->length = ByteSwap16(buffer.position - sizeof(*ethernet) - sizeof(*ip)); \ + } + +#define DHCP_OPTION_MESSAGE_TYPE(x) 53, 1, (x) +#define DHCP_OPTION_REQUESTED_IP(x) 50, 4, (x).d[0], (x).d[1], (x).d[2], (x).d[3] +#define DHCP_OPTION_SERVER_IDENTIFIER(x) 54, 4, (x).d[0], (x).d[1], (x).d[2], (x).d[3] + +#define DHCPDISCOVER (1) +#define DHCPOFFER (2) +#define DHCPREQUEST (3) +#define DHCPACK (5) +#define DHCPNAK (6) +#define DHCPRELEASE (7) + +#define DHCP_BOOTREQUEST (1) +#define DHCP_BOOTREPLY (2) + +struct ARPHeader { + uint16_t hardwareAddressSpace; + uint16_t protocolAddressSpace; + uint8_t hardwareAddressLength; + uint8_t protocolAddressLength; + uint16_t opCode; +} __attribute__((packed)); + +#define ARP_ETHERNET (0x0001) +#define ARP_IPV4 (0x0800) + +#define ARP_REQUEST (1) +#define ARP_REPLY (2) + +struct ARPEntry { + KIPAddress ip; + KMACAddress mac; +}; + +struct ARPRequest { + KIPAddress ip; + NetTask *task; +}; + +struct ICMPHeader { + uint8_t type; + uint8_t code; + uint16_t checksum; + + uint16_t CalculateChecksum(size_t dataBytes) const { + const uint8_t *in = (const uint8_t *) this; + uint32_t sum = 0; + + for (uintptr_t i = 0; i < 4 + dataBytes; i += 2) { + if (i == 2) continue; + sum += ((uint16_t) in[i] << 8) + (uint16_t) in[i + 1]; + } + + while (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + + return SwapBigEndian16(~sum); + } +} __attribute__((packed)); + +struct DNSHeader { + uint16_t identifier; + uint16_t flags; + uint16_t questionCount; + uint16_t answerCount; + uint16_t authorityCount; + uint16_t additionalCount; +} __attribute__((packed)); + +struct Networking { + KMutex interfacesListMutex; + SimpleList interfaces; + +#define MAX_UDP_TASKS (1024) + NetTask *udpTasks[MAX_UDP_TASKS]; + KMutex udpTaskBitsetMutex; + Bitset udpTaskBitset; + +#define MAX_TCP_TASKS (1024) + uintptr_t tcpTasks[MAX_TCP_TASKS]; // If (1 << 0) set, task is in use. + uint16_t tcpTaskLRU, tcpTaskMRU; + KMutex tcpTaskListMutex; + + KMutex echoRequestTaskMutex; + NetTask *echoRequestTask; + + KMutex transmitBufferPoolMutex; + EsArena transmitBufferPool; +}; + +struct NetDomainNameResolveTask : NetTask { + const char *name; + size_t nameBytes; + EsAddress *address; + uint16_t identifier; + KEvent *event; +}; + +struct NetEchoRequestTask : NetTask { + uint8_t *data; + EsAddress *address; + KEvent *event; +}; + +struct NetTCPConnectionTask : NetTask { + uint32_t sendUnacknowledged; // Points at the end of the data the server has acknowledged receiving from us. + uint32_t sendNext; // Points at the end of data we've sent. + uint32_t sendWindow; // The maximum distance sendNext can be past sendUnacknowledged. + uint32_t receiveNext; // Points at the end of data we've acknowledged receiving from the server. + uint16_t receiveWindow; // The maximum distance the server can sent data past receiveNext. + + uint32_t initialSend, initialReceive; + uint32_t finSequence; + uint32_t sendWL1; + uint32_t sendWL2; + + KMACAddress destinationMAC; +}; + +struct NetConnection { + NetTCPConnectionTask task; + + MMSharedRegion *bufferRegion; + uint8_t *sendBuffer; + uint8_t *receiveBuffer; + size_t sendBufferBytes; + size_t receiveBufferBytes; + + uintptr_t sendReadPointer; // The end of the data that we've sent to the server (possibly unacknolwedged). + uintptr_t sendWritePointer; // The end of the data that the application has written for us to send. + uintptr_t receiveWritePointer; // The end of the data that we've received from the server with no missing segments. + uintptr_t receiveReadPointer; // The end of the data that the user has processed from the receive buffer. + + RangeSet receivedData; + + EsAddress address; + KMutex mutex; + + volatile uintptr_t handles; +}; + +void NetDomainNameResolve(NetTask *_task, void *data); +void NetEchoRequest(NetTask *_task, void *data); +void NetTCPConnection(NetTask *_task, void *data); +void NetAddressSetup(NetTask *_task, void *data); + +NetConnection *NetConnectionOpen(EsAddress *address, size_t sendBufferBytes, size_t receiveBufferBytes, uint32_t flags); +void NetConnectionClose(NetConnection *connection); +void NetConnectionNotify(NetConnection *connection, uintptr_t sendWritePointer, uintptr_t receiveReadPointer); +void NetConnectionDestroy(NetConnection *connection); + +extern Networking networking; + +#else + +Networking networking; + +const KIPAddress broadcastIP = { 255, 255, 255, 255 }; +const KMACAddress broadcastMAC = { 255, 255, 255, 255, 255, 255 }; + +void NetPrintPacket(const char *cName, const void *packet, size_t bytes) { + EsPrint("%z packet: ", cName); + + for (uintptr_t i = 0; i < bytes; i++) { + EsPrint("%X ", ((uint8_t *) packet)[i]); + } + + EsPrint("\n"); +} + +EsBuffer NetTransmitBufferGet() { + KMutexAcquire(&networking.transmitBufferPoolMutex); + EsBuffer buffer = {}; + buffer.out = (uint8_t *) EsArenaAllocate(&networking.transmitBufferPool, false); + buffer.bytes = networking.transmitBufferPool.slotSize; + + if (!buffer.out) { + buffer.error = true, buffer.bytes = 0; + KernelLog(LOG_ERROR, "Networking", "out of memory", "Could not allocate a transmit buffer.\n"); + } + + KMutexRelease(&networking.transmitBufferPoolMutex); + return buffer; +} + +void NetTransmitBufferReturn(void *data) { + KMutexAcquire(&networking.transmitBufferPoolMutex); + EsArenaFree(&networking.transmitBufferPool, data); + KMutexRelease(&networking.transmitBufferPoolMutex); +} + +bool NetTransmit(NetInterface *interface, EsBuffer *buffer, NetPacketType packetType) { + if (buffer->error) { + KernelPanic("NetTransmit - Trying to transmit a write buffer with errors.\n"); + } + + if (packetType == NET_PACKET_ETHERNET) { + if (buffer->position < 64) { + buffer->Write(nullptr, 64 - buffer->position); + } + + EthernetHeader *ethernet = (EthernetHeader *) buffer->out; + + if (ethernet->type == SwapBigEndian16(ETHERNET_TYPE_IPV4)) { + IPHeader *ip = (IPHeader *) (ethernet + 1); + + if (ip->protocol == IP_PROTOCOL_UDP) { + UDPHeader *udp = (UDPHeader *) (ip + 1); + udp->checksum = udp->CalculateChecksum(); + } else if (ip->protocol == IP_PROTOCOL_TCP) { + TCPHeader *tcp = (TCPHeader *) (ip + 1); + tcp->checksum = tcp->CalculateChecksum(ByteSwap16(ip->totalLength) - sizeof(*ip)); + } else if (ip->protocol == IP_PROTOCOL_ICMP) { + ICMPHeader *icmp = (ICMPHeader *) (ip + 1); + icmp->checksum = icmp->CalculateChecksum(ByteSwap16(ip->totalLength) - sizeof(*ip)); + } + + ip->headerChecksum = ip->CalculateHeaderChecksum(); + } + } + + uintptr_t address = (uintptr_t) buffer->out; + uintptr_t physical = (address & (K_PAGE_SIZE - 1)) + MMArchTranslateAddress(kernelMMSpace, address); + + if (!interface->transmit(interface, buffer->out, physical, buffer->position)) { + NetTransmitBufferReturn(buffer->out); + return false; + } + + return true; +} + +bool NetARPLookup(NetTask *task, KIPAddress targetIP, KMACAddress *targetMAC) { + NetInterface *interface = task->interface; + + KWriterLockTake(&interface->arpTableLock, K_LOCK_SHARED); + + for (uintptr_t i = 0; i < interface->arpTable.Length(); i++) { + if (0 == EsMemoryCompare(&interface->arpTable[i].ip, &targetIP, sizeof(KIPAddress))) { + *targetMAC = interface->arpTable[i].mac; + KWriterLockReturn(&interface->arpTableLock, K_LOCK_SHARED); + return true; + } + } + + KWriterLockReturn(&interface->arpTableLock, K_LOCK_SHARED); + + KernelLog(LOG_INFO, "Networking", "send ARP", "Sending ARP to find MAC address of IP %d.%d.%d.%d.\n", + targetIP.d[0], targetIP.d[1], targetIP.d[2], targetIP.d[3]); + + // TODO Prevent sending multiple requests for a given MAC address at the same time. + + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return false; + } + + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_ARP, broadcastMAC); + ARPHeader *arp = (ARPHeader *) buffer.Write(nullptr, sizeof(ARPHeader)); + + if (arp) { + arp->hardwareAddressSpace = SwapBigEndian16(ARP_ETHERNET); + arp->protocolAddressSpace = SwapBigEndian16(ARP_IPV4); + arp->hardwareAddressLength = 6; + arp->protocolAddressLength = 4; + arp->opCode = SwapBigEndian16(ARP_REQUEST); + } + + buffer.Write(&interface->macAddress, sizeof(KMACAddress)); + buffer.Write(&interface->ipAddress, sizeof(KIPAddress)); + buffer.Write(nullptr, sizeof(KMACAddress)); + buffer.Write(&targetIP, sizeof(KIPAddress)); + + if (buffer.error) { + KernelPanic("NetARPLookup - Network interface buffer size too small.\n"); + } + + KWriterLockTake(&interface->arpTableLock, K_LOCK_EXCLUSIVE); + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } else { + ARPRequest request = { targetIP, task }; + interface->arpRequests.Add(request); + } + + KWriterLockReturn(&interface->arpTableLock, K_LOCK_EXCLUSIVE); + + return false; +} + +void NetARPReceive(NetInterface *interface, EsBuffer *buffer) { + const ARPHeader *arp = (const ARPHeader *) buffer->Read(sizeof(ARPHeader)); + + if (!arp) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing ARP header.\n"); + return; + } + + if (SwapBigEndian16(arp->hardwareAddressSpace) != ARP_ETHERNET + || SwapBigEndian16(arp->protocolAddressSpace) != ARP_IPV4) { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "ARP packet has unrecognised address space(s).\n"); + return; + } + + const KMACAddress *senderMAC = (const KMACAddress *) buffer->Read(sizeof(KMACAddress)); + const KIPAddress *senderIP = (const KIPAddress *) buffer->Read(sizeof(KIPAddress)); + const KMACAddress *targetMAC = (const KMACAddress *) buffer->Read(sizeof(KMACAddress)); + const KIPAddress *targetIP = (const KIPAddress *) buffer->Read(sizeof(KIPAddress)); + + if (!senderMAC || !senderIP || !targetMAC || !targetIP) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "ARP packet too short.\n"); + return; + } + + KernelLog(LOG_INFO, "Networking", "received ARP packet", + "Received ARP packet. Sender: %d.%d.%d.%d (%X:%X:%X:%X:%X:%X). Destination: %d.%d.%d.%d (%X:%X:%X:%X:%X:%X). Op code %d.\n", + senderIP->d[0], senderIP->d[1], senderIP->d[2], senderIP->d[3], + senderMAC->d[0], senderMAC->d[1], senderMAC->d[2], senderMAC->d[3], senderMAC->d[4], senderMAC->d[5], + targetIP->d[0], targetIP->d[1], targetIP->d[2], targetIP->d[3], + targetMAC->d[0], targetMAC->d[1], targetMAC->d[2], targetMAC->d[3], targetMAC->d[4], targetMAC->d[5], + SwapBigEndian16(arp->opCode)); + + bool merged = false; + + Array completedRequests = {}; + + KWriterLockTake(&interface->arpTableLock, K_LOCK_EXCLUSIVE); + + for (uintptr_t i = 0; i < interface->arpTable.Length(); i++) { + if (0 == EsMemoryCompare(&interface->arpTable[i].ip, senderIP, sizeof(KIPAddress))) { + interface->arpTable[i].mac = *senderMAC; + merged = true; + } + } + + if (interface->hasIP && 0 == EsMemoryCompare(targetIP, &interface->ipAddress, sizeof(KIPAddress))) { + if (!merged) { + ARPEntry entry = {}; + entry.ip = *senderIP; + entry.mac = *senderMAC; + + if (!interface->arpTable.Add(entry)) { + KernelLog(LOG_ERROR, "Networking", "allocation error", "Could not add entry to ARP table.\n"); + } + + for (uintptr_t i = 0; i < interface->arpRequests.Length(); i++) { + if (0 == EsMemoryCompare(&interface->arpRequests[i].ip, &entry.ip, sizeof(KIPAddress))) { + completedRequests.Add(interface->arpRequests[i].task); + interface->arpRequests.DeleteSwap(i); + i--; + } + } + } + + if (SwapBigEndian16(arp->opCode) == ARP_REQUEST) { + // Reply with our MAC address. + EsBuffer buffer = NetTransmitBufferGet(); + + if (!buffer.error) { + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_ARP, broadcastMAC); + ARPHeader *arpReply = (ARPHeader *) buffer.Write(arp, sizeof(ARPHeader)); + buffer.Write(&interface->macAddress, sizeof(KMACAddress)); + buffer.Write(targetIP, sizeof(KIPAddress)); + buffer.Write(senderMAC, sizeof(KMACAddress)); + buffer.Write(senderIP, sizeof(KIPAddress)); + + if (buffer.error) { + KernelPanic("NetARPReceive - Network interface buffer size too small.\n"); + } else { + arpReply->opCode = ARP_REPLY; + NetTransmit(interface, &buffer, NET_PACKET_ETHERNET); // Don't care about errors. + } + } + } else if (SwapBigEndian16(arp->opCode) == ARP_REPLY) { + // Don't need to do anything. + } else { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Unrecognised ARP op code %d.\n", SwapBigEndian16(arp->opCode)); + } + } else { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "ARP packet not destined for us.\n"); + } + + KWriterLockReturn(&interface->arpTableLock, K_LOCK_EXCLUSIVE); + + for (uintptr_t i = 0; i < completedRequests.Length(); i++) { + completedRequests[i]->callback(completedRequests[i], nullptr); + } + + completedRequests.Free(); +} + +void NetICMPReceive(NetInterface *interface, EsBuffer *buffer, const IPHeader *ip, const EthernetHeader *ethernet) { + const ICMPHeader *icmp = (const ICMPHeader *) buffer->Read(sizeof(ICMPHeader)); + + if (!icmp) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing ICMP header.\n"); + return; + } + + if (icmp->checksum != icmp->CalculateChecksum(buffer->bytes - buffer->position)) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Incorrect ICMP checksum.\n"); + return; + } + + if (icmp->type == 8 /* echo request */) { + // Send echo reply. + // TODO Test this. + + EsBuffer bufferReply = NetTransmitBufferGet(); + if (bufferReply.error) return; + + EthernetHeader *ethernetReply = (EthernetHeader *) bufferReply.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernetReply, ETHERNET_TYPE_IPV4, ethernet->sourceMAC); + IPHeader *ipReply = (IPHeader *) bufferReply.Write(nullptr, sizeof(IPHeader)); + IP_HEADER(ipReply, ip->sourceAddress, IP_PROTOCOL_ICMP); + ICMPHeader *icmpReply = (ICMPHeader *) bufferReply.Write(icmp, sizeof(ICMPHeader)); + bufferReply.Write(icmp + 1, buffer->bytes - buffer->position); + + if (bufferReply.error) { + KernelPanic("NetICMPReceive - Network interface buffer size too small.\n"); + } else { + icmpReply->type = 0; // Echo reply. + ipReply->totalLength = ByteSwap16(bufferReply.position - sizeof(*ethernetReply)); + NetTransmit(interface, &bufferReply, NET_PACKET_ETHERNET); // Don't care about errors. + } + } else if (icmp->type == 0 /* echo reply */) { + if (networking.echoRequestTask) { + networking.echoRequestTask->callback(networking.echoRequestTask, buffer); + } else { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Unexpected ICMP echo reply.\n"); + } + } +} + +void NetTCPReceive(NetInterface *interface, EsBuffer *buffer, const IPHeader *ip, const EthernetHeader *ethernet) { + // Validate the TCP header. + + size_t tcpPosition = buffer->position; + const TCPHeader *tcp = (const TCPHeader *) buffer->Read(sizeof(TCPHeader)); + + if (!tcp) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing TCP header.\n"); + return; + } + + uint16_t flags = SwapBigEndian16(tcp->flags); + uint32_t headerDWORDs = flags >> 12; + + if (headerDWORDs < 5) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "TCP header DWORDs was less than 5.\n"); + return; + } + + if (tcp->CalculateChecksum(buffer->bytes - tcpPosition) != tcp->checksum) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "TCP header has incorrect checksum.\n"); + return; + } + + if (!buffer->Read((headerDWORDs - 5) * sizeof(uint32_t))) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "TCP header is shorter than expected.\n"); + return; + } + + uint32_t segmentLength = buffer->bytes - buffer->position; + + // If a task exists at the destination port, send it the segment. + // TODO Locking on getting the task. + + NetTCPConnectionTask *task = nullptr; + uint16_t destinationPort = SwapBigEndian16(tcp->destinationPort); + + if (destinationPort >= TCP_PORT_BASE + && destinationPort < TCP_PORT_BASE + MAX_TCP_TASKS + && (networking.tcpTasks[destinationPort - TCP_PORT_BASE] & 1)) { + task = (NetTCPConnectionTask *) (networking.tcpTasks[destinationPort - TCP_PORT_BASE] & ~1); + OpenHandleToObject(task, KERNEL_OBJECT_CONNECTION); + } + + TCPReceivedData _data = {}; + _data.ethernet = ethernet; + _data.ip = ip; + _data.tcp = tcp; + _data.flags = flags; + _data.segmentLength = segmentLength; + _data.segment = buffer->Read(segmentLength); + _data.sequenceNumber = SwapBigEndian32(tcp->sequenceNumber); + _data.ackNumber = SwapBigEndian32(tcp->ackNumber); + TCPReceivedData *data = &_data; + + if (task) { + task->callback(task, data); + CloseHandleToObject(task, KERNEL_OBJECT_CONNECTION); + return; + } + + // The destination port is closed. + // If the segment does not have the RST flag, then we should send a RST segment in response. + + if (~flags & (1 << 2 /* RST */)) { + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + return; // Ignore. + } + + TCP_PREPARE_REPLY(nullptr, 0, nullptr, 0); + + tcpReply->sourcePort = tcp->destinationPort; + tcpReply->destinationPort = tcp->sourcePort; + tcpReply->flags = SwapBigEndian16(TCP_RST | ~(flags & TCP_ACK) | (5 << 12 /* header is 5 DWORDs */)); + tcpReply->sequenceNumber = (flags & TCP_ACK) ? tcp->ackNumber : 0; + tcpReply->ackNumber = (flags & TCP_ACK) ? 0 : SwapBigEndian32(SwapBigEndian32(tcp->sequenceNumber) + segmentLength); + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } + } +} + +void NetUDPReceive(NetInterface *interface, EsBuffer *buffer) { + const UDPHeader *udp = (const UDPHeader *) buffer->Read(sizeof(UDPHeader)); + + if (!udp) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing UDP header.\n"); + return; + } + + if (!interface->hasIP && udp->destinationPort != SwapBigEndian16(68)) { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Only expecting DHCP packets until IP address accepted.\n"); + return; + } + + if (SwapBigEndian16(udp->length) > buffer->bytes - buffer->position + sizeof(UDPHeader)) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "UDP length was longer than remaining buffer size.\n"); + return; + } + + if (udp->CalculateChecksum() != udp->checksum) { // NOTE Don't compute the checksum until the length field has been validated! + KernelLog(LOG_ERROR, "Networking", "bad packet", "Incorrect checksum in UDP header.\n"); + return; + } + + uint16_t destinationPort = SwapBigEndian16(udp->destinationPort); + + if (destinationPort == 68 /* DHCP */) { + interface->addressSetupTask.callback(&interface->addressSetupTask, buffer); + } else if (destinationPort >= UDP_PORT_BASE + && destinationPort < UDP_PORT_BASE + MAX_UDP_TASKS + && !networking.udpTaskBitset.Read(destinationPort - UDP_PORT_BASE)) { + NetTask *task = networking.udpTasks[destinationPort - UDP_PORT_BASE]; + task->callback(task, buffer); + } else { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Unknown destination UDP port %d.\n", udp->destinationPort); + } +} + +void NetIPReceive(NetInterface *interface, EsBuffer *buffer, const EthernetHeader *ethernet) { + const IPHeader *ip = (const IPHeader *) buffer->Read(sizeof(IPHeader)); + + if (!ip) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing IP header.\n"); + return; + } + + if ((ip->versionAndLength >> 4) != 4) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Unsupported IP version %d.\n", ip->versionAndLength >> 4); + return; + } + + size_t headerLength = (ip->versionAndLength & 0xF) * 4; + + if (headerLength < 20) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "IP header too short.\n"); + return; + } + + uint16_t totalLength = SwapBigEndian16(ip->totalLength); + + if (totalLength > buffer->bytes - buffer->position + sizeof(IPHeader)) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "IP header total length was longer than remaining buffer size.\n"); + return; + } + + buffer->bytes = buffer->position + totalLength - sizeof(IPHeader); + + if (totalLength < headerLength) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "IP header total length was less than header length.\n"); + return; + } + + if (interface->hasIP && EsMemoryCompare(&interface->ipAddress, &ip->destinationAddress, 4) + && EsMemoryCompare(&broadcastIP, &ip->destinationAddress, 4)) { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Destination IP address mismatch (%d.%d.%d.%d).\n", + ip->destinationAddress.d[0], ip->destinationAddress.d[1], ip->destinationAddress.d[2], ip->destinationAddress.d[3]); + return; + } + + if (ip->CalculateHeaderChecksum() != ip->headerChecksum) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Incorrect checksum in IP header.\n"); + return; + } + + buffer->Read(headerLength - 20); + + if (!interface->hasIP && ip->protocol != IP_PROTOCOL_UDP) { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Only expecting DHCP packets over UDP until IP address accepted.\n"); + return; + } + + if (ip->protocol == IP_PROTOCOL_ICMP) { + NetICMPReceive(interface, buffer, ip, ethernet); + } else if (ip->protocol == IP_PROTOCOL_TCP) { + NetTCPReceive(interface, buffer, ip, ethernet); + } else if (ip->protocol == IP_PROTOCOL_UDP) { + NetUDPReceive(interface, buffer); + } else { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Unrecognised IP protocol type %d.\n", ip->protocol); + } +} + +void NetEthernetReceive(NetInterface *interface, EsBuffer *buffer) { + const EthernetHeader *ethernet = (const EthernetHeader *) buffer->Read(sizeof(EthernetHeader)); + + if (!ethernet) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing ethernet header.\n"); + return; + } + + if (EsMemoryCompare(ðernet->destinationMAC, &interface->macAddress, sizeof(KMACAddress)) + && EsMemoryCompare(ðernet->destinationMAC, &broadcastMAC, sizeof(KMACAddress))) { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Destination MAC address mismatch.\n"); + return; + } + + if (SwapBigEndian16(ethernet->type) == ETHERNET_TYPE_IPV4) { + NetIPReceive(interface, buffer, ethernet); + } else if (SwapBigEndian16(ethernet->type) == ETHERNET_TYPE_ARP) { + NetARPReceive(interface, buffer); + } else { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Unrecognised ethernet packet type %x.\n", SwapBigEndian16(ethernet->type)); + } +} + +void NetInterfaceReceive(NetInterface *interface, const uint8_t *data, size_t dataBytes, NetPacketType packetType) { + KWriterLockTake(&interface->connectionLock, K_LOCK_SHARED); + + EsBuffer buffer = { .in = data, .bytes = dataBytes }; + + if (!interface->connected) { + KernelLog(LOG_ERROR, "Networking", "packet while disconnected", "Interface %x is disconnected.\n", interface); + } else if (packetType == NET_PACKET_ETHERNET) { + NetEthernetReceive(interface, &buffer); + } else { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Unsupported packet type %d.\n", packetType); + } + + KWriterLockReturn(&interface->connectionLock, K_LOCK_SHARED); + + if (interface->addressSetupTask.changedState) { + interface->addressSetupTask.changedState = false; + KWriterLockTake(&interface->connectionLock, K_LOCK_EXCLUSIVE); + + interface->hasIP = interface->addressSetupTask.error == ES_SUCCESS; + + if (!interface->hasIP) { + // TODO Report connection lost and cancel in progress tasks. + // TODO Retry the addressSetupTask. + KernelLog(LOG_INFO, "Networking", "interface disconnected", "NetInterfaceReceive - Interface %x has lost IP address.\n", interface); + } + + KWriterLockReturn(&interface->connectionLock, K_LOCK_EXCLUSIVE); + } +} + +void NetInterfaceShutdown(NetInterface *interface) { + if (!interface->hasIP) { + return; + } + + // Release our IP address. + + EsBuffer buffer = NetTransmitBufferGet(); + if (buffer.error) return; + DHCP_START(); + + uint8_t dhcpOptions[] = { + DHCP_OPTION_MESSAGE_TYPE(DHCPRELEASE), + DHCP_OPTION_SERVER_IDENTIFIER(interface->serverIdentifier), + 255, // End of options. + }; + + buffer.Write(dhcpOptions, sizeof(dhcpOptions)); + DHCP_END(); + + if (buffer.error) { + KernelPanic("NetInterface::ReceiveDHCPReply - Network interface buffer size too small.\n"); + } + + NetTransmit(interface, &buffer, NET_PACKET_ETHERNET); // Don't care about errors. +} + +void NetInterfaceSetConnected(NetInterface *interface, bool connected) { + if (interface->connected == connected) { + return; + } + + KWriterLockTake(&interface->connectionLock, K_LOCK_EXCLUSIVE); + + interface->connected = connected; + + if (!connected) { + // TODO Report connection lost and cancel in progress tasks. + KernelLog(LOG_INFO, "Networking", "interface disconnected", "NetInterface::SetConnected - Interface %x has disconnected.\n", interface); + interface->hasIP = false; + interface->arpTable.SetLength(0); + interface->arpRequests.SetLength(0); + } else { + KernelLog(LOG_INFO, "Networking", "interface connected", "NetInterface::SetConnected - Interface %x has connected. Requesting an IP address...\n", interface); + } + + KWriterLockReturn(&interface->connectionLock, K_LOCK_EXCLUSIVE); + + if (connected) { + NetTaskBegin(&interface->addressSetupTask); + } +} + +void NetDomainNameResolve(NetTask *_task, void *_buffer) { + EsBuffer *buffer = (EsBuffer *) _buffer; + NetDomainNameResolveTask *task = (NetDomainNameResolveTask *) _task; + NetInterface *interface = task->interface; + + if (task->completed) { + if (task->index != 0xFFFF) { + KMutexAcquire(&networking.udpTaskBitsetMutex); + networking.udpTaskBitset.Put(task->index); + KMutexRelease(&networking.udpTaskBitsetMutex); + } + + if (task->event) { + // This must be the last thing we do, otherwise the NetTask might be freed. + KEventSet(task->event); + } + } else if (task->step == 0) { + KMACAddress dnsServerMAC; + + if (!NetARPLookup(task, interface->dnsServerIP, &dnsServerMAC)) { + return; + } + + KMutexAcquire(&networking.udpTaskBitsetMutex); + ptrdiff_t taskIndex = networking.udpTaskBitset.Get(); + + if (taskIndex == -1) { + KMutexRelease(&networking.udpTaskBitsetMutex); + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + + networking.udpTasks[taskIndex] = task; + task->index = taskIndex; + KMutexRelease(&networking.udpTaskBitsetMutex); + + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_IPV4, dnsServerMAC); + IPHeader *ip = (IPHeader *) buffer.Write(nullptr, sizeof(IPHeader)); + IP_HEADER(ip, interface->dnsServerIP, IP_PROTOCOL_UDP); + UDPHeader *udp = (UDPHeader *) buffer.Write(nullptr, sizeof(UDPHeader)); + UDP_HEADER(udp, taskIndex + UDP_PORT_BASE, 53 /* DNS server */); + + DNSHeader *dns = (DNSHeader *) buffer.Write(nullptr, sizeof(DNSHeader)); + dns->identifier = task->identifier = EsRandomU64(); + dns->flags = SwapBigEndian16(1 << 8 /* recursion desired */); + dns->questionCount = SwapBigEndian16(1); + + for (uintptr_t i = 0, j = 0; i <= task->nameBytes; i++) { + if (i == task->nameBytes || task->name[i] == '.') { + uint8_t bytes = i - j; + buffer.Write(&bytes, 1); + buffer.Write(task->name + j, bytes); + + j = i + 1; + } + } + + { + uint8_t zero = 0; + buffer.Write(&zero, 1); + + uint16_t queryType = SwapBigEndian16(1 /* A - IPv4 address */); + buffer.Write(&queryType, 2); + + uint16_t queryClass = SwapBigEndian16(1 /* IN - the internet */); + buffer.Write(&queryClass, 2); + } + + if (buffer.error) { + KernelPanic("NetInterface::DomainNameResolve - Network interface buffer size too small.\n"); + } + + ip->totalLength = ByteSwap16(buffer.position - sizeof(*ethernet)); + udp->length = ByteSwap16(buffer.position - sizeof(*ethernet) - sizeof(*ip)); + + task->step++; + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + } else if (task->step == 1) { + const DNSHeader *header = (const DNSHeader *) buffer->Read(sizeof(DNSHeader)); + + if (!header) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing DNS header.\n"); + return; + } + + if (header->identifier != task->identifier) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Received DNS packet with wrong identifier.\n"); + return; + } + + uint16_t flags = SwapBigEndian16(header->flags); + + if (~flags & (1 << 15)) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Received DNS request (expecting reponse).\n"); + return; + } + + EsError error = ES_ERROR_UNKNOWN; + + if ((flags & 15) == 3) { + error = ES_ERROR_NO_ADDRESS_FOR_DOMAIN_NAME; + } else if ((flags & 15) == 0) { + error = ES_SUCCESS; + } + + for (uintptr_t i = 0; i < SwapBigEndian16(header->questionCount); i++) { + while (true) { + const uint8_t *length = (const uint8_t *) buffer->Read(1); + if (!length) break; + + if ((*length & 0xC0) == 0xC0) { + buffer->Read(1); + break; + } else if (*length == 0) { + break; + } + + buffer->Read(*length); + } + + buffer->Read(4); + } + + bool foundAddress = false; + + for (uintptr_t i = 0; i < SwapBigEndian16(header->answerCount); i++) { + while (true) { + const uint8_t *length = (const uint8_t *) buffer->Read(1); + if (!length) break; + + if ((*length & 0xC0) == 0xC0) { + buffer->Read(1); + break; + } else if (*length == 0) { + break; + } + + buffer->Read(*length); + } + + const uint16_t *type = (const uint16_t *) buffer->Read(2); + const uint16_t *classType = (const uint16_t *) buffer->Read(2); + const uint32_t *timeToLive = (const uint32_t *) buffer->Read(4); + const uint16_t *dataLength = (const uint16_t *) buffer->Read(2); + + if (!type || !classType || !timeToLive || !dataLength) { + break; + } + + const void *data = (const void *) buffer->Read(SwapBigEndian16(*dataLength)); + + if (!data) { + break; + } + + if (SwapBigEndian16(*type) == 1 /* A - IPv4 address */ + && SwapBigEndian16(*classType) == 1 /* IN - the internet */) { + if (SwapBigEndian16(*dataLength) != 4) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "IPv4 address was not 4 bytes.\n"); + return; + } + + EsMemoryCopy(&task->address->ipv4, data, 4); + foundAddress = true; + break; + } + } + + if (buffer->error) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing data after DNS header.\n"); + return; + } + + if (!foundAddress) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Could not find IP address in DNS packet.\n"); + error = ES_ERROR_UNKNOWN; + } + + NetTaskComplete(task, error); + } else { + KernelPanic("NetDomainNameResolve - Invalid step.\n"); + } +} + +void NetEchoRequest(NetTask *_task, void *_buffer) { + EsBuffer *buffer = (EsBuffer *) _buffer; + NetEchoRequestTask *task = (NetEchoRequestTask *) _task; + NetInterface *interface = task->interface; + + if (task->completed) { + KMutexAcquire(&networking.echoRequestTaskMutex); + + if (networking.echoRequestTask == task) { + networking.echoRequestTask = nullptr; + } + + KMutexRelease(&networking.echoRequestTaskMutex); + + if (task->event) { + // This must be the last thing we do, otherwise the NetTask might be freed. + KEventSet(task->event); + } + } else if (task->step == 0) { + KMACAddress routerMAC; + + if (!NetARPLookup(task, interface->routerIP, &routerMAC)) { + return; + } + + KMutexAcquire(&networking.echoRequestTaskMutex); + + if (networking.echoRequestTask) { + KMutexRelease(&networking.echoRequestTaskMutex); + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + + networking.echoRequestTask = task; + KMutexRelease(&networking.echoRequestTaskMutex); + + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_IPV4, routerMAC); + IPHeader *ip = (IPHeader *) buffer.Write(nullptr, sizeof(IPHeader)); + KIPAddress destinationIP; + EsMemoryCopy(&destinationIP, &task->address->ipv4, sizeof(KIPAddress)); + IP_HEADER(ip, destinationIP, IP_PROTOCOL_ICMP); + ICMPHeader *icmp = (ICMPHeader *) buffer.Write(nullptr, sizeof(ICMPHeader)); + buffer.Write(task->data, ES_ECHO_REQUEST_MAX_LENGTH); + + if (buffer.error) { + KernelPanic("NetInterface::DomainNameResolve - Network interface buffer size too small.\n"); + } + + icmp->type = 8; // Echo request. + ip->totalLength = ByteSwap16(buffer.position - sizeof(*ethernet)); + task->step++; + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + } else if (task->step == 1) { + size_t dataBytes = buffer->bytes - buffer->position; + const uint8_t *data = (const uint8_t *) buffer->Read(dataBytes); + + if (dataBytes > ES_ECHO_REQUEST_MAX_LENGTH) { + dataBytes = ES_ECHO_REQUEST_MAX_LENGTH; + } + + EsMemoryZero(task->data, ES_ECHO_REQUEST_MAX_LENGTH); + EsMemoryCopy(task->data, data, dataBytes); + + NetTaskComplete(task, ES_SUCCESS); + } else { + KernelPanic("NetEchoRequest - Invalid step.\n"); + } +} + +bool NetTCPIsBetween(uint32_t low, uint32_t value, uint32_t high) { + if (low <= high) { + return low <= value && value <= high; + } else { + return high <= value && value <= low; + } +} + +bool NetTCPIsLessThan(uint32_t left, uint32_t right) { + return left - right > 0x80000000; +} + +bool NetTCPIsLessThanOrEqual(uint32_t left, uint32_t right) { + return left - right - 1 > 0x80000000; +} + +void NetTCPFreeTaskIndex(uint16_t index, bool initialFree = false) { + if (index != 0xFFFF) { + // Free the port index. + + KMutexAcquire(&networking.tcpTaskListMutex); + + if ((~networking.tcpTasks[index] & 1) && !initialFree) { + KernelPanic("NetTCPFreeTaskIndex - TCP task list double-free.\n"); + } else if (networking.tcpTaskLRU == 0xFFFF && networking.tcpTaskMRU == 0xFFFF) { + networking.tcpTaskLRU = index; + networking.tcpTaskMRU = index; + networking.tcpTasks[index] = 0xFFFF << 1; + } else if (networking.tcpTaskLRU == 0xFFFF || networking.tcpTaskMRU == 0xFFFF + || networking.tcpTasks[networking.tcpTaskMRU] != (0xFFFF << 1)) { + KernelPanic("NetTCPFreeTaskIndex - Broken TCP task list.\n"); + } else { + networking.tcpTasks[networking.tcpTaskMRU] = index << 1; + networking.tcpTaskMRU = index; + networking.tcpTasks[index] = 0xFFFF << 1; + } + + KMutexRelease(&networking.tcpTaskListMutex); + } +} + +bool NetTCPAllocateTaskIndex(NetTask *task) { + KMutexAcquire(&networking.tcpTaskListMutex); + uint16_t taskIndex = networking.tcpTaskLRU; + + if (taskIndex == 0xFFFF) { + KMutexRelease(&networking.tcpTaskListMutex); + return false; + } + + networking.tcpTaskLRU = networking.tcpTasks[taskIndex] >> 1; + if (networking.tcpTaskLRU == 0xFFFF) networking.tcpTaskMRU = 0xFFFF; + networking.tcpTasks[taskIndex] = (uintptr_t) task | 1; + task->index = taskIndex; + KMutexRelease(&networking.tcpTaskListMutex); + return true; +} + +bool NetConnectionTransmitData(NetConnection *connection) { + // TODO Send segments as a NetTask, so that they can be retransmitted. + + NetTCPConnectionTask *task = &connection->task; + NetInterface *interface = task->interface; + KWriterLockAssertShared(&interface->connectionLock); + + bool sent = false; + + while (connection->sendReadPointer != connection->sendWritePointer) { + uintptr_t bytesAvailable = connection->sendWritePointer - connection->sendReadPointer; + + if (connection->sendReadPointer > connection->sendWritePointer) { + bytesAvailable += connection->sendBufferBytes; + } + + uintptr_t maximumBytesPerSegment = 1000; // TODO Parse the maximum segment size option. + uintptr_t bytesToSendInSegment = MinimumInteger(maximumBytesPerSegment, bytesAvailable); + + const void *data1 = connection->sendBuffer + connection->sendReadPointer; + const void *data2 = connection->sendBuffer; + size_t dataBytes1 = bytesToSendInSegment; + size_t dataBytes2 = 0; + + if (connection->sendReadPointer + bytesToSendInSegment > connection->sendBufferBytes) { + dataBytes1 = connection->sendBufferBytes - connection->sendReadPointer; + dataBytes2 = bytesToSendInSegment - dataBytes1; + } + + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return true; + } + + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_IPV4, task->destinationMAC); + IPHeader *ip = (IPHeader *) buffer.Write(nullptr, sizeof(IPHeader)); + IP_HEADER(ip, *(KIPAddress *) &connection->address.ipv4, IP_PROTOCOL_TCP); + TCPHeader *tcp = (TCPHeader *) buffer.Write(nullptr, sizeof(TCPHeader)); + buffer.Write(data1, dataBytes1); + buffer.Write(data2, dataBytes2); + + if (buffer.error) { + KernelPanic("NetConnectionTransmitData - Network interface buffer size too small.\n"); + } + + ip->totalLength = ByteSwap16(buffer.position - sizeof(*ethernet)); + ip->flagsAndFragmentOffset = SwapBigEndian16(1 << 14 /* do not fragment */); + ip->headerChecksum = ip->CalculateHeaderChecksum(); + + tcp->sourcePort = SwapBigEndian16(task->index + TCP_PORT_BASE); + tcp->destinationPort = SwapBigEndian16(connection->address.port); + tcp->flags = SwapBigEndian16(TCP_ACK | (5 << 12 /* header is 5 DWORDs */)); + tcp->sequenceNumber = SwapBigEndian32(task->sendNext); + tcp->ackNumber = SwapBigEndian32(task->receiveNext); + tcp->window = SwapBigEndian16(task->receiveWindow); + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return true; + } + + sent = true; + connection->sendReadPointer = (connection->sendReadPointer + bytesToSendInSegment) % connection->sendBufferBytes; + task->sendNext += bytesToSendInSegment; + } + + return sent; +} + +bool NetConnectionUpdateReceiveWindow(NetConnection *connection) { + NetTCPConnectionTask *task = &connection->task; + uint16_t oldReceiveWindow = task->receiveWindow; + + if (connection->receiveReadPointer == connection->receiveWritePointer) { + task->receiveWindow = MinimumInteger(0xF000, connection->receiveBufferBytes - 1); + } else if (connection->receiveReadPointer < connection->receiveWritePointer) { + task->receiveWindow = MinimumInteger(0xF000, connection->receiveReadPointer - connection->receiveWritePointer + connection->receiveBufferBytes); + } else { + task->receiveWindow = MinimumInteger(0xF000, connection->receiveReadPointer - connection->receiveWritePointer); + } + + EsPrint("ORW: %d; RW: %d; RRP: %d; RWP: %d; RBB: %d\n", oldReceiveWindow, task->receiveWindow, + connection->receiveReadPointer, connection->receiveWritePointer, connection->receiveBufferBytes); + + return oldReceiveWindow != task->receiveWindow; +} + +void NetConnectionNotify(NetConnection *connection, uintptr_t sendWritePointer, uintptr_t receiveReadPointer) { + NetTCPConnectionTask *task = &connection->task; + NetInterface *interface = task->interface; + KWriterLockTake(&interface->connectionLock, K_LOCK_SHARED); + KMutexAcquire(&connection->mutex); + + connection->sendWritePointer = sendWritePointer % connection->sendBufferBytes; + connection->receiveReadPointer = receiveReadPointer % connection->receiveBufferBytes; + + bool receiveWindowModified = NetConnectionUpdateReceiveWindow(connection); + + if (task->step == TCP_STEP_ESTABLISHED + && !NetConnectionTransmitData(connection) + && receiveWindowModified) { + // ACK the new window size. + + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } else { + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_IPV4, task->destinationMAC); + IPHeader *ip = (IPHeader *) buffer.Write(nullptr, sizeof(IPHeader)); + IP_HEADER(ip, *(KIPAddress *) &connection->address.ipv4, IP_PROTOCOL_TCP); + TCPHeader *tcp = (TCPHeader *) buffer.Write(nullptr, sizeof(TCPHeader)); + + if (buffer.error) { + KernelPanic("NetConnectionNotify - Network interface buffer size too small.\n"); + } + + ip->totalLength = ByteSwap16(buffer.position - sizeof(*ethernet)); + ip->flagsAndFragmentOffset = SwapBigEndian16(1 << 14 /* do not fragment */); + ip->headerChecksum = ip->CalculateHeaderChecksum(); + + tcp->sourcePort = SwapBigEndian16(task->index + TCP_PORT_BASE); + tcp->destinationPort = SwapBigEndian16(connection->address.port); + tcp->flags = SwapBigEndian16(TCP_ACK | (5 << 12 /* header is 5 DWORDs */)); + tcp->sequenceNumber = SwapBigEndian32(task->sendNext); + tcp->ackNumber = SwapBigEndian32(task->receiveNext); + tcp->window = SwapBigEndian16(task->receiveWindow); + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } + } + } + + KMutexRelease(&connection->mutex); + KWriterLockReturn(&interface->connectionLock, K_LOCK_SHARED); +} + +void NetTCPConnection(NetTask *_task, void *_data) { + TCPReceivedData *data = (TCPReceivedData *) _data; + NetTCPConnectionTask *task = (NetTCPConnectionTask *) _task; + NetInterface *interface = task->interface; + NetConnection *connection = EsContainerOf(NetConnection, task, task); + + if (task->completed) { + NetTCPFreeTaskIndex(task->index); + CloseHandleToObject(connection, KERNEL_OBJECT_CONNECTION); + return; + } + + KMutexAcquire(&connection->mutex); + EsDefer(KMutexRelease(&connection->mutex)); + + if (task->step == 0) { + if (!NetARPLookup(task, interface->routerIP, &task->destinationMAC)) { + return; + } + + if (!NetTCPAllocateTaskIndex(task)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + + task->initialSend = (uint32_t) EsRandomU64() & 0x0FFFFFFF; + task->sendUnacknowledged = task->initialSend; + task->sendNext = task->initialSend + 1; + task->step = TCP_STEP_SYN_SENT; + + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_IPV4, task->destinationMAC); + IPHeader *ip = (IPHeader *) buffer.Write(nullptr, sizeof(IPHeader)); + KIPAddress destinationIP = {}; + EsMemoryCopy(&destinationIP, &connection->address.ipv4, sizeof(KIPAddress)); + IP_HEADER(ip, destinationIP, IP_PROTOCOL_TCP); + TCPHeader *tcp = (TCPHeader *) buffer.Write(nullptr, sizeof(TCPHeader)); + + if (buffer.error) { + KernelPanic("NetTCPConnection - Network interface buffer size too small.\n"); + } + + ip->totalLength = ByteSwap16(buffer.position - sizeof(*ethernet)); + ip->flagsAndFragmentOffset = SwapBigEndian16(1 << 14 /* do not fragment */); + + tcp->window = SwapBigEndian16(task->receiveWindow); + tcp->flags = SwapBigEndian16(TCP_SYN | (5 << 12 /* header is 5 DWORDs */)); + tcp->sourcePort = SwapBigEndian16(task->index + TCP_PORT_BASE); + tcp->destinationPort = SwapBigEndian16(connection->address.port); + tcp->sequenceNumber = SwapBigEndian32(task->initialSend); + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } + } else if (task->step == TCP_STEP_SYN_SENT) { + if ((data->flags & TCP_ACK) && !NetTCPIsBetween(task->sendUnacknowledged, data->ackNumber, task->sendNext)) { + if (data->flags & TCP_RST) return; + EsBuffer buffer = NetTransmitBufferGet(); + if (buffer.error) return; + TCP_PREPARE_REPLY(nullptr, 0, nullptr, 0); + tcpReply->flags = SwapBigEndian16(TCP_RST | (5 << 12 /* header is 5 DWORDs */)); + tcpReply->sequenceNumber = data->tcp->ackNumber; + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } else if (data->flags & TCP_RST) { + NetTaskComplete(task, ES_ERROR_CONNECTION_RESET); + } else if (data->flags & TCP_SYN) { + task->initialReceive = data->sequenceNumber; + task->receiveNext = data->sequenceNumber + 1; + + if (data->flags & TCP_ACK) { + task->sendUnacknowledged = data->ackNumber; + task->step = TCP_STEP_ESTABLISHED; + TCP_MAKE_STANDARD_REPLY(TCP_ACK); + NetConnectionTransmitData(connection); + } else { + task->step = TCP_STEP_SYN_RECEIVED; + TCP_MAKE_STANDARD_REPLY(TCP_SYN | TCP_ACK); + } + } + } else { + bool acceptable = NetTCPIsBetween(task->receiveNext, data->sequenceNumber, task->receiveNext + task->receiveWindow - 1); + + if (!data->segmentLength && !task->receiveWindow) { + acceptable = data->sequenceNumber == task->receiveNext; + } else if (!data->segmentLength && task->receiveWindow) { + acceptable = NetTCPIsBetween(task->receiveNext, data->sequenceNumber, task->receiveNext + task->receiveWindow - 1); + } else if (data->segmentLength && task->receiveWindow) { + acceptable = NetTCPIsBetween(task->receiveNext, data->sequenceNumber, task->receiveNext + task->receiveWindow - 1) + || NetTCPIsBetween(task->receiveNext, data->sequenceNumber + data->segmentLength - 1, task->receiveNext + task->receiveWindow - 1); + } + + if (!acceptable) { + // ACK the unacceptable segment (if the RST flag wasn't set). + if (~data->flags & TCP_RST) TCP_MAKE_STANDARD_REPLY(TCP_ACK); + return; + } + + { + // Truncate segments that are partially outside the window. + // TODO Test this! + + if (NetTCPIsLessThan(data->sequenceNumber, task->receiveNext)) { + data->segment = (uint8_t *) data->segment + task->receiveNext - data->sequenceNumber; + data->segmentLength -= task->receiveNext - data->sequenceNumber; + data->sequenceNumber = task->receiveNext; + } + + if (NetTCPIsLessThan(task->receiveNext + task->receiveWindow, data->sequenceNumber + data->segmentLength)) { + data->segmentLength = (task->receiveNext + task->receiveWindow) - data->sequenceNumber; + } + } + + if (data->flags & TCP_RST) { + if (task->step == TCP_STEP_SYN_RECEIVED) { + NetTaskComplete(task, ES_ERROR_CONNECTION_REFUSED); + } else if (task->step >= TCP_STEP_ESTABLISHED && task->step <= TCP_STEP_CLOSE_WAIT) { + NetTaskComplete(task, ES_ERROR_CONNECTION_RESET); + } else { + NetTaskComplete(task, ES_SUCCESS); + } + } else if (data->flags & TCP_SYN) { + TCP_MAKE_STANDARD_REPLY(TCP_RST); + NetTaskComplete(task, ES_ERROR_CONNECTION_RESET); + } else if (data->flags & TCP_ACK) { + if (task->step == TCP_STEP_SYN_RECEIVED) { + if (NetTCPIsBetween(task->sendUnacknowledged, data->ackNumber, task->sendNext)) { + task->step = TCP_STEP_ESTABLISHED; + task->sendUnacknowledged = data->ackNumber; + task->sendWindow = SwapBigEndian16(data->tcp->window); + TCP_MAKE_STANDARD_REPLY(TCP_ACK); + NetConnectionTransmitData(connection); + } else { + task->sendNext = data->ackNumber; + task->receiveNext = 0; + TCP_MAKE_STANDARD_REPLY(TCP_RST); + return; + } + } else if (task->step == TCP_STEP_LAST_ACK) { + if (NetTCPIsLessThanOrEqual(task->finSequence, task->sendUnacknowledged)) { + NetTaskComplete(task, ES_SUCCESS); + } + } else { + if (NetTCPIsBetween(task->sendUnacknowledged + 1, data->ackNumber, task->sendNext)) { + task->sendUnacknowledged = data->ackNumber; + + // Don't update the window using old packets. + if (NetTCPIsLessThan(task->sendWL1, data->sequenceNumber) + || (task->sendWL1 == data->sequenceNumber && NetTCPIsLessThanOrEqual(task->sendWL2, data->ackNumber))) { + task->sendWindow = SwapBigEndian16(data->tcp->window); + task->sendWL1 = data->sequenceNumber; + task->sendWL2 = data->ackNumber; + } + } else if (NetTCPIsLessThanOrEqual(data->ackNumber, task->sendUnacknowledged)) { + TCP_MAKE_STANDARD_REPLY(TCP_ACK); + return; + } + + if (NetTCPIsLessThanOrEqual(task->finSequence, task->sendUnacknowledged)) { + if (task->step == TCP_STEP_FIN_WAIT_1) { + task->step = TCP_STEP_FIN_WAIT_2; + } else if (task->step == TCP_STEP_CLOSING) { + NetTaskComplete(task, ES_SUCCESS); + return; + } + } + } + } + + if (task->step >= TCP_STEP_ESTABLISHED && task->step <= TCP_STEP_FIN_WAIT_2 && data->segmentLength) { + uint32_t start = data->sequenceNumber - task->receiveNext; + uint32_t end = data->sequenceNumber + data->segmentLength - task->receiveNext; + + if (start >= task->receiveWindow || end > task->receiveWindow || (end - start) >= connection->receiveBufferBytes) { + KernelPanic("NetTCPConnection - Segment %x incorrectly truncated to fit inside receive window of task %x.\n", data, task); + } + + uintptr_t startWrite = (start + connection->receiveWritePointer) % connection->receiveBufferBytes; + uintptr_t endWrite = (end + connection->receiveWritePointer) % connection->receiveBufferBytes; + + if (startWrite < endWrite) { + EsMemoryCopy(connection->receiveBuffer + startWrite, data->segment, endWrite - startWrite); +#if 0 + EsPrint("Writing segment RSN %d to %d->%d: %s\n", + data->sequenceNumber - task->initialReceive, startWrite, endWrite, + data->segmentLength, data->segment); +#endif + } else { + uintptr_t firstCopy = connection->receiveBufferBytes - startWrite; + EsMemoryCopy(connection->receiveBuffer + startWrite, data->segment, firstCopy); + EsMemoryCopy(connection->receiveBuffer, (uint8_t *) data->segment + firstCopy, endWrite); +#if 0 + EsPrint("Writing segment RSN %d to %d->%d and %d->%d: %s\n", + data->sequenceNumber - task->initialReceive, + startWrite, firstCopy, 0, endWrite, + data->segmentLength, data->segment); +#endif + } + + if (start) { + if (!connection->receivedData.Set(start, end, nullptr, true)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + return; + } + } else { + uintptr_t advanceBy = end; + + if (connection->receivedData.contiguous) { + KernelPanic("NetTCPConnection - Received data range set in %x was unexpectedly contiguous.\n", connection); + } + + if (connection->receivedData.ranges.Length()) { + if (connection->receivedData.ranges.Length() + && connection->receivedData.ranges[0].from <= advanceBy) { + advanceBy = connection->receivedData.ranges[0].to; + connection->receivedData.ranges.Delete(0); + } + + for (uintptr_t i = 0; i < connection->receivedData.ranges.Length(); i++) { + connection->receivedData.ranges[0].from -= advanceBy; + connection->receivedData.ranges[0].to -= advanceBy; + } + + connection->receivedData.Validate(); + } + + task->receiveNext += advanceBy; + connection->receiveWritePointer = (connection->receiveWritePointer + advanceBy) % connection->receiveBufferBytes; + NetConnectionUpdateReceiveWindow(connection); + + TCP_MAKE_STANDARD_REPLY(TCP_ACK); + } + } + + if (data->flags & TCP_FIN) { + task->receiveNext = data->sequenceNumber + 1; + TCP_MAKE_STANDARD_REPLY(TCP_ACK); + + if (task->step == TCP_STEP_SYN_RECEIVED || task->step == TCP_STEP_ESTABLISHED) { + task->step = TCP_STEP_CLOSE_WAIT; + } else if (task->step == TCP_STEP_FIN_WAIT_1) { + if (NetTCPIsLessThanOrEqual(task->finSequence, task->sendUnacknowledged)) { + NetTaskComplete(task, ES_SUCCESS); + } else { + task->step = TCP_STEP_CLOSING; + } + } else if (task->step == TCP_STEP_FIN_WAIT_2) { + NetTaskComplete(task, ES_SUCCESS); + } + } + } +} + +void NetAddressSetup(NetTask *_task, void *_buffer) { + EsBuffer *buffer = (EsBuffer *) _buffer; + NetAddressSetupTask *task = (NetAddressSetupTask *) _task; + NetInterface *interface = task->interface; + const DHCPHeader *dhcp; + + if (task->completed) { + return; + } else if (task->step == 0) { + // Broadcast a DHCPDISCOVER request to get an IP address. + + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + return; + } + + DHCP_START(); + + uint8_t dhcpOptions[] = { + DHCP_OPTION_MESSAGE_TYPE(DHCPDISCOVER), + 55, 2, 3 /* get the router's IP */, 6 /* get the DNS server's IP */, + 255, // End of options. + }; + + buffer.Write(dhcpOptions, sizeof(dhcpOptions)); + DHCP_END(); + + if (buffer.error) { + KernelPanic("NetAddressSetup - Network interface buffer size too small.\n"); + } + + task->dhcpTransactionID = dhcp->transactionID; + task->step++; + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } + + return; + } + + dhcp = (const DHCPHeader *) buffer->Read(sizeof(DHCPHeader)); + + if (dhcp->opCode != DHCP_BOOTREPLY /* boot reply */ + || dhcp->hardwareAddressType != 0x01 /* ethernet */ + || dhcp->hardwareAddressLength != 6 + || dhcp->transactionID != task->dhcpTransactionID + || dhcp->optionsMagic[0] != 99 + || dhcp->optionsMagic[1] != 130 + || dhcp->optionsMagic[2] != 83 + || dhcp->optionsMagic[3] != 99) { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Unsupported DHCP packet.\n"); + return; + } + + task->dhcpTransactionID = 0; + + const KIPAddress *dnsServerOption = nullptr; + const KIPAddress *serverIdentifierOption = nullptr; + const KIPAddress *routerIPOption = nullptr; + const uint8_t *messageTypeOption = nullptr; + + while (true) { + const uint8_t *optionType = (const uint8_t *) buffer->Read(sizeof(uint8_t)); + + if (!optionType) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing DHCP option type.\n"); + return; + } + + if (*optionType == 0) { + continue; + } else if (*optionType == 255) { + break; + } else { + const uint8_t *optionLength = (const uint8_t *) buffer->Read(sizeof(uint8_t)); + + if (!optionLength) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing DHCP option length.\n"); + return; + } + + const uint8_t *optionValue = (const uint8_t *) buffer->Read(*optionLength); + + if (!optionValue) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing DHCP option value.\n"); + return; + } + + if (*optionType == 6 /* DNS server */) { + if (*optionLength < 4) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "DNS server IP in DHCP option too short.\n"); + return; + } + + dnsServerOption = (const KIPAddress *) optionValue; + } else if (*optionType == 3 /* Router IP */) { + if (*optionLength < 4) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Router IP in DHCP option too short.\n"); + return; + } + + routerIPOption = (const KIPAddress *) optionValue; + } else if (*optionType == 54 /* server identifier */) { + if (*optionLength < 4) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Server identifier in DHCP option too short.\n"); + return; + } + + serverIdentifierOption = (const KIPAddress *) optionValue; + } else if (*optionType == 53 /* message type */) { + if (*optionLength < 1) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Message type in DHCP option too short.\n"); + return; + } + + messageTypeOption = (const uint8_t *) optionValue; + } + } + } + + if (!messageTypeOption) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Message type option in DHCP missing.\n"); + return; + } + + uint8_t messageType = *messageTypeOption; + + if (messageType == DHCPOFFER) { + if (task->step != 1) { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Received DHCPOFFER, but task step is %d.\n", task->step); + return; + } + + if (!serverIdentifierOption) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Server identifier option missing in DHCPOFFER.\n"); + return; + } + + KIPAddress offer = dhcp->yourIPAddress; + KernelLog(LOG_INFO, "Networking", "received IP", "Network interface %x has been offered IP address %d.%d.%d.%d.\n", + interface, offer.d[0], offer.d[1], offer.d[2], offer.d[3]); + + // Broadcast a DHCPREQUEST message to accept this IP address. + + EsBuffer buffer = NetTransmitBufferGet(); + if (buffer.error) return; + DHCP_START(); + + uint8_t dhcpOptions[] = { + DHCP_OPTION_MESSAGE_TYPE(DHCPREQUEST), + DHCP_OPTION_REQUESTED_IP(offer), + DHCP_OPTION_SERVER_IDENTIFIER(*serverIdentifierOption), + 55, 2, 3 /* get the router's IP */, 6 /* get the DNS server's IP */, + 255, // End of options. + }; + + buffer.Write(dhcpOptions, sizeof(dhcpOptions)); + DHCP_END(); + + if (buffer.error) { + KernelPanic("KNetworkInterface::ReceiveDHCPReply - Network interface buffer size too small.\n"); + } + + task->dhcpTransactionID = dhcp->transactionID; + task->step++; + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } + } else if (messageType == DHCPACK) { + if (task->step != 2) { + KernelLog(LOG_ERROR, "Networking", "ignored packet", "Received DHCPACK, but task step is %d.\n", task->step); + return; + } + + if (!dnsServerOption || !serverIdentifierOption || !routerIPOption) { + KernelLog(LOG_ERROR, "Networking", "bad packet", "Missing options in DHCPACK.\n"); + return; + } + + interface->ipAddress = dhcp->yourIPAddress; + interface->routerIP = *routerIPOption; + interface->dnsServerIP = *dnsServerOption; + interface->serverIdentifier = *serverIdentifierOption; + + KernelLog(LOG_INFO, "Networking", "accepted IP", + "Network interface %x has accepted IP address %d.%d.%d.%d with DNS server %d.%d.%d.%d and router %d.%d.%d.%d.\n", + interface, dhcp->yourIPAddress.d[0], dhcp->yourIPAddress.d[1], dhcp->yourIPAddress.d[2], dhcp->yourIPAddress.d[3], + dnsServerOption->d[0], dnsServerOption->d[1], dnsServerOption->d[2], dnsServerOption->d[3], + routerIPOption->d[0], routerIPOption->d[1], routerIPOption->d[2], routerIPOption->d[3]); + + task->changedState = true; + NetTaskComplete(task, ES_SUCCESS); + } else if (messageType == DHCPNAK) { + KernelLog(LOG_INFO, "Networking", "lost IP", "Network interface %x has lost IP address %d.%d.%d.%d.\n", + interface, interface->ipAddress.d[0], interface->ipAddress.d[1], interface->ipAddress.d[2], interface->ipAddress.d[3]); + task->changedState = true; + NetTaskComplete(task, ES_ERROR_LOST_IP_ADDRESS); + } +} + +void NetTaskBegin(NetTask *task) { + if (!task->interface) { + KMutexAcquire(&networking.interfacesListMutex); + SimpleList *item = networking.interfaces.first; + + while (item && item != &networking.interfaces) { + NetInterface *interface = EsContainerOf(NetInterface, item, item); + KWriterLockTake(&interface->connectionLock, K_LOCK_SHARED); + + if (interface->connected && interface->hasIP) { + task->interface = interface; + break; + } + + KWriterLockReturn(&interface->connectionLock, K_LOCK_SHARED); + item = item->next; + } + + KMutexRelease(&networking.interfacesListMutex); + } else { + KWriterLockTake(&task->interface->connectionLock, K_LOCK_SHARED); + } + + if (!task->interface) { + NetTaskComplete(task, ES_ERROR_NO_CONNECTED_NETWORK_INTERFACES); + } else { + task->index = 0xFFFF; + task->callback(task, nullptr); + KWriterLockReturn(&task->interface->connectionLock, K_LOCK_SHARED); + } +} + +void NetTaskComplete(NetTask *task, EsError error) { + KWriterLockAssertShared(&task->interface->connectionLock); + + if (task->completed) { + KernelPanic("NetTaskComplete - Task already completed.\n"); + } + + task->error = error; + task->completed = true; + task->callback(task, nullptr); +} + +void NetConnectionDestroy(NetConnection *connection) { + MMFree(kernelMMSpace, connection->sendBuffer, connection->sendBufferBytes + connection->receiveBufferBytes); + connection->receivedData.ranges.Free(); + CloseHandleToObject(connection->bufferRegion, KERNEL_OBJECT_SHMEM); + EsHeapFree(connection, sizeof(NetConnection), K_FIXED); +} + +NetConnection *NetConnectionOpen(EsAddress *address, size_t sendBufferBytes, size_t receiveBufferBytes, uint32_t flags) { + (void) flags; + + NetConnection *connection = (NetConnection *) EsHeapAllocate(sizeof(NetConnection), true, K_FIXED); + + if (!connection) { + return nullptr; + } + + connection->sendBufferBytes = sendBufferBytes; + connection->receiveBufferBytes = receiveBufferBytes; + connection->address = *address; + connection->handles = 2; + + connection->bufferRegion = MMSharedCreateRegion(sendBufferBytes + receiveBufferBytes, true); + + if (!connection->bufferRegion) { + EsHeapFree(connection, sizeof(NetConnection), K_FIXED); + return nullptr; + } + + connection->sendBuffer = (uint8_t *) MMMapShared(kernelMMSpace, connection->bufferRegion, 0, sendBufferBytes + receiveBufferBytes); + connection->receiveBuffer = connection->sendBuffer + sendBufferBytes; + + connection->task.callback = NetTCPConnection; + connection->task.receiveWindow = MinimumInteger(receiveBufferBytes - 1, 0xF000); + NetTaskBegin(&connection->task); + + return connection; +} + +void NetConnectionClose(NetConnection *connection) { + bool destroy = false; + + NetTCPConnectionTask *task = &connection->task; + NetInterface *interface = task->interface; + KWriterLockTake(&interface->connectionLock, K_LOCK_SHARED); + KMutexAcquire(&connection->mutex); + connection->handles++; // Prevent NetTaskComplete from destroying the connection. + + if (task->completed) { + destroy = true; + } else if (task->step == TCP_STEP_SYN_RECEIVED || task->step == TCP_STEP_ESTABLISHED || task->step == TCP_STEP_CLOSE_WAIT) { + // Send a FIN packet. + + EsBuffer buffer = NetTransmitBufferGet(); + + if (buffer.error) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } else { + EthernetHeader *ethernet = (EthernetHeader *) buffer.Write(nullptr, sizeof(EthernetHeader)); + ETHERNET_HEADER(ethernet, ETHERNET_TYPE_IPV4, task->destinationMAC); + IPHeader *ip = (IPHeader *) buffer.Write(nullptr, sizeof(IPHeader)); + IP_HEADER(ip, *(KIPAddress *) &connection->address.ipv4, IP_PROTOCOL_TCP); + TCPHeader *tcp = (TCPHeader *) buffer.Write(nullptr, sizeof(TCPHeader)); + + if (buffer.error) { + KernelPanic("NetConnectionClose - Network interface buffer size too small.\n"); + } + + ip->totalLength = ByteSwap16(buffer.position - sizeof(*ethernet)); + ip->flagsAndFragmentOffset = SwapBigEndian16(1 << 14 /* do not fragment */); + ip->headerChecksum = ip->CalculateHeaderChecksum(); + + tcp->sourcePort = SwapBigEndian16(task->index + TCP_PORT_BASE); + tcp->destinationPort = SwapBigEndian16(connection->address.port); + tcp->flags = SwapBigEndian16(TCP_FIN | TCP_ACK | (5 << 12 /* header is 5 DWORDs */)); + tcp->sequenceNumber = SwapBigEndian32(task->sendNext); + tcp->ackNumber = SwapBigEndian32(task->receiveNext); + tcp->window = SwapBigEndian16(task->receiveWindow); + + task->finSequence = task->sendNext; + task->sendNext++; + task->step = TCP_STEP_FIN_WAIT_1; + + if (!NetTransmit(interface, &buffer, NET_PACKET_ETHERNET)) { + NetTaskComplete(task, ES_ERROR_INSUFFICIENT_RESOURCES); + } + } + } + + connection->handles--; + KMutexRelease(&connection->mutex); + KWriterLockReturn(&interface->connectionLock, K_LOCK_SHARED); + + if (destroy) { + NetConnectionDestroy(connection); + } +} + +void KRegisterNetInterface(NetInterface *interface) { + KernelLog(LOG_INFO, "Networking", "register interface", "Registered interface with MAC address %X:%X:%X:%X:%X:%X and name '%z'.\n", + interface->macAddress.d[0], interface->macAddress.d[1], interface->macAddress.d[2], + interface->macAddress.d[3], interface->macAddress.d[4], interface->macAddress.d[5], + interface->cDebugName); + + KMutexAcquire(&networking.interfacesListMutex); + networking.interfaces.Insert(&interface->item, false /* end */); + KMutexRelease(&networking.interfacesListMutex); + + interface->addressSetupTask.interface = interface; + interface->addressSetupTask.callback = NetAddressSetup; +} + +void NetInitialise(KDevice *) { + networking.udpTaskBitset.Initialise(MAX_UDP_TASKS); + networking.udpTaskBitset.PutAll(); + EsArenaInitialise(&networking.transmitBufferPool, 1048576, 2048); + + networking.tcpTaskLRU = networking.tcpTaskMRU = 0xFFFF; + + for (uintptr_t i = 0; i < MAX_TCP_TASKS; i++) { + NetTCPFreeTaskIndex(i, true); + } +} + +KDriver driverNetworking = { + .attach = NetInitialise, +}; + +#endif diff --git a/kernel/objects.cpp b/kernel/objects.cpp new file mode 100644 index 0000000..ed3da60 --- /dev/null +++ b/kernel/objects.cpp @@ -0,0 +1,701 @@ +// TODO Reject opening handles if the handle table has been destroyed!! + +#ifndef IMPLEMENTATION + +inline KernelObjectType operator|(KernelObjectType a, KernelObjectType b) { + return (KernelObjectType) ((int) a | (int) b); +} + +struct Handle { + void *object; + uint32_t flags; + KernelObjectType type; +}; + +struct ConstantBuffer { + volatile size_t handles; + size_t bytes : 48, + isPaged : 1; + // Data follows. +}; + +struct Pipe { +#define PIPE_READER (1) +#define PIPE_WRITER (2) +#define PIPE_BUFFER_SIZE (K_PAGE_SIZE) +#define PIPE_CLOSED (0) + + volatile char buffer[PIPE_BUFFER_SIZE]; + volatile size_t writers, readers; + volatile uintptr_t writePosition, readPosition, unreadData; + KEvent canWrite, canRead; + KMutex mutex; + + size_t Access(void *buffer, size_t bytes, bool write, bool userBlockRequest); +}; + +struct EventSink { + KEvent available; + KSpinlock spinlock; // Take after the scheduler's spinlock. + volatile size_t handles; + uintptr_t queuePosition; + size_t queueCount; + bool overflow, ignoreDuplicates; + EsGeneric queue[ES_MAX_EVENT_SINK_BUFFER_SIZE]; + + EsError Push(EsGeneric data); +}; + +struct EventSinkTable { + EventSink *sink; + EsGeneric data; +}; + +size_t totalHandleCount; + +struct HandleTableL2 { +#define HANDLE_TABLE_L2_ENTRIES (256) + Handle t[HANDLE_TABLE_L2_ENTRIES]; +}; + +struct HandleTableL1 { +#define HANDLE_TABLE_L1_ENTRIES (256) + HandleTableL2 *t[HANDLE_TABLE_L1_ENTRIES]; + uint16_t u[HANDLE_TABLE_L1_ENTRIES]; +}; + +struct HandleTable { + HandleTableL1 l1r; + KMutex lock; + Process *process; + bool destroyed; + uint32_t handleCount; + + EsHandle OpenHandle(void *_object, uint32_t _flags, KernelObjectType _type, EsHandle at = ES_INVALID_HANDLE); + bool CloseHandle(EsHandle handle); + + // Resolve the handle if it is valid and return the type in type. + // The initial value of type is used as a mask of expected object types for the handle. + void ResolveHandle(struct KObject *object, EsHandle handle); + + void Destroy(); +}; + +struct KObject { + void Initialise(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type); + + KObject() { EsMemoryZero(this, sizeof(*this)); } + KObject(Process *process, EsHandle _handle, KernelObjectType _type); + KObject(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type); + + ~KObject() { + if (!checked && valid) { + KernelPanic("KObject - Object not checked!\n"); + } + + if (parentObject && close) { + CloseHandleToObject(parentObject, parentType, parentFlags); + } + } + + void *object, *parentObject; + uint32_t flags, parentFlags; + KernelObjectType type, parentType; + bool valid, checked, close, softFailure; +}; + +void InitialiseObjectManager(); + +#endif + +#ifdef IMPLEMENTATION + +KObject::KObject(Process *process, EsHandle _handle, KernelObjectType _type) { + EsMemoryZero(this, sizeof(*this)); + Initialise(&process->handleTable, _handle, _type); +} + +KObject::KObject(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type) { + EsMemoryZero(this, sizeof(*this)); + Initialise(handleTable, _handle, _type); +} + +void KObject::Initialise(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type) { + type = _type; + + handleTable->ResolveHandle(this, _handle); + parentObject = object, parentType = type, parentFlags = flags; + + if (!valid) { + KernelLog(LOG_ERROR, "Object Manager", "invalid handle", "KObject::Initialise - Invalid handle %d for type mask %x.\n", _handle, _type); + } +} + +// A lock used to change the handle count on several objects. +// TODO Make changing handle count lockless wherever possible? +KMutex objectHandleCountChange; + +// TODO Use uint64_t for handle counts, or restrict OpenHandleToObject to some maximum (...but most callers don't check if OpenHandleToObject succeeds). + +bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags, bool maybeHasNoHandles) { + bool hadNoHandles = false, failed = false; + + switch (type) { + case KERNEL_OBJECT_EVENT: { + KMutexAcquire(&objectHandleCountChange); + KEvent *event = (KEvent *) object; + if (!event->handles) hadNoHandles = true; + else event->handles++; + KMutexRelease(&objectHandleCountChange); + } break; + + case KERNEL_OBJECT_PROCESS: { + KSpinlockAcquire(&scheduler.lock); + Process *process = (Process *) object; + if (!process->handles) hadNoHandles = true; + else process->handles++; // NOTE Scheduler::OpenProcess and MMBalanceThread also adjust process handles. + KernelLog(LOG_VERBOSE, "Scheduler", "open process handle", "Opened handle to process %d; %d handles.\n", process->id, process->handles); + KSpinlockRelease(&scheduler.lock); + } break; + + case KERNEL_OBJECT_THREAD: { + KSpinlockAcquire(&scheduler.lock); + Thread *thread = (Thread *) object; + if (!thread->handles) hadNoHandles = true; + else thread->handles++; + KSpinlockRelease(&scheduler.lock); + } break; + + case KERNEL_OBJECT_SHMEM: { + MMSharedRegion *region = (MMSharedRegion *) object; + KMutexAcquire(®ion->mutex); + if (!region->handles) hadNoHandles = true; + else region->handles++; + KMutexRelease(®ion->mutex); + } break; + + case KERNEL_OBJECT_WINDOW: { + // NOTE The handle count of Window object is modified elsewhere. + Window *window = (Window *) object; + hadNoHandles = 0 == __sync_fetch_and_add(&window->handles, 1); + } break; + + case KERNEL_OBJECT_EMBEDDED_WINDOW: { + EmbeddedWindow *window = (EmbeddedWindow *) object; + hadNoHandles = 0 == __sync_fetch_and_add(&window->handles, 1); + } break; + + case KERNEL_OBJECT_CONSTANT_BUFFER: { + ConstantBuffer *buffer = (ConstantBuffer *) object; + KMutexAcquire(&objectHandleCountChange); + if (!buffer->handles) hadNoHandles = true; + else buffer->handles++; + KMutexRelease(&objectHandleCountChange); + } break; + +#ifdef ENABLE_POSIX_SUBSYSTEM + case KERNEL_OBJECT_POSIX_FD: { + POSIXFile *file = (POSIXFile *) object; + KMutexAcquire(&file->mutex); + if (!file->handles) hadNoHandles = true; + else file->handles++; + KMutexRelease(&file->mutex); + } break; +#endif + + case KERNEL_OBJECT_NODE: { + failed = ES_SUCCESS != FSNodeOpenHandle((KNode *) object, flags, FS_NODE_OPEN_HANDLE_STANDARD); + } break; + + case KERNEL_OBJECT_PIPE: { + Pipe *pipe = (Pipe *) object; + KMutexAcquire(&pipe->mutex); + + if (((flags & PIPE_READER) && !pipe->readers) + || ((flags & PIPE_WRITER) && !pipe->writers)) { + hadNoHandles = true; + } else { + if (flags & PIPE_READER) { + pipe->readers++; + } + + if (flags & PIPE_WRITER) { + pipe->writers++; + } + } + + KMutexRelease(&pipe->mutex); + } break; + + case KERNEL_OBJECT_EVENT_SINK: { + EventSink *sink = (EventSink *) object; + KSpinlockAcquire(&sink->spinlock); + if (!sink->handles) hadNoHandles = true; + else sink->handles++; + KSpinlockRelease(&sink->spinlock); + } break; + + case KERNEL_OBJECT_CONNECTION: { + NetConnection *connection = (NetConnection *) object; + hadNoHandles = 0 == __sync_fetch_and_add(&connection->handles, 1); + } break; + + default: { + KernelPanic("OpenHandleToObject - Cannot open object of type %x.\n", type); + } break; + } + + if (hadNoHandles) { + if (maybeHasNoHandles) { + return false; + } else { + KernelPanic("OpenHandleToObject - Object %x of type %x had no handles.\n", object, type); + } + } + + return !failed; +} + +void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags) { + switch (type) { + case KERNEL_OBJECT_PROCESS: { + CloseHandleToProcess(object); + } break; + + case KERNEL_OBJECT_THREAD: { + CloseHandleToThread(object); + } break; + + case KERNEL_OBJECT_NODE: { + FSNodeCloseHandle((KNode *) object, flags); + } break; + + case KERNEL_OBJECT_EVENT: { + KEvent *event = (KEvent *) object; + KMutexAcquire(&objectHandleCountChange); + bool destroy = event->handles == 1; + event->handles--; + KMutexRelease(&objectHandleCountChange); + + if (destroy) { + if (event->sinkTable) { + for (uintptr_t i = 0; i < ES_MAX_EVENT_FORWARD_COUNT; i++) { + if (event->sinkTable[i].sink) { + CloseHandleToObject(event->sinkTable[i].sink, KERNEL_OBJECT_EVENT_SINK, 0); + } + } + + EsHeapFree(event->sinkTable, sizeof(EventSinkTable) * ES_MAX_EVENT_FORWARD_COUNT, K_FIXED); + } + + EsHeapFree(event, sizeof(KEvent), K_FIXED); + } + } break; + + case KERNEL_OBJECT_CONSTANT_BUFFER: { + ConstantBuffer *buffer = (ConstantBuffer *) object; + KMutexAcquire(&objectHandleCountChange); + bool destroy = buffer->handles == 1; + buffer->handles--; + KMutexRelease(&objectHandleCountChange); + + if (destroy) { + EsHeapFree(object, sizeof(ConstantBuffer) + buffer->bytes, buffer->isPaged ? K_PAGED : K_FIXED); + } + } break; + + case KERNEL_OBJECT_SHMEM: { + MMSharedRegion *region = (MMSharedRegion *) object; + KMutexAcquire(®ion->mutex); + bool destroy = region->handles == 1; + region->handles--; + KMutexRelease(®ion->mutex); + + if (destroy) { + MMSharedDestroyRegion(region); + } + } break; + + case KERNEL_OBJECT_WINDOW: { + Window *window = (Window *) object; + unsigned previous = __sync_fetch_and_sub(&window->handles, 1); + if (!previous) KernelPanic("CloseHandleToObject - Window %x has no handles.\n", window); + + if (previous == 2) { + KEventSet(&windowManager.windowsToCloseEvent, false, true /* maybe already set */); + } else if (previous == 1) { + window->Destroy(); + } + } break; + + case KERNEL_OBJECT_EMBEDDED_WINDOW: { + EmbeddedWindow *window = (EmbeddedWindow *) object; + unsigned previous = __sync_fetch_and_sub(&window->handles, 1); + if (!previous) KernelPanic("CloseHandleToObject - EmbeddedWindow %x has no handles.\n", window); + + if (previous == 2) { + KEventSet(&windowManager.windowsToCloseEvent, false, true /* maybe already set */); + } else if (previous == 1) { + window->Destroy(); + } + } break; + +#ifdef ENABLE_POSIX_SUBSYSTEM + case KERNEL_OBJECT_POSIX_FD: { + POSIXFile *file = (POSIXFile *) object; + KMutexAcquire(&file->mutex); + file->handles--; + bool destroy = !file->handles; + KMutexRelease(&file->mutex); + + if (destroy) { + if (file->type == POSIX_FILE_NORMAL || file->type == POSIX_FILE_DIRECTORY) CloseHandleToObject(file->node, KERNEL_OBJECT_NODE, file->openFlags); + if (file->type == POSIX_FILE_PIPE) CloseHandleToObject(file->pipe, KERNEL_OBJECT_PIPE, file->openFlags); + EsHeapFree(file->path, 0, K_FIXED); + EsHeapFree(file->directoryBuffer, file->directoryBufferLength, K_PAGED); + EsHeapFree(file, sizeof(POSIXFile), K_FIXED); + } + } break; +#endif + + case KERNEL_OBJECT_PIPE: { + Pipe *pipe = (Pipe *) object; + KMutexAcquire(&pipe->mutex); + + if (flags & PIPE_READER) { + pipe->readers--; + + if (!pipe->readers) { + // If there are no more readers, wake up any blocking writers. + KEventSet(&pipe->canWrite, false, true); + } + } + + if (flags & PIPE_WRITER) { + pipe->writers--; + + if (!pipe->writers) { + // If there are no more writers, wake up any blocking readers. + KEventSet(&pipe->canRead, false, true); + } + } + + bool destroy = pipe->readers == 0 && pipe->writers == 0; + + KMutexRelease(&pipe->mutex); + + if (destroy) { + EsHeapFree(pipe, sizeof(Pipe), K_PAGED); + } + } break; + + case KERNEL_OBJECT_EVENT_SINK: { + EventSink *sink = (EventSink *) object; + KSpinlockAcquire(&sink->spinlock); + bool destroy = sink->handles == 1; + sink->handles--; + KSpinlockRelease(&sink->spinlock); + + if (destroy) { + EsHeapFree(sink, sizeof(EventSink), K_FIXED); + } + } break; + + case KERNEL_OBJECT_CONNECTION: { + NetConnection *connection = (NetConnection *) object; + unsigned previous = __sync_fetch_and_sub(&connection->handles, 1); + if (!previous) KernelPanic("CloseHandleToObject - NetConnection %x has no handles.\n", connection); + if (previous == 1) NetConnectionClose(connection); + } break; + + default: { + KernelPanic("CloseHandleToObject - Cannot close object of type %x.\n", type); + } break; + } +} + +bool HandleTable::CloseHandle(EsHandle handle) { + if (handle > HANDLE_TABLE_L1_ENTRIES * HANDLE_TABLE_L2_ENTRIES) { + return false; + } + + KMutexAcquire(&lock); + HandleTableL1 *l1 = &l1r; + HandleTableL2 *l2 = l1->t[handle / HANDLE_TABLE_L2_ENTRIES]; + if (!l2) { KMutexRelease(&lock); return false; } + Handle *_handle = l2->t + (handle % HANDLE_TABLE_L2_ENTRIES); + KernelObjectType type = _handle->type; + uint64_t flags = _handle->flags; + void *object = _handle->object; + if (!object) { KMutexRelease(&lock); return false; } + EsMemoryZero(_handle, sizeof(Handle)); + l1->u[handle / HANDLE_TABLE_L2_ENTRIES]--; + handleCount--; + KMutexRelease(&lock); + + __sync_fetch_and_sub(&totalHandleCount, 1); + CloseHandleToObject(object, type, flags); + return true; +} + +void HandleTable::ResolveHandle(KObject *object, EsHandle handle) { + KernelObjectType requestedType = object->type; + object->type = COULD_NOT_RESOLVE_HANDLE; + + // Special handles. + if (handle == ES_CURRENT_THREAD && (requestedType & KERNEL_OBJECT_THREAD)) { + object->type = KERNEL_OBJECT_THREAD, object->valid = true, object->object = GetCurrentThread(); + return; + } else if (handle == ES_CURRENT_PROCESS && (requestedType & KERNEL_OBJECT_PROCESS)) { + object->type = KERNEL_OBJECT_PROCESS, object->valid = true, object->object = GetCurrentThread()->process; + return; + } else if (handle == ES_INVALID_HANDLE && (requestedType & KERNEL_OBJECT_NONE)) { + object->type = KERNEL_OBJECT_NONE, object->valid = true; + return; + } + + // Check that the handle is within the correct bounds. + if ((!handle) || handle >= HANDLE_TABLE_L1_ENTRIES * HANDLE_TABLE_L2_ENTRIES) { + return; + } + + KMutexAcquire(&lock); + EsDefer(KMutexRelease(&lock)); + + HandleTableL2 *l2 = l1r.t[handle / HANDLE_TABLE_L2_ENTRIES]; + + if (l2) { + Handle *_handle = l2->t + (handle % HANDLE_TABLE_L2_ENTRIES); + + if ((_handle->type & requestedType) && (_handle->object)) { + // Open a handle to the object so that it can't be destroyed while the system call is still using it. + // The handle is closed in the KObject's destructor. + if (OpenHandleToObject(_handle->object, _handle->type, _handle->flags)) { + object->type = _handle->type, object->object = _handle->object, object->flags = _handle->flags; + object->valid = object->close = true; + } + } + } +} + +// TODO Switch the order of flags and type, so that the default value of flags can be 0. +EsHandle HandleTable::OpenHandle(void *object, uint32_t flags, KernelObjectType type, EsHandle at) { + KMutexAcquire(&lock); + EsDefer(KMutexRelease(&lock)); + + Handle handle = {}; + handle.object = object; + handle.flags = flags; + handle.type = type; + + { + if (destroyed) goto error; + + if (!handle.object) { + KernelPanic("HandleTable::OpenHandle - Invalid object.\n"); + } + + HandleTableL1 *l1 = &l1r; + uintptr_t l1Index = HANDLE_TABLE_L1_ENTRIES; + + for (uintptr_t i = 1 /* The first set of handles are reserved. */; i < HANDLE_TABLE_L1_ENTRIES; i++) { + if (at) i = at / HANDLE_TABLE_L2_ENTRIES; + + if (l1->u[i] != HANDLE_TABLE_L2_ENTRIES) { + l1->u[i]++; + handleCount++; + l1Index = i; + break; + } + + if (at) goto error; + } + + if (l1Index == HANDLE_TABLE_L1_ENTRIES) goto error; + + if (!l1->t[l1Index]) l1->t[l1Index] = (HandleTableL2 *) EsHeapAllocate(sizeof(HandleTableL2), true, K_FIXED); + HandleTableL2 *l2 = l1->t[l1Index]; + uintptr_t l2Index = HANDLE_TABLE_L2_ENTRIES; + + for (uintptr_t i = 0; i < HANDLE_TABLE_L2_ENTRIES; i++) { + if (at) i = at % HANDLE_TABLE_L2_ENTRIES; + + if (!l2->t[i].object) { + l2Index = i; + break; + } + + if (at) goto error; + } + + if (l2Index == HANDLE_TABLE_L2_ENTRIES) KernelPanic("HandleTable::OpenHandle - Unexpected lack of free handles.\n"); + Handle *_handle = l2->t + l2Index; + *_handle = handle; + + __sync_fetch_and_add(&totalHandleCount, 1); + + EsHandle index = l2Index + (l1Index * HANDLE_TABLE_L2_ENTRIES); + return index; + } + + error:; + // TODO Close the handle to the object with CloseHandleToObject? + return ES_INVALID_HANDLE; +} + +void HandleTable::Destroy() { + KMutexAcquire(&lock); + EsDefer(KMutexRelease(&lock)); + + if (destroyed) { + return; + } + + destroyed = true; + HandleTableL1 *l1 = &l1r; + + for (uintptr_t i = 0; i < HANDLE_TABLE_L1_ENTRIES; i++) { + if (!l1->u[i]) continue; + + for (uintptr_t k = 0; k < HANDLE_TABLE_L2_ENTRIES; k++) { + Handle *handle = &l1->t[i]->t[k]; + if (handle->object) CloseHandleToObject(handle->object, handle->type, handle->flags); + } + + EsHeapFree(l1->t[i], 0, K_FIXED); + } +} + +ConstantBuffer *MakeConstantBuffer(K_USER_BUFFER const void *data, size_t bytes) { + ConstantBuffer *buffer = (ConstantBuffer *) EsHeapAllocate(sizeof(ConstantBuffer) + bytes, false, K_FIXED); + if (!buffer) return nullptr; + EsMemoryZero(buffer, sizeof(ConstantBuffer)); + buffer->handles = 1; + buffer->bytes = bytes; + EsMemoryCopy(buffer + 1, data, buffer->bytes); + return buffer; +} + +EsHandle MakeConstantBuffer(K_USER_BUFFER const void *data, size_t bytes, Process *process) { + void *object = MakeConstantBuffer(data, bytes); + + if (!object) { + return ES_INVALID_HANDLE; + } + + EsHandle h = process->handleTable.OpenHandle(object, 0, KERNEL_OBJECT_CONSTANT_BUFFER); + + if (h == ES_INVALID_HANDLE) { + CloseHandleToObject(object, KERNEL_OBJECT_CONSTANT_BUFFER, 0); + return ES_INVALID_HANDLE; + } + + return h; +} + +EsHandle MakeConstantBufferForDesktop(K_USER_BUFFER const void *data, size_t bytes) { + return MakeConstantBuffer(data, bytes, desktopProcess); +} + +size_t Pipe::Access(void *_buffer, size_t bytes, bool write, bool user) { + size_t amount = 0; + Thread *currentThread = GetCurrentThread(); + // EsPrint("--> %z %d\n", write ? "Write" : "Read", bytes); + + while (bytes) { + if (user) currentThread->terminatableState = THREAD_USER_BLOCK_REQUEST; + + if (write) { + // Wait until we can write to the pipe. + KEventWait(&canWrite, ES_WAIT_NO_TIMEOUT); + } else { + // Wait until we can read from the pipe. + KEventWait(&canRead, ES_WAIT_NO_TIMEOUT); + } + + if (user) { + currentThread->terminatableState = THREAD_IN_SYSCALL; + if (currentThread->terminating) goto done; + } + + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + if (write) { + // EsPrint("Write:\n"); + + size_t spaceAvailable = PIPE_BUFFER_SIZE - unreadData; + size_t toWrite = bytes > spaceAvailable ? spaceAvailable : bytes; + + size_t spaceAvailableRight = PIPE_BUFFER_SIZE - writePosition; + size_t toWriteRight = toWrite > spaceAvailableRight ? spaceAvailableRight : toWrite; + size_t toWriteLeft = toWrite - toWriteRight; + + // EsPrint("\tunread: %d; wp: %d\n", unreadData, writePosition); + // EsPrint("\t%d, %d, %d, %d, %d\n", spaceAvailable, spaceAvailableRight, toWrite, toWriteRight, toWriteLeft); + + EsMemoryCopy((uint8_t *) buffer + writePosition, _buffer, toWriteRight); + EsMemoryCopy((uint8_t *) buffer, (uint8_t *) _buffer + toWriteRight, toWriteLeft); + + writePosition += toWrite; + writePosition %= PIPE_BUFFER_SIZE; + unreadData += toWrite; + bytes -= toWrite; + _buffer = (uint8_t *) _buffer + toWrite; + amount += toWrite; + + KEventSet(&canRead, false, true); + + if (!readers) { + // EsPrint("\tPipe closed\n"); + // Nobody is reading from the pipe, so there's no point writing to it. + goto done; + } else if (PIPE_BUFFER_SIZE == unreadData) { + KEventReset(&canWrite); + // EsPrint("\treset canWrite\n"); + } + } else { + // EsPrint("Read:\n"); + + size_t dataAvailable = unreadData; + size_t toRead = bytes > dataAvailable ? dataAvailable : bytes; + + size_t spaceAvailableRight = PIPE_BUFFER_SIZE - readPosition; + size_t toReadRight = toRead > spaceAvailableRight ? spaceAvailableRight : toRead; + size_t toReadLeft = toRead - toReadRight; + + // EsPrint("\tunread: %d; rp: %d\n", unreadData, readPosition); + // EsPrint("\t%d, %d, %d, %d, %d\n", dataAvailable, spaceAvailableRight, toRead, toReadRight, toReadLeft); + + EsMemoryCopy(_buffer, (uint8_t *) buffer + readPosition, toReadRight); + EsMemoryCopy((uint8_t *) _buffer + toReadRight, (uint8_t *) buffer, toReadLeft); + + readPosition += toRead; + readPosition %= PIPE_BUFFER_SIZE; + unreadData -= toRead; + bytes -= toRead; + _buffer = (uint8_t *) _buffer + toRead; + amount += toRead; + + KEventSet(&canWrite, false, true); + + if (!writers) { + // Nobody is writing to the pipe, so there's no point reading from it. + // EsPrint("\tPipe closed\n"); + goto done; + } else if (!unreadData) { + KEventReset(&canRead); + } + + // Don't block when reading from pipes after the first chunk of data. + // TODO Change this behaviour? + goto done; + } + } + + done:; + // EsPrint("<-- %d (%d remaining, %z)\n", amount, bytes, write ? "Write" : "Read"); + return amount; +} + +#endif diff --git a/kernel/posix.cpp b/kernel/posix.cpp new file mode 100644 index 0000000..7fd0436 --- /dev/null +++ b/kernel/posix.cpp @@ -0,0 +1,821 @@ +#ifndef IMPLEMENTATION + +struct POSIXFile { + uint64_t posixFlags; // The flags given in SYS_open. + volatile size_t handles; + char *path; // Resolved path. + EsFileOffset offsetIntoFile; + uint64_t openFlags; // The flags used to open the object. + KMutex mutex; + KNode *node; + Pipe *pipe; + void *directoryBuffer; + size_t directoryBufferLength; + +#define POSIX_FILE_TERMINAL (1) +#define POSIX_FILE_NORMAL (2) +#define POSIX_FILE_PIPE (3) +#define POSIX_FILE_ZERO (4) +#define POSIX_FILE_NULL (5) +#define POSIX_FILE_DIRECTORY (6) + int type; +}; + +namespace POSIX { + uintptr_t DoSyscall(_EsPOSIXSyscall syscall, uintptr_t *userStackPointer); + KMutex forkMutex; + KMutex threadPOSIXDataMutex; +} + +struct POSIXThread { + void *forkStack; + size_t forkStackSize; + uintptr_t forkUSP; + Process *forkProcess; +}; + +#define SYSCALL_BUFFER_POSIX(address, length, index, write) \ + MMRegion *_region ## index = MMFindAndPinRegion(currentVMM, (address), (length)); \ + if (!_region ## index && !fromKernel) { KernelLog(LOG_ERROR, "POSIX", "EFAULT", "POSIX application EFAULT at %x.\n", address); return -EFAULT; } \ + EsDefer(if (_region ## index) MMUnpinRegion(currentVMM, _region ## index)); \ + if (write && (_region ## index->flags & MM_REGION_READ_ONLY) && (~_region ## index->flags & MM_REGION_COPY_ON_WRITE)) \ + { KernelLog(LOG_ERROR, "POSIX", "EFAULT", "POSIX application EFAULT (2) at %x.\n", address); return -EFAULT; } +#define SYSCALL_BUFFER_ALLOW_NULL_POSIX(address, length, index) \ + MMRegion *_region ## index = MMFindAndPinRegion(currentVMM, (address), (length)); \ + EsDefer(if (_region ## index) MMUnpinRegion(currentVMM, _region ## index)); + +#define SYSCALL_HANDLE_POSIX(handle, __object, index) \ + KObject _object ## index(handleTable, ConvertStandardInputTo3(handle), KERNEL_OBJECT_POSIX_FD); \ + *((void **) &__object) = _object ## index .object; \ + if (! _object ## index .valid) return -EBADF; else _object ## index .checked = true; \ + +#endif + +#ifdef IMPLEMENTATION + +#define _POSIX_SOURCE +#define _GNU_SOURCE + +namespace POSIX { + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + EsHandle ConvertStandardInputTo3(EsHandle handle) { + if (handle) { + return handle; + } else { + return 3; + } + } + + intptr_t Read(POSIXFile *file, K_USER_BUFFER void *base, size_t length, bool baseMappedToFile) { + if (!length) return 0; + + // EsPrint("Read %d bytes from %x into %x\n", length, file, base); + + if (file->type == POSIX_FILE_TERMINAL) { + return 0; + } else if (file->type == POSIX_FILE_PIPE) { + return file->pipe->Access(base, length, false, true); + } else if (file->type == POSIX_FILE_NORMAL) { + // EsPrint("READ '%z' %d/%d\n", file->path, file->offsetIntoFile, length); + KMutexAcquire(&file->mutex); + EsDefer(KMutexRelease(&file->mutex)); + size_t count = FSFileReadSync(file->node, (void *) base, file->offsetIntoFile, length, baseMappedToFile ? FS_FILE_ACCESS_USER_BUFFER_MAPPED : 0); + if (ES_CHECK_ERROR(count)) return -EIO; + else { file->offsetIntoFile += count; return count; } + } else if (file->type == POSIX_FILE_ZERO) { + EsMemoryZero(base, length); + return length; + } else if (file->type == POSIX_FILE_NULL) { + return 0; + } else if (file->type == POSIX_FILE_DIRECTORY) { + return 0; + } + + return -EACCES; + } + + intptr_t Write(POSIXFile *file, K_USER_BUFFER void *base, size_t length, bool baseMappedToFile) { + if (file->posixFlags & O_APPEND) { + // TODO Make this atomic. + file->offsetIntoFile = file->node->directoryEntry->totalSize; + } + + if (!length) return 0; + + if (file->type == POSIX_FILE_TERMINAL) { + EsPrint("%s", length, base); + return length; + } else if (file->type == POSIX_FILE_PIPE) { + // EsPrint("Write %d bytes to pipe %x...\n", length, file->pipe); + return file->pipe->Access(base, length, true, true); + } else if (file->type == POSIX_FILE_NORMAL) { + // EsPrint("WRITE '%z' %d/%d\n", file->path, file->offsetIntoFile, length); + KMutexAcquire(&file->mutex); + EsDefer(KMutexRelease(&file->mutex)); + size_t count = FSFileWriteSync(file->node, (void *) base, file->offsetIntoFile, length, + (baseMappedToFile ? FS_FILE_ACCESS_USER_BUFFER_MAPPED : 0)); + if (ES_CHECK_ERROR(count)) return -EIO; + else { file->offsetIntoFile += count; return count; } + } else if (file->type == POSIX_FILE_ZERO || file->type == POSIX_FILE_NULL) { + return length; + } else if (file->type == POSIX_FILE_DIRECTORY) { + return length; + } + + return -EACCES; + } + + void Stat(int type, KNode *node, struct stat *buffer) { + EsMemoryZero(buffer, sizeof(struct stat)); + + if (type == POSIX_FILE_NORMAL) { + buffer->st_ino = node->id; + buffer->st_mode = S_IFREG; + buffer->st_nlink = 1; + + if (node->directoryEntry->type == ES_NODE_FILE) { + buffer->st_size = node->directoryEntry->totalSize; + buffer->st_blksize = 512; + buffer->st_blocks = buffer->st_size / 512; + } + } else if (type == POSIX_FILE_DIRECTORY) { + buffer->st_ino = node->id; + buffer->st_mode = S_IFDIR; + buffer->st_nlink = 1; + } else if (type == POSIX_FILE_PIPE) { + buffer->st_mode = S_IFIFO; + } else { + buffer->st_mode = S_IFCHR; + } + } + + void CloneFileDescriptorTable(Process *forkProcess, HandleTable *handleTable) { + HandleTable *source = handleTable, + *destination = &forkProcess->handleTable; + KMutexAcquire(&source->lock); + EsDefer(KMutexRelease(&source->lock)); + HandleTableL1 *l1 = &source->l1r; + + for (uintptr_t i = 0; i < HANDLE_TABLE_L1_ENTRIES; i++) { + if (!l1->u[i]) continue; + HandleTableL2 *l2 = l1->t[i]; + + for (uintptr_t k = 0; k < HANDLE_TABLE_L2_ENTRIES; k++) { + Handle *handle = l2->t + k; + if (!handle->object) continue; + if (handle->type != KERNEL_OBJECT_POSIX_FD) continue; + if (handle->flags & FD_CLOEXEC) continue; + + POSIXFile *file = (POSIXFile *) handle->object; + OpenHandleToObject(file, KERNEL_OBJECT_POSIX_FD, handle->flags); + destination->OpenHandle(handle->object, handle->flags, handle->type, k + i * HANDLE_TABLE_L2_ENTRIES); + } + } + } + + uintptr_t DoSyscall(_EsPOSIXSyscall syscall, uintptr_t *userStackPointer) { + Thread *currentThread = GetCurrentThread(); + Process *currentProcess = currentThread->process; + MMSpace *currentVMM = currentProcess->vmm; + HandleTable *handleTable = ¤tProcess->handleTable; + bool fromKernel = false; + + if (!currentThread->posixData) { + KMutexAcquire(&threadPOSIXDataMutex); + if (!currentThread->posixData) currentThread->posixData = (POSIXThread *) EsHeapAllocate(sizeof(POSIXThread), true, K_FIXED); + KMutexRelease(&threadPOSIXDataMutex); + } + + if (currentThread->posixData->forkProcess) { + handleTable = ¤tThread->posixData->forkProcess->handleTable; + } + + // EsPrint("%x, %x, %x, %x, %x, %x, %x, %x\n", syscall.index, syscall.arguments[0], syscall.arguments[1], syscall.arguments[2], + // syscall.arguments[3], syscall.arguments[4], syscall.arguments[5], syscall.arguments[6]); + + switch (syscall.index) { + case SYS_open: { + if (syscall.arguments[6] > SYSCALL_BUFFER_LIMIT) return -ENOMEM; + SYSCALL_BUFFER_POSIX(syscall.arguments[0], syscall.arguments[6], 1, false); + char *path2 = (char *) syscall.arguments[0]; + size_t pathLength = syscall.arguments[6]; + char *path = (char *) EsHeapAllocate(pathLength, false, K_FIXED); + if (!path) return -ENOMEM; + EsMemoryCopy(path, path2, pathLength); + EsDefer(EsHeapFree(path, 0, K_FIXED)); + int flags = syscall.arguments[1]; + uint64_t openFlags = ES_FLAGS_DEFAULT; + + POSIXFile *file = (POSIXFile *) EsHeapAllocate(sizeof(POSIXFile), true, K_FIXED); + if (!file) return -ENOMEM; + file->posixFlags = flags; + file->handles = 1; + + const char *devZero = "/dev/zero"; + const char *devNull = "/dev/null"; + + // EsPrint("Open: %s, %x\n", pathLength, path, flags); + + if ((EsCStringLength(devZero) == pathLength && 0 == EsMemoryCompare(path, devZero, pathLength))) { + file->type = POSIX_FILE_ZERO; + } else if (EsCStringLength(devNull) == pathLength && 0 == EsMemoryCompare(path, devNull, pathLength)) { + file->type = POSIX_FILE_NULL; + } else { + if (flags & O_EXCL) openFlags |= ES_NODE_FAIL_IF_FOUND; + else if (flags & O_CREAT) {} + else openFlags |= ES_NODE_FAIL_IF_NOT_FOUND; + if (flags & O_DIRECTORY) openFlags |= ES_NODE_DIRECTORY; + if (flags & O_APPEND) openFlags |= ES_FILE_WRITE; + else if (flags & O_RDWR) openFlags |= ES_FILE_WRITE; + else if (flags & O_WRONLY) openFlags |= ES_FILE_WRITE; + else if (!(flags & O_PATH)) openFlags |= ES_FILE_READ; + + KNodeInformation information = FSNodeOpen(path, pathLength, openFlags, (KNode *) syscall.arguments[4]); + + if (!information.node) { + EsHeapFree(file, sizeof(POSIXFile), K_FIXED); + return (information.error == ES_ERROR_FILE_DOES_NOT_EXIST || information.error == ES_ERROR_PATH_NOT_TRAVERSABLE) ? -ENOENT : -EACCES; + } + + if (information.node->directoryEntry->type == ES_NODE_DIRECTORY && !(flags & O_DIRECTORY) && !(flags & O_PATH)) { + EsHeapFree(file, sizeof(POSIXFile), K_FIXED); + CloseHandleToObject(information.node, KERNEL_OBJECT_NODE, openFlags); + return -EISDIR; + } + + file->node = information.node; + file->openFlags = openFlags; + file->type = file->node->directoryEntry->type == ES_NODE_DIRECTORY ? POSIX_FILE_DIRECTORY : POSIX_FILE_NORMAL; + } + + file->path = (char *) EsHeapAllocate(pathLength + 1, true, K_FIXED); + EsMemoryCopy(file->path, path, pathLength); + + EsHandle fd = handleTable->OpenHandle(file, (flags & O_CLOEXEC) ? FD_CLOEXEC : 0, KERNEL_OBJECT_POSIX_FD); + + // EsPrint("OPEN '%s' %z\n", pathLength, path, (openFlags & ES_NODE_WRITE_ACCESS) ? "Write" : ((openFlags & ES_NODE_READ_ACCESS) ? "Read" : "None")); + + if (!fd) { + if (file->type == POSIX_FILE_NORMAL || file->type == POSIX_FILE_DIRECTORY) { + CloseHandleToObject(file->node, KERNEL_OBJECT_NODE, openFlags); + } + + EsHeapFree(file->path, pathLength + 1, K_FIXED); + EsHeapFree(file, sizeof(POSIXFile), K_FIXED); + return -ENFILE; + } + + if ((flags & O_TRUNC) && file->type == POSIX_FILE_NORMAL) { + FSFileResize(file->node, 0); + } + + return fd; + } break; + + case ES_POSIX_SYSCALL_GET_POSIX_FD_PATH: { + if (syscall.arguments[2] > SYSCALL_BUFFER_LIMIT) return -ENOMEM; + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + SYSCALL_BUFFER_POSIX(syscall.arguments[1], syscall.arguments[2], 2, true); + KMutexAcquire(&file->mutex); + EsDefer(KMutexRelease(&file->mutex)); + int length = EsCStringLength(file->path); + if (length > syscall.arguments[2]) length = syscall.arguments[2]; + EsMemoryZero((void *) syscall.arguments[1], syscall.arguments[2]); + EsMemoryCopy((void *) syscall.arguments[1], file->path, length); + return length; + } break; + + case SYS_close: { + if (!handleTable->CloseHandle(ConvertStandardInputTo3(syscall.arguments[0]))) { + return -EBADF; + } + + return 0; + } break; + + case SYS_fstat: { + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + SYSCALL_BUFFER_POSIX(syscall.arguments[1], sizeof(struct stat), 1, true); + struct stat temp; + KMutexAcquire(&file->mutex); + Stat(file->type, file->node, &temp); + KMutexRelease(&file->mutex); + EsMemoryCopy((struct stat *) syscall.arguments[1], &temp, sizeof(struct stat)); + return 0; + } break; + + case SYS_fcntl: { + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + + if (syscall.arguments[1] == F_GETFD) { + return _object1.flags; + } else if (syscall.arguments[1] == F_SETFD) { + KObject object; + uint64_t newFlags = syscall.arguments[2]; + handleTable->ResolveHandle(&object, syscall.arguments[0], &newFlags); + } else if (syscall.arguments[1] == F_GETFL) { + return file->posixFlags; + } else if (syscall.arguments[1] == F_DUPFD) { + OpenHandleToObject(file, KERNEL_OBJECT_POSIX_FD, _object1.flags); + int fd = handleTable->OpenHandle(_object1.object, _object1.flags, _object1.type); + + if (!fd) { + CloseHandleToObject(file, KERNEL_OBJECT_POSIX_FD, _object1.flags); + return -EBUSY; + } else return fd; + } else if (syscall.arguments[1] == F_DUPFD_CLOEXEC) { + KObject object; + uint64_t newFlags = syscall.arguments[2]; + handleTable->ResolveHandle(&object, syscall.arguments[0], &newFlags); + + OpenHandleToObject(file, KERNEL_OBJECT_POSIX_FD, _object1.flags); + int fd = handleTable->OpenHandle(_object1.object, _object1.flags, _object1.type); + + if (!fd) { + CloseHandleToObject(file, KERNEL_OBJECT_POSIX_FD, _object1.flags); + return -EBUSY; + } else return fd; + } else { + KernelPanic("POSIX::DoSyscall - Unimplemented fcntl %d.\n", syscall.arguments[1]); + } + } break; + + case SYS_lseek: { + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + + KMutexAcquire(&file->mutex); + EsDefer(KMutexRelease(&file->mutex)); + + if (syscall.arguments[2] == SEEK_SET) { + file->offsetIntoFile = syscall.arguments[1]; + } else if (syscall.arguments[2] == SEEK_CUR) { + file->offsetIntoFile += syscall.arguments[1]; + } else if (syscall.arguments[2] == SEEK_END && file->type == POSIX_FILE_NORMAL) { + file->offsetIntoFile = file->node->directoryEntry->totalSize + syscall.arguments[1]; + } else { + return -EINVAL; + } + + return file->offsetIntoFile; + } break; + + case SYS_ioctl: { + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + + KMutexAcquire(&file->mutex); + EsDefer(KMutexRelease(&file->mutex)); + + if (syscall.arguments[1] == TIOCGWINSZ) { + if (file->type == POSIX_FILE_TERMINAL || file->type == POSIX_FILE_PIPE) { + SYSCALL_BUFFER_POSIX(syscall.arguments[1], sizeof(struct winsize), 1, true); + struct winsize *size = (struct winsize *) syscall.arguments[2]; + size->ws_row = 80; + size->ws_col = 25; + size->ws_xpixel = 800; + size->ws_ypixel = 800; + return 0; + } else { + return -EINVAL; + } + } + } break; + + case SYS_read: { + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + SYSCALL_BUFFER_POSIX(syscall.arguments[1], syscall.arguments[2], 3, false); + return Read(file, (void *) syscall.arguments[1], syscall.arguments[2], _region3->flags & MM_REGION_FILE); + } break; + + case SYS_readv: { + POSIXFile *file; + if (syscall.arguments[2] > 1024) return -EINVAL; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + SYSCALL_BUFFER_POSIX(syscall.arguments[1], syscall.arguments[2] * sizeof(struct iovec *), 2, false); + + struct iovec *vectors = (struct iovec *) EsHeapAllocate(syscall.arguments[2] * sizeof(struct iovec), false, K_FIXED); + if (!vectors) return -ENOMEM; + EsMemoryCopy(vectors, (void *) syscall.arguments[1], syscall.arguments[2] * sizeof(struct iovec)); + EsDefer(EsHeapFree(vectors, syscall.arguments[2] * sizeof(struct iovec), K_FIXED)); + + size_t bytesRead = 0; + + for (uintptr_t i = 0; i < (uintptr_t) syscall.arguments[2]; i++) { + if (!vectors[i].iov_len) continue; + SYSCALL_BUFFER_POSIX((uintptr_t) vectors[i].iov_base, vectors[i].iov_len, 3, false); + intptr_t result = Read(file, vectors[i].iov_base, vectors[i].iov_len, _region3->flags & MM_REGION_FILE); + if (result < 0) return result; + bytesRead += result; + } + + return bytesRead; + } break; + + case SYS_write: { + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + SYSCALL_BUFFER_POSIX(syscall.arguments[1], syscall.arguments[2], 3, true); + + if (file->type == POSIX_FILE_NORMAL && !(file->openFlags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE))) { + return -EACCES; + } + + return Write(file, (void *) syscall.arguments[1], syscall.arguments[2], _region3->flags & MM_REGION_FILE); + } break; + + case SYS_writev: { + POSIXFile *file; + if (syscall.arguments[2] > 1024) return -EINVAL; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + SYSCALL_BUFFER_POSIX(syscall.arguments[1], syscall.arguments[2] * sizeof(struct iovec *), 2, false); + + struct iovec *vectors = (struct iovec *) EsHeapAllocate(syscall.arguments[2] * sizeof(struct iovec), false, K_FIXED); + if (!vectors) return -ENOMEM; + EsMemoryCopy(vectors, (void *) syscall.arguments[1], syscall.arguments[2] * sizeof(struct iovec)); + EsDefer(EsHeapFree(vectors, syscall.arguments[2] * sizeof(struct iovec), K_FIXED)); + + size_t bytesWritten = 0; + + if (file->type == POSIX_FILE_NORMAL && !(file->openFlags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE))) { + return -EACCES; + } + + for (uintptr_t i = 0; i < (uintptr_t) syscall.arguments[2]; i++) { + if (!vectors[i].iov_len) continue; + // EsPrint("writev %d: %x/%d\n", i, vectors[i].iov_base, vectors[i].iov_len); + SYSCALL_BUFFER_POSIX((uintptr_t) vectors[i].iov_base, vectors[i].iov_len, 3, true); + intptr_t result = Write(file, vectors[i].iov_base, vectors[i].iov_len, _region3->flags & MM_REGION_FILE); + if (result < 0) return result; + bytesWritten += result; + } + + return bytesWritten; + } break; + + case SYS_vfork: { + // To vfork: save the stack and return 0. + // To exec*: create the new process, restore the state of our stack, then return the new process's ID. + + KMutexAcquire(&forkMutex); + EsDefer(KMutexRelease(&forkMutex)); + + // Did we complete the last vfork? + if (currentThread->posixData->forkStack) return -ENOMEM; + + // EsPrint("vfork->\n"); + + // Allocate the process. + Process *forkProcess = currentThread->posixData->forkProcess = scheduler.SpawnProcess(); + forkProcess->pgid = currentProcess->pgid; + + // Clone our FDs. + CloneFileDescriptorTable(forkProcess, handleTable); + + // Save the state of the user's stack. + currentThread->posixData->forkStackSize = currentThread->userStackCommit; + currentThread->posixData->forkStack = (void *) EsHeapAllocate(currentThread->posixData->forkStackSize, false, K_PAGED); +#ifdef K_STACK_GROWS_DOWN + EsMemoryCopy(currentThread->posixData->forkStack, + (void *) (currentThread->userStackBase + currentThread->userStackReserve - currentThread->posixData->forkStackSize), + currentThread->posixData->forkStackSize); +#else + EsMemoryCopy(currentThread->posixData->forkStack, (void *) currentThread->userStackBase, currentThread->posixData->forkStackSize); +#endif + currentThread->posixData->forkUSP = *userStackPointer; + + // Return 0. + return 0; + } break; + + case SYS_execve: { + KMutexAcquire(&forkMutex); + EsDefer(KMutexRelease(&forkMutex)); + + // Are we vforking? + if (!currentThread->posixData->forkStack) return -ENOMEM; + if (syscall.arguments[1] > K_MAX_PATH) return -ENOMEM; + if (syscall.arguments[3] > SYSCALL_BUFFER_LIMIT) return -ENOMEM; + + // EsPrint("<-execve\n"); + + SYSCALL_BUFFER_POSIX(syscall.arguments[0], syscall.arguments[1], 1, false); + SYSCALL_BUFFER_POSIX(syscall.arguments[2], syscall.arguments[3], 2, false); + + // Setup the process object. + + char *path = (char *) EsHeapAllocate(syscall.arguments[1], false, K_FIXED); + if (!path) return -ENOMEM; + EsMemoryCopy(path, (void *) syscall.arguments[0], syscall.arguments[1]); + + Process *process = currentThread->posixData->forkProcess; + process->creationArguments[CREATION_ARGUMENT_ENVIRONMENT] = MakeConstantBuffer((void *) syscall.arguments[2], syscall.arguments[3], process); + process->posixForking = true; + process->permissions = currentProcess->permissions; + + EsMountPoint mountPoint = {}; + OpenHandleToObject((void *) syscall.arguments[4], KERNEL_OBJECT_NODE, _ES_NODE_DIRECTORY_WRITE); + mountPoint.base = process->handleTable.OpenHandle((void *) syscall.arguments[4], _ES_NODE_DIRECTORY_WRITE, KERNEL_OBJECT_NODE); + mountPoint.prefixBytes = EsStringFormat(mountPoint.prefix, sizeof(mountPoint.prefix), "|POSIX:"); + process->creationArguments[CREATION_ARGUMENT_INITIAL_MOUNT_POINTS] = MakeConstantBuffer(&mountPoint, sizeof(EsMountPoint), process); + + // Start the process. + + if (!process->Start(path, syscall.arguments[1])) { + EsHeapFree(path, 0, K_FIXED); + return -ENOMEM; + } + + KSpinlockAcquire(&scheduler.lock); + + process->posixForking = false; + + if (process->allThreadsTerminated) { + KEventSet(&process->killedEvent, true); + } + + KSpinlockRelease(&scheduler.lock); + + EsHeapFree(path, 0, K_FIXED); + CloseHandleToObject(process->executableMainThread, KERNEL_OBJECT_THREAD); + + // Restore the state of our stack. +#ifdef K_STACK_GROWS_DOWN + EsMemoryCopy((void *) (currentThread->userStackBase + currentThread->userStackReserve - currentThread->posixData->forkStackSize), + currentThread->posixData->forkStack, currentThread->posixData->forkStackSize); +#else + EsMemoryCopy((void *) currentThread->userStackBase, currentThread->posixData->forkStack, currentThread->posixData->forkStackSize); +#endif + EsHeapFree(currentThread->posixData->forkStack, currentThread->posixData->forkStackSize, K_PAGED); + *userStackPointer = currentThread->posixData->forkUSP; + + // Fork complete. + currentThread->posixData->forkProcess = nullptr; + currentThread->posixData->forkStack = nullptr; + currentThread->posixData->forkUSP = 0; + + if (!process) return -ENOMEM; + + EsHandle processHandle = currentProcess->handleTable.OpenHandle(process, 0, KERNEL_OBJECT_PROCESS); + if (!processHandle) CloseHandleToObject(process, KERNEL_OBJECT_PROCESS); + + return processHandle; + } break; + + case SYS_exit_group: { + EsHandle processHandle = 0; + + KMutexAcquire(&forkMutex); + + // Are we vforking? + if (currentThread->posixData->forkStack) { + // Restore the state of our stack. +#ifdef K_STACK_GROWS_DOWN + EsMemoryCopy((void *) (currentThread->userStackBase + currentThread->userStackReserve - currentThread->posixData->forkStackSize), + currentThread->posixData->forkStack, currentThread->posixData->forkStackSize); +#else + EsMemoryCopy((void *) currentThread->userStackBase, currentThread->posixData->forkStack, currentThread->posixData->forkStackSize); +#endif + EsHeapFree(currentThread->posixData->forkStack, currentThread->posixData->forkStackSize, K_PAGED); + *userStackPointer = currentThread->posixData->forkUSP; + + // Set the exit status. + Process *process = currentThread->posixData->forkProcess; + process->exitStatus = syscall.arguments[0]; + process->allThreadsTerminated = true; // Set in case execve() was not attempted. + KEventSet(&process->killedEvent); + + processHandle = currentProcess->handleTable.OpenHandle(currentThread->posixData->forkProcess, 0, KERNEL_OBJECT_PROCESS); + if (!processHandle) CloseHandleToObject(currentThread->posixData->forkProcess, KERNEL_OBJECT_PROCESS); + + // Close any handles the process owned. + process->handleTable.Destroy(); + + // Cancel the vfork. + currentThread->posixData->forkProcess = nullptr; + currentThread->posixData->forkStack = nullptr; + currentThread->posixData->forkUSP = 0; + } + + KMutexRelease(&forkMutex); + + if (processHandle) { + return processHandle; + } else { + scheduler.TerminateProcess(currentProcess, syscall.arguments[0]); + } + } break; + + case SYS_sysinfo: { + SYSCALL_BUFFER_POSIX(syscall.arguments[0], sizeof(struct sysinfo), 1, true); + struct sysinfo *buffer = (struct sysinfo *) syscall.arguments[0]; + EsMemoryZero(buffer, sizeof(struct sysinfo)); + + // TODO Incomplete. + buffer->totalram = K_PAGE_SIZE * pmm.commitFixedLimit; + buffer->freeram = K_PAGE_SIZE * (pmm.countZeroedPages + pmm.countFreePages); + buffer->procs = scheduler.allProcesses.count; + buffer->mem_unit = 1; + + return 0; + } break; + + case SYS_dup2: { + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + + // Try to close the newfd. + + handleTable->CloseHandle(ConvertStandardInputTo3(syscall.arguments[1])); + + // Clone the oldfd as newfd. + + OpenHandleToObject(file, KERNEL_OBJECT_POSIX_FD, _object1.flags); + + if (!handleTable->OpenHandle(_object1.object, _object1.flags, _object1.type, ConvertStandardInputTo3(syscall.arguments[1]))) { + CloseHandleToObject(file, KERNEL_OBJECT_POSIX_FD, _object1.flags); + return -EBUSY; + } else return 0; + } break; + + case SYS_pipe2: { + if (syscall.arguments[1] & ~O_CLOEXEC) { + return -EINVAL; + } + + SYSCALL_BUFFER_POSIX(syscall.arguments[0], sizeof(int) * 2, 1, true); + int *fildes = (int *) syscall.arguments[0]; + + Pipe *pipe = (Pipe *) EsHeapAllocate(sizeof(Pipe), true, K_PAGED); + POSIXFile *reader = (POSIXFile *) EsHeapAllocate(sizeof(POSIXFile), true, K_FIXED); + POSIXFile *writer = (POSIXFile *) EsHeapAllocate(sizeof(POSIXFile), true, K_FIXED); + + if (!reader || !writer || !pipe) { + EsHeapFree(pipe, sizeof(Pipe), K_PAGED); + EsHeapFree(reader, 0, K_FIXED); + EsHeapFree(writer, 0, K_FIXED); + return -ENOMEM; + } + + KEventSet(&pipe->canWrite); + + reader->type = POSIX_FILE_PIPE; + reader->openFlags = PIPE_READER; + reader->handles = 1; + reader->pipe = pipe; + + writer->type = POSIX_FILE_PIPE; + writer->openFlags = PIPE_WRITER; + writer->handles = 1; + writer->pipe = pipe; + + EsHandle fd0, fd1; + fd0 = handleTable->OpenHandle(reader, (syscall.arguments[1] & O_CLOEXEC) ? FD_CLOEXEC : 0, KERNEL_OBJECT_POSIX_FD); + + if (!fd0) { + EsHeapFree(pipe, sizeof(Pipe), K_PAGED); + EsHeapFree(reader, 0, K_FIXED); + EsHeapFree(writer, 0, K_FIXED); + return -EMFILE; + } + + pipe->readers = 1; + + fd1 = handleTable->OpenHandle(writer, (syscall.arguments[1] & O_CLOEXEC) ? FD_CLOEXEC : 0, KERNEL_OBJECT_POSIX_FD); + + if (!fd1) { + handleTable->CloseHandle(ConvertStandardInputTo3(fd0)); + EsHeapFree(writer, 0, K_FIXED); + return -EMFILE; + } + + pipe->writers = 1; + + fildes[0] = fd0, fildes[1] = fd1; + return 0; + } break; + + case SYS_getdents64: { + // TODO This is a bit of a hack. + // Especially allocating the entire directory list in the kernel's memory space. + + if (syscall.arguments[2] > SYSCALL_BUFFER_LIMIT) return -ENOMEM; + + POSIXFile *file; + SYSCALL_HANDLE_POSIX(syscall.arguments[0], file, 1); + SYSCALL_BUFFER_POSIX(syscall.arguments[1], syscall.arguments[2], 3, true); + + KMutexAcquire(&file->mutex); + EsDefer(KMutexRelease(&file->mutex)); + + if (file->type != POSIX_FILE_DIRECTORY) { + return -EACCES; + } + + if (!file->offsetIntoFile || !file->directoryBuffer) { + EsHeapFree(file->directoryBuffer, file->directoryBufferLength, K_PAGED); + + file->directoryBuffer = nullptr; + file->offsetIntoFile = 0; + file->directoryBufferLength = 0; + + uintptr_t bufferSize = file->node->directoryEntry->directoryChildren; + EsDirectoryChild *buffer = (EsDirectoryChild *) EsHeapAllocate(sizeof(EsDirectoryChild) * bufferSize, false, K_FIXED); + + if (!buffer) { + return -ENOMEM; + } + + size_t count = FSDirectoryEnumerateChildren(file->node, buffer, bufferSize); + + if (ES_CHECK_ERROR(count)) { + EsHeapFree(buffer, sizeof(EsDirectoryChild) * bufferSize, K_FIXED); + return -EIO; + } + + size_t neededSize = 0; + + for (uintptr_t i = 0; i < count; i++) { + neededSize += RoundUp(19 + buffer[i].nameBytes + 1, (size_t) 8); + } + + file->directoryBuffer = EsHeapAllocate(neededSize, true, K_PAGED); + + if (!file->directoryBuffer) { + EsHeapFree(buffer, bufferSize * sizeof(EsDirectoryChild), K_FIXED); + return -ENOMEM; + } + + file->directoryBufferLength = neededSize; + + uint8_t *position = (uint8_t *) file->directoryBuffer; + + for (uintptr_t i = 0; i < count; i++) { + // EsPrint("%d - %d\n", i, position - (uint8_t *) file->directoryBuffer); + size_t size = RoundUp(19 + buffer[i].nameBytes + 1, (size_t) 8); + EsDirectoryChild *entry = buffer + i; + ((uint64_t *) position)[0] = EsRandomU64(); // We don't have a concept of inodes. + ((uint64_t *) position)[1] = position - (uint8_t *) file->directoryBuffer + size; + ((uint16_t *) position)[8] = size; + ((uint8_t *) position)[18] = entry->type == ES_NODE_DIRECTORY ? 4 /* DT_DIR */ + : entry->type == ES_NODE_FILE ? 8 /* DT_REG */ : 0 /* DT_UNKNOWN */; + EsMemoryCopy(position + 19, entry->name, entry->nameBytes); + *(position + 19 + entry->nameBytes) = 0; + position += size; + } + + EsHeapFree(buffer, bufferSize * sizeof(EsDirectoryChild), K_FIXED); + } + + uint64_t offset = file->offsetIntoFile; + size_t bufferSize = syscall.arguments[2]; + + while (offset + 19 < file->directoryBufferLength) { + uint8_t *position = (uint8_t *) file->directoryBuffer + offset; + uint64_t nextOffset = ((uint64_t *) position)[1]; + + if (nextOffset > file->directoryBufferLength || nextOffset < offset + 19 + || nextOffset - file->offsetIntoFile >= bufferSize) { + break; + } + + offset = nextOffset; + } + + size_t bytesToReturn = offset - file->offsetIntoFile; + + if (bytesToReturn > bufferSize) { + bytesToReturn = bufferSize; + } + + EsMemoryCopy((void *) syscall.arguments[1], (uint8_t *) file->directoryBuffer + file->offsetIntoFile, bytesToReturn); + file->offsetIntoFile += bytesToReturn; + return bytesToReturn; + } break; + + case SYS_setpgid: { + Process *process = (Process *) syscall.arguments[0]; + process->pgid = syscall.arguments[1]; + return 0; + } break; + } + + return -1; + } +}; + +#endif diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp new file mode 100644 index 0000000..7128be4 --- /dev/null +++ b/kernel/scheduler.cpp @@ -0,0 +1,1423 @@ +#ifndef IMPLEMENTATION + +#define PREEMPT_AFTER_MUTEX_RELEASE + +#define THREAD_PRIORITY_NORMAL (0) // Lower value = higher priority. +#define THREAD_PRIORITY_LOW (1) +#define THREAD_PRIORITY_COUNT (2) + +void CloseHandleToThread(void *_thread); +void CloseHandleToProcess(void *_thread); +void KillThread(EsGeneric _thread); + +void RegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, struct Process *targetProcess, + bool needed /*If false, the task may not be registered if there are many queued tasks.*/, + bool unlocked = false /*Set to true if you haven't acquired the scheduler's lock.*/); + +enum ThreadState : int8_t { + THREAD_ACTIVE, // An active thread. Not necessarily executing; `executing` determines if it executing. + THREAD_WAITING_MUTEX, // Waiting for a mutex to be released. + THREAD_WAITING_EVENT, // Waiting for a event to be notified. + THREAD_WAITING_WRITER_LOCK, // Waiting for a writer lock to be notified. + THREAD_TERMINATED, // The thread has been terminated. It will be deallocated when all handles are closed. + // I believe this is called a "zombie thread" in UNIX terminology. +}; + +enum ThreadType : int8_t { + THREAD_NORMAL, // A normal thread. + THREAD_IDLE, // The CPU's idle thread. + THREAD_ASYNC_TASK, // A thread that processes the CPU's asynchronous tasks. +}; + +enum ThreadTerminatableState : int8_t { + THREAD_INVALID_TS, + THREAD_TERMINATABLE, // The thread is currently executing user code. + THREAD_IN_SYSCALL, // The thread is currently executing kernel code from a system call. + // It cannot be terminated/paused until it returns from the system call. + THREAD_USER_BLOCK_REQUEST, // The thread is sleeping because of a user system call to sleep. + // It can be unblocked, and then terminated when it returns from the system call. +}; + +struct Thread { + void SetAddressSpace(MMSpace *space); // Set a temporary address space for the thread. + // Used by the asynchronous task threads, + // and the memory manager's balancer. + + LinkedItem item; // Entry in relevent thread queue or blockedThreads list for mutexes/writer locks. + LinkedItem allItem; // Entry in the allThreads list. + LinkedItem processItem; // Entry in the process's list of threads. + LinkedItem *blockedItems; // Entries in the blockedThreads lists for events (not mutexes). + + struct Process *process; + + uint64_t id; + volatile uintptr_t cpuTimeSlices; + volatile size_t handles; + int executingProcessorID; + + uintptr_t userStackBase; + uintptr_t kernelStackBase; + uintptr_t kernelStack; + uintptr_t tlsAddress; + size_t userStackReserve; + volatile size_t userStackCommit; + + ThreadType type; + bool isKernelThread, isPageGenerator; + int8_t priority; + int32_t blockedThreadPriorities[THREAD_PRIORITY_COUNT]; // The number of threads blocking on this thread at each priority level. + + volatile ThreadState state; + volatile ThreadTerminatableState terminatableState; + volatile bool executing; + volatile bool terminating; // Set when a request to terminate the thread has been registered. + volatile bool paused; // Set to pause a thread, usually when it has crashed or being debugged. The scheduler will skip threads marked as paused when deciding what to run. + volatile bool receivedYieldIPI; // Used to terminate a thread executing on a different processor. + + union { + KMutex *volatile mutex; + + struct { + KWriterLock *volatile writerLock; + bool writerLockType; + }; + + struct { + KEvent *volatile events[ES_MAX_WAIT_COUNT]; + volatile size_t eventCount; + }; + } blocking; + + KEvent killedEvent; + + // If the type of the thread is THREAD_ASYNC_TASK, + // then this is the virtual address space that should be loaded + // when the task is being executed. + MMSpace *volatile temporaryAddressSpace; + + InterruptContext *interruptContext; // TODO Store the userland interrupt context instead? + uintptr_t lastKnownExecutionAddress; // For debugging. + +#ifdef ENABLE_POSIX_SUBSYSTEM + struct POSIXThread *posixData; +#endif + + const char *cName; +}; + +enum ProcessType { + PROCESS_NORMAL, + PROCESS_KERNEL, + PROCESS_DESKTOP, +}; + +struct Process { + bool StartWithNode(KNode *node); + bool Start(char *imagePath, size_t imagePathLength); + + MMSpace *vmm; + HandleTable handleTable; + MessageQueue messageQueue; + LinkedList threads; + + // Creation information: + KNode *executableNode; + char cExecutableName[ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH + 1]; + uintptr_t creationArguments[4]; + uint64_t permissions; + uint64_t creationFlags; + ProcessType type; + + // Object management: + uint64_t id; + volatile size_t handles; + LinkedItem allItem; + + // Crashing: + KMutex crashMutex; + EsCrashReason crashReason; + bool crashed; + + // Termination: + bool allThreadsTerminated; + bool terminating; + int exitStatus; + KEvent killedEvent; + + // Executable state: + uint8_t executableState; + bool executableStartRequest; + KEvent executableLoadAttemptComplete; + Thread *executableMainThread; + + // Statistics: + uintptr_t cpuTimeSlices, idleTimeSlices; + +#ifdef ENABLE_POSIX_SUBSYSTEM + bool posixForking; + int pgid; +#endif +}; + +Process _kernelProcess; +Process *kernelProcess = &_kernelProcess; + +struct Scheduler { + // External API: + + void Yield(InterruptContext *context); + +#define SPAWN_THREAD_MANUALLY_ACTIVATED (1) +#define SPAWN_THREAD_USERLAND (2) +#define SPAWN_THREAD_LOW_PRIORITY (4) +#define SPAWN_THREAD_PAUSED (8) + Thread *SpawnThread(const char *cName, uintptr_t startAddress, uintptr_t argument1 = 0, + unsigned flags = ES_FLAGS_DEFAULT, Process *process = kernelProcess, uintptr_t argument2 = 0); + void TerminateThread(Thread *thread, bool lockAlreadyAcquired = false); + void PauseThread(Thread *thread, bool resume /*true to resume, false to pause*/, bool lockAlreadyAcquired = false); + + Process *SpawnProcess(ProcessType processType = PROCESS_NORMAL); + void TerminateProcess(Process *process, int status); + void PauseProcess(Process *process, bool resume); + void CrashProcess(Process *process, EsCrashReason *reason); + + Process *OpenProcess(uint64_t id); + + void WaitMutex(KMutex *mutex); + uintptr_t WaitEvents(KEvent **events, size_t count); // Returns index of notified object. + + void Shutdown(); + + // Internal functions: + + void CreateProcessorThreads(CPULocalStorage *local); + + void RemoveProcess(Process *process); // Do not call. Use TerminateProcess/CloseHandleToObject. + void RemoveThread(Thread *thread); // Do not call. Use TerminateThread/CloseHandleToObject. + void AddActiveThread(Thread *thread, bool start /*Put it at the start*/); // Add an active thread into the queue. + void InsertNewThread(Thread *thread, bool addToActiveList, Process *owner); // Used during thread creation. + void MaybeUpdateActiveList(Thread *thread); // After changing the priority of a thread, call this to move it to the correct active thread queue if needed. + + void NotifyObject(LinkedList *blockedThreads, bool unblockAll, Thread *previousMutexOwner = nullptr); + void UnblockThread(Thread *unblockedThread, Thread *previousMutexOwner = nullptr); + + Thread *PickThread(CPULocalStorage *local); // Pick the next thread to execute. + int8_t GetThreadEffectivePriority(Thread *thread); + + // Variables: + + KSpinlock lock; + + KEvent killedEvent; // Set during shutdown when all processes have been terminated. + uintptr_t blockShutdownProcessCount; + + LinkedList activeThreads[THREAD_PRIORITY_COUNT], pausedThreads; + LinkedList activeTimers; + + Pool threadPool, processPool, mmSpacePool; + LinkedList allThreads; + LinkedList allProcesses; + uint64_t nextThreadID; + uint64_t nextProcessID; + size_t activeProcessCount; + + volatile bool started, panic, shutdown; + + uint64_t timeMs, lastTimeStamp; + + unsigned currentProcessorID; + +#ifdef DEBUG_BUILD + EsThreadEventLogEntry *volatile threadEventLog; + volatile uintptr_t threadEventLogPosition; + volatile size_t threadEventLogAllocated; +#endif +}; + +extern Scheduler scheduler; + +#endif + +#ifdef IMPLEMENTATION + +Scheduler scheduler; + +int8_t Scheduler::GetThreadEffectivePriority(Thread *thread) { + KSpinlockAssertLocked(&lock); + + for (int8_t i = 0; i < thread->priority; i++) { + if (thread->blockedThreadPriorities[i]) { + // A thread is blocking on a resource owned by this thread, + // and the blocking thread has a higher priority than this thread. + // Therefore, this thread should assume that higher priority, + // until it releases the resource. + return i; + } + } + + return thread->priority; +} + +void Scheduler::AddActiveThread(Thread *thread, bool start) { + if (thread->type == THREAD_ASYNC_TASK) { + // An asynchronous task thread was unblocked. + // It will be run immediately, so there's no need to add it to the active thread list. + return; + } + + KSpinlockAssertLocked(&lock); + + if (thread->state != THREAD_ACTIVE) { + KernelPanic("Scheduler::AddActiveThread - Thread %d not active\n", thread->id); + } else if (thread->executing) { + KernelPanic("Scheduler::AddActiveThread - Thread %d executing\n", thread->id); + } else if (thread->type != THREAD_NORMAL) { + KernelPanic("Scheduler::AddActiveThread - Thread %d has type %d\n", thread->id, thread->type); + } else if (thread->item.list) { + KernelPanic("Scheduler::AddActiveThread - Thread %d is already in queue %x.\n", thread->id, thread->item.list); + } + + if (thread->paused && thread->terminatableState == THREAD_TERMINATABLE) { + // The thread is paused, so we can put it into the paused queue until it is resumed. + pausedThreads.InsertStart(&thread->item); + } else { + int8_t effectivePriority = GetThreadEffectivePriority(thread); + + if (start) { + activeThreads[effectivePriority].InsertStart(&thread->item); + } else { + activeThreads[effectivePriority].InsertEnd(&thread->item); + } + } +} + +void Scheduler::MaybeUpdateActiveList(Thread *thread) { + // TODO Is this correct with regards to paused threads? + + if (thread->type == THREAD_ASYNC_TASK) { + // Asynchronous task threads do not go in the activeThreads lists. + return; + } + + if (thread->type != THREAD_NORMAL) { + KernelPanic("Scheduler::MaybeUpdateActiveList - Trying to update the active list of a non-normal thread %x.\n", thread); + } + + KSpinlockAssertLocked(&lock); + + if (thread->state != THREAD_ACTIVE || thread->executing) { + // The thread is not currently in an active list, + // so it'll end up in the correct activeThreads list when it becomes active. + return; + } + + if (!thread->item.list) { + KernelPanic("Scheduler::MaybeUpdateActiveList - Despite thread %x being active and not executing, it is not in an activeThreads lists.\n", thread); + } + + int8_t effectivePriority = GetThreadEffectivePriority(thread); + + if (&activeThreads[effectivePriority] == thread->item.list) { + // The thread's effective priority has not changed. + // We don't need to do anything. + return; + } + + // Remove the thread from its previous active list. + thread->item.RemoveFromList(); + + // Add it to the start of its new active list. + // TODO I'm not 100% sure we want to always put it at the start. + activeThreads[effectivePriority].InsertStart(&thread->item); +} + +void Scheduler::InsertNewThread(Thread *thread, bool addToActiveList, Process *owner) { + KSpinlockAcquire(&lock); + EsDefer(KSpinlockRelease(&lock)); + + // New threads are initialised here. + thread->id = nextThreadID++; + thread->process = owner; + + owner->handles++; // Each thread owns a handles to the owner process. + // This makes sure the process isn't destroyed before all its threads have been destroyed. + // EsPrint("Open handle to process %d/%x (new thread). New handle count: %d.\n", owner->id, owner, owner->handles); + + thread->item.thisItem = thread; + thread->allItem.thisItem = thread; + thread->processItem.thisItem = thread; + owner->threads.InsertEnd(&thread->processItem); + + KernelLog(LOG_INFO, "Scheduler", "create thread", "Create thread ID %d, type %d, owner process %d\n", thread->id, thread->type, owner->id); + + if (addToActiveList) { + // Add the thread to the start of the active thread list to make sure that it runs immediately. + AddActiveThread(thread, true); + } else { + // Some threads (such as idle threads) do this themselves. + } + + allThreads.InsertStart(&thread->allItem); +} + +Thread *Scheduler::SpawnThread(const char *cName, uintptr_t startAddress, uintptr_t argument1, unsigned flags, Process *process, uintptr_t argument2) { + bool userland = flags & SPAWN_THREAD_USERLAND; + + if (userland && process == kernelProcess) { + KernelPanic("Scheduler::SpawnThread - Cannot add userland thread to kernel process.\n"); + } + + KSpinlockAcquire(&scheduler.lock); + bool terminating = process->terminating; + KSpinlockRelease(&scheduler.lock); + + if (shutdown && userland) return nullptr; + if (terminating) return nullptr; + + Thread *thread = (Thread *) threadPool.Add(sizeof(Thread)); + KernelLog(LOG_INFO, "Scheduler", "spawn thread", "Created thread, %x to start at %x\n", thread, startAddress); + thread->isKernelThread = !userland; + thread->priority = (flags & SPAWN_THREAD_LOW_PRIORITY) ? THREAD_PRIORITY_LOW : THREAD_PRIORITY_NORMAL; + thread->cName = cName; + + // 2 handles to the thread: + // One for spawning the thread, + // and the other for remaining during the thread's life. + thread->handles = 2; + + // Allocate the thread's stacks. + uintptr_t kernelStackSize = userland ? 0x4000 /* 16KB */ : 0x10000 /* 64KB */; + uintptr_t userStackReserve = userland ? 0x400000 /* 4MB */ : kernelStackSize; + uintptr_t userStackCommit = userland ? 0x20000 /* 128KB */ : 0; + uintptr_t stack = 0, kernelStack = (uintptr_t) MMStandardAllocate(kernelMMSpace, kernelStackSize, MM_REGION_FIXED); + + if (!kernelStack) goto fail; + + if (userland) { + stack = (uintptr_t) MMStandardAllocate(process->vmm, userStackReserve, ES_FLAGS_DEFAULT, nullptr, false); + + MMRegion *region = MMFindAndPinRegion(process->vmm, stack, userStackReserve); + KMutexAcquire(&process->vmm->reserveMutex); +#ifdef K_STACK_GROWS_DOWN + bool success = MMCommitRange(process->vmm, region, (userStackReserve - userStackCommit) / K_PAGE_SIZE, userStackCommit / K_PAGE_SIZE); +#else + bool success = MMCommitRange(process->vmm, region, 0, userStackCommit / K_PAGE_SIZE); +#endif + KMutexRelease(&process->vmm->reserveMutex); + MMUnpinRegion(process->vmm, region); + if (!success) goto fail; + } else { + stack = kernelStack; + } + + if (!stack) goto fail; + + KernelLog(LOG_INFO, "Scheduler", "thread stacks", + "Spawning thread with stacks (k,u): %x->%x, %x->%x\n", kernelStack, kernelStack + kernelStackSize, stack, stack + userStackReserve); + + thread->kernelStackBase = kernelStack; + thread->userStackBase = userland ? stack : 0; + thread->userStackReserve = userStackReserve; + thread->userStackCommit = userStackCommit; + thread->paused = flags & SPAWN_THREAD_PAUSED; + thread->terminatableState = userland ? THREAD_TERMINATABLE : THREAD_IN_SYSCALL; + thread->interruptContext = ArchInitialiseThread(kernelStack, kernelStackSize, thread, + startAddress, argument1, argument2, + userland, stack, userStackReserve); + + InsertNewThread(thread, ~flags & SPAWN_THREAD_MANUALLY_ACTIVATED, process); + return thread; + + fail:; + if (stack) MMFree(process->vmm, (void *) stack); + if (kernelStack) MMFree(kernelMMSpace, (void *) kernelStack); + threadPool.Remove(thread); + return nullptr; +} + +void Scheduler::TerminateProcess(Process *process, int status) { + KSpinlockAcquire(&scheduler.lock); + + KernelLog(LOG_INFO, "Scheduler", "terminate process", "Terminating process %d '%z' with status %i...\n", + process->id, process->cExecutableName, status); + process->exitStatus = status; + process->terminating = true; + + Thread *currentThread = GetCurrentThread(); + bool isCurrentProcess = process == currentThread->process; + bool foundCurrentThread = false; + + LinkedItem *thread = process->threads.firstItem; + + while (thread) { + Thread *threadObject = thread->thisItem; + thread = thread->nextItem; + + if (threadObject != currentThread) { + TerminateThread(threadObject, true); + } else if (isCurrentProcess) { + foundCurrentThread = true; + } else { + KernelPanic("Scheduler::TerminateProcess - Found current thread in the wrong process?!\n"); + } + } + + if (!foundCurrentThread && isCurrentProcess) { + KernelPanic("Scheduler::TerminateProcess - Could not find current thread in the current process?!\n"); + } else if (isCurrentProcess) { + // This doesn't return. + TerminateThread(currentThread, true); + } + + KSpinlockRelease(&scheduler.lock); + ProcessorFakeTimerInterrupt(); // Process the asynchronous tasks. +} + +void Scheduler::TerminateThread(Thread *thread, bool terminatingProcess) { + // Overview: + // Set terminating true, and paused false. + // Is this the current thread? + // Mark as terminatable, then yield. + // Else, is thread->terminating not set? + // Set thread->terminating. + // + // Is this the current thread? + // Mark as terminatable, then yield. + // Else, are we executing user code? + // If we aren't currently executing the thread, remove the thread from its scheduling queue and kill it. + // Else, is the user waiting on a mutex/event? + // If we aren't currently executing the thread, unblock the thread. + + if (!terminatingProcess) { + KSpinlockAcquire(&scheduler.lock); + } else { + KSpinlockAssertLocked(&scheduler.lock); + } + + bool yield = false; + + if (thread->terminating) { + KernelLog(LOG_INFO, "Scheduler", "thread already terminating", "Already terminating thread %d.\n", thread->id); + if (thread == GetCurrentThread()) goto terminateThisThread; + else goto done; + } + + KernelLog(LOG_INFO, "Scheduler", "terminate thread", "Terminating thread %d...\n", thread->id); + thread->terminating = true; + thread->paused = false; + + if (thread == GetCurrentThread()) { + terminateThisThread:; + + // Mark the thread as terminatable. + thread->terminatableState = THREAD_TERMINATABLE; + KSpinlockRelease(&scheduler.lock); + + // We cannot return to the previous function as it expects to be killed. + ProcessorFakeTimerInterrupt(); + KernelPanic("Scheduler::TerminateThread - ProcessorFakeTimerInterrupt returned.\n"); + } else { + if (thread->terminatableState == THREAD_TERMINATABLE) { + // We're in user code.. + + if (thread->executing) { + // The thread is executing, so the next time it tries to make a system call or + // is pre-empted, it will be terminated. + } else { + if (thread->state != THREAD_ACTIVE) { + KernelPanic("Scheduler::TerminateThread - Terminatable thread non-active.\n"); + } + + // The thread is terminatable and it isn't executing. + // Remove it from its queue, and then remove the thread. + thread->item.RemoveFromList(); + RegisterAsyncTask(KillThread, thread, thread->process, true); + yield = true; + } + } else if (thread->terminatableState == THREAD_USER_BLOCK_REQUEST) { + // We're in the kernel, but because the user wanted to block on a mutex/event. + + if (thread->executing) { + // The mutex and event waiting code is designed to recognise when a thread is in this state, + // and exit to the system call handler immediately. + // If the thread however is pre-empted while in a blocked state before this code can execute, + // Scheduler::Yield will automatically force the thread to be active again. + } else { + // Unblock the thread. + // See comment above. + if (thread->state == THREAD_WAITING_MUTEX || thread->state == THREAD_WAITING_EVENT) { + UnblockThread(thread); + } + } + } else { + // The thread is executing kernel code. + // Therefore, we can't simply terminate the thread. + // The thread will set its state to THREAD_TERMINATABLE whenever it can be terminated. + } + } + + done:; + + if (!terminatingProcess) { + KSpinlockRelease(&scheduler.lock); + if (yield) ProcessorFakeTimerInterrupt(); // Process the asynchronous task. + } +} + +void NewProcess() { + Process *thisProcess = GetCurrentThread()->process; + + KernelLog(LOG_INFO, "Scheduler", "new process", + "New process %d %x, '%z'.\n", thisProcess->id, thisProcess, thisProcess->cExecutableName); + + KLoadedExecutable api = {}; + EsError loadError = ES_SUCCESS; + + { + uint64_t fileFlags = ES_FILE_READ | ES_NODE_FAIL_IF_NOT_FOUND; + KNodeInformation node = FSNodeOpen(EsLiteral(K_DESKTOP_EXECUTABLE), fileFlags); + loadError = node.error; + + if (node.error == ES_SUCCESS) { + if (node.node->directoryEntry->type != ES_NODE_FILE) { + loadError = ES_ERROR_INCORRECT_NODE_TYPE; + } else { + loadError = KLoadELF(node.node, &api); + } + + CloseHandleToObject(node.node, KERNEL_OBJECT_NODE, fileFlags); + } + } + + KLoadedExecutable application = {}; + + if (thisProcess != desktopProcess && loadError == ES_SUCCESS) { + loadError = KLoadELF(thisProcess->executableNode, &application); + } + + bool success = loadError == ES_SUCCESS; + + if (success) { + // We "link" the API by putting its table of function pointers at a known address. + + MMSharedRegion *tableRegion = MMSharedOpenRegion(EsLiteral("Desktop.APITable"), 0xF000, ES_FLAGS_DEFAULT); + // TODO Write protection. + + if (!MMMapShared(thisProcess->vmm, tableRegion, 0, 0xF000, ES_FLAGS_DEFAULT, ES_API_BASE)) { + success = false; + } + } + + EsProcessStartupInformation *startupInformation; + + if (success) { + startupInformation = (EsProcessStartupInformation *) MMStandardAllocate( + thisProcess->vmm, sizeof(EsProcessStartupInformation), ES_FLAGS_DEFAULT); + + if (!startupInformation) { + success = false; + } else { + startupInformation->isDesktop = thisProcess == desktopProcess; + startupInformation->applicationStartAddress = application.startAddress; + startupInformation->tlsImageStart = application.tlsImageStart; + startupInformation->tlsImageBytes = application.tlsImageBytes; + startupInformation->tlsBytes = application.tlsBytes; + } + } + + if (success) { + uint64_t threadFlags = SPAWN_THREAD_USERLAND; + if (thisProcess->creationFlags & ES_PROCESS_CREATE_PAUSED) threadFlags |= SPAWN_THREAD_PAUSED; + + thisProcess->executableState = ES_PROCESS_EXECUTABLE_LOADED; + thisProcess->executableMainThread = scheduler.SpawnThread("MainThread", api.startAddress, + (uintptr_t) startupInformation, threadFlags, thisProcess); + + if (!thisProcess->executableMainThread) { + success = false; + } + } + + if (!success) { + if (thisProcess->type != PROCESS_NORMAL) { + KernelPanic("NewProcess - Failed to start the critical process %z.\n", thisProcess->cExecutableName); + } + + thisProcess->executableState = ES_PROCESS_EXECUTABLE_FAILED_TO_LOAD; + } + + KEventSet(&thisProcess->executableLoadAttemptComplete); +} + +bool Process::Start(char *imagePath, size_t imagePathLength) { + uint64_t flags = ES_FILE_READ | ES_NODE_FAIL_IF_NOT_FOUND; + KNodeInformation node = FSNodeOpen(imagePath, imagePathLength, flags); + + if (ES_CHECK_ERROR(node.error)) { + return false; + } + + if (node.node->directoryEntry->type != ES_NODE_FILE) { + CloseHandleToObject(node.node, KERNEL_OBJECT_NODE, flags); + return false; + } + + bool result = StartWithNode(node.node); + CloseHandleToObject(node.node, KERNEL_OBJECT_NODE, flags); + return result; +} + +bool Process::StartWithNode(KNode *node) { + KSpinlockAcquire(&scheduler.lock); + + if (executableStartRequest) { + KSpinlockRelease(&scheduler.lock); + return false; + } + + executableStartRequest = true; + + KSpinlockRelease(&scheduler.lock); + + KWriterLockTake(&node->writerLock, K_LOCK_SHARED); + size_t byteCount = node->directoryEntry->item.key.longKeyBytes; + if (byteCount > ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH) byteCount = ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH; + EsMemoryCopy(cExecutableName, node->directoryEntry->item.key.longKey, byteCount); + cExecutableName[byteCount] = 0; + KWriterLockReturn(&node->writerLock, K_LOCK_SHARED); + + bool success = MMSpaceInitialise(vmm); + if (!success) return false; + + // NOTE If you change these flags, make sure to update the flags when the handle is closed! + + if (!OpenHandleToObject(node, KERNEL_OBJECT_NODE, ES_FILE_READ)) { + KernelPanic("Process::StartWithNode - Could not open read handle to node %x.\n", node); + } + + executableNode = node; + + KSpinlockAcquire(&scheduler.lock); + scheduler.allProcesses.InsertEnd(&allItem); + scheduler.activeProcessCount++; + scheduler.blockShutdownProcessCount++; + KSpinlockRelease(&scheduler.lock); + + Thread *newProcessThread = scheduler.SpawnThread("NewProcess", (uintptr_t) NewProcess, 0, ES_FLAGS_DEFAULT, this); + + if (!newProcessThread) { + CloseHandleToObject(this, KERNEL_OBJECT_PROCESS); + return false; + } + + CloseHandleToObject(newProcessThread, KERNEL_OBJECT_THREAD); + KEventWait(&executableLoadAttemptComplete, ES_WAIT_NO_TIMEOUT); + + if (executableState == ES_PROCESS_EXECUTABLE_FAILED_TO_LOAD) { + KernelLog(LOG_ERROR, "Scheduler", "executable load failure", "Executable failed to load.\n"); + return false; + } + + return true; +} + +Process *Scheduler::SpawnProcess(ProcessType processType) { + if (shutdown) return nullptr; + + Process *process = processType == PROCESS_KERNEL ? kernelProcess : (Process *) processPool.Add(sizeof(Process)); + + if (!process) { + return nullptr; + } + + process->vmm = processType == PROCESS_KERNEL ? kernelMMSpace : (MMSpace *) mmSpacePool.Add(sizeof(MMSpace)); + + if (!process->vmm) { + processPool.Remove(process); + return nullptr; + } + + KSpinlockAcquire(&scheduler.lock); + process->id = nextProcessID++; + KSpinlockRelease(&scheduler.lock); + + process->allItem.thisItem = process; + process->handles = 1; + process->handleTable.process = process; + process->permissions = ES_PERMISSION_ALL; + process->type = processType; + + if (processType == PROCESS_KERNEL) { + EsCRTstrcpy(process->cExecutableName, "Kernel"); + scheduler.allProcesses.InsertEnd(&process->allItem); + MMInitialise(); + scheduler.SpawnThread("InitKernel", (uintptr_t) KernelInitialise); + } + + return process; +} + +void Thread::SetAddressSpace(MMSpace *space) { + temporaryAddressSpace = space; + + if (this == GetCurrentThread()) { + ProcessorSetAddressSpace(VIRTUAL_ADDRESS_SPACE_IDENTIFIER(space ? space : kernelMMSpace)); + } +} + +void AsyncTaskThread() { + CPULocalStorage *local = GetLocalStorage(); + + while (true) { + if (local->asyncTasksRead == local->asyncTasksWrite) { + ProcessorFakeTimerInterrupt(); + } else { + volatile AsyncTask *task = local->asyncTasks + local->asyncTasksRead; + if (task->addressSpace) local->currentThread->SetAddressSpace(task->addressSpace); + task->callback(task->argument); + local->currentThread->SetAddressSpace(nullptr); + local->asyncTasksRead++; + } + } +} + +void Scheduler::CreateProcessorThreads(CPULocalStorage *local) { + Thread *idleThread = (Thread *) threadPool.Add(sizeof(Thread)); + idleThread->isKernelThread = true; + idleThread->state = THREAD_ACTIVE; + idleThread->executing = true; + idleThread->type = THREAD_IDLE; + idleThread->terminatableState = THREAD_IN_SYSCALL; + idleThread->cName = "Idle"; + local->currentThread = local->idleThread = idleThread; + + KSpinlockAcquire(&lock); + + if (currentProcessorID >= K_MAX_PROCESSORS) { + KernelPanic("Scheduler::CreateProcessorThreads - Maximum processor count (%d) exceeded.\n", currentProcessorID); + } + + local->processorID = currentProcessorID++; + + // Force release the lock because we've changed our currentThread value. + KSpinlockRelease(&lock); + + InsertNewThread(idleThread, false, kernelProcess); + + local->asyncTaskThread = SpawnThread("AsyncTasks", (uintptr_t) AsyncTaskThread, 0, SPAWN_THREAD_MANUALLY_ACTIVATED); + local->asyncTaskThread->type = THREAD_ASYNC_TASK; +} + +void RegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, Process *targetProcess, bool needed, bool unlocked) { + if (!unlocked) KSpinlockAssertLocked(&scheduler.lock); + else KSpinlockAcquire(&scheduler.lock); + EsDefer(if (unlocked) KSpinlockRelease(&scheduler.lock)); + + if (targetProcess == nullptr) { + targetProcess = kernelProcess; + } + + CPULocalStorage *local = GetLocalStorage(); + + int difference = local->asyncTasksWrite - local->asyncTasksRead; + if (difference < 0) difference += MAX_ASYNC_TASKS; + + if (difference >= MAX_ASYNC_TASKS / 2 && !needed) { + return; + } + + if (difference == MAX_ASYNC_TASKS - 1) { + KernelPanic("RegisterAsyncTask - Maximum number of queued asynchronous tasks reached.\n"); + } + + // We need to register tasks for terminating processes. +#if 0 + if (!targetProcess->handles) { + KernelPanic("RegisterAsyncTask - Process has no handles.\n"); + } +#endif + + volatile AsyncTask *task = local->asyncTasks + local->asyncTasksWrite; + task->callback = callback; + task->argument = argument.p; + task->addressSpace = targetProcess->vmm; + local->asyncTasksWrite++; +} + +void KRegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, bool needed) { + RegisterAsyncTask(callback, argument, kernelProcess, needed, true); +} + +void Scheduler::RemoveProcess(Process *process) { + KernelLog(LOG_INFO, "Scheduler", "remove process", "Removing process %d.\n", process->id); + + bool started = process->executableStartRequest; + + if (started) { + // Make sure that the process cannot be opened. + + KSpinlockAcquire(&lock); + + allProcesses.Remove(&process->allItem); + + if (pmm.nextProcessToBalance == process) { + // If the balance thread got interrupted while balancing this process, + // start at the beginning of the next process. + + pmm.nextProcessToBalance = process->allItem.nextItem ? process->allItem.nextItem->thisItem : nullptr; + pmm.nextRegionToBalance = nullptr; + pmm.balanceResumePosition = 0; + } + + KSpinlockRelease(&lock); + + // At this point, no pointers to the process (should) remain (I think). + + if (!process->allThreadsTerminated) { + KernelPanic("Scheduler::RemoveProcess - The process is being removed before all its threads have terminated?!\n"); + } + + // Close the handle to the executable node. + + CloseHandleToObject(process->executableNode, KERNEL_OBJECT_NODE, ES_FILE_READ); + } + + // Destroy the process's handle table, if it has already been destroyed. + // For most processes, the handle table is destroyed when the last thread terminates. + + process->handleTable.Destroy(); + + // Free all the remaining messages in the message queue. + // This is done after closing all handles, since closing handles can generate messages. + + process->messageQueue.messages.Free(); + + // Free the process. + + KRegisterAsyncTask([] (EsGeneric process) { + MMSpace *space = ((Process *) process.p)->vmm; + MMFinalizeVAS(space); + scheduler.mmSpacePool.Remove(space); + scheduler.processPool.Remove(process.p); + }, process); + + if (started) { + // If all processes (except the kernel process) have terminated, set the scheduler's killedEvent. + + KSpinlockAcquire(&scheduler.lock); + scheduler.blockShutdownProcessCount--; + + if (!scheduler.blockShutdownProcessCount) { + KEventSet(&scheduler.killedEvent, true, false); + } + + KSpinlockRelease(&scheduler.lock); + } +} + +void Scheduler::RemoveThread(Thread *thread) { + KernelLog(LOG_INFO, "Scheduler", "remove thread", "Removing thread %d.\n", thread->id); + + // The last handle to the thread has been closed, + // so we can finally deallocate the thread. + +#ifdef ENABLE_POSIX_SUBSYSTEM + if (thread->posixData) { + if (thread->posixData->forkStack) { + EsHeapFree(thread->posixData->forkStack, thread->posixData->forkStackSize, K_PAGED); + CloseHandleToObject(thread->posixData->forkProcess, KERNEL_OBJECT_PROCESS); + } + + EsHeapFree(thread->posixData, sizeof(POSIXThread), K_PAGED); + } +#endif + + // TODO Deallocate user and kernel stacks. + + scheduler.threadPool.Remove(thread); +} + +void Scheduler::CrashProcess(Process *process, EsCrashReason *crashReason) { + if (process == kernelProcess) { + KernelPanic("Scheduler::CrashProcess - Kernel process has crashed (%d).\n", crashReason->errorCode); + } + + if (process->type != PROCESS_NORMAL) { + KernelPanic("Scheduler::CrashProcess - A critical process has crashed (%d).\n", crashReason->errorCode); + } + + if (GetCurrentThread()->process != process) { + KernelPanic("Scheduler::CrashProcess - Attempt to crash process from different process.\n"); + } + + KMutexAcquire(&process->crashMutex); + + if (process->crashed) { + KMutexRelease(&process->crashMutex); + return; + } + + process->crashed = true; + + KernelLog(LOG_ERROR, "Scheduler", "process crashed", "Process %x has crashed! (%d)\n", process, crashReason->errorCode); + + EsMemoryCopy(&process->crashReason, crashReason, sizeof(EsCrashReason)); + + if (!shutdown) { + OpenHandleToObject(process, KERNEL_OBJECT_PROCESS); + _EsMessageWithObject m; + EsMemoryZero(&m, sizeof(m)); + m.message.type = ES_MSG_APPLICATION_CRASH; + m.message.crash.process = desktopProcess->handleTable.OpenHandle(process, 0, KERNEL_OBJECT_PROCESS); + m.message.crash.pid = process->id; + EsMemoryCopy(&m.message.crash.reason, crashReason, sizeof(EsCrashReason)); + desktopProcess->messageQueue.SendMessage(&m); + } + + KMutexRelease(&process->crashMutex); + + // TODO Shouldn't this be done before sending the desktop message? + scheduler.PauseProcess(GetCurrentThread()->process, false); +} + +void Scheduler::PauseThread(Thread *thread, bool resume, bool lockAlreadyAcquired) { + if (!lockAlreadyAcquired) KSpinlockAcquire(&lock); + + if (thread->paused == !resume) { + return; + } + + thread->paused = !resume; + + if (!resume && thread->terminatableState == THREAD_TERMINATABLE) { + if (thread->state == THREAD_ACTIVE) { + if (thread->executing) { + if (thread == GetCurrentThread()) { + KSpinlockRelease(&lock); + + // Yield. + ProcessorFakeTimerInterrupt(); + + if (thread->paused) { + KernelPanic("Scheduler::PauseThread - Current thread incorrectly resumed.\n"); + } + } else { + // The thread is executing, but on a different processor. + // Send them an IPI to stop. + thread->receivedYieldIPI = false; + KSpinlockAcquire(&ipiLock); + ProcessorSendIPI(YIELD_IPI, false); + KSpinlockRelease(&ipiLock); + while (!thread->receivedYieldIPI); // Spin until the thread gets the IPI. + // TODO The interrupt context might not be set at this point. + } + } else { + // Remove the thread from the active queue, and put it into the paused queue. + thread->item.RemoveFromList(); + AddActiveThread(thread, false); + } + } else { + // The thread doesn't need to be in the paused queue as it won't run anyway. + // If it is unblocked, then AddActiveThread will put it into the correct queue. + } + } else if (resume && thread->item.list == &pausedThreads) { + // Remove the thread from the paused queue, and put it into the active queue. + pausedThreads.Remove(&thread->item); + AddActiveThread(thread, false); + } + + if (!lockAlreadyAcquired) KSpinlockRelease(&lock); +} + +void Scheduler::PauseProcess(Process *process, bool resume) { + Thread *currentThread = GetCurrentThread(); + bool isCurrentProcess = process == currentThread->process; + bool foundCurrentThread = false; + + { + KSpinlockAcquire(&scheduler.lock); + EsDefer(KSpinlockRelease(&scheduler.lock)); + + LinkedItem *thread = process->threads.firstItem; + + while (thread) { + Thread *threadObject = thread->thisItem; + thread = thread->nextItem; + + if (threadObject != currentThread) { + PauseThread(threadObject, resume, true); + } else if (isCurrentProcess) { + foundCurrentThread = true; + } else { + KernelPanic("Scheduler::PauseProcess - Found current thread in the wrong process?!\n"); + } + } + } + + if (!foundCurrentThread && isCurrentProcess) { + KernelPanic("Scheduler::PauseProcess - Could not find current thread in the current process?!\n"); + } else if (isCurrentProcess) { + PauseThread(currentThread, resume, false); + } +} + +void _RemoveProcess(EsGeneric process) { + scheduler.RemoveProcess((Process *) process.p); +} + +void CloseHandleToProcess(void *_process) { + KSpinlockAcquire(&scheduler.lock); + Process *process = (Process *) _process; + if (!process->handles) KernelPanic("CloseHandleToProcess - All handles to the process have been closed.\n"); + process->handles--; + bool removeProcess = !process->handles; + + KernelLog(LOG_VERBOSE, "Scheduler", "close process handle", "Closed handle to process %d; %d handles remain.\n", process->id, process->handles); + + if (removeProcess && process->executableStartRequest) { + // This must be done in the correct virtual address space! + RegisterAsyncTask(_RemoveProcess, process, process, true); + } + + KSpinlockRelease(&scheduler.lock); + + if (removeProcess && !process->executableStartRequest) { + // The process was never started, so we can't make a RemoveProcess task, because it doesn't have an MMSpace yet. + scheduler.RemoveProcess(process); + } + + ProcessorFakeTimerInterrupt(); // Process the asynchronous task. +} + +void CloseHandleToThread(void *_thread) { + KSpinlockAcquire(&scheduler.lock); + Thread *thread = (Thread *) _thread; + if (!thread->handles) KernelPanic("CloseHandleToThread - All handles to the thread have been closed.\n"); + thread->handles--; + bool removeThread = thread->handles == 0; + // EsPrint("Thread %d has %d handles\n", thread->id, thread->handles); + KSpinlockRelease(&scheduler.lock); + + if (removeThread) { + scheduler.RemoveThread(thread); + } +} + +void KillThread(EsGeneric _thread) { + Thread *thread = (Thread *) _thread.p; + + KSpinlockAcquire(&scheduler.lock); + scheduler.allThreads.Remove(&thread->allItem); + thread->process->threads.Remove(&thread->processItem); + + KernelLog(LOG_INFO, "Scheduler", "killing thread", + "Killing thread (ID %d, %d remain in process %d) %x...\n", thread->id, thread->process->threads.count, thread->process->id, _thread); + + if (thread->process->threads.count == 0) { + Process *process = thread->process; + KernelLog(LOG_INFO, "Scheduler", "killing process", + "Killing process (%d) %x...\n", process->id, process); + + process->allThreadsTerminated = true; + scheduler.activeProcessCount--; + + bool setProcessKilledEvent = true; + +#ifdef ENABLE_POSIX_SUBSYSTEM + if (process->posixForking) { + // If the process is from an incomplete vfork(), + // then the parent process gets to set the killed event + // and the exit status. + setProcessKilledEvent = false; + } +#endif + + if (setProcessKilledEvent) { + // We can now also set the killed event on the process. + KEventSet(&process->killedEvent, true); + } + + KSpinlockRelease(&scheduler.lock); + + // There are no threads left in this process. + // We should destroy the handle table at this point. + // Otherwise, the process might never be freed + // because of a cyclic-dependency. + process->handleTable.Destroy(); + + // Destroy the virtual memory space. + // Don't actually deallocate it yet though; that is done on an async task queued by RemoveProcess. + // This must be destroyed after the handle table! + MMSpaceDestroy(process->vmm); + + // Tell Desktop the process has terminated. + if (!scheduler.shutdown) { + _EsMessageWithObject m; + EsMemoryZero(&m, sizeof(m)); + m.message.type = ES_MSG_PROCESS_TERMINATED; + m.message.crash.pid = process->id; + desktopProcess->messageQueue.SendMessage(&m); + } + } else { + KSpinlockRelease(&scheduler.lock); + } + + MMFree(kernelMMSpace, (void *) thread->kernelStackBase); + if (thread->userStackBase) MMFree(thread->process->vmm, (void *) thread->userStackBase); + + KEventSet(&thread->killedEvent); + + // Close the handle that this thread owns of its owner process. + CloseHandleToObject(thread->process, KERNEL_OBJECT_PROCESS); + + CloseHandleToThread(thread); +} + +Thread *Scheduler::PickThread(CPULocalStorage *local) { + KSpinlockAssertLocked(&lock); + + if (local->asyncTasksRead != local->asyncTasksWrite + && local->asyncTaskThread->state == THREAD_ACTIVE) { + // If the asynchronous task thread for this processor isn't blocked, and has tasks to process, execute it. + return local->asyncTaskThread; + } + + for (int i = 0; i < THREAD_PRIORITY_COUNT; i++) { + // For every priority, check if there is a thread available. If so, execute it. + LinkedItem *item = activeThreads[i].firstItem; + if (!item) continue; + item->RemoveFromList(); + return item->thisItem; + } + + // If we couldn't find a thread to execute, idle. + return local->idleThread; +} + +void Scheduler::Yield(InterruptContext *context) { + CPULocalStorage *local = GetLocalStorage(); + + if (!started || !local || !local->schedulerReady) { + return; + } + + if (local->spinlockCount) { + KernelPanic("Scheduler::Yield - Spinlocks acquired while attempting to yield (2).\n"); + } + + if (local->spinlockCount) { + KernelPanic("Scheduler::Yield - Spinlocks acquired while attempting to yield.\n"); + } + + ProcessorDisableInterrupts(); // We don't want interrupts to get reenabled after the context switch. + KSpinlockAcquire(&lock); + + local->currentThread->interruptContext = context; + + if (lock.interruptsEnabled) { + KernelPanic("Scheduler::Yield - Interrupts were enabled when scheduler lock was acquired.\n"); + } + + local->currentThread->executing = false; + + bool killThread = local->currentThread->terminatableState == THREAD_TERMINATABLE + && local->currentThread->terminating; + bool keepThreadAlive = local->currentThread->terminatableState == THREAD_USER_BLOCK_REQUEST + && local->currentThread->terminating; // The user can't make the thread block if it is terminating. + + if (killThread) { + local->currentThread->state = THREAD_TERMINATED; + KernelLog(LOG_INFO, "Scheduler", "terminate yielded thread", "Terminated yielded thread %x\n", local->currentThread); + RegisterAsyncTask(KillThread, local->currentThread, local->currentThread->process, true); + } + + // If the thread is waiting for an object to be notified, put it in the relevant blockedThreads list. + // But if the object has been notified yet hasn't made itself active yet, do that for it. + + else if (local->currentThread->state == THREAD_WAITING_MUTEX) { + KMutex *mutex = local->currentThread->blocking.mutex; + + if (!keepThreadAlive && mutex->owner) { + mutex->owner->blockedThreadPriorities[local->currentThread->priority]++; + MaybeUpdateActiveList(mutex->owner); + mutex->blockedThreads.InsertEnd(&local->currentThread->item); + } else { + local->currentThread->state = THREAD_ACTIVE; + } + } + + else if (local->currentThread->state == THREAD_WAITING_EVENT) { + if (keepThreadAlive) { + local->currentThread->state = THREAD_ACTIVE; + } else { + bool unblocked = false; + + for (uintptr_t i = 0; i < local->currentThread->blocking.eventCount; i++) { + if (local->currentThread->blocking.events[i]->state) { + local->currentThread->state = THREAD_ACTIVE; + unblocked = true; + break; + } + } + + if (!unblocked) { + for (uintptr_t i = 0; i < local->currentThread->blocking.eventCount; i++) { + local->currentThread->blocking.events[i]->blockedThreads.InsertEnd(&local->currentThread->blockedItems[i]); + } + } + } + } + + else if (local->currentThread->state == THREAD_WAITING_WRITER_LOCK) { + KWriterLock *lock = local->currentThread->blocking.writerLock; + + if ((local->currentThread->blocking.writerLockType == K_LOCK_SHARED && lock->state >= 0) + || (local->currentThread->blocking.writerLockType == K_LOCK_EXCLUSIVE && lock->state == 0)) { + local->currentThread->state = THREAD_ACTIVE; + } else { + local->currentThread->blocking.writerLock->blockedThreads.InsertEnd(&local->currentThread->item); + } + } + + // Put the current thread at the end of the activeThreads list. + if (!killThread && local->currentThread->state == THREAD_ACTIVE) { + if (local->currentThread->type == THREAD_NORMAL) { + AddActiveThread(local->currentThread, false); + } else if (local->currentThread->type == THREAD_IDLE || local->currentThread->type == THREAD_ASYNC_TASK) { + // Do nothing. + } else { + KernelPanic("Scheduler::Yield - Unrecognised thread type\n"); + } + } + + // Notify any triggered timers. + + LinkedItem *_timer = activeTimers.firstItem; + + while (_timer) { + KTimer *timer = _timer->thisItem; + LinkedItem *next = _timer->nextItem; + + if (timer->triggerTimeMs <= timeMs) { + activeTimers.Remove(_timer); + KEventSet(&timer->event, true /* scheduler already locked */); + + if (timer->callback) { + RegisterAsyncTask(timer->callback, timer->argument, nullptr, true); + } + } else { + break; // Timers are kept sorted, so there's no point continuing. + } + + _timer = next; + } + + // Get the next thread to execute. + Thread *newThread = local->currentThread = PickThread(local); + + if (!newThread) { + KernelPanic("Scheduler::Yield - Could not find a thread to execute.\n"); + } + + if (newThread->executing) { + KernelPanic("Scheduler::Yield - Thread (ID %d) in active queue already executing with state %d, type %d.\n", + local->currentThread->id, local->currentThread->state, local->currentThread->type); + } + + // Store information about the thread. + newThread->executing = true; + newThread->executingProcessorID = local->processorID; + newThread->cpuTimeSlices++; + if (newThread->type == THREAD_IDLE) newThread->process->idleTimeSlices++; + else newThread->process->cpuTimeSlices++; + + // Prepare the next timer interrupt. + uint64_t time = 1; + ArchNextTimer(time); + + InterruptContext *newContext = newThread->interruptContext; + + if (!local->processorID) { + // Update the scheduler's time. + timeMs = ProcessorReadTimeStamp() / KGetTimeStampTicksPerMs(); + + // Update the time stamp counter synchronization value. + extern volatile uint64_t timeStampCounterSynchronizationValue; + timeStampCounterSynchronizationValue = ((timeStampCounterSynchronizationValue & 0x8000000000000000) + ^ 0x8000000000000000) | ProcessorReadTimeStamp(); + } + + MMSpace *addressSpace = newThread->process->vmm; + if (newThread->temporaryAddressSpace) addressSpace = newThread->temporaryAddressSpace; + DoContextSwitch(newContext, VIRTUAL_ADDRESS_SPACE_IDENTIFIER(addressSpace), newThread->kernelStack, newThread); +} + +void Scheduler::Shutdown() { + // Prevent the creation of new proceses or threads, + // or terminate this thread if we're already shutting down. + if (__sync_val_compare_and_swap(&scheduler.shutdown, false, true)) KThreadTerminate(); + + // Close our handle to the desktop process. + CloseHandleToObject(desktopProcess->executableMainThread, KERNEL_OBJECT_THREAD); + CloseHandleToObject(desktopProcess, KERNEL_OBJECT_PROCESS); + + KernelLog(LOG_INFO, "Scheduler", "killing all processes", "Scheduler::Destroy - Killing all processes....\n"); + + while (true) { + KSpinlockAcquire(&lock); + Process *process = allProcesses.firstItem->thisItem; + + while (process && (process->terminating || process == kernelProcess)) { + LinkedItem *item = process->allItem.nextItem; + process = item ? item->thisItem : nullptr; + } + + KSpinlockRelease(&lock); + if (!process) break; + + TerminateProcess(process, -1); + } + + KEventWait(&killedEvent); +} + +Process *Scheduler::OpenProcess(uint64_t id) { + KSpinlockAcquire(&scheduler.lock); + + LinkedItem *item = scheduler.allProcesses.firstItem; + + while (item) { + Process *process = item->thisItem; + + if (process->id == id + && process->handles /* if the process has no handles, it's about to be removed */ + && process->type != PROCESS_KERNEL /* the kernel process cannot be opened */) { + process->handles++; + break; + } + + item = item->nextItem; + } + + KSpinlockRelease(&scheduler.lock); + + return item ? item->thisItem : nullptr; +} + +bool KThreadCreate(const char *cName, void (*startAddress)(uintptr_t), uintptr_t argument) { + return scheduler.SpawnThread(cName, (uintptr_t) startAddress, argument) ? true : false; +} + +void KThreadTerminate() { + scheduler.TerminateThread(GetCurrentThread()); +} + +void KYield() { + ProcessorFakeTimerInterrupt(); +} + +uint64_t KCPUCurrentID() { return GetLocalStorage() ->processorID; } +uint64_t KProcessCurrentID() { return GetCurrentThread()->process->id; } +uint64_t KThreadCurrentID() { return GetCurrentThread() ->id; } + +#endif diff --git a/kernel/symbols.cpp b/kernel/symbols.cpp new file mode 100644 index 0000000..af20c53 --- /dev/null +++ b/kernel/symbols.cpp @@ -0,0 +1,46 @@ +#include +#include + +extern "C" int EsStringCompareRaw(const char *s1, size_t b1, const char *s2, size_t b2); +void EsPrint(const char *format, ...); + +extern "C" void KernelMain(); +extern "C" void ProcessorHalt(); + +struct ExportedKernelFunction { + void *address; + const char *name; +}; + +ExportedKernelFunction exportedKernelFunctions[] = { +#include +}; + +static bool linked; + +void *ResolveKernelSymbol(const char *name, size_t nameBytes) { + // EsPrint("Resolve: '%s'.\n", nameBytes, name); + + if (!linked) { + linked = true; + + // As we get the function addresses before the kernel is linked (this file needs to be linked with the kernel), + // they are relative to wherever the kernel_all.o's text is placed in the executable's text section. + + uintptr_t offset = (uintptr_t) ResolveKernelSymbol("KernelMain", 10) - (uintptr_t) KernelMain; + + for (uintptr_t i = 0; i < sizeof(exportedKernelFunctions) / sizeof(exportedKernelFunctions[0]); i++) { + exportedKernelFunctions[i].address = (void *) ((uintptr_t) exportedKernelFunctions[i].address - offset); + } + } + + for (uintptr_t i = 0; i < sizeof(exportedKernelFunctions) / sizeof(exportedKernelFunctions[0]); i++) { + if (0 == EsStringCompareRaw(exportedKernelFunctions[i].name, -1, name, nameBytes)) { + return exportedKernelFunctions[i].address; + } + } + + EsPrint("ResolveKernelSymbol - Could not find symbol '%s'.\n", nameBytes, name); + + return nullptr; +} diff --git a/kernel/synchronisation.cpp b/kernel/synchronisation.cpp new file mode 100644 index 0000000..04a69f9 --- /dev/null +++ b/kernel/synchronisation.cpp @@ -0,0 +1,862 @@ +#ifdef IMPLEMENTATION + +#ifdef DEBUG_BUILD +uintptr_t nextMutexID; +#endif + +void KSpinlockAcquire(KSpinlock *spinlock) { + if (scheduler.panic) return; + + bool _interruptsEnabled = ProcessorAreInterruptsEnabled(); + ProcessorDisableInterrupts(); + + CPULocalStorage *storage = GetLocalStorage(); + +#ifdef DEBUG_BUILD + if (storage && storage->currentThread && spinlock->owner && spinlock->owner == storage->currentThread) { + KernelPanic("KSpinlock::Acquire - Attempt to acquire a spinlock owned by the current thread (%x/%x, CPU: %d/%d).\nAcquired at %x.\n", + storage->currentThread, spinlock->owner, storage->processorID, spinlock->ownerCPU, spinlock->acquireAddress); + } +#endif + + if (storage) { + storage->spinlockCount++; + } + + while (__sync_val_compare_and_swap(&spinlock->state, 0, 1)); + __sync_synchronize(); + + spinlock->interruptsEnabled = _interruptsEnabled; + + if (storage) { +#ifdef DEBUG_BUILD + spinlock->owner = storage->currentThread; +#endif + spinlock->ownerCPU = storage->processorID; + } else { + // Because spinlocks can be accessed very early on in initialisation there may not be + // a CPULocalStorage available for the current processor. Therefore, just set this field to nullptr. + +#ifdef DEBUG_BUILD + spinlock->owner = nullptr; +#endif + } + +#ifdef DEBUG_BUILD + spinlock->acquireAddress = (uintptr_t) __builtin_return_address(0); +#endif +} + +void KSpinlockRelease(KSpinlock *spinlock, bool force) { + if (scheduler.panic) return; + + CPULocalStorage *storage = GetLocalStorage(); + + if (storage) { + storage->spinlockCount--; + } + + if (!force) { + KSpinlockAssertLocked(spinlock); + } + + volatile bool wereInterruptsEnabled = spinlock->interruptsEnabled; + +#ifdef DEBUG_BUILD + spinlock->owner = nullptr; +#endif + __sync_synchronize(); + spinlock->state = 0; + + if (wereInterruptsEnabled) ProcessorEnableInterrupts(); + +#ifdef DEBUG_BUILD + spinlock->releaseAddress = (uintptr_t) __builtin_return_address(0); +#endif +} + +void KSpinlockAssertLocked(KSpinlock *spinlock) { + if (scheduler.panic) return; + +#ifdef DEBUG_BUILD + CPULocalStorage *storage = GetLocalStorage(); + + if (!spinlock->state || ProcessorAreInterruptsEnabled() + || (storage && spinlock->owner != storage->currentThread)) { +#else + if (!spinlock->state || ProcessorAreInterruptsEnabled()) { +#endif + KernelPanic("KSpinlock::AssertLocked - KSpinlock not correctly acquired\n" + "Return address = %x.\n" + "state = %d, ProcessorAreInterruptsEnabled() = %d, this = %x\n", + __builtin_return_address(0), spinlock->state, + ProcessorAreInterruptsEnabled(), spinlock); + } +} + +Thread *AttemptMutexAcquisition(KMutex *mutex, Thread *currentThread) { + KSpinlockAcquire(&scheduler.lock); + + Thread *old = mutex->owner; + + if (!old) { + mutex->owner = currentThread; + } + + KSpinlockRelease(&scheduler.lock); + + return old; +} + +#ifdef DEBUG_BUILD +bool _KMutexAcquire(KMutex *mutex, const char *cMutexString, const char *cFile, int line) { +#else +bool KMutexAcquire(KMutex *mutex) { +#endif + if (scheduler.panic) return false; + + Thread *currentThread = GetCurrentThread(); + bool hasThread = currentThread; + + if (!currentThread) { + currentThread = (Thread *) 1; + } else { + if (currentThread->terminatableState == THREAD_TERMINATABLE) { + KernelPanic("KMutex::Acquire - Thread is terminatable.\n"); + } + } + + if (hasThread && mutex->owner && mutex->owner == currentThread) { +#ifdef DEBUG_BUILD + KernelPanic("KMutex::Acquire - Attempt to acquire mutex (%x) at %x owned by current thread (%x) acquired at %x.\n", + mutex, __builtin_return_address(0), currentThread, mutex->acquireAddress); +#else + KernelPanic("KMutex::Acquire - Attempt to acquire mutex (%x) at %x owned by current thread (%x).\n", + mutex, __builtin_return_address(0), currentThread); +#endif + } + + if (!ProcessorAreInterruptsEnabled()) { + KernelPanic("KMutex::Acquire - Trying to acquire a mutex while interrupts are disabled.\n"); + } + + while (AttemptMutexAcquisition(mutex, currentThread)) { + __sync_synchronize(); + + if (GetLocalStorage() && GetLocalStorage()->schedulerReady) { + // Instead of spinning on the lock, + // let's tell the scheduler to not schedule this thread + // until it's released. + scheduler.WaitMutex(mutex); + + if (currentThread->terminating && currentThread->terminatableState == THREAD_USER_BLOCK_REQUEST) { + // We didn't acquire the mutex because the thread is terminating. + return false; + } + } + } + + __sync_synchronize(); + + if (mutex->owner != currentThread) { + KernelPanic("KMutex::Acquire - Invalid owner thread (%x, expected %x).\n", mutex->owner, currentThread); + } + +#ifdef DEBUG_BUILD + mutex->acquireAddress = (uintptr_t) __builtin_return_address(0); + KMutexAssertLocked(mutex); + + if (!mutex->id) { + mutex->id = __sync_fetch_and_add(&nextMutexID, 1); + } + + if (currentThread && scheduler.threadEventLog) { + uintptr_t position = __sync_fetch_and_add(&scheduler.threadEventLogPosition, 1); + + if (position < scheduler.threadEventLogAllocated) { + EsThreadEventLogEntry *entry = scheduler.threadEventLog + position; + entry->event = ES_THREAD_EVENT_MUTEX_ACQUIRE; + entry->objectID = mutex->id; + entry->threadID = currentThread->id; + entry->line = line; + entry->fileBytes = EsCStringLength(cFile); + if (entry->fileBytes > sizeof(entry->file)) entry->fileBytes = sizeof(entry->file); + entry->expressionBytes = EsCStringLength(cMutexString); + if (entry->expressionBytes > sizeof(entry->expression)) entry->expressionBytes = sizeof(entry->expression); + EsMemoryCopy(entry->file, cFile, entry->fileBytes); + EsMemoryCopy(entry->expression, cMutexString, entry->expressionBytes); + } + } +#endif + + return true; +} + +#ifdef DEBUG_BUILD +void _KMutexRelease(KMutex *mutex, const char *cMutexString, const char *cFile, int line) { +#else +void KMutexRelease(KMutex *mutex) { +#endif + if (scheduler.panic) return; + + KMutexAssertLocked(mutex); + Thread *currentThread = GetCurrentThread(); + KSpinlockAcquire(&scheduler.lock); + +#ifdef DEBUG_BUILD + // EsPrint("$%x:%x:0\n", owner, id); +#endif + + if (currentThread) { + Thread *temp = __sync_val_compare_and_swap(&mutex->owner, currentThread, nullptr); + if (currentThread != temp) KernelPanic("KMutex::Release - Invalid owner thread (%x, expected %x).\n", temp, currentThread); + } else mutex->owner = nullptr; + + volatile bool preempt = mutex->blockedThreads.count; + + if (scheduler.started) { + // NOTE We unblock all waiting threads, because of how blockedThreadPriorities works. + scheduler.NotifyObject(&mutex->blockedThreads, true, currentThread); + } + + KSpinlockRelease(&scheduler.lock); + __sync_synchronize(); + +#ifdef DEBUG_BUILD + mutex->releaseAddress = (uintptr_t) __builtin_return_address(0); + + if (currentThread && scheduler.threadEventLog) { + uintptr_t position = __sync_fetch_and_add(&scheduler.threadEventLogPosition, 1); + + if (position < scheduler.threadEventLogAllocated) { + EsThreadEventLogEntry *entry = scheduler.threadEventLog + position; + entry->event = ES_THREAD_EVENT_MUTEX_RELEASE; + entry->objectID = mutex->id; + entry->threadID = currentThread->id; + entry->line = line; + entry->fileBytes = EsCStringLength(cFile); + if (entry->fileBytes > sizeof(entry->file)) entry->fileBytes = sizeof(entry->file); + entry->expressionBytes = EsCStringLength(cMutexString); + if (entry->expressionBytes > sizeof(entry->expression)) entry->expressionBytes = sizeof(entry->expression); + EsMemoryCopy(entry->file, cFile, entry->fileBytes); + EsMemoryCopy(entry->expression, cMutexString, entry->expressionBytes); + } + } +#endif + +#ifdef PREEMPT_AFTER_MUTEX_RELEASE + if (preempt) ProcessorFakeTimerInterrupt(); +#endif +} + +void KMutexAssertLocked(KMutex *mutex) { + Thread *currentThread = GetCurrentThread(); + + if (!currentThread) { + currentThread = (Thread *) 1; + } + + if (mutex->owner != currentThread) { +#ifdef DEBUG_BUILD + KernelPanic("KMutex::AssertLocked - Mutex not correctly acquired\n" + "currentThread = %x, owner = %x\nthis = %x\nReturn %x/%x\nLast used from %x->%x\n", + currentThread, mutex->owner, mutex, __builtin_return_address(0), __builtin_return_address(1), + mutex->acquireAddress, mutex->releaseAddress); +#else + KernelPanic("KMutex::AssertLocked - Mutex not correctly acquired\n" + "currentThread = %x, owner = %x\nthis = %x\nReturn %x\n", + currentThread, mutex->owner, mutex, __builtin_return_address(0)); +#endif + } +} + +bool KSemaphorePoll(KSemaphore *semaphore) { + bool success = false; + KMutexAcquire(&semaphore->mutex); + if (semaphore->units) { success = true; semaphore->units--; } + if (!semaphore->units && semaphore->available.state) KEventReset(&semaphore->available); + KMutexRelease(&semaphore->mutex); + return success; +} + +bool KSemaphoreTake(KSemaphore *semaphore, uintptr_t u, uintptr_t timeoutMs) { + // All-or-nothing approach to prevent deadlocks. + + uintptr_t taken = 0; + + while (u) { + if (!KEventWait(&semaphore->available, timeoutMs)) { + KSemaphoreReturn(semaphore, taken); + return false; + } + + KMutexAcquire(&semaphore->mutex); + if (semaphore->units >= u) { semaphore->units -= u; u = 0; taken += u; } + if (!semaphore->units && semaphore->available.state) KEventReset(&semaphore->available); + KMutexRelease(&semaphore->mutex); + + semaphore->lastTaken = (uintptr_t) __builtin_return_address(0); + } + + return true; +} + +void KSemaphoreReturn(KSemaphore *semaphore, uintptr_t u) { + KMutexAcquire(&semaphore->mutex); + if (!semaphore->available.state) KEventSet(&semaphore->available); + semaphore->units += u; + KMutexRelease(&semaphore->mutex); +} + +void KSemaphoreSet(KSemaphore *semaphore, uintptr_t u) { + KMutexAcquire(&semaphore->mutex); + if (!semaphore->available.state && u) KEventSet(&semaphore->available); + else if (semaphore->available.state && !u) KEventReset(&semaphore->available); + semaphore->units = u; + KMutexRelease(&semaphore->mutex); +} + +EsError EventSink::Push(EsGeneric data) { + EsError result = ES_SUCCESS; + + KSpinlockAssertLocked(&scheduler.lock); + + KSpinlockAcquire(&spinlock); + + if (queueCount == ES_MAX_EVENT_SINK_BUFFER_SIZE) { + overflow = true; + result = ES_ERROR_EVENT_SINK_OVERFLOW; + KernelLog(LOG_VERBOSE, "Event Sinks", "push overflow", "Push %d into %x.\n", data.i, this); + } else { + bool ignored = false; + + if (ignoreDuplicates) { + uintptr_t index = queuePosition; + + for (uintptr_t i = 0; i < queueCount; i++) { + if (queue[index] == data) { + ignored = true; + result = ES_ERROR_EVENT_SINK_DUPLICATE; + KernelLog(LOG_VERBOSE, "Event Sinks", "push ignored", "Push %d into %x.\n", data.i, this); + break; + } + + index++; + + if (index == ES_MAX_EVENT_SINK_BUFFER_SIZE) { + index = 0; + } + } + } + + if (!ignored) { + uintptr_t writeIndex = queuePosition + queueCount; + if (writeIndex >= ES_MAX_EVENT_SINK_BUFFER_SIZE) writeIndex -= ES_MAX_EVENT_SINK_BUFFER_SIZE; + if (writeIndex >= ES_MAX_EVENT_SINK_BUFFER_SIZE) KernelPanic("EventSink::Push - Invalid event sink (%x) queue.\n", this); + KernelLog(LOG_VERBOSE, "Event Sinks", "push", "Push %d into %x at %d (%d/%d).\n", data.i, this, writeIndex, queuePosition, queueCount); + queue[writeIndex] = data; + queueCount++; + KEventSet(&available, true, true); + } + } + + KSpinlockRelease(&spinlock); + + return result; +} + +bool KEventSet(KEvent *event, bool schedulerAlreadyLocked, bool maybeAlreadySet) { + if (event->state && !maybeAlreadySet) { + KernelLog(LOG_ERROR, "Synchronisation", "event already set", "KEvent::Set - Attempt to set a event that had already been set\n"); + } + + if (!schedulerAlreadyLocked) { + KSpinlockAcquire(&scheduler.lock); + } else { + KSpinlockAssertLocked(&scheduler.lock); + } + + volatile bool unblockedThreads = false; + + if (!event->state) { + if (event->sinkTable) { + for (uintptr_t i = 0; i < ES_MAX_EVENT_FORWARD_COUNT; i++) { + if (!event->sinkTable[i].sink) continue; + event->sinkTable[i].sink->Push(event->sinkTable[i].data); + } + } + + event->state = true; + + if (scheduler.started) { + if (event->blockedThreads.count) { + unblockedThreads = true; + } + + scheduler.NotifyObject(&event->blockedThreads, !event->autoReset /* if this is a manually reset event, unblock all the waiting threads */); + } + } + + if (!schedulerAlreadyLocked) { + KSpinlockRelease(&scheduler.lock); + } + + return unblockedThreads; +} + +void KEventReset(KEvent *event) { + if (event->blockedThreads.firstItem && event->state) { + // TODO Is it possible for this to happen? + KernelLog(LOG_ERROR, "Synchronisation", "reset event with threads blocking", + "KEvent::Reset - Attempt to reset a event while threads are blocking on the event\n"); + } + + event->state = false; +} + +bool KEventPoll(KEvent *event) { + if (event->autoReset) { + return __sync_val_compare_and_swap(&event->state, true, false); + } else { + return event->state; + } +} + +bool KEventWait(KEvent *_this, uint64_t timeoutMs) { + KEvent *events[2]; + events[0] = _this; + + if (timeoutMs == (uint64_t) ES_WAIT_NO_TIMEOUT) { + int index = scheduler.WaitEvents(events, 1); + return index == 0; + } else { + KTimer timer = {}; + KTimerSet(&timer, timeoutMs); + events[1] = &timer.event; + int index = scheduler.WaitEvents(events, 2); + KTimerRemove(&timer); + return index == 0; + } +} + +void KWriterLockAssertLocked(KWriterLock *lock) { + if (lock->state == 0) { + KernelPanic("KWriterLock::AssertLocked - Unlocked.\n"); + } +} + +void KWriterLockAssertShared(KWriterLock *lock) { + if (lock->state == 0) { + KernelPanic("KWriterLock::AssertShared - Unlocked.\n"); + } else if (lock->state < 0) { + KernelPanic("KWriterLock::AssertShared - In exclusive mode.\n"); + } +} + +void KWriterLockAssertExclusive(KWriterLock *lock) { + if (lock->state == 0) { + KernelPanic("KWriterLock::AssertExclusive - Unlocked.\n"); + } else if (lock->state > 0) { + KernelPanic("KWriterLock::AssertExclusive - In shared mode, with %d readers.\n", lock->state); + } +} + +void KWriterLockReturn(KWriterLock *lock, bool write) { + KSpinlockAcquire(&scheduler.lock); + + if (lock->state == -1) { + if (!write) { + KernelPanic("KWriterLock::Return - Attempting to return shared access to an exclusively owned lock.\n"); + } + + lock->state = 0; + } else if (lock->state == 0) { + KernelPanic("KWriterLock::Return - Attempting to return access to an unowned lock.\n"); + } else { + if (write) { + KernelPanic("KWriterLock::Return - Attempting to return exclusive access to an shared lock.\n"); + } + + lock->state--; + } + + if (!lock->state) { + scheduler.NotifyObject(&lock->blockedThreads, true); + } + + KSpinlockRelease(&scheduler.lock); +} + +bool KWriterLockTake(KWriterLock *lock, bool write, bool poll) { + // TODO Preventing exclusive access starvation. + // TODO Do this without taking the scheduler's lock? + + bool done = false; + + Thread *thread = GetCurrentThread(); + + if (thread) { + thread->blocking.writerLock = lock; + thread->blocking.writerLockType = write; + } + + while (true) { + KSpinlockAcquire(&scheduler.lock); + + if (write) { + if (lock->state == 0) { + lock->state = -1; + done = true; +#ifdef DEBUG_BUILD + lock->exclusiveOwner = thread; +#endif + } + } else { + if (lock->state >= 0) { + lock->state++; + done = true; + } + } + + KSpinlockRelease(&scheduler.lock); + + if (poll || done) { + break; + } else { + if (!thread) { + KernelPanic("KWriterLock::Take - Scheduler not ready yet.\n"); + } + + thread->state = THREAD_WAITING_WRITER_LOCK; + ProcessorFakeTimerInterrupt(); + thread->state = THREAD_ACTIVE; + } + } + + return done; +} + +void KWriterLockTakeMultiple(KWriterLock **locks, size_t lockCount, bool write) { + uintptr_t i = 0, taken = 0; + + while (taken != lockCount) { + if (KWriterLockTake(locks[i], write, taken)) { + taken++, i++; + if (i == lockCount) i = 0; + } else { + intptr_t j = i - 1; + + while (taken) { + if (j == -1) j = lockCount - 1; + KWriterLockReturn(locks[j], write); + j--, taken--; + } + } + } +} + +void KWriterLockConvertExclusiveToShared(KWriterLock *lock) { + KSpinlockAcquire(&scheduler.lock); + KWriterLockAssertExclusive(lock); + lock->state = 1; + scheduler.NotifyObject(&lock->blockedThreads, true); + KSpinlockRelease(&scheduler.lock); +} + +#if 0 + +volatile int testState; +KWriterLock testWriterLock; + +void TestWriterLocksThread1(uintptr_t) { + KEvent wait = {}; + testWriterLock.Take(K_LOCK_SHARED); + EsPrint("-->1\n"); + testState = 1; + while (testState != 2); + wait.Wait(1000); + EsPrint("-->3\n"); + testWriterLock.Return(K_LOCK_SHARED); + testState = 3; +} + +void TestWriterLocksThread2(uintptr_t) { + while (testState != 1); + testWriterLock.Take(K_LOCK_SHARED); + EsPrint("-->2\n"); + testState = 2; + while (testState != 3); + testWriterLock.Return(K_LOCK_SHARED); +} + +void TestWriterLocksThread3(uintptr_t) { + while (testState < 1); + testWriterLock.Take(K_LOCK_EXCLUSIVE); + EsPrint("!!!!!!!!!!!!!!!!!!! %d\n", testState); + testWriterLock.Return(K_LOCK_EXCLUSIVE); + testState = 5; +} + +#define TEST_WRITER_LOCK_THREADS (4) + +void TestWriterLocksThread4(uintptr_t) { + __sync_fetch_and_add(&testState, 1); + + while (testState < 6 + TEST_WRITER_LOCK_THREADS) { + bool type = EsRandomU8() < 0xC0; + testWriterLock.Take(type); + testWriterLock.Return(type); + } + + __sync_fetch_and_add(&testState, 1); +} + +void TestWriterLocks() { + testState = 0; + EsPrint("TestWriterLocks...\n"); + KThreadCreate("Test1", TestWriterLocksThread1); + KThreadCreate("Test2", TestWriterLocksThread2); + KThreadCreate("Test3", TestWriterLocksThread3); + EsPrint("waiting for state 5...\n"); + while (testState != 5); + while (true) { + testState = 5; + for (int i = 0; i < TEST_WRITER_LOCK_THREADS; i++) { + KThreadCreate("Test", TestWriterLocksThread4, i); + } + while (testState != TEST_WRITER_LOCK_THREADS + 5); + EsPrint("All threads ready.\n"); + KEvent wait = {}; + wait.Wait(10000); + testState++; + while (testState != TEST_WRITER_LOCK_THREADS * 2 + 6); + EsPrint("Test complete!\n"); + } +} + +#endif + +void KTimerSet(KTimer *timer, uint64_t triggerInMs, KAsyncTaskCallback _callback, EsGeneric _argument) { + KSpinlockAcquire(&scheduler.lock); + EsDefer(KSpinlockRelease(&scheduler.lock)); + + // Reset the timer state. + + if (timer->item.list) { + scheduler.activeTimers.Remove(&timer->item); + } + + KEventReset(&timer->event); + + // Set the timer information. + + timer->triggerTimeMs = triggerInMs + scheduler.timeMs; + timer->callback = _callback; + timer->argument = _argument; + timer->item.thisItem = timer; + + // Add the timer to the list of active timers, keeping the list sorted by trigger time. + + LinkedItem *_timer = scheduler.activeTimers.firstItem; + + while (_timer) { + KTimer *timer2 = _timer->thisItem; + LinkedItem *next = _timer->nextItem; + + if (timer2->triggerTimeMs > timer->triggerTimeMs) { + break; // Insert before this timer. + } + + _timer = next; + } + + if (_timer) { + scheduler.activeTimers.InsertBefore(&timer->item, _timer); + } else { + scheduler.activeTimers.InsertEnd(&timer->item); + } +} + +void KTimerRemove(KTimer *timer) { + KSpinlockAcquire(&scheduler.lock); + EsDefer(KSpinlockRelease(&scheduler.lock)); + + if (timer->callback) { + KernelPanic("KTimer::Remove - Timers with callbacks cannot be removed.\n"); + } + + if (timer->item.list) { + scheduler.activeTimers.Remove(&timer->item); + } +} + +void Scheduler::WaitMutex(KMutex *mutex) { + Thread *thread = GetCurrentThread(); + + if (thread->state != THREAD_ACTIVE) { + KernelPanic("Scheduler::WaitMutex - Attempting to wait on a mutex in a non-active thread.\n"); + } + + KSpinlockAcquire(&lock); + + thread->state = THREAD_WAITING_MUTEX; + thread->blocking.mutex = mutex; + + // Is the owner of this mutex executing? + // If not, there's no point in spinning on it. + bool spin = mutex && mutex->owner && mutex->owner->executing; + + KSpinlockRelease(&lock); + + if (!spin && thread->blocking.mutex->owner) { + ProcessorFakeTimerInterrupt(); + } + + // Early exit if this is a user request to block the thread and the thread is terminating. + while ((!thread->terminating || thread->terminatableState != THREAD_USER_BLOCK_REQUEST) && mutex->owner) { + thread->state = THREAD_WAITING_MUTEX; + } + + thread->state = THREAD_ACTIVE; +} + +uintptr_t Scheduler::WaitEvents(KEvent **events, size_t count) { + if (count > ES_MAX_WAIT_COUNT) { + KernelPanic("Scheduler::WaitEvents - count (%d) > ES_MAX_WAIT_COUNT (%d)\n", count, ES_MAX_WAIT_COUNT); + } else if (!count) { + KernelPanic("Scheduler::WaitEvents - Count is 0.\n"); + } else if (!ProcessorAreInterruptsEnabled()) { + KernelPanic("Scheduler::WaitEvents - Interrupts disabled.\n"); + } + + Thread *thread = GetCurrentThread(); + thread->blocking.eventCount = count; + + LinkedItem blockedItems[count]; // Max size 16 * 32 = 512. + EsMemoryZero(blockedItems, count * sizeof(LinkedItem)); + thread->blockedItems = blockedItems; + EsDefer(thread->blockedItems = nullptr); + + for (uintptr_t i = 0; i < count; i++) { + thread->blockedItems[i].thisItem = thread; + thread->blocking.events[i] = events[i]; + } + + while (!thread->terminating || thread->terminatableState != THREAD_USER_BLOCK_REQUEST) { + thread->state = THREAD_WAITING_EVENT; + + for (uintptr_t i = 0; i < count; i++) { + if (events[i]->autoReset) { + if (events[i]->state) { + thread->state = THREAD_ACTIVE; + + if (__sync_val_compare_and_swap(&events[i]->state, true, false)) { + return i; + } + + thread->state = THREAD_WAITING_EVENT; + } + } else { + if (events[i]->state) { + thread->state = THREAD_ACTIVE; + return i; + } + } + } + + ProcessorFakeTimerInterrupt(); + } + + return -1; // Exited from termination. +} + +uintptr_t KWaitEvents(KEvent **events, size_t count) { + return scheduler.WaitEvents(events, count); +} + +void Scheduler::UnblockThread(Thread *unblockedThread, Thread *previousMutexOwner) { + KSpinlockAssertLocked(&lock); + + if (unblockedThread->state == THREAD_WAITING_MUTEX) { + if (unblockedThread->item.list) { + // If we get here from KMutex::Release -> Scheduler::NotifyObject -> Scheduler::UnblockedThread, + // the mutex owner has already been cleared to nullptr, so use the previousMutexOwner parameter. + // But if we get here from Scheduler::TerminateThread, the mutex wasn't released; + // rather, the waiting thread was unblocked as it is in the WAIT system call, but needs to terminate. + + if (!previousMutexOwner) { + KMutex *mutex = EsContainerOf(KMutex, blockedThreads, unblockedThread->item.list); + + if (&mutex->blockedThreads != unblockedThread->item.list) { + KernelPanic("Scheduler::UnblockThread - Unblocked thread %x was not in a mutex blockedThreads list.\n", + unblockedThread); + } + + previousMutexOwner = mutex->owner; + } + + if (!previousMutexOwner->blockedThreadPriorities[unblockedThread->priority]) { + KernelPanic("Scheduler::UnblockThread - blockedThreadPriorities was zero (%x/%x).\n", + unblockedThread, previousMutexOwner); + } + + previousMutexOwner->blockedThreadPriorities[unblockedThread->priority]--; + MaybeUpdateActiveList(previousMutexOwner); + + unblockedThread->item.RemoveFromList(); + } + } else if (unblockedThread->state == THREAD_WAITING_EVENT) { + for (uintptr_t i = 0; i < unblockedThread->blocking.eventCount; i++) { + if (unblockedThread->blockedItems[i].list) { + unblockedThread->blockedItems[i].RemoveFromList(); + } + } + } else if (unblockedThread->state == THREAD_WAITING_WRITER_LOCK) { + if (unblockedThread->item.list) { + KWriterLock *lock = EsContainerOf(KWriterLock, blockedThreads, unblockedThread->item.list); + + if (&lock->blockedThreads != unblockedThread->item.list) { + KernelPanic("Scheduler::UnblockThread - Unblocked thread %x was not in a writer lock blockedThreads list.\n", + unblockedThread); + } + + if ((unblockedThread->blocking.writerLockType == K_LOCK_SHARED && lock->state >= 0) + || (unblockedThread->blocking.writerLockType == K_LOCK_EXCLUSIVE && lock->state == 0)) { + unblockedThread->item.RemoveFromList(); + } + } + } else { + KernelPanic("Scheduler::UnblockedThread - Blocked thread in invalid state %d.\n", + unblockedThread->state); + } + + unblockedThread->state = THREAD_ACTIVE; + + if (!unblockedThread->executing) { + // Put the unblocked thread at the start of the activeThreads list + // so that it is immediately executed when the scheduler yields. + AddActiveThread(unblockedThread, true); + } + + // TODO If any processors are idleing, send them a yield IPI. +} + +void Scheduler::NotifyObject(LinkedList *blockedThreads, bool unblockAll, Thread *previousMutexOwner) { + KSpinlockAssertLocked(&lock); + + LinkedItem *unblockedItem = blockedThreads->firstItem; + + if (!unblockedItem) { + // There weren't any threads blocking on the object. + return; + } + + do { + LinkedItem *nextUnblockedItem = unblockedItem->nextItem; + Thread *unblockedThread = unblockedItem->thisItem; + UnblockThread(unblockedThread, previousMutexOwner); + unblockedItem = nextUnblockedItem; + } while (unblockAll && unblockedItem); +} + +#endif diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp new file mode 100644 index 0000000..c00f39a --- /dev/null +++ b/kernel/syscall.cpp @@ -0,0 +1,2095 @@ +// TODO Replace ES_ERROR_UNKNOWN with proper errors. +// TODO Clean up the return values for system calls; with FATAL_ERRORs there should need to be less error codes returned. +// TODO Close handles if OpenHandle fails or SendMessage fails. +// TODO If a file system call fails with an error indicating the file system is corrupted, or a drive is failing, report the problem to the user. + +#ifndef IMPLEMENTATION + +KMutex eventForwardMutex; + +uintptr_t DoSyscall(EsSyscallType index, + uintptr_t argument0, uintptr_t argument1, + uintptr_t argument2, uintptr_t argument3, + uint64_t flags, bool *fatal, uintptr_t *userStackPointer); + +#define DO_SYSCALL_BATCHED (2) + +struct MessageQueue { + bool SendMessage(void *target, EsMessage *message); // Returns false if the message queue is full. + bool SendMessage(_EsMessageWithObject *message); // Returns false if the message queue is full. + bool GetMessage(_EsMessageWithObject *message); + +#define MESSAGE_QUEUE_MAX_LENGTH (4096) + Array<_EsMessageWithObject, K_FIXED> messages; + + uintptr_t mouseMovedMessage, + windowResizedMessage, + eyedropResultMessage, + keyRepeatMessage; + + bool pinged; + + KMutex mutex; + KEvent notEmpty; +}; + +#endif + +#ifdef IMPLEMENTATION + +bool MessageQueue::SendMessage(void *object, EsMessage *_message) { + // TODO Remove unnecessary copy. + _EsMessageWithObject message = { object, *_message }; + return SendMessage(&message); +} + +bool MessageQueue::SendMessage(_EsMessageWithObject *_message) { + // TODO Don't send messages if the process has been terminated. + + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + if (messages.Length() == MESSAGE_QUEUE_MAX_LENGTH) { + KernelLog(LOG_ERROR, "Messages", "message dropped", "Message of type %d and target %x has been dropped because queue %x was full.\n", + _message->message.type, _message->object, this); + return false; + } + +#define MERGE_MESSAGES(variable, change) \ + do { \ + if (variable && messages[variable - 1].object == _message->object) { \ + if (change) EsMemoryCopy(&messages[variable - 1], _message, sizeof(_EsMessageWithObject)); \ + } else if (messages.AddPointer(_message)) { \ + variable = messages.Length(); \ + } else { \ + return false; \ + } \ + } while (0) + + // NOTE Don't forget to update GetMessage with the merged messages! + + if (_message->message.type == ES_MSG_MOUSE_MOVED) { + MERGE_MESSAGES(mouseMovedMessage, true); + } else if (_message->message.type == ES_MSG_WINDOW_RESIZED) { + MERGE_MESSAGES(windowResizedMessage, true); + } else if (_message->message.type == ES_MSG_EYEDROP_REPORT) { + MERGE_MESSAGES(eyedropResultMessage, true); + } else if (_message->message.type == ES_MSG_KEY_DOWN && _message->message.keyboard.repeat) { + MERGE_MESSAGES(keyRepeatMessage, false); + } else { + if (!messages.AddPointer(_message)) { + return false; + } + + if (_message->message.type == ES_MSG_PING) { + pinged = true; + } + } + + KEventSet(¬Empty, false, true); + + return true; +} + +bool MessageQueue::GetMessage(_EsMessageWithObject *_message) { + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + if (!messages.Length()) { + return false; + } + + *_message = messages[0]; + messages.Delete(0); + + if (mouseMovedMessage) mouseMovedMessage--; + if (windowResizedMessage) windowResizedMessage--; + if (eyedropResultMessage) eyedropResultMessage--; + if (keyRepeatMessage) keyRepeatMessage--; + + pinged = false; + + if (!messages.Length()) { + KEventReset(¬Empty); + } + + return true; +} + +#define CHECK_OBJECT(x) if (!x.valid) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, !x.softFailure); else x.checked = true +#define SYSCALL_BUFFER_LIMIT (64 * 1024 * 1024) // To prevent overflow and DOS attacks. +#define SYSCALL_BUFFER(address, length, index, write) \ + MMRegion *_region ## index = MMFindAndPinRegion(currentVMM, (address), (length)); \ + if (!_region ## index) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); \ + EsDefer(if (_region ## index) MMUnpinRegion(currentVMM, _region ## index)); \ + if (write && (_region ## index->flags & MM_REGION_READ_ONLY) && (~_region ## index->flags & MM_REGION_COPY_ON_WRITE)) \ + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); +#define SYSCALL_HANDLE(handle, type, __object, index) \ + KObject _object ## index(currentProcess, handle, type); \ + CHECK_OBJECT(_object ## index); \ + *((void **) &__object) = (_object ## index).object; +#define SYSCALL_READ(destination, source, length) \ + do { if ((length) > 0) { \ + SYSCALL_BUFFER((uintptr_t) (source), (length), 0, false); \ + EsMemoryCopy((void *) (destination), (const void *) (source), (length)); \ + __sync_synchronize(); \ + }} while (0) +#define SYSCALL_READ_HEAP(destination, source, length) \ + if ((length) > 0) { \ + void *x = EsHeapAllocate((length), false, K_FIXED); \ + if (!x) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); \ + bool success = false; \ + EsDefer(if (!success) EsHeapFree(x, 0, K_FIXED);); \ + SYSCALL_BUFFER((uintptr_t) (source), (length), 0, false); \ + *((void **) &(destination)) = x; \ + EsMemoryCopy((void *) (destination), (const void *) (source), (length)); \ + success = true; \ + __sync_synchronize(); \ + } else destination = nullptr; EsDefer(EsHeapFree(destination, 0, K_FIXED)) +#define SYSCALL_WRITE(destination, source, length) \ + do { \ + __sync_synchronize(); \ + SYSCALL_BUFFER((uintptr_t) (destination), (length), 0, true); \ + EsMemoryCopy((void *) (destination), (const void *) (source), (length)); \ + } while (0) +#define SYSCALL_ARGUMENTS uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, uintptr_t argument3, \ + Thread *currentThread, Process *currentProcess, MMSpace *currentVMM, uintptr_t *userStackPointer, bool *fatalError +#define SYSCALL_IMPLEMENT(_type) uintptr_t Do ## _type ( SYSCALL_ARGUMENTS ) +#define SYSCALL_RETURN(value, fatal) do { *fatalError = fatal; return (value); } while (0) +#define SYSCALL_PERMISSION(x) do { if ((x) != (currentProcess->permissions & (x))) { *fatalError = true; return ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS; } } while (0) +typedef uintptr_t (*SyscallFunction)(SYSCALL_ARGUMENTS); +#pragma GCC diagnostic ignored "-Wunused-parameter" push + +SYSCALL_IMPLEMENT(ES_SYSCALL_COUNT) { + SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PRINT) { + char *buffer; + if (argument1 > SYSCALL_BUFFER_LIMIT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + SYSCALL_READ_HEAP(buffer, argument0, argument1); + EsPrint("%s", argument1, buffer); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_ALLOCATE) { + EsMemoryProtection protection = (EsMemoryProtection) argument2; + uint32_t flags = MM_REGION_USER; + if (protection == ES_MEMORY_PROTECTION_READ_ONLY) flags |= MM_REGION_READ_ONLY; + if (protection == ES_MEMORY_PROTECTION_EXECUTABLE) flags |= MM_REGION_EXECUTABLE; + uintptr_t address = (uintptr_t) MMStandardAllocate(currentVMM, argument0, flags, nullptr, argument1 & ES_MEMORY_RESERVE_COMMIT_ALL); + SYSCALL_RETURN(address, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_FREE) { + if (!MMFree(currentVMM, (void *) argument0, argument1, true /* only allow freeing regions marked with MM_REGION_USER */)) { + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_MEMORY_REGION, true); + } + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_COMMIT) { + SYSCALL_BUFFER(argument0 << K_PAGE_BITS, argument1 << K_PAGE_BITS, 0, false); + + argument0 -= _region0->baseAddress >> K_PAGE_BITS; + + if (argument0 >= _region0->pageCount + || argument1 > _region0->pageCount - argument0 + || (~_region0->flags & MM_REGION_NORMAL) + || (~_region0->flags & MM_REGION_USER) + || !argument1) { + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_MEMORY_REGION, true); + } + + bool success = false; + + if (argument2 == 0) { + KMutexAcquire(¤tVMM->reserveMutex); + success = MMCommitRange(currentVMM, _region0, argument0, argument1); + KMutexRelease(¤tVMM->reserveMutex); + } else if (argument2 == 1) { + KMutexAcquire(¤tVMM->reserveMutex); + success = MMDecommitRange(currentVMM, _region0, argument0, argument1); + KMutexRelease(¤tVMM->reserveMutex); + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); + } + + SYSCALL_RETURN(success ? ES_SUCCESS : ES_ERROR_INSUFFICIENT_RESOURCES, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_FAULT_RANGE) { + uintptr_t start = argument0 & ~(K_PAGE_SIZE - 1); + uintptr_t end = (argument0 + argument1 - 1) & ~(K_PAGE_SIZE - 1); + + for (uintptr_t page = start; page <= end; page += K_PAGE_SIZE) { + if (!MMArchHandlePageFault(page, ES_FLAGS_DEFAULT)) { + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + } + } + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_CREATE) { + SYSCALL_PERMISSION(ES_PERMISSION_PROCESS_CREATE); + + EsProcessCreationArguments arguments; + SYSCALL_READ(&arguments, argument0, sizeof(EsProcessCreationArguments)); + + if (arguments.permissions == ES_PERMISSION_INHERIT) { + arguments.permissions = currentProcess->permissions; + } + + if (arguments.permissions & ~currentProcess->permissions) { + SYSCALL_RETURN(ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS, true); + } + + KObject executableObject(currentProcess, arguments.executable, KERNEL_OBJECT_NODE); + CHECK_OBJECT(executableObject); + + if (((KNode *) executableObject.object)->directoryEntry->type != ES_NODE_FILE) { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + } + + EsProcessInformation processInformation; + EsMemoryZero(&processInformation, sizeof(EsProcessInformation)); + + Process *process = scheduler.SpawnProcess(); + + if (!process) { + SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + } + + process->creationFlags = arguments.flags; + process->creationArguments[CREATION_ARGUMENT_MAIN] = arguments.creationArgument.u; + process->permissions = arguments.permissions; + + // TODO Free the process object if something fails here. + + if (arguments.environmentBlockBytes) { + if (arguments.environmentBlockBytes > SYSCALL_BUFFER_LIMIT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + SYSCALL_BUFFER((uintptr_t) arguments.environmentBlock, arguments.environmentBlockBytes, 1, false); + process->creationArguments[CREATION_ARGUMENT_ENVIRONMENT] = MakeConstantBuffer(arguments.environmentBlock, arguments.environmentBlockBytes, process); + } + + if (arguments.initialMountPointCount) { + if (arguments.initialMountPointCount > ES_MOUNT_POINT_MAX_COUNT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + + EsMountPoint *mountPoints = (EsMountPoint *) EsHeapAllocate(arguments.initialMountPointCount * sizeof(EsMountPoint), false, K_FIXED); + EsDefer(EsHeapFree(mountPoints, arguments.initialMountPointCount * sizeof(EsMountPoint), K_FIXED)); + SYSCALL_READ(mountPoints, (uintptr_t) arguments.initialMountPoints, arguments.initialMountPointCount * sizeof(EsMountPoint)); + + for (uintptr_t i = 0; i < arguments.initialMountPointCount; i++) { + // Open handles to the mount points for the new process. + // TODO Handling errors when opening handles. + KObject object(currentProcess, mountPoints[i].base, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + if (!mountPoints[i].write) object.flags &= ~_ES_NODE_DIRECTORY_WRITE; + OpenHandleToObject(object.object, object.type, object.flags); + mountPoints[i].base = process->handleTable.OpenHandle(object.object, object.flags, object.type); + } + + process->creationArguments[CREATION_ARGUMENT_INITIAL_MOUNT_POINTS] + = MakeConstantBuffer(mountPoints, arguments.initialMountPointCount * sizeof(EsMountPoint), process); + } + + if (!process->StartWithNode((KNode *) executableObject.object)) { + CloseHandleToObject(process, KERNEL_OBJECT_PROCESS); + SYSCALL_RETURN(ES_ERROR_UNKNOWN, false); + } + + processInformation.handle = currentProcess->handleTable.OpenHandle(process, 0, KERNEL_OBJECT_PROCESS); + processInformation.pid = process->id; + + processInformation.mainThread.handle = currentProcess->handleTable.OpenHandle(process->executableMainThread, 0, KERNEL_OBJECT_THREAD); + processInformation.mainThread.tid = process->executableMainThread->id; + + SYSCALL_WRITE(argument2, &processInformation, sizeof(EsProcessInformation)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_GET_CREATION_ARGUMENT) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(object); + + Process *process = (Process *) object.object; + + if (argument1 >= sizeof(process->creationArguments) / sizeof(process->creationArguments[0])) { + SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true); + } + + SYSCALL_RETURN(process->creationArguments[argument1], false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SCREEN_FORCE_UPDATE) { + if (argument0) { + SYSCALL_PERMISSION(ES_PERMISSION_SCREEN_MODIFY); + } + + KMutexAcquire(&windowManager.mutex); + + if (argument0) { + windowManager.Redraw(ES_POINT(0, 0), graphics.frameBuffer.width, graphics.frameBuffer.height, nullptr); + } + + GraphicsUpdateScreen(); + KMutexRelease(&windowManager.mutex); + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_EYEDROP_START) { + KObject _avoid(currentProcess, argument1, KERNEL_OBJECT_WINDOW); + CHECK_OBJECT(_avoid); + Window *avoid = (Window *) _avoid.object; + + windowManager.StartEyedrop(argument0, avoid, argument2); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MESSAGE_GET) { + _EsMessageWithObject message; + EsMemoryZero(&message, sizeof(_EsMessageWithObject)); + + if (currentProcess->messageQueue.GetMessage(&message)) { + SYSCALL_WRITE(argument0, &message, sizeof(_EsMessageWithObject)); + SYSCALL_RETURN(ES_SUCCESS, false); + } else { + SYSCALL_RETURN(ES_ERROR_NO_MESSAGES_AVAILABLE, false); + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MESSAGE_WAIT) { + currentThread->terminatableState = THREAD_USER_BLOCK_REQUEST; + KEventWait(¤tProcess->messageQueue.notEmpty, argument0 /* timeout */); + currentThread->terminatableState = THREAD_IN_SYSCALL; + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_CREATE) { + SYSCALL_PERMISSION(ES_PERMISSION_WINDOW_MANAGER); + + if (argument0 == ES_WINDOW_NORMAL) { + void *_window = windowManager.CreateEmbeddedWindow(currentProcess, (void *) argument2); + SYSCALL_RETURN(currentProcess->handleTable.OpenHandle(_window, 0, KERNEL_OBJECT_EMBEDDED_WINDOW), false); + } else { + void *_window = windowManager.CreateWindow(currentProcess, (void *) argument2, (EsWindowStyle) argument0); + + if (!_window) { + SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + } else { + SYSCALL_RETURN(currentProcess->handleTable.OpenHandle(_window, 0, KERNEL_OBJECT_WINDOW), false); + } + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_CLOSE) { + KObject _window(currentProcess, argument0, KERNEL_OBJECT_WINDOW | KERNEL_OBJECT_EMBEDDED_WINDOW); + CHECK_OBJECT(_window); + KMutexAcquire(&windowManager.mutex); + + if (_window.type == KERNEL_OBJECT_EMBEDDED_WINDOW) { + EmbeddedWindow *window = (EmbeddedWindow *) _window.object; + window->Close(); + } else { + Window *window = (Window *) _window.object; + window->Close(); + } + + KMutexRelease(&windowManager.mutex); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_SET_OBJECT) { + EmbeddedWindow *window; + SYSCALL_HANDLE(argument0, KERNEL_OBJECT_EMBEDDED_WINDOW, window, 1); + + if (window->owner != currentProcess) { + // TODO Permissions. + } + + void *old = window->apiWindow; + window->apiWindow = (void *) argument2; + __sync_synchronize(); + + KMutexAcquire(&windowManager.mutex); + + if (window->container) { + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_WINDOW_RESIZED; + int embedWidth = window->container->width - WINDOW_INSET * 2; + int embedHeight = window->container->height - WINDOW_INSET * 2 - CONTAINER_TAB_BAND_HEIGHT; + message.windowResized.content = ES_RECT_4(0, embedWidth, 0, embedHeight); + window->owner->messageQueue.SendMessage((void *) argument2, &message); + } + + KMutexRelease(&windowManager.mutex); + + SYSCALL_RETURN((uintptr_t) old, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_SET_PROPERTY) { + uint8_t property = argument3; + + KObject _window(currentProcess, argument0, (property & 0x80) ? KERNEL_OBJECT_EMBEDDED_WINDOW : KERNEL_OBJECT_WINDOW); + CHECK_OBJECT(_window); + Window *window = (Window *) _window.object; + EmbeddedWindow *embed = (EmbeddedWindow *) _window.object; + + if (property == ES_WINDOW_PROPERTY_SOLID) { + window->solid = (argument1 & ES_WINDOW_SOLID_TRUE) != 0; + window->noClickActivate = (argument1 & ES_WINDOW_SOLID_NO_ACTIVATE) != 0; + window->noBringToFront = (argument1 & ES_WINDOW_SOLID_NO_BRING_TO_FRONT) != 0; + window->solidInsets = ES_RECT_1I(argument2); + KMutexAcquire(&windowManager.mutex); + windowManager.MoveCursor(0, 0); + KMutexRelease(&windowManager.mutex); + } else if (property == ES_WINDOW_PROPERTY_OPAQUE_BOUNDS) { + SYSCALL_READ(&window->opaqueBounds, argument1, sizeof(EsRectangle)); + } else if (property == ES_WINDOW_PROPERTY_BLUR_BOUNDS) { + SYSCALL_READ(&window->blurBounds, argument1, sizeof(EsRectangle)); + } else if (property == ES_WINDOW_PROPERTY_ALPHA) { + window->alpha = argument1 & 0xFF; + } else if (property == ES_WINDOW_PROPERTY_FOCUSED) { + KMutexAcquire(&windowManager.mutex); + windowManager.ActivateWindow(window); + windowManager.MoveCursor(0, 0); + KMutexRelease(&windowManager.mutex); + } else if (property == ES_WINDOW_PROPERTY_MATERIAL) { + window->material = argument1; + } else if (property == ES_WINDOW_PROPERTY_EMBED) { + KObject _embed(currentProcess, argument1, KERNEL_OBJECT_EMBEDDED_WINDOW | KERNEL_OBJECT_NONE); + CHECK_OBJECT(_embed); + EmbeddedWindow *embed = (EmbeddedWindow *) _embed.object; + KMutexAcquire(&windowManager.mutex); + window->SetEmbed(embed); + KMutexRelease(&windowManager.mutex); + } else if (property == ES_WINDOW_PROPERTY_OBJECT) { + if (embed->owner != currentProcess) { + // TODO Permissions. + } + + embed->apiWindow = (void *) argument2; + __sync_synchronize(); + + KMutexAcquire(&windowManager.mutex); + + if (embed->container) { + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_WINDOW_RESIZED; + int embedWidth = embed->container->width - WINDOW_INSET * 2; + int embedHeight = embed->container->height - WINDOW_INSET * 2 - CONTAINER_TAB_BAND_HEIGHT; + message.windowResized.content = ES_RECT_4(0, embedWidth, 0, embedHeight); + embed->owner->messageQueue.SendMessage((void *) argument2, &message); + } + + KMutexRelease(&windowManager.mutex); + } else if (property == ES_WINDOW_PROPERTY_EMBED_OWNER) { + Process *process; + SYSCALL_HANDLE(argument1, KERNEL_OBJECT_PROCESS, process, 2); + OpenHandleToObject(embed, KERNEL_OBJECT_EMBEDDED_WINDOW); + EsHandle handle = process->handleTable.OpenHandle(embed, 0, KERNEL_OBJECT_EMBEDDED_WINDOW); + KMutexAcquire(&windowManager.mutex); + embed->SetEmbedOwner(process); + KMutexRelease(&windowManager.mutex); + SYSCALL_RETURN(handle, false); + } else if (property == ES_WINDOW_PROPERTY_RESIZE_CLEAR_COLOR) { + embed->resizeClearColor = argument1; + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true); + } + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_REDRAW) { + KObject _window(currentProcess, argument0, KERNEL_OBJECT_WINDOW); + CHECK_OBJECT(_window); + Window *window = (Window *) _window.object; + KMutexAcquire(&windowManager.mutex); + window->Update(nullptr, true); + GraphicsUpdateScreen(); + KMutexRelease(&windowManager.mutex); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_SET_BITS) { + KObject _window(currentProcess, argument0, KERNEL_OBJECT_WINDOW | KERNEL_OBJECT_EMBEDDED_WINDOW); + CHECK_OBJECT(_window); + + EsRectangle region; + SYSCALL_READ(®ion, argument1, sizeof(EsRectangle)); + + if (!ES_RECT_VALID(region)) { + SYSCALL_RETURN(ES_SUCCESS, false); + } + + if (region.l < 0 || region.r > (int32_t) graphics.width * 2 + || region.t < 0 || region.b > (int32_t) graphics.height * 2 + || region.l >= region.r || region.t >= region.b) { + SYSCALL_RETURN(ES_SUCCESS, false); + } + + bool isEmbed = _window.type == KERNEL_OBJECT_EMBEDDED_WINDOW; + Window *window = isEmbed ? ((EmbeddedWindow *) _window.object)->container : ((Window *) _window.object); + Surface *surface = &window->surface; + + if (!window || (isEmbed && currentProcess != ((EmbeddedWindow *) _window.object)->owner)) { + SYSCALL_RETURN(ES_SUCCESS, false); + } + + if (isEmbed) { + region = Translate(region, WINDOW_INSET, WINDOW_INSET + CONTAINER_TAB_BAND_HEIGHT); + } + + if (argument3 == WINDOW_SET_BITS_SCROLL_VERTICAL || argument3 == WINDOW_SET_BITS_SCROLL_HORIZONTAL) { + ptrdiff_t scrollDelta = argument2; + bool scrollVertical = argument3 == WINDOW_SET_BITS_SCROLL_VERTICAL; + + if (scrollVertical) { + if (scrollDelta < 0) region.b += scrollDelta; + else region.t += scrollDelta; + } else { + if (scrollDelta < 0) region.r += scrollDelta; + else region.l += scrollDelta; + } + + KMutexAcquire(&windowManager.mutex); + + if (window->closed + || region.l < 0 || region.r > (int32_t) surface->width + || region.t < 0 || region.b > (int32_t) surface->height + || region.l >= region.r || region.t >= region.b) { + } else { + surface->Scroll(region, scrollDelta, scrollVertical); + window->Update(®ion, true); + window->queuedScrollUpdate = true; + // Don't update the screen until the rest of the window is painted. + } + + KMutexRelease(&windowManager.mutex); + } else { + bool skipUpdate = false; + SYSCALL_BUFFER(argument2, Width(region) * Height(region) * 4, 1, false); + KMutexAcquire(&windowManager.mutex); + + bool resizeQueued = false; + + if (argument3 == WINDOW_SET_BITS_AFTER_RESIZE && windowManager.resizeWindow == window) { + if (isEmbed) windowManager.resizeReceivedBitsFromEmbed = true; + else windowManager.resizeReceivedBitsFromContainer = true; + + if (windowManager.resizeReceivedBitsFromContainer && windowManager.resizeReceivedBitsFromEmbed) { + // Resize complete. + resizeQueued = windowManager.resizeQueued; + windowManager.resizeQueued = false; + windowManager.resizeWindow = nullptr; + windowManager.resizeSlow = KGetTimeInMs() - windowManager.resizeStartTimeStampMs >= RESIZE_SLOW_THRESHOLD + || windowManager.inspectorWindowCount /* HACK anti-flicker logic interfers with the inspector's logging */; + +#if 0 + EsPrint("Resize complete in %dms%z.\n", KGetTimeInMs() - windowManager.resizeStartTimeStampMs, windowManager.resizeSlow ? " (slow)" : ""); +#endif + } + } + + if (window->closed) { + skipUpdate = true; + } else { + uintptr_t stride = Width(region) * 4; + EsRectangle clippedRegion = EsRectangleIntersection(region, ES_RECT_2S(surface->width, surface->height)); + + if (argument3 != WINDOW_SET_BITS_AFTER_RESIZE) { + skipUpdate = window->UpdateDirect((K_USER_BUFFER uint32_t *) argument2, stride, clippedRegion); + } + +#define SET_BITS_REGION(...) { \ + EsRectangle subRegion = EsRectangleIntersection(clippedRegion, ES_RECT_4(__VA_ARGS__)); \ + if (ES_RECT_VALID(subRegion)) { surface->SetBits((K_USER_BUFFER const uint8_t *) argument2 \ + + stride * (subRegion.t - clippedRegion.t) + 4 * (subRegion.l - clippedRegion.l), stride, subRegion); } } + + if (window->style == ES_WINDOW_CONTAINER && !isEmbed) { + SET_BITS_REGION(0, window->width, 0, CONTAINER_TAB_BAND_HEIGHT + WINDOW_INSET); + SET_BITS_REGION(0, WINDOW_INSET, CONTAINER_TAB_BAND_HEIGHT + WINDOW_INSET, window->height - WINDOW_INSET); + SET_BITS_REGION(window->width - WINDOW_INSET, window->width, CONTAINER_TAB_BAND_HEIGHT + WINDOW_INSET, window->height - WINDOW_INSET); + SET_BITS_REGION(0, window->width, window->height - WINDOW_INSET, window->height); + } else if (window->style == ES_WINDOW_CONTAINER && isEmbed) { + SET_BITS_REGION(WINDOW_INSET, window->width - WINDOW_INSET, WINDOW_INSET + CONTAINER_TAB_BAND_HEIGHT, window->height - WINDOW_INSET); + } else { + SET_BITS_REGION(0, window->width, 0, window->height); + } + } + + window->Update(®ion, !skipUpdate); + + if (!skipUpdate || window->queuedScrollUpdate) { + window->queuedScrollUpdate = false; + GraphicsUpdateScreen(); + } + + if (resizeQueued) { + window->Move(windowManager.resizeQueuedRectangle, ES_WINDOW_MOVE_DYNAMIC); + } + + KMutexRelease(&windowManager.mutex); + } + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CLIPBOARD_ADD) { + SYSCALL_PERMISSION(ES_PERMISSION_WINDOW_MANAGER); + + if (argument0 != ES_CLIPBOARD_PRIMARY) { + SYSCALL_RETURN(ES_ERROR_INVALID_CLIPBOARD, false); + } + + EsError error = primaryClipboard.Add((uintptr_t) argument1, (const void *) argument2, argument3); + SYSCALL_RETURN(error, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CLIPBOARD_HAS) { + SYSCALL_PERMISSION(ES_PERMISSION_WINDOW_MANAGER); + + if (argument0 != ES_CLIPBOARD_PRIMARY) { + SYSCALL_RETURN(ES_ERROR_INVALID_CLIPBOARD, false); + } + + bool result = primaryClipboard.Has((uintptr_t) argument1); + SYSCALL_RETURN(result, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CLIPBOARD_READ) { + SYSCALL_PERMISSION(ES_PERMISSION_WINDOW_MANAGER); + + if (argument0 != ES_CLIPBOARD_PRIMARY) { + SYSCALL_RETURN(ES_ERROR_INVALID_CLIPBOARD, false); + } + + EsHandle handle = primaryClipboard.Read((uintptr_t) argument1, (size_t *) argument3, currentProcess); + SYSCALL_RETURN(handle, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_CREATE) { + KEvent *event = (KEvent *) EsHeapAllocate(sizeof(KEvent), true, K_FIXED); + if (!event) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + event->handles = 1; + event->autoReset = argument0; + SYSCALL_RETURN(currentProcess->handleTable.OpenHandle(event, 0, KERNEL_OBJECT_EVENT), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_HANDLE_CLOSE) { + if (!currentProcess->handleTable.CloseHandle(argument0)) { + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, true); + } + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_THREAD_TERMINATE) { + bool self = false; + + { + KObject _thread(currentProcess, argument0, KERNEL_OBJECT_THREAD); + CHECK_OBJECT(_thread); + Thread *thread = (Thread *) _thread.object; + + if (thread == currentThread) self = true; + else scheduler.TerminateThread(thread); + } + + if (self) scheduler.TerminateThread(currentThread); + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_TERMINATE) { + // TODO Prevent the termination of the kernel/desktop. + + bool self = false; + + { + KObject _process(currentProcess, argument0, KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(_process); + Process *process = (Process *) _process.object; + + if (process == currentProcess) self = true; + else scheduler.TerminateProcess(process, argument1); + } + + if (self) scheduler.TerminateProcess(currentProcess, argument1); + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_THREAD_CREATE) { + EsThreadInformation thread; + EsMemoryZero(&thread, sizeof(EsThreadInformation)); + Thread *threadObject = scheduler.SpawnThread("Syscall", argument0, argument3, SPAWN_THREAD_USERLAND, currentProcess, argument1); + + if (!threadObject) { + SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + } + + // Register processObject as a handle. + thread.handle = currentProcess->handleTable.OpenHandle(threadObject, 0, KERNEL_OBJECT_THREAD); + thread.tid = threadObject->id; + + SYSCALL_WRITE(argument2, &thread, sizeof(EsThreadInformation)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_OPEN) { + if (argument0 > ES_SHARED_MEMORY_MAXIMUM_SIZE) SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true); + if (argument1 && !argument2) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + if (argument2 > ES_SHARED_MEMORY_NAME_MAX_LENGTH) SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true); + + char *name; + if (argument2 > SYSCALL_BUFFER_LIMIT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + SYSCALL_READ_HEAP(name, argument1, argument2); + + MMSharedRegion *region = MMSharedOpenRegion(name, argument2, argument0, argument3); + if (!region) SYSCALL_RETURN(ES_INVALID_HANDLE, false); + + SYSCALL_RETURN(currentProcess->handleTable.OpenHandle(region, 0, KERNEL_OBJECT_SHMEM), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_MAP_OBJECT) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_SHMEM | KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + + if (object.type == KERNEL_OBJECT_SHMEM) { + // TODO Access permissions and modes. + MMSharedRegion *region = (MMSharedRegion *) object.object; + + if (argument2 == ES_MAP_OBJECT_ALL) { + argument2 = region->sizeBytes; + } + + uintptr_t address = (uintptr_t) MMMapShared(currentVMM, region, argument1, argument2, MM_REGION_USER); + SYSCALL_RETURN(address, false); + } else if (object.type == KERNEL_OBJECT_NODE) { + KNode *file = (KNode *) object.object; + + if (file->directoryEntry->type != ES_NODE_FILE) SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + + if (argument3 == ES_MAP_OBJECT_READ_WRITE) { + if (!(object.flags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE))) { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true); + } + } else { + if (!(object.flags & (ES_FILE_READ | ES_FILE_READ_SHARED))) { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true); + } + } + + if (argument2 == ES_MAP_OBJECT_ALL) { + argument2 = file->directoryEntry->totalSize; + } + + uintptr_t address = (uintptr_t) MMMapFile(currentVMM, (FSFile *) file, argument1, argument2, argument3, nullptr, 0, MM_REGION_USER); + SYSCALL_RETURN(address, false); + } + + KernelPanic("ES_SYSCALL_MEMORY_MAP_OBJECT - Unhandled case.\n"); + SYSCALL_RETURN(0, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CONSTANT_BUFFER_SHARE) { + KObject buffer(currentProcess, argument0, KERNEL_OBJECT_CONSTANT_BUFFER); + CHECK_OBJECT(buffer); + ConstantBuffer *object = (ConstantBuffer *) buffer.object; + + KObject process(currentProcess, argument1, KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(process); + + SYSCALL_RETURN(MakeConstantBuffer(object + 1, object->bytes, (Process *) process.object), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CONSTANT_BUFFER_CREATE) { + if (argument2 > SYSCALL_BUFFER_LIMIT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + SYSCALL_BUFFER(argument0, argument2, 1, false); + + KObject process(currentProcess, argument1, KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(process); + + SYSCALL_RETURN(MakeConstantBuffer((void *) argument0, argument2, (Process *) process.object), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_SHARE) { + // TODO Sort out flags. + + KObject _region(currentProcess, argument0, KERNEL_OBJECT_SHMEM); + CHECK_OBJECT(_region); + MMSharedRegion *region = (MMSharedRegion *) _region.object; + + KObject _process(currentProcess, argument1, KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(_process); + Process *process = (Process *) _process.object; + + OpenHandleToObject(region, KERNEL_OBJECT_SHMEM); + + SYSCALL_RETURN(process->handleTable.OpenHandle(region, argument2, KERNEL_OBJECT_SHMEM), false); +} + +#define SYSCALL_SHARE_OBJECT(syscallName, objectType) \ +SYSCALL_IMPLEMENT(syscallName) { \ + KObject share(currentProcess, argument0, objectType); \ + CHECK_OBJECT(share); \ + KObject _process(currentProcess, argument1, KERNEL_OBJECT_PROCESS); \ + CHECK_OBJECT(_process); \ + Process *process = (Process *) _process.object; \ + OpenHandleToObject(share.object, objectType, share.flags); \ + SYSCALL_RETURN(process->handleTable.OpenHandle(share.object, share.flags, objectType), false); \ +} + +SYSCALL_SHARE_OBJECT(ES_SYSCALL_PROCESS_SHARE, KERNEL_OBJECT_PROCESS); +SYSCALL_SHARE_OBJECT(ES_SYSCALL_NODE_SHARE, KERNEL_OBJECT_NODE); + +SYSCALL_IMPLEMENT(ES_SYSCALL_VOLUME_GET_INFORMATION) { + if (~currentProcess->permissions & ES_PERMISSION_GET_VOLUME_INFORMATION) { + SYSCALL_RETURN(0, false); + } + + KObject object(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + KNode *node = (KNode *) object.object; + KFileSystem *fileSystem = node->fileSystem; + + EsVolumeInformation information; + EsMemoryZero(&information, sizeof(EsVolumeInformation)); + EsMemoryCopy(information.label, fileSystem->name, sizeof(fileSystem->name)); + information.labelBytes = fileSystem->nameBytes; + information.driveType = fileSystem->block->driveType; + information.spaceUsed = fileSystem->spaceUsed; + information.spaceTotal = fileSystem->spaceTotal; + information.id = fileSystem->id; + + SYSCALL_WRITE(argument1, &information, sizeof(EsVolumeInformation)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_NODE_OPEN) { + size_t pathLength = (size_t) argument1; + uint64_t flags = (uint64_t) argument2; + + flags &= ~_ES_NODE_FROM_WRITE_EXCLUSIVE | _ES_NODE_NO_WRITE_BASE; + + bool needWritePermission = flags & (ES_FILE_WRITE_EXCLUSIVE | ES_FILE_WRITE | _ES_NODE_DIRECTORY_WRITE); + + char *path; + if (argument1 > K_MAX_PATH) SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true); + SYSCALL_READ_HEAP(path, argument0, argument1); + + _EsNodeInformation information; + SYSCALL_READ(&information, argument3, sizeof(_EsNodeInformation)); + + KNode *directory = nullptr; + + KObject _directory(currentProcess, information.handle, KERNEL_OBJECT_NODE); + CHECK_OBJECT(_directory); + + directory = (KNode *) _directory.object; + + if (directory->directoryEntry->type != ES_NODE_DIRECTORY) { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + } + + if ((~_directory.flags & _ES_NODE_DIRECTORY_WRITE) && needWritePermission) { + SYSCALL_RETURN(ES_ERROR_FILE_PERMISSION_NOT_GRANTED, false); + } + + if (~_directory.flags & _ES_NODE_DIRECTORY_WRITE) { + flags |= _ES_NODE_NO_WRITE_BASE; + } + + KNodeInformation _information = FSNodeOpen(path, pathLength, flags, directory); + + if (!_information.node) { + SYSCALL_RETURN(_information.error, false); + } + + if (flags & ES_FILE_WRITE_EXCLUSIVE) { + // Mark this handle as being the exclusive writer for this file. + // This way, when the handle is used, OpenHandleToObject succeeds. + // The exclusive writer flag will only be removed from the file where countWrite drops to zero. + flags |= _ES_NODE_FROM_WRITE_EXCLUSIVE; + } + + EsMemoryZero(&information, sizeof(_EsNodeInformation)); + information.type = _information.node->directoryEntry->type; + information.fileSize = _information.node->directoryEntry->totalSize; + information.directoryChildren = _information.node->directoryEntry->directoryChildren; + information.handle = currentProcess->handleTable.OpenHandle(_information.node, flags, KERNEL_OBJECT_NODE); + SYSCALL_WRITE(argument3, &information, sizeof(_EsNodeInformation)); + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_NODE_DELETE) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + KNode *node = (KNode *) object.object; + + if (object.flags & _ES_NODE_NO_WRITE_BASE) { + SYSCALL_RETURN(ES_ERROR_FILE_PERMISSION_NOT_GRANTED, false); + } + + if (node->directoryEntry->type == ES_NODE_FILE && (~object.flags & ES_FILE_WRITE_EXCLUSIVE)) { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true); + } + + if (node->directoryEntry->type == ES_NODE_DIRECTORY || node->directoryEntry->type == ES_NODE_FILE) { + SYSCALL_RETURN(FSNodeDelete(node), false); + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_NODE_MOVE) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + KNode *file = (KNode *) object.object; + + KObject object2(currentProcess, argument1, KERNEL_OBJECT_NODE | KERNEL_OBJECT_NONE); + CHECK_OBJECT(object2); + KNode *directory = (KNode *) object2.object; + + char *newPath; + if (argument3 > SYSCALL_BUFFER_LIMIT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + SYSCALL_READ_HEAP(newPath, argument2, argument3); + SYSCALL_RETURN(FSNodeMove(file, directory, newPath, (size_t) argument3), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_FILE_READ_SYNC) { + if (!argument2) SYSCALL_RETURN(0, false); + + KObject object(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + KNode *file = (KNode *) object.object; + + if (file->directoryEntry->type != ES_NODE_FILE) SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + + SYSCALL_BUFFER(argument3, argument2, 1, false); + + size_t result = FSFileReadSync(file, (void *) argument3, argument1, argument2, + (_region1->flags & MM_REGION_FILE) ? FS_FILE_ACCESS_USER_BUFFER_MAPPED : 0); + SYSCALL_RETURN(result, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_FILE_WRITE_SYNC) { + if (!argument2) SYSCALL_RETURN(0, false); + + KObject object(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + KNode *file = (KNode *) object.object; + + if (file->directoryEntry->type != ES_NODE_FILE) SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + + SYSCALL_BUFFER(argument3, argument2, 1, true /* write */); + + if (object.flags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE)) { + size_t result = FSFileWriteSync(file, (void *) argument3, argument1, argument2, + (_region1->flags & MM_REGION_FILE) ? FS_FILE_ACCESS_USER_BUFFER_MAPPED : 0); + SYSCALL_RETURN(result, false); + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true); + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_FILE_GET_SIZE) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + KNode *file = (KNode *) object.object; + if (file->directoryEntry->type != ES_NODE_FILE) SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + SYSCALL_RETURN(file->directoryEntry->totalSize, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_FILE_RESIZE) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + KNode *file = (KNode *) object.object; + + if (file->directoryEntry->type != ES_NODE_FILE) SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + + if (object.flags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE)) { + SYSCALL_RETURN(FSFileResize(file, argument1), false); + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true); + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_SET) { + KObject _event(currentProcess, argument0, KERNEL_OBJECT_EVENT); + CHECK_OBJECT(_event); + KEvent *event = (KEvent *) _event.object; + KEventSet(event, false, true); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_RESET) { + KObject _event(currentProcess, argument0, KERNEL_OBJECT_EVENT); + CHECK_OBJECT(_event); + KEvent *event = (KEvent *) _event.object; + KEventReset(event); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SLEEP) { + KTimer timer = {}; + KTimerSet(&timer, (argument0 << 32) | argument1); + currentThread->terminatableState = THREAD_USER_BLOCK_REQUEST; + KEventWait(&timer.event, ES_WAIT_NO_TIMEOUT); + currentThread->terminatableState = THREAD_IN_SYSCALL; + KTimerRemove(&timer); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WAIT) { + if (argument1 >= ES_MAX_WAIT_COUNT - 1 /* leave room for timeout timer */) { + SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true); + } + + EsHandle handles[ES_MAX_WAIT_COUNT]; + SYSCALL_READ(handles, argument0, argument1 * sizeof(EsHandle)); + + KEvent *events[ES_MAX_WAIT_COUNT]; + KObject _objects[ES_MAX_WAIT_COUNT] = {}; + + for (uintptr_t i = 0; i < argument1; i++) { + _objects[i].Initialise(¤tProcess->handleTable, handles[i], + KERNEL_OBJECT_PROCESS | KERNEL_OBJECT_THREAD | KERNEL_OBJECT_EVENT | KERNEL_OBJECT_EVENT_SINK); + CHECK_OBJECT(_objects[i]); + + void *object = _objects[i].object; + + switch (_objects[i].type) { + case KERNEL_OBJECT_PROCESS: { + events[i] = &((Process *) object)->killedEvent; + } break; + + case KERNEL_OBJECT_THREAD: { + events[i] = &((Thread *) object)->killedEvent; + } break; + + case KERNEL_OBJECT_EVENT_SINK: { + events[i] = &((EventSink *) object)->available; + } break; + + case KERNEL_OBJECT_EVENT: { + events[i] = (KEvent *) object; + } break; + + default: { + KernelPanic("DoSyscall - Unexpected wait object type %d.\n", _objects[i].type); + } break; + } + } + + size_t waitObjectCount = argument1; + KTimer timer = {}; + + if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) { + KTimerSet(&timer, argument2); + events[waitObjectCount++] = &timer.event; + } + + uintptr_t waitReturnValue; + currentThread->terminatableState = THREAD_USER_BLOCK_REQUEST; + waitReturnValue = scheduler.WaitEvents(events, waitObjectCount); + currentThread->terminatableState = THREAD_IN_SYSCALL; + + if (waitReturnValue == argument1) { + waitReturnValue = ES_ERROR_TIMEOUT_REACHED; + } + + if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) { + KTimerRemove(&timer); + } + + SYSCALL_RETURN(waitReturnValue, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_SET_CURSOR) { + KObject _window(currentProcess, argument0, KERNEL_OBJECT_WINDOW | KERNEL_OBJECT_EMBEDDED_WINDOW); + CHECK_OBJECT(_window); + + uint32_t imageWidth = (argument2 >> 16) & 0xFF; + uint32_t imageHeight = (argument2 >> 24) & 0xFF; + + SYSCALL_BUFFER(argument1, imageWidth * imageHeight * 4, 1, false); + + KMutexAcquire(&windowManager.mutex); + Window *window; + + if (_window.type == KERNEL_OBJECT_EMBEDDED_WINDOW) { + EmbeddedWindow *embeddedWindow = (EmbeddedWindow *) _window.object; + window = embeddedWindow->container; + + if (!window || !window->hoveringOverEmbed || embeddedWindow->owner != currentProcess) { + KMutexRelease(&windowManager.mutex); + SYSCALL_RETURN(ES_SUCCESS, false); + } + } else { + window = (Window *) _window.object; + + if (window->hoveringOverEmbed) { + KMutexRelease(&windowManager.mutex); + SYSCALL_RETURN(ES_SUCCESS, false); + } + } + + bool changedCursor = false; + + if (!window->closed && argument1 != windowManager.cursorID && !windowManager.eyedropping && (windowManager.hoverWindow == window || !windowManager.hoverWindow)) { + windowManager.cursorID = argument1; + windowManager.cursorImageOffsetX = (int8_t) ((argument2 >> 0) & 0xFF); + windowManager.cursorImageOffsetY = (int8_t) ((argument2 >> 8) & 0xFF); + windowManager.cursorXOR = argument3 >> 31; + + if (windowManager.cursorSurface.Resize(imageWidth, imageHeight)) { + windowManager.cursorSwap.Resize(imageWidth, imageHeight); + windowManager.cursorSurface.SetBits((K_USER_BUFFER const void *) argument1, argument3 & 0xFFFFFF, + ES_RECT_4(0, windowManager.cursorSurface.width, 0, windowManager.cursorSurface.height)); + } + + windowManager.changedCursorImage = true; + changedCursor = true; + } + + KMutexRelease(&windowManager.mutex); + + SYSCALL_RETURN(changedCursor, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_MOVE) { + KObject _window(currentProcess, argument0, KERNEL_OBJECT_WINDOW); + CHECK_OBJECT(_window); + + Window *window = (Window *) _window.object; + + bool success = true; + + EsRectangle rectangle; + + if (argument1) { + SYSCALL_READ(&rectangle, argument1, sizeof(EsRectangle)); + } else { + EsMemoryZero(&rectangle, sizeof(EsRectangle)); + } + + KMutexAcquire(&windowManager.mutex); + + if (argument3 & ES_WINDOW_MOVE_HIDDEN) { + windowManager.HideWindow(window); + } else { + window->Move(rectangle, argument3); + } + + if (argument3 & ES_WINDOW_MOVE_UPDATE_SCREEN) { + GraphicsUpdateScreen(); + } + + KMutexRelease(&windowManager.mutex); + + SYSCALL_RETURN(success ? ES_SUCCESS : ES_ERROR_INVALID_DIMENSIONS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CURSOR_POSITION_GET) { + EsPoint point = ES_POINT(windowManager.cursorX, windowManager.cursorY); + SYSCALL_WRITE(argument0, &point, sizeof(EsPoint)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CURSOR_POSITION_SET) { + KMutexAcquire(&windowManager.mutex); + windowManager.cursorX = argument0; + windowManager.cursorY = argument1; + windowManager.cursorXPrecise = argument0 * 10; + windowManager.cursorYPrecise = argument1 * 10; + KMutexRelease(&windowManager.mutex); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_GAME_CONTROLLER_STATE_POLL) { + EsGameControllerState gameControllers[ES_GAME_CONTROLLER_MAX_COUNT]; + size_t gameControllerCount; + + KMutexAcquire(&windowManager.gameControllersMutex); + gameControllerCount = windowManager.gameControllerCount; + EsMemoryCopy(gameControllers, windowManager.gameControllers, sizeof(EsGameControllerState) * gameControllerCount); + KMutexRelease(&windowManager.gameControllersMutex); + + SYSCALL_WRITE(argument0, gameControllers, sizeof(EsGameControllerState) * gameControllerCount); + SYSCALL_RETURN(gameControllerCount, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_GET_BOUNDS) { + KObject _window(currentProcess, argument0, KERNEL_OBJECT_WINDOW | KERNEL_OBJECT_EMBEDDED_WINDOW); + CHECK_OBJECT(_window); + + EsRectangle rectangle; + EsMemoryZero(&rectangle, sizeof(EsRectangle)); + KMutexAcquire(&windowManager.mutex); + + if (_window.type == KERNEL_OBJECT_WINDOW) { + Window *window = (Window *) _window.object; + rectangle.l = window->position.x; + rectangle.t = window->position.y; + rectangle.r = window->position.x + window->width; + rectangle.b = window->position.y + window->height; + } else if (_window.type == KERNEL_OBJECT_EMBEDDED_WINDOW) { + EmbeddedWindow *embed = (EmbeddedWindow *) _window.object; + Window *window = embed->container; + + if (window) { + rectangle.l = window->position.x + WINDOW_INSET; + rectangle.t = window->position.y + WINDOW_INSET + CONTAINER_TAB_BAND_HEIGHT; + rectangle.r = window->position.x + window->width - WINDOW_INSET; + rectangle.b = window->position.y + window->height - WINDOW_INSET; + } else { + rectangle.l = 0; + rectangle.t = 0; + rectangle.r = 0; + rectangle.b = 0; + } + } + + KMutexRelease(&windowManager.mutex); + SYSCALL_WRITE(argument1, &rectangle, sizeof(EsRectangle)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_PAUSE) { + KObject _process(currentProcess, argument0, KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(_process); + Process *process = (Process *) _process.object; + + scheduler.PauseProcess(process, (bool) argument1); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_CRASH) { + KernelLog(LOG_ERROR, "Syscall", "process crash request", "Process crash request, reason %d\n", argument0); + SYSCALL_RETURN(argument0, true); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MESSAGE_POST) { + KObject object(currentProcess, argument2, KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(object); + void *process = object.object; + + _EsMessageWithObject message; + SYSCALL_READ(&message.message, argument0, sizeof(EsMessage)); + message.object = (void *) argument1; + + if (((Process *) process)->messageQueue.SendMessage(&message)) { + SYSCALL_RETURN(ES_SUCCESS, false); + } else { + SYSCALL_RETURN(ES_ERROR_MESSAGE_QUEUE_FULL, false); + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_THREAD_GET_ID) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_THREAD | KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(object); + + if (object.type == KERNEL_OBJECT_THREAD) { + SYSCALL_RETURN(((Thread *) object.object)->id, false); + } else if (object.type == KERNEL_OBJECT_PROCESS) { + Process *process = (Process *) object.object; + +#ifdef ENABLE_POSIX_SUBSYSTEM + if (currentThread->posixData && currentThread->posixData->forkProcess) { + SYSCALL_RETURN(currentThread->posixData->forkProcess->id, false); + } +#endif + + SYSCALL_RETURN(process->id, false); + } + + KernelPanic("ES_SYSCALL_THREAD_GET_ID - Unhandled case.\n"); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_THREAD_STACK_SIZE) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_THREAD); + CHECK_OBJECT(object); + Thread *thread = (Thread *) object.object; + + SYSCALL_WRITE(argument1, &thread->userStackCommit, sizeof(thread->userStackCommit)); + SYSCALL_WRITE(argument2, &thread->userStackReserve, sizeof(thread->userStackReserve)); + + bool success = true; + + if (argument3) { + MMRegion *region = MMFindAndPinRegion(currentVMM, thread->userStackBase, thread->userStackReserve); + KMutexAcquire(¤tVMM->reserveMutex); + + if (thread->userStackCommit <= argument3 && argument3 <= thread->userStackReserve && !(argument3 & (K_PAGE_BITS - 1)) && region) { +#ifdef K_STACK_GROWS_DOWN + success = MMCommitRange(currentVMM, region, (thread->userStackReserve - argument3) / K_PAGE_SIZE, argument3 / K_PAGE_SIZE); +#else + success = MMCommitRange(currentVMM, region, 0, argument3 / K_PAGE_SIZE); +#endif + } else { + success = false; + } + + if (success) thread->userStackCommit = argument3; + KMutexRelease(¤tVMM->reserveMutex); + if (region) MMUnpinRegion(currentVMM, region); + } + + SYSCALL_RETURN(success ? ES_SUCCESS : ES_ERROR_INSUFFICIENT_RESOURCES, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_DIRECTORY_ENUMERATE) { + KObject _node(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(_node); + KNode *node = (KNode *) _node.object; + + if (node->directoryEntry->type != ES_NODE_DIRECTORY) SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + + if (argument2 > SYSCALL_BUFFER_LIMIT / sizeof(EsDirectoryChild)) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + SYSCALL_BUFFER(argument1, argument2 * sizeof(EsDirectoryChild), 1, true /* write */); + + SYSCALL_RETURN(FSDirectoryEnumerateChildren(node, (K_USER_BUFFER EsDirectoryChild *) argument1, argument2), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_FILE_CONTROL) { + KObject object(currentProcess, argument0, KERNEL_OBJECT_NODE); + CHECK_OBJECT(object); + KNode *file = (KNode *) object.object; + + if (file->directoryEntry->type != ES_NODE_FILE) { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + } + + SYSCALL_RETURN(FSFileControl(file, argument1), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_BATCH) { + EsBatchCall *calls; + if (argument1 > SYSCALL_BUFFER_LIMIT / sizeof(EsBatchCall)) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + SYSCALL_READ_HEAP(calls, argument0, sizeof(EsBatchCall) * argument1); + + size_t count = argument1; + + for (uintptr_t i = 0; i < count; i++) { + EsBatchCall call = calls[i]; + bool fatal = false; + uintptr_t _returnValue = calls[i].returnValue = DoSyscall(call.index, call.argument0, call.argument1, call.argument2, call.argument3, + DO_SYSCALL_BATCHED, &fatal, userStackPointer); + if (fatal) SYSCALL_RETURN(_returnValue, true); + if (calls->stopBatchIfError && ES_CHECK_ERROR(_returnValue)) break; + if (currentThread->terminating) break; + } + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CONSTANT_BUFFER_READ) { + KObject _buffer(currentProcess, argument0, KERNEL_OBJECT_CONSTANT_BUFFER); + CHECK_OBJECT(_buffer); + ConstantBuffer *buffer = (ConstantBuffer *) _buffer.object; + if (!argument1) SYSCALL_RETURN(buffer->bytes, false); + SYSCALL_WRITE(argument1, buffer + 1, buffer->bytes); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_GET_STATE) { + KObject _process(currentProcess, argument0, KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(_process); + Process *process = (Process *) _process.object; + + EsProcessState state; + EsMemoryZero(&state, sizeof(EsProcessState)); + state.crashReason = process->crashReason; + state.id = process->id; + state.executableState = process->executableState; + state.flags = (process->allThreadsTerminated ? ES_PROCESS_STATE_ALL_THREADS_TERMINATED : 0) + | (process->terminating ? ES_PROCESS_STATE_TERMINATING : 0) + | (process->crashed ? ES_PROCESS_STATE_CRASHED : 0) + | (process->messageQueue.pinged ? ES_PROCESS_STATE_PINGED : 0); + + SYSCALL_WRITE(argument1, &state, sizeof(EsProcessState)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SHUTDOWN) { + SYSCALL_PERMISSION(ES_PERMISSION_SHUTDOWN); + KThreadCreate("Shutdown", [] (uintptr_t action) { KernelShutdown(action); }, argument0); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_GET_ID) { + KObject _window(currentProcess, argument0, KERNEL_OBJECT_WINDOW | KERNEL_OBJECT_EMBEDDED_WINDOW); + CHECK_OBJECT(_window); + + if (_window.type == KERNEL_OBJECT_WINDOW) { + SYSCALL_RETURN(((Window *) _window.object)->id, false); + } else { + SYSCALL_RETURN(((EmbeddedWindow *) _window.object)->id, false); + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_YIELD_SCHEDULER) { + ProcessorFakeTimerInterrupt(); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_GET_CONSTANTS) { + SYSCALL_BUFFER(argument0, sizeof(uint64_t) * ES_SYSTEM_CONSTANT_COUNT, 1, true /* write */); + uint64_t *systemConstants = (uint64_t *) argument0; + systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] = timeStampTicksPerMs / 1000; + systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET] = WINDOW_INSET; + systemConstants[ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT] = CONTAINER_TAB_BAND_HEIGHT; + systemConstants[ES_SYSTEM_CONSTANT_NO_FANCY_GRAPHICS] = graphics.target ? graphics.target->reducedColors : false; + systemConstants[ES_SYSTEM_CONSTANT_UI_SCALE] = UI_SCALE; + systemConstants[ES_SYSTEM_CONSTANT_BORDER_THICKNESS] = BORDER_THICKNESS; + systemConstants[ES_SYSTEM_CONSTANT_OPTIMAL_WORK_QUEUE_THREAD_COUNT] = scheduler.currentProcessorID; // TODO Update this as processors are added/removed. + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_TAKE_SNAPSHOT) { + SYSCALL_PERMISSION(ES_PERMISSION_TAKE_SYSTEM_SNAPSHOT); + + int type = argument0; + void *buffer = nullptr; + size_t bufferSize = 0; + EsDefer(EsHeapFree(buffer, 0, K_FIXED)); + + switch (type) { + case ES_SYSTEM_SNAPSHOT_PROCESSES: { + KSpinlockAcquire(&scheduler.lock); + size_t count = scheduler.allProcesses.count + 8; + bufferSize = sizeof(EsSnapshotProcesses) + sizeof(EsSnapshotProcessesItem) * count; + KSpinlockRelease(&scheduler.lock); + + buffer = EsHeapAllocate(bufferSize, true, K_FIXED); + EsMemoryZero(buffer, bufferSize); + + KSpinlockAcquire(&scheduler.lock); + + if (scheduler.allProcesses.count < count) { + count = scheduler.allProcesses.count; + } + + EsSnapshotProcesses *snapshot = (EsSnapshotProcesses *) buffer; + + LinkedItem *item = scheduler.allProcesses.firstItem; + uintptr_t index = 0; + + while (item && index < count) { + Process *process = item->thisItem; + if (process->terminating) goto next; + + { + snapshot->processes[index].pid = process->id; + snapshot->processes[index].memoryUsage = process->vmm->commit * K_PAGE_SIZE; + snapshot->processes[index].cpuTimeSlices = process->cpuTimeSlices; + snapshot->processes[index].idleTimeSlices = process->idleTimeSlices; + snapshot->processes[index].handleCount = process->handleTable.handleCount; + snapshot->processes[index].isKernel = process->type == PROCESS_KERNEL; + + snapshot->processes[index].nameBytes = EsCStringLength(process->cExecutableName); + EsMemoryCopy(snapshot->processes[index].name, process->cExecutableName, snapshot->processes[index].nameBytes); + + index++; + } + + next:; + item = item->nextItem; + } + + snapshot->count = index; + bufferSize = sizeof(EsSnapshotProcesses) + sizeof(EsSnapshotProcessesItem) * index; + KSpinlockRelease(&scheduler.lock); + } break; + + default: { + SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true); + } break; + } + + EsHandle constantBuffer = MakeConstantBuffer(buffer, bufferSize, currentProcess); + SYSCALL_WRITE(argument1, &bufferSize, sizeof(size_t)); + SYSCALL_RETURN(constantBuffer, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_OPEN) { + SYSCALL_PERMISSION(ES_PERMISSION_PROCESS_OPEN); + + Process *process = scheduler.OpenProcess(argument0); + + if (process) { + SYSCALL_RETURN(currentProcess->handleTable.OpenHandle(process, 0, KERNEL_OBJECT_PROCESS), false); + } else { + SYSCALL_RETURN(ES_INVALID_HANDLE, false); + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_SET_TLS) { + currentThread->tlsAddress = argument0; // Set this first, otherwise we could get pre-empted and restore without TLS set. + ProcessorSetThreadStorage(argument0); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_GET_TLS) { + SYSCALL_RETURN(currentThread->tlsAddress, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SCREEN_BOUNDS_GET) { + EsRectangle rectangle; + EsMemoryZero(&rectangle, sizeof(EsRectangle)); + + rectangle.l = 0; + rectangle.t = 0; + rectangle.r = graphics.width; + rectangle.b = graphics.height; + + SYSCALL_WRITE(argument1, &rectangle, sizeof(EsRectangle)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SCREEN_WORK_AREA_SET) { + SYSCALL_PERMISSION(ES_PERMISSION_SCREEN_MODIFY); + EsRectangle rectangle; + SYSCALL_READ(&rectangle, argument1, sizeof(EsRectangle)); + windowManager.workArea = rectangle; + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SCREEN_WORK_AREA_GET) { + EsRectangle rectangle = windowManager.workArea; + SYSCALL_WRITE(argument1, &rectangle, sizeof(EsRectangle)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_MESSAGE_DESKTOP) { + char *buffer; + if (argument1 > SYSCALL_BUFFER_LIMIT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + SYSCALL_READ_HEAP(buffer, argument0, argument1); + + KObject _window(currentProcess, argument2, KERNEL_OBJECT_EMBEDDED_WINDOW | KERNEL_OBJECT_NONE); + CHECK_OBJECT(_window); + + EmbeddedWindow *window = (EmbeddedWindow *) _window.object; + + if (!scheduler.shutdown) { + _EsMessageWithObject m = {}; + m.message.type = ES_MSG_DESKTOP; + m.message.desktop.buffer = MakeConstantBufferForDesktop(buffer, argument1); + m.message.desktop.bytes = argument1; + m.message.desktop.windowID = window ? window->id : 0; + desktopProcess->messageQueue.SendMessage(&m); + } + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +#ifdef ENABLE_POSIX_SUBSYSTEM +SYSCALL_IMPLEMENT(ES_SYSCALL_POSIX) { + SYSCALL_PERMISSION(ES_PERMISSION_POSIX_SUBSYSTEM); + + _EsPOSIXSyscall syscall; + SYSCALL_READ(&syscall, argument0, sizeof(_EsPOSIXSyscall)); + + if (syscall.index == 2 /* open */ || syscall.index == 59 /* execve */) { + KObject node(currentProcess, syscall.arguments[4], KERNEL_OBJECT_NODE); + CHECK_OBJECT(node); + syscall.arguments[4] = (long) node.object; + if (~node.flags & _ES_NODE_DIRECTORY_WRITE) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, true); + long result = POSIX::DoSyscall(syscall, userStackPointer); + SYSCALL_RETURN(result, false); + } else if (syscall.index == 109 /* setpgid */) { + KObject process(currentProcess, syscall.arguments[0], KERNEL_OBJECT_PROCESS); + CHECK_OBJECT(process); + syscall.arguments[0] = (long) process.object; + long result = POSIX::DoSyscall(syscall, userStackPointer); + SYSCALL_RETURN(result, false); + } else { + long result = POSIX::DoSyscall(syscall, userStackPointer); + SYSCALL_RETURN(result, false); + } +} +#else +SYSCALL_IMPLEMENT(ES_SYSCALL_POSIX) { + SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); +} +#endif + +SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_GET_STATUS) { + Process *process; + SYSCALL_HANDLE(argument0, KERNEL_OBJECT_PROCESS, process, 1); + SYSCALL_RETURN(process->exitStatus, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PIPE_CREATE) { + Pipe *pipe = (Pipe *) EsHeapAllocate(sizeof(Pipe), true, K_PAGED); + if (!pipe) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + pipe->writers = pipe->readers = 1; + KEventSet(&pipe->canWrite); + SYSCALL_RETURN(currentProcess->handleTable.OpenHandle(pipe, PIPE_READER | PIPE_WRITER, KERNEL_OBJECT_PIPE), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PIPE_READ) { + Pipe *pipe; + SYSCALL_HANDLE(argument0, KERNEL_OBJECT_PIPE, pipe, 1); + SYSCALL_BUFFER(argument1, argument2, 2, false); + SYSCALL_RETURN(pipe->Access((void *) argument1, argument2, false, true), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_PIPE_WRITE) { + Pipe *pipe; + SYSCALL_HANDLE(argument0, KERNEL_OBJECT_PIPE, pipe, 1); + SYSCALL_BUFFER(argument1, argument2, 2, true /* write */); + SYSCALL_RETURN(pipe->Access((void *) argument1, argument2, true, true), false); +} + +KMutex systemConfigurationMutex; +ConstantBuffer *systemConfiguration; + +SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_CONFIGURATION_WRITE) { + SYSCALL_PERMISSION(ES_PERMISSION_SYSTEM_CONFIGURATION_WRITE); + + // TODO Broadcast message? + + if (argument1 > SYSCALL_BUFFER_LIMIT) { + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + } + + ConstantBuffer *buffer = (ConstantBuffer *) EsHeapAllocate(sizeof(ConstantBuffer) + argument1, false, K_PAGED); + if (!buffer) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + EsMemoryZero(buffer, sizeof(ConstantBuffer)); + buffer->handles = 1; + buffer->bytes = argument1; + buffer->isPaged = true; + EsDefer(CloseHandleToObject(buffer, KERNEL_OBJECT_CONSTANT_BUFFER)); + SYSCALL_READ(buffer + 1, argument0, argument1); + + KMutexAcquire(&systemConfigurationMutex); + if (systemConfiguration) CloseHandleToObject(systemConfiguration, KERNEL_OBJECT_CONSTANT_BUFFER); + OpenHandleToObject(buffer, KERNEL_OBJECT_CONSTANT_BUFFER); + systemConfiguration = buffer; + KMutexRelease(&systemConfigurationMutex); + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_CONFIGURATION_READ) { + EsHandle handle = ES_INVALID_HANDLE; + size_t bytes = 0; + + KMutexAcquire(&systemConfigurationMutex); + + if (systemConfiguration && OpenHandleToObject(systemConfiguration, KERNEL_OBJECT_CONSTANT_BUFFER)) { + bytes = systemConfiguration->bytes; + handle = currentProcess->handleTable.OpenHandle(systemConfiguration, 0, KERNEL_OBJECT_CONSTANT_BUFFER); + } + + KMutexRelease(&systemConfigurationMutex); + + SYSCALL_WRITE(argument2, &bytes, sizeof(bytes)); + SYSCALL_RETURN(handle, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_SINK_CREATE) { + EventSink *sink = (EventSink *) EsHeapAllocate(sizeof(EventSink), true, K_FIXED); + + if (!sink) { + SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + } + + sink->ignoreDuplicates = argument0; + sink->handles = 1; + + SYSCALL_RETURN(currentProcess->handleTable.OpenHandle(sink, 0, KERNEL_OBJECT_EVENT_SINK), false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_FORWARD) { + KEvent *event; + SYSCALL_HANDLE(argument0, KERNEL_OBJECT_EVENT, event, 1); + EventSink *sink; + SYSCALL_HANDLE(argument1, KERNEL_OBJECT_EVENT_SINK, sink, 2); + EsGeneric data = argument2; + + bool error = false, limitExceeded = false; + + KMutexAcquire(&eventForwardMutex); + + if (!event->sinkTable) { + event->sinkTable = (EventSinkTable *) EsHeapAllocate(sizeof(EventSinkTable) * ES_MAX_EVENT_FORWARD_COUNT, true, K_FIXED); + + if (!event->sinkTable) { + error = true; + } + } + + if (!error) { + limitExceeded = true; + + for (uintptr_t i = 0; i < ES_MAX_EVENT_FORWARD_COUNT; i++) { + if (!event->sinkTable[i].sink) { + if (!OpenHandleToObject(sink, KERNEL_OBJECT_EVENT_SINK, 0, false)) { + error = true; + break; + } + + KSpinlockAcquire(&scheduler.lock); + event->sinkTable[i].sink = sink; + event->sinkTable[i].data = data; + KSpinlockRelease(&scheduler.lock); + + limitExceeded = false; + break; + } + } + } + + KMutexRelease(&eventForwardMutex); + + if (limitExceeded) { + SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true); + } else if (error) { + SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + } else { + SYSCALL_RETURN(0, false); + } +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_SINK_POP) { + EventSink *sink; + SYSCALL_HANDLE(argument0, KERNEL_OBJECT_EVENT_SINK, sink, 1); + + bool empty = false, overflow = false; + EsGeneric data = {}; + + KSpinlockAcquire(&sink->spinlock); + + if (!sink->queueCount) { + if (sink->overflow) { + overflow = true; + sink->overflow = false; + } else { + empty = true; + } + } else { + data = sink->queue[sink->queuePosition]; + sink->queuePosition++; + sink->queueCount--; + + if (sink->queuePosition == ES_MAX_EVENT_SINK_BUFFER_SIZE) { + sink->queuePosition = 0; + } + } + + if (!sink->queueCount && !sink->overflow) { + KEventReset(&sink->available); // KEvent::Reset doesn't take the scheduler lock, so this won't deadlock! + } + + KSpinlockRelease(&sink->spinlock); + + SYSCALL_WRITE(argument1, &data, sizeof(EsGeneric)); + SYSCALL_RETURN(overflow ? ES_ERROR_EVENT_SINK_OVERFLOW : empty ? ES_ERROR_EVENT_NOT_SET : ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_SINK_PUSH) { + EventSink *sink; + SYSCALL_HANDLE(argument0, KERNEL_OBJECT_EVENT_SINK, sink, 1); + KSpinlockAcquire(&scheduler.lock); + EsError result = sink->Push(argument1); + KSpinlockRelease(&scheduler.lock); + SYSCALL_RETURN(result, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_DOMAIN_NAME_RESOLVE) { + SYSCALL_PERMISSION(ES_PERMISSION_NETWORKING); + + if (argument1 > ES_DOMAIN_NAME_MAX_LENGTH) { + SYSCALL_RETURN(ES_ERROR_BAD_DOMAIN_NAME, false); + } + + char domainName[ES_DOMAIN_NAME_MAX_LENGTH]; + SYSCALL_READ(domainName, argument0, argument1); + + EsAddress address; + EsMemoryZero(&address, sizeof(EsAddress)); + + KEvent completeEvent = {}; + + NetDomainNameResolveTask task = {}; + task.event = &completeEvent; + task.name = domainName; + task.nameBytes = (size_t) argument1; + task.address = &address; + task.callback = NetDomainNameResolve; + NetTaskBegin(&task); + + KEventWait(&completeEvent); + + if (task.error == ES_SUCCESS) { + SYSCALL_WRITE(argument2, &address, sizeof(EsAddress)); + } + + SYSCALL_RETURN(task.error, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_ECHO_REQUEST) { + SYSCALL_PERMISSION(ES_PERMISSION_NETWORKING); + + if (argument1 > ES_ECHO_REQUEST_MAX_LENGTH) { + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + } + + uint8_t data[48]; + EsMemoryZero(data, sizeof(data)); + SYSCALL_READ(data, argument0, argument1); + + EsAddress address; + SYSCALL_READ(&address, argument2, sizeof(EsAddress)); + + KEvent completeEvent = {}; + + NetEchoRequestTask task = {}; + task.event = &completeEvent; + task.address = &address; + task.data = data; + task.callback = NetEchoRequest; + NetTaskBegin(&task); + + KEventWait(&completeEvent); + + if (task.error == ES_SUCCESS) { + SYSCALL_WRITE(argument0, data, argument1); + } + + SYSCALL_RETURN(task.error, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CONNECTION_OPEN) { + SYSCALL_PERMISSION(ES_PERMISSION_NETWORKING); + + EsConnection connection; + SYSCALL_READ(&connection, argument0, sizeof(EsConnection)); + + if (connection.sendBufferBytes < 1024 || connection.receiveBufferBytes < 1024) { + SYSCALL_RETURN(ES_ERROR_BUFFER_TOO_SMALL, false); + } + + // TODO Upper limit on buffer sizes? + + NetConnection *netConnection = NetConnectionOpen(&connection.address, connection.sendBufferBytes, connection.receiveBufferBytes, argument1); + + if (!netConnection) { + SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + } + + connection.sendBuffer = (uint8_t *) MMMapShared(currentVMM, netConnection->bufferRegion, 0, connection.sendBufferBytes + connection.receiveBufferBytes); + connection.receiveBuffer = connection.sendBuffer + connection.sendBufferBytes; + + if (!connection.sendBuffer) { + CloseHandleToObject(netConnection, KERNEL_OBJECT_CONNECTION); + SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); + } + + connection.handle = currentProcess->handleTable.OpenHandle(netConnection, 0, KERNEL_OBJECT_CONNECTION); + connection.error = ES_SUCCESS; + + SYSCALL_WRITE(argument0, &connection, sizeof(EsConnection)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CONNECTION_POLL) { + SYSCALL_BUFFER(argument0, sizeof(EsConnection), 0, true /* write */); + EsConnection *connection = (EsConnection *) argument0; + NetConnection *netConnection; + SYSCALL_HANDLE(argument3, KERNEL_OBJECT_CONNECTION, netConnection, 1); + + connection->receiveWritePointer = netConnection->receiveWritePointer; + connection->sendReadPointer = netConnection->sendReadPointer; + connection->open = netConnection->task.step == TCP_STEP_ESTABLISHED; + connection->error = netConnection->task.completed ? netConnection->task.error : ES_SUCCESS; + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_CONNECTION_NOTIFY) { + NetConnection *netConnection; + SYSCALL_HANDLE(argument3, KERNEL_OBJECT_CONNECTION, netConnection, 1); + NetConnectionNotify(netConnection, argument1, argument2); + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SYSCALL_IMPLEMENT(ES_SYSCALL_DEBUG_COMMAND) { +#ifdef DEBUG_BUILD + if (argument0 == 1) { + ArchResetCPU(); + } else if (argument0 == 2) { + KernelPanic("Debug command 2.\n"); + } else if (argument0 == 3) { + extern char kernelLog[]; + extern uintptr_t kernelLogPosition; + size_t bytes = kernelLogPosition; + if (argument2 < bytes) bytes = argument2; + EsMemoryCopy((void *) argument1, kernelLog, bytes); + SYSCALL_RETURN(bytes, false); + } else if (argument0 == 4) { + SYSCALL_BUFFER(argument1, 1, 0, false); + + if (_region0->data.normal.commitPageCount != (argument3 & 0x7FFFFFFFFFFFFFFF)) { + KernelPanic("Commit page count mismatch.\n"); + } + + if (_region0->data.normal.commit.Contains(argument2) != (argument3 >> 63)) { + KernelPanic("Commit contains mismatch at %x.\n", argument1); + } + } else if (argument0 == 6) { + // SYSCALL_RETURN(DriversDebugGetEnumeratedPCIDevices((EsPCIDevice *) argument1, argument2), false); + } else if (argument0 == 7) { + EsAssert(!scheduler.threadEventLog); + EsThreadEventLogEntry *buffer = (EsThreadEventLogEntry *) EsHeapAllocate(argument0 * sizeof(EsThreadEventLogEntry), false, K_FIXED); + scheduler.threadEventLogAllocated = argument0; + scheduler.threadEventLogPosition = 0; + __sync_synchronize(); + scheduler.threadEventLog = buffer; + } else if (argument0 == 8) { + SYSCALL_RETURN(scheduler.threadEventLogPosition, false); + } else if (argument0 == 9) { + SYSCALL_WRITE(argument1, scheduler.threadEventLog, scheduler.threadEventLogPosition * sizeof(EsThreadEventLogEntry)); + } else if (argument0 == 10) { + scheduler.threadEventLogAllocated = 0; + // HACK Wait for threads to stop writing... + KEvent event = {}; + KEventWait(&event, 1000); + EsHeapFree(scheduler.threadEventLog, 0, K_FIXED); + scheduler.threadEventLog = nullptr; + } else if (argument0 == 12) { + EsMemoryStatistics statistics; + EsMemoryZero(&statistics, sizeof(statistics)); + statistics.fixedHeapAllocationCount = K_FIXED->allocationsCount; + statistics.fixedHeapTotalSize = K_FIXED->size; + statistics.coreHeapAllocationCount = K_CORE->allocationsCount; + statistics.coreHeapTotalSize = K_CORE->size; + statistics.cachedNodes = fs.bootFileSystem->cachedNodes.count; + statistics.cachedDirectoryEntries = fs.bootFileSystem->cachedDirectoryEntries.count; + statistics.totalSurfaceBytes = graphics.totalSurfaceBytes; + statistics.commitPageable = pmm.commitPageable; + statistics.commitFixed = pmm.commitFixed; + statistics.commitLimit = pmm.commitLimit; + statistics.commitFixedLimit = pmm.commitFixedLimit; + statistics.commitRemaining = MM_REMAINING_COMMIT(); + statistics.maximumObjectCachePages = MM_OBJECT_CACHE_PAGES_MAXIMUM(); + statistics.approximateObjectCacheSize = pmm.approximateTotalObjectCacheBytes; + SYSCALL_WRITE(argument1, &statistics, sizeof(statistics)); + } +#endif + + SYSCALL_RETURN(ES_SUCCESS, false); +} + +SyscallFunction syscallFunctions[ES_SYSCALL_COUNT + 1] { +#include +}; + +#pragma GCC diagnostic pop + +uintptr_t DoSyscall(EsSyscallType index, + uintptr_t argument0, uintptr_t argument1, + uintptr_t argument2, uintptr_t argument3, + uint64_t flags, bool *fatal, uintptr_t *userStackPointer) { + bool batched = flags & DO_SYSCALL_BATCHED; + + // Interrupts need to be enabled during system calls, + // because many of them block on mutexes or events. + ProcessorEnableInterrupts(); + + Thread *currentThread = GetCurrentThread(); + Process *currentProcess = currentThread->process; + MMSpace *currentVMM = currentProcess->vmm; + + if (!batched) { + if (currentThread->terminating) { + // The thread has been terminated. + // Yield the scheduler so it can be removed. + ProcessorFakeTimerInterrupt(); + } + + if (currentThread->terminatableState != THREAD_TERMINATABLE) { + KernelPanic("DoSyscall - Current thread %x was not terminatable (was %d).\n", + currentThread, currentThread->terminatableState); + } + + currentThread->terminatableState = THREAD_IN_SYSCALL; + } + + EsError returnValue = ES_FATAL_ERROR_UNKNOWN_SYSCALL; + bool fatalError = true; + + if (index < ES_SYSCALL_COUNT) { + SyscallFunction function = syscallFunctions[index]; + + if (batched && index == ES_SYSCALL_BATCH) { + // This could cause a stack overflow, so it's a fatal error. + } else if (function) { + returnValue = (EsError) function(argument0, argument1, argument2, argument3, + currentThread, currentProcess, currentVMM, userStackPointer, &fatalError); + } + } + + if (fatal) *fatal = false; + + if (fatalError) { + if (fatal) { + *fatal = true; + } else { + EsCrashReason reason; + EsMemoryZero(&reason, sizeof(EsCrashReason)); + reason.errorCode = (EsFatalError) returnValue; + reason.duringSystemCall = index; + KernelLog(LOG_ERROR, "Syscall", "syscall failure", + "Process crashed during system call [%x, %x, %x, %x, %x]\n", index, argument0, argument1, argument2, argument3); + scheduler.CrashProcess(currentProcess, &reason); + } + } + + if (!batched) { + currentThread->terminatableState = THREAD_TERMINATABLE; + + if (currentThread->terminating || currentThread->paused) { + // The thread has been terminated or paused. + // Yield the scheduler so it can be removed or sent to the paused thread queue. + ProcessorFakeTimerInterrupt(); + } + } + + return returnValue; +} + +bool KCopyToUser(K_USER_BUFFER void *destination, const void *source, size_t length) { + __sync_synchronize(); + Thread *currentThread = GetCurrentThread(); + MMRegion *region = MMFindAndPinRegion(currentThread->process->vmm, (uintptr_t) destination, length); + if (!region) return false; + EsMemoryCopy(destination, source, length); + MMUnpinRegion(currentThread->process->vmm, region); + return true; +} + +bool KCopyFromUser(void *destination, K_USER_BUFFER const void *source, size_t length) { + __sync_synchronize(); + Thread *currentThread = GetCurrentThread(); + MMRegion *region = MMFindAndPinRegion(currentThread->process->vmm, (uintptr_t) source, length); + if (!region) return false; + EsMemoryCopy(destination, source, length); + MMUnpinRegion(currentThread->process->vmm, region); + return true; +} + +#endif diff --git a/kernel/terminal.cpp b/kernel/terminal.cpp new file mode 100644 index 0000000..ae40540 --- /dev/null +++ b/kernel/terminal.cpp @@ -0,0 +1,431 @@ +// TODO Everything in this file is a hack just so I can debug the kernel. +// Replace all of it!!! + +#ifdef IMPLEMENTATION + +#include +#include "x86_64.h" + +#define TERMINAL_ADDRESS ((uint16_t *) (LOW_MEMORY_MAP_START + 0xB8000)) + +#if 1 +KSpinlock terminalLock; +KSpinlock printLock; +#else +KMutex terminalLock; +KMutex printLock; +#endif + +void DebugWriteCharacter(uintptr_t character); + +#ifdef ARCH_X86_COMMON +bool printToDebugger = false; +uintptr_t terminalPosition = 80; + +#define EARLY_DEBUGGING +// #define VGA_TEXT_MODE + +#ifdef EARLY_DEBUGGING +char kernelLog[262144]; +uintptr_t kernelLogPosition; +#endif + +static void TerminalCallback(int character, void *) { + if (!character) return; + + KSpinlockAcquire(&terminalLock); + EsDefer(KSpinlockRelease(&terminalLock)); + +#ifdef EARLY_DEBUGGING + { + kernelLog[kernelLogPosition] = character; + kernelLogPosition++; + if (kernelLogPosition == sizeof(kernelLog)) kernelLogPosition = 0; + } +#endif + +#ifdef VGA_TEXT_MODE + { + if (character == '\n') { + terminalPosition = terminalPosition - (terminalPosition % 80) + 80; + } else { + TERMINAL_ADDRESS[terminalPosition] = (uint16_t) character | 0x0700; + terminalPosition++; + } + + if (terminalPosition >= 80 * 25) { + for (int i = 80; i < 80 * 25; i++) { + TERMINAL_ADDRESS[i - 80] = TERMINAL_ADDRESS[i]; + } + + for (int i = 80 * 24; i < 80 * 25; i++) { + TERMINAL_ADDRESS[i] = 0x700; + } + + terminalPosition -= 80; + + // uint64_t start = ProcessorReadTimeStamp(); + // uint64_t end = start + 250 * KGetTimeStampTicksPerMs(); + // while (ProcessorReadTimeStamp() < end); + } + + { + ProcessorOut8(0x3D4, 0x0F); + ProcessorOut8(0x3D5, terminalPosition); + ProcessorOut8(0x3D4, 0x0E); + ProcessorOut8(0x3D5, terminalPosition >> 8); + } + } +#endif + + { + ProcessorDebugOutputByte((uint8_t) character); + + if (character == '\n') { + ProcessorDebugOutputByte((uint8_t) 13); + } + } + + if (printToDebugger) { + DebugWriteCharacter(character); + if (character == '\t') DebugWriteCharacter(' '); + } +} +#endif + +size_t debugRows, debugColumns, debugCurrentRow, debugCurrentColumn; + +void DebugWriteCharacter(uintptr_t character) { + if (!graphics.target || !graphics.target->debugPutBlock) return; + + if (debugCurrentRow == debugRows) { + debugCurrentRow = 0; + + // uint64_t start = ProcessorReadTimeStamp(); + // uint64_t end = start + 3000 * KGetTimeStampTicksPerMs(); + // while (ProcessorReadTimeStamp() < end); + + graphics.target->debugClearScreen(); + } + + uintptr_t row = debugCurrentRow; + uintptr_t column = debugCurrentColumn; + + if (character == '\n') { + debugCurrentRow++; + debugCurrentColumn = 0; + return; + } + + if (character > 127) character = ' '; + if (row >= debugRows) return; + if (column >= debugColumns) return; + + for (int j = 0; j < VGA_FONT_HEIGHT; j++) { + uint8_t byte = ((uint8_t *) vgaFont)[character * 16 + j]; + + for (int i = 0; i < 8; i++) { + uint8_t bit = byte & (1 << i); + if (bit) graphics.target->debugPutBlock((column + 1) * 9 + i, row * 16 + j, false); + } + } + + debugCurrentColumn++; + + if (debugCurrentColumn == debugColumns) { + debugCurrentRow++; + debugCurrentColumn = 4; + } +} + +void StartDebugOutput() { + if (graphics.target && graphics.target->debugClearScreen && graphics.target->debugPutBlock) { + debugRows = (graphics.height - 1) / VGA_FONT_HEIGHT; + debugColumns = (graphics.width - 1) / VGA_FONT_WIDTH - 2; + debugCurrentRow = debugCurrentColumn = 0; + printToDebugger = true; + graphics.target->debugClearScreen(); + } +} + +bool debugKeyPressed; + +void KDebugKeyPressed() { + if (debugKeyPressed) return; + debugKeyPressed = true; + KernelPanic("Debug key pressed.\n"); +} + +uintptr_t DebugReadNumber() { + uintptr_t value = 0; + + for (uintptr_t i = 0; i < 2 * sizeof(uintptr_t); i++) { + value <<= 4; + + while (true) { + int key = KWaitKey(); + if (key == ES_SCANCODE_0) { EsPrint("0"); value |= 0; } + else if (key == ES_SCANCODE_1) { EsPrint("1"); value |= 1; } + else if (key == ES_SCANCODE_2) { EsPrint("2"); value |= 2; } + else if (key == ES_SCANCODE_3) { EsPrint("3"); value |= 3; } + else if (key == ES_SCANCODE_4) { EsPrint("4"); value |= 4; } + else if (key == ES_SCANCODE_5) { EsPrint("5"); value |= 5; } + else if (key == ES_SCANCODE_6) { EsPrint("6"); value |= 6; } + else if (key == ES_SCANCODE_7) { EsPrint("7"); value |= 7; } + else if (key == ES_SCANCODE_8) { EsPrint("8"); value |= 8; } + else if (key == ES_SCANCODE_9) { EsPrint("9"); value |= 9; } + else if (key == ES_SCANCODE_A) { EsPrint("A"); value |= 10; } + else if (key == ES_SCANCODE_B) { EsPrint("B"); value |= 11; } + else if (key == ES_SCANCODE_C) { EsPrint("C"); value |= 12; } + else if (key == ES_SCANCODE_D) { EsPrint("D"); value |= 13; } + else if (key == ES_SCANCODE_E) { EsPrint("E"); value |= 14; } + else if (key == ES_SCANCODE_F) { EsPrint("F"); value |= 15; } + else if (key == ES_SCANCODE_ENTER) { value >>= 4; return value; } + else continue; + break; + } + } + + return value; +} + +void KernelPanic(const char *format, ...) { + ProcessorDisableInterrupts(); + ProcessorSendIPI(KERNEL_PANIC_IPI, true); + + // Disable synchronisation objects. The panic IPI must be sent before this, + // so other processors don't start getting "mutex not correctly acquired" panics. + scheduler.panic = true; + + if (debugKeyPressed) { + DriversDumpState(); + } + + if (!printToDebugger) StartDebugOutput(); + + EsPrint("\n--- System Error ---\n>> "); + + va_list arguments; + va_start(arguments, format); + _StringFormat(TerminalCallback, (void *) 0x4F00, format, arguments); + va_end(arguments); + + EsPrint("Current thread = %x\n", GetCurrentThread()); + EsPrint("Trace: %x\n", __builtin_return_address(0)); + EsPrint("RSP: %x; RBP: %x\n", ProcessorGetRSP(), ProcessorGetRBP()); + // EsPrint("Memory: %x/%x\n", pmm.pagesAllocated, pmm.startPageCount); + + { + EsPrint("Threads:\n"); + + LinkedItem *item = scheduler.allThreads.firstItem; + + while (item) { + Thread *thread = item->thisItem; + + EsPrint("%z %d %x @%x:%x ", (GetCurrentThread() == thread) ? "=>" : " ", + thread->id, thread, thread->interruptContext->rip, thread->interruptContext->rbp); + + if (thread->state == THREAD_WAITING_EVENT) { + EsPrint("WaitEvent(Count:%d, %x) ", thread->blocking.eventCount, thread->blocking.events[0]); + } else if (thread->state == THREAD_WAITING_MUTEX) { + EsPrint("WaitMutex(%x, Owner:%d) ", thread->blocking.mutex, thread->blocking.mutex->owner->id); + } else if (thread->state == THREAD_WAITING_WRITER_LOCK) { + EsPrint("WaitWriterLock(%x, %d) ", thread->blocking.writerLock, thread->blocking.writerLockType); + } + + Process *process = thread->process; + EsPrint("%z:%z\n", process->cExecutableName, thread->cName); + + item = item->nextItem; + } + } + + for (uintptr_t i = 0; i < KGetCPUCount(); i++) { + CPULocalStorage *local = KGetCPULocal(i); + + if (local->panicContext) { + EsPrint("CPU %d LS %x RIP/RBP %x:%x TID %d\n", local->processorID, local, + local->panicContext->rip, local->panicContext->rbp, + local->currentThread ? local->currentThread->id : 0); + } + } + +#ifdef EARLY_DEBUGGING + uintptr_t kernelLogEnd = kernelLogPosition; + EsPrint("Press 'D' to enter debugger.\n"); + while (KWaitKey() != ES_SCANCODE_D); + graphics.debuggerActive = true; + + while (true) { +#ifdef VGA_TEXT_MODE + for (uintptr_t i = 0; i < 80 * 25; i++) { + TERMINAL_ADDRESS[i] = 0x0700; + } + + terminalPosition = 80; +#else + graphics.target->debugClearScreen(); + + debugCurrentRow = debugCurrentColumn = 0; +#endif + + + EsPrint("0 - view log\n1 - reset\n2 - view pmem\n3 - view vmem\n4 - stack trace\n"); + + int key = KWaitKey(); + + if (key == ES_SCANCODE_0) { + uintptr_t position = 0, nextPosition = 0; + uintptr_t x = 0, y = 0; + + + +#ifdef VGA_TEXT_MODE + for (uintptr_t i = 0; i < 80 * 25; i++) { + TERMINAL_ADDRESS[i] = 0x0700; + } +#else + graphics.target->debugClearScreen(); +#endif + + while (position < kernelLogEnd) { + char c = kernelLog[position]; + + if (c != '\n') { +#ifdef VGA_TEXT_MODE + TERMINAL_ADDRESS[x + y * 80] = c | 0x0700; +#else + debugCurrentRow = y, debugCurrentColumn = x; + DebugWriteCharacter(c); +#endif + } + + x++; + + if (x == +#ifdef VGA_TEXT_MODE + 80 +#else + debugColumns +#endif + || c == '\n') { + x = 0; + y++; + + if (y == 1) { + nextPosition = position; + } + } + + if (y == +#ifdef VGA_TEXT_MODE + 25 +#else + debugRows +#endif + ) { + while (true) { + int key = KWaitKey(); + + if (key == ES_SCANCODE_SPACE || key == ES_SCANCODE_DOWN_ARROW) { + position = nextPosition; + break; + } else if (key == ES_SCANCODE_UP_ARROW) { + position = nextPosition; + if (position < 240) position = 0; + else position -= 240; + break; + } + } + +#ifdef VGA_TEXT_MODE + for (uintptr_t i = 0; i < 80 * 25; i++) { + TERMINAL_ADDRESS[i] = 0x0700; + } +#else + graphics.target->debugClearScreen(); +#endif + + y = 0; + } + + position++; + } + + KWaitKey(); + } else if (key == ES_SCANCODE_1) { + ArchResetCPU(); + } else if (key == ES_SCANCODE_2) { + EsPrint("Enter address: "); + uintptr_t address = DebugReadNumber(); + uintptr_t offset = address & (K_PAGE_SIZE - 1); + MMArchRemap(kernelMMSpace, pmm.pmManipulationRegion, address - offset); + uintptr_t *data = (uintptr_t *) ((uint8_t *) pmm.pmManipulationRegion + offset); + + for (uintptr_t i = 0; i < 8 && (offset + 8 * sizeof(uintptr_t) < K_PAGE_SIZE); i++) { + EsPrint("\n%x - %x\n", address + 8 * sizeof(uintptr_t), data[i]); + } + + while (KWaitKey() != ES_SCANCODE_ENTER); + } else if (key == ES_SCANCODE_3) { + EsPrint("Enter address: "); + uintptr_t address = DebugReadNumber(); + uintptr_t offset = address & (K_PAGE_SIZE - 1); + uintptr_t *data = (uintptr_t *) address; + + for (uintptr_t i = 0; i < 8 && (offset + i * sizeof(uintptr_t) < K_PAGE_SIZE); i++) { + EsPrint("\n%x - %x", address + i * sizeof(uintptr_t), data[i]); + } + + while (KWaitKey() != ES_SCANCODE_ENTER); + } else if (key == ES_SCANCODE_4) { + EsPrint("Enter RBP: "); + uintptr_t address = DebugReadNumber(); + + while (address) { + EsPrint("\n%x", ((uintptr_t *) address)[1]); + address = ((uintptr_t *) address)[0]; + } + + while (KWaitKey() != ES_SCANCODE_ENTER); + } + } +#endif + + ProcessorHalt(); +} + +void EsPrint(const char *format, ...) { + KSpinlockAcquire(&printLock); + EsDefer(KSpinlockRelease(&printLock)); + + va_list arguments; + va_start(arguments, format); + _StringFormat(TerminalCallback, (void *) 0x0700, format, arguments); + va_end(arguments); +} + +void __KernelLog(const char *format, ...) { + va_list arguments; + va_start(arguments, format); + _StringFormat(TerminalCallback, nullptr, format, arguments); + va_end(arguments); +} + +void KernelLog(KLogLevel level, const char *subsystem, const char *event, const char *format, ...) { + if (level == LOG_VERBOSE) return; + (void) event; + + KSpinlockAcquire(&printLock); + EsDefer(KSpinlockRelease(&printLock)); + + __KernelLog("[%z:%z] ", level == LOG_INFO ? "Info" : level == LOG_ERROR ? "**Error**" : level == LOG_VERBOSE ? "Verbose" : "", subsystem); + + va_list arguments; + va_start(arguments, format); + _StringFormat(TerminalCallback, nullptr, format, arguments); + va_end(arguments); +} + +#endif diff --git a/kernel/windows.cpp b/kernel/windows.cpp new file mode 100644 index 0000000..5924e80 --- /dev/null +++ b/kernel/windows.cpp @@ -0,0 +1,1407 @@ +#ifndef IMPLEMENTATION + +// TODO Don't send key released messages if the focused window has changed. +// TODO Blur clamping is incorrect with minimal repainting! + +struct EmbeddedWindow { + void Destroy(); + void Close(); + void SetEmbedOwner(Process *process); + + Process *volatile owner; + void *volatile apiWindow; + volatile uint32_t handles; + struct Window *container; + uint64_t id; + uint32_t resizeClearColor; + bool closed; +}; + +struct Window { + void Update(EsRectangle *region, bool addToModifiedRegion); + bool UpdateDirect(K_USER_BUFFER void *bits, uintptr_t stride, EsRectangle region); + void Destroy(); + void Close(); + bool Move(EsRectangle newBounds, uint32_t flags); + void SetEmbed(EmbeddedWindow *window); + bool IsVisible(); + + // State: + EsWindowStyle style; + EsRectangle solidInsets; + bool solid, noClickActivate, hidden, isMaximised, alwaysOnTop, hoveringOverEmbed, queuedScrollUpdate, activationClick, noBringToFront; + volatile bool closed; + + // Appearance: + Surface surface; + EsRectangle opaqueBounds, blurBounds; + uint8_t alpha, material; + uint32_t resizeClearColor; + + // Owner and children: + Process *owner; + void *apiWindow; + EmbeddedWindow *embed; + volatile uint64_t handles; + uint64_t id; + + // Location: + EsPoint position; + size_t width, height; +}; + +struct WindowManager { + void *CreateWindow(Process *process, void *apiWindow, EsWindowStyle style); + void *CreateEmbeddedWindow(Process *process, void *apiWindow); + Window *FindWindowAtPosition(int cursorX, int cursorY); + + void Initialise(); + + void MoveCursor(int xMovement, int yMovement); + void ClickCursor(unsigned buttons); + void UpdateCursor(int xMovement, int yMovement, unsigned buttons); + void PressKey(unsigned scancode); + + void Redraw(EsPoint position, int width, int height, Window *except = nullptr, int startingAt = 0, bool addToModifiedRegion = true); + + bool ActivateWindow(Window *window); // Returns true if any menus were closed. + void HideWindow(Window *window); + Window *FindWindowToActivate(Window *excluding = nullptr); + uintptr_t GetActivationZIndex(); + void ChangeWindowDepth(Window *window, bool alwaysRedraw, ptrdiff_t newZDepth); + intptr_t FindWindowDepth(Window *window); + bool CloseMenus(); // Returns true if any menus were closed. + + void StartEyedrop(uintptr_t object, Window *avoid, uint32_t cancelColor); + void EndEyedrop(bool cancelled); + + bool initialised; + + // Windows: + + Array windows; // Sorted by z. + Array embeddedWindows; + Window *pressedWindow, *activeWindow, *hoverWindow; + KMutex mutex; + KEvent windowsToCloseEvent; + uint64_t currentWindowID; + size_t inspectorWindowCount; + + // Cursor: + + int cursorX, cursorY; + int cursorXPrecise, cursorYPrecise; // Scaled up by a factor of 10. + unsigned lastButtons; + + Surface cursorSurface, cursorSwap; + int cursorImageOffsetX, cursorImageOffsetY; + uintptr_t cursorID; + bool cursorXOR; + bool changedCursorImage; + + // Keyboard: + + bool shift, alt, ctrl, flag; + bool shift2, alt2, ctrl2, flag2; + bool numlock; + uint8_t modifiers; + + // Eyedropper: + + uintptr_t eyedropObject; + bool eyedropping; + Process *eyedropProcess; + uint64_t eyedropAvoidID; + uint32_t eyedropCancelColor; + + // Miscellaneous: + + EsRectangle workArea; + + // Game controllers: + + KMutex gameControllersMutex; + EsGameControllerState gameControllers[ES_GAME_CONTROLLER_MAX_COUNT]; + size_t gameControllerCount; + uint64_t gameControllerID; + + // Flicker-free resizing: + +#define RESIZE_FLICKER_TIMEOUT_MS (40) +#define RESIZE_SLOW_THRESHOLD (RESIZE_FLICKER_TIMEOUT_MS * 3 / 4) + Window *resizeWindow; + bool resizeReceivedBitsFromContainer; + bool resizeReceivedBitsFromEmbed; + uint64_t resizeStartTimeStampMs; + EsRectangle resizeQueuedRectangle; + bool resizeQueued; + bool resizeSlow; // Set if the previous resize went past RESIZE_FLICKER_SLOW_THRESHOLD; + // when set, the old surface bits are copied on resize, so that if the resize times out the result will be reasonable. +}; + +struct ClipboardItem { + uint64_t format; + ConstantBuffer *buffer; +}; + +struct Clipboard { + KMutex mutex; +#define CLIPBOARD_ITEM_COUNT (1) + ClipboardItem items[CLIPBOARD_ITEM_COUNT]; + +#define CLIPBOARD_ITEM_SIZE_LIMIT (64 * 1024 * 1024) + EsError Add(uint64_t format, K_USER_BUFFER const void *data, size_t dataBytes); + bool Has(uint64_t format); + EsHandle Read(uint64_t format, K_USER_BUFFER size_t *bytes, Process *process); +}; + +WindowManager windowManager; +Clipboard primaryClipboard; + +void SendMessageToWindow(Window *window, EsMessage *message); + +#ifdef TEST_HIGH_UI_SCALE +#define UI_SCALE (140) +#else +#define UI_SCALE (100) +#endif + +#define WINDOW_INSET (19 * UI_SCALE / 100) +#define CONTAINER_TAB_BAND_HEIGHT (33 * UI_SCALE / 100) +#define BORDER_THICKNESS (9 * UI_SCALE / 100) + +#else + +bool Window::IsVisible() { + return !hidden && !closed && (id != windowManager.eyedropAvoidID || !windowManager.eyedropping); +} + +void SendMessageToWindow(Window *window, EsMessage *message) { + KMutexAssertLocked(&windowManager.mutex); + + if (window->closed) { + return; + } + + if (!window->owner->handles) { + KernelPanic("SendMessageToWindow - (%x:%d/%x:%d) No handles.\n", window, window->handles, window->owner, window->owner->handles); + } + + if (window->style != ES_WINDOW_CONTAINER || !window->embed) { + window->owner->messageQueue.SendMessage(window->apiWindow, message); + return; + } + + if (message->type == ES_MSG_WINDOW_RESIZED) { + message->windowResized.content = ES_RECT_4(0, window->width, 0, window->height); + window->owner->messageQueue.SendMessage(window->apiWindow, message); + + message->windowResized.content = ES_RECT_4(0, window->width - WINDOW_INSET * 2, 0, window->height - WINDOW_INSET * 2 - CONTAINER_TAB_BAND_HEIGHT); + window->embed->owner->messageQueue.SendMessage(window->embed->apiWindow, message); + } else if (message->type == ES_MSG_WINDOW_DEACTIVATED || message->type == ES_MSG_WINDOW_ACTIVATED) { + window->owner->messageQueue.SendMessage(window->apiWindow, message); + window->embed->owner->messageQueue.SendMessage(window->embed->apiWindow, message); + } else if (message->type == ES_MSG_MOUSE_MOVED) { + EsRectangle embedRegion = ES_RECT_4(WINDOW_INSET, window->width - WINDOW_INSET, WINDOW_INSET + CONTAINER_TAB_BAND_HEIGHT, window->height - WINDOW_INSET); + bool inEmbed = windowManager.pressedWindow + ? window->hoveringOverEmbed + : EsRectangleContains(embedRegion, message->mouseMoved.newPositionX, message->mouseMoved.newPositionY); + + if (inEmbed) { + message->mouseMoved.newPositionX -= WINDOW_INSET; + message->mouseMoved.newPositionY -= WINDOW_INSET + CONTAINER_TAB_BAND_HEIGHT; + + window->embed->owner->messageQueue.SendMessage(window->embed->apiWindow, message); + + if (!windowManager.pressedWindow && !window->hoveringOverEmbed) { + message->type = ES_MSG_MOUSE_EXIT; + window->owner->messageQueue.SendMessage(window->apiWindow, message); + } + } else { + window->owner->messageQueue.SendMessage(window->apiWindow, message); + + if (!windowManager.pressedWindow && window->hoveringOverEmbed) { + message->type = ES_MSG_MOUSE_EXIT; + window->embed->owner->messageQueue.SendMessage(window->embed->apiWindow, message); + } + } + + if (!windowManager.pressedWindow) { + window->hoveringOverEmbed = inEmbed; + } + } else if (message->type >= ES_MSG_MOUSE_LEFT_DOWN && message->type <= ES_MSG_MOUSE_MIDDLE_UP) { + if (window->hoveringOverEmbed) { + message->mouseDown.positionX -= WINDOW_INSET; + message->mouseDown.positionY -= WINDOW_INSET + CONTAINER_TAB_BAND_HEIGHT; + + if (!window->activationClick) { + window->embed->owner->messageQueue.SendMessage(window->embed->apiWindow, message); + } + } else { + window->owner->messageQueue.SendMessage(window->apiWindow, message); + } + } else if (message->type == ES_MSG_KEY_DOWN || message->type == ES_MSG_KEY_UP) { + window->embed->owner->messageQueue.SendMessage(window->embed->apiWindow, message); + + // TODO Better method of handling keyboard shortcuts that Desktop needs to process? + // By sending the message to both processes, two threads will wake up, + // which could increase latency of handling the message. + window->owner->messageQueue.SendMessage(window->apiWindow, message); + } else if (message->type == ES_MSG_MOUSE_EXIT || message->type == ES_MSG_PRIMARY_CLIPBOARD_UPDATED) { + window->embed->owner->messageQueue.SendMessage(window->embed->apiWindow, message); + window->owner->messageQueue.SendMessage(window->apiWindow, message); + } else { + window->owner->messageQueue.SendMessage(window->apiWindow, message); + } +} + +Window *WindowManager::FindWindowAtPosition(int cursorX, int cursorY) { + KMutexAssertLocked(&mutex); + + for (intptr_t i = windows.Length() - 1; i >= 0; i--) { + Window *window = windows[i]; + EsRectangle bounds = ES_RECT_4PD(window->position.x, window->position.y, window->width, window->height); + + if (window->solid && !window->hidden && EsRectangleContains(EsRectangleAdd(bounds, window->solidInsets), cursorX, cursorY) + && (!window->isMaximised || EsRectangleContains(workArea, cursorX, cursorY))) { + return window; + } + } + + return nullptr; +} + +void WindowManager::UpdateCursor(int xMovement, int yMovement, unsigned buttons) { + if (!initialised) { + return; + } + + if (xMovement || yMovement) { + if (xMovement * xMovement + yMovement * yMovement < 10 && buttons != lastButtons) { + // This seems to be movement noise generated when the buttons were pressed/released. + } else { + KMutexAcquire(&mutex); + MoveCursor(xMovement, yMovement); + KMutexRelease(&mutex); + } + } + + ClickCursor(buttons); +} + +void WindowManager::EndEyedrop(bool cancelled) { + KMutexAssertLocked(&mutex); + + eyedropping = false; + + EsMessage m = { ES_MSG_EYEDROP_REPORT }; + uint32_t color = *(uint32_t *) ((uint8_t *) graphics.frameBuffer.bits + 4 * cursorX + graphics.frameBuffer.stride * cursorY) | 0xFF000000; + m.eyedrop.color = cancelled ? eyedropCancelColor : color; + m.eyedrop.cancelled = cancelled; + eyedropProcess->messageQueue.SendMessage((void *) eyedropObject, &m); + CloseHandleToObject(eyedropProcess, KERNEL_OBJECT_PROCESS); + eyedropProcess = nullptr; + + Redraw(ES_POINT(0, 0), graphics.width, graphics.height); +} + +void WindowManager::PressKey(unsigned scancode) { + if (!initialised) { + return; + } + + bool moveCursorNone = false; + + KMutexAcquire(&mutex); + + if (scancode == ES_SCANCODE_NUM_DIVIDE) { + KernelPanic("WindowManager::PressKey - Panic key pressed.\n"); + } + + if (eyedropping) { + if (scancode == (ES_SCANCODE_ESCAPE | K_SCANCODE_KEY_RELEASED)) { + EndEyedrop(true); + moveCursorNone = true; + } + + goto done; + } + + // TODO Caps lock. + + if (scancode == ES_SCANCODE_LEFT_CTRL) ctrl = true; + if (scancode == (ES_SCANCODE_LEFT_CTRL | K_SCANCODE_KEY_RELEASED)) ctrl = false; + if (scancode == ES_SCANCODE_LEFT_SHIFT) shift = true; + if (scancode == (ES_SCANCODE_LEFT_SHIFT | K_SCANCODE_KEY_RELEASED)) shift = false; + if (scancode == ES_SCANCODE_LEFT_ALT) alt = true; + if (scancode == (ES_SCANCODE_LEFT_ALT | K_SCANCODE_KEY_RELEASED)) alt = false; + if (scancode == ES_SCANCODE_LEFT_FLAG) flag = true; + if (scancode == (ES_SCANCODE_LEFT_FLAG | K_SCANCODE_KEY_RELEASED)) flag = false; + + if (scancode == ES_SCANCODE_RIGHT_CTRL) ctrl2 = true; + if (scancode == (ES_SCANCODE_RIGHT_CTRL | K_SCANCODE_KEY_RELEASED)) ctrl2 = false; + if (scancode == ES_SCANCODE_RIGHT_SHIFT) shift2 = true; + if (scancode == (ES_SCANCODE_RIGHT_SHIFT | K_SCANCODE_KEY_RELEASED)) shift2 = false; + if (scancode == ES_SCANCODE_RIGHT_ALT) alt2 = true; + if (scancode == (ES_SCANCODE_RIGHT_ALT | K_SCANCODE_KEY_RELEASED)) alt2 = false; + if (scancode == ES_SCANCODE_RIGHT_FLAG) flag2 = true; + if (scancode == (ES_SCANCODE_RIGHT_FLAG | K_SCANCODE_KEY_RELEASED)) flag2 = false; + + modifiers = ((alt | alt2) ? ES_MODIFIER_ALT : 0) + | ((ctrl | ctrl2) ? ES_MODIFIER_CTRL : 0) + | ((shift | shift2) ? ES_MODIFIER_SHIFT : 0) + | ((flag | flag2) ? ES_MODIFIER_FLAG : 0); + + if (activeWindow) { + Window *window = activeWindow; + + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = (scancode & K_SCANCODE_KEY_RELEASED) ? ES_MSG_KEY_UP : ES_MSG_KEY_DOWN; + message.keyboard.modifiers = modifiers; + message.keyboard.scancode = scancode & ~K_SCANCODE_KEY_RELEASED; + message.keyboard.numlock = numlock; + + static uint8_t heldKeys[512 / 8] = {}; + + if (message.keyboard.scancode >= 512) { + KernelPanic("WindowManager::PressKey - Scancode outside valid range.\n"); + } + + if (message.type == ES_MSG_KEY_DOWN && (heldKeys[message.keyboard.scancode / 8] & (1 << (message.keyboard.scancode % 8)))) { + message.keyboard.repeat = true; + } + + if (message.type == ES_MSG_KEY_DOWN) { + heldKeys[message.keyboard.scancode / 8] |= (1 << (message.keyboard.scancode % 8)); + } else { + heldKeys[message.keyboard.scancode / 8] &= ~(1 << (message.keyboard.scancode % 8)); + } + + SendMessageToWindow(window, &message); + } + + done:; + if (moveCursorNone) MoveCursor(0, 0); + KMutexRelease(&mutex); +} + +Window *WindowManager::FindWindowToActivate(Window *excluding) { + for (uintptr_t i = windows.Length(); i > 0; i--) { + if (!windows[i - 1]->hidden + && windows[i - 1]->style == ES_WINDOW_CONTAINER + && windows[i - 1] != excluding) { + return windows[i - 1]; + } + } + + return nullptr; +} + +uintptr_t WindowManager::GetActivationZIndex() { + for (uintptr_t i = windows.Length(); i > 0; i--) { + if (!windows[i - 1]->alwaysOnTop) { + return i; + } + } + + return 0; +} + +void WindowManager::HideWindow(Window *window) { + KMutexAssertLocked(&mutex); + + if (window->hidden) return; + window->hidden = true; + + if (window == activeWindow) { + ActivateWindow(FindWindowToActivate()); + } + + Redraw(ES_POINT(window->position.x, window->position.y), window->width, window->height); +} + +intptr_t WindowManager::FindWindowDepth(Window *window) { + KMutexAssertLocked(&windowManager.mutex); + + for (uintptr_t i = 0; i < windows.Length(); i++) { + if (windows[i] == window) { + return i; + } + } + + return -1; +} + +void WindowManager::ChangeWindowDepth(Window *window, bool redraw, ptrdiff_t _newZDepth) { + KMutexAssertLocked(&windowManager.mutex); + + // Reorder the windows in the array, and update the depth buffer. + intptr_t oldZDepth = FindWindowDepth(window); + if (oldZDepth == -1) KernelPanic("WindowManager::ChangeWindowDepth - Window %x was not in array.\n", window); + windows.Delete(oldZDepth); + intptr_t newZDepth = _newZDepth != -1 ? _newZDepth : GetActivationZIndex(); + windows.Insert(window, newZDepth); + + if (oldZDepth != newZDepth || redraw) { + // Redraw the modified area of the screen. + windowManager.Redraw(ES_POINT(window->position.x, window->position.y), window->width, window->height); + } +} + +bool WindowManager::CloseMenus() { + KMutexAssertLocked(&mutex); + + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + + bool result = false; + + for (uintptr_t i = 0; i < windows.Length(); i++) { + // Close any open menus. + + if (windows[i]->style == ES_WINDOW_MENU) { + message.type = ES_MSG_WINDOW_DEACTIVATED; + SendMessageToWindow(windows[i], &message); + result = true; + } + } + + return result; +} + +bool WindowManager::ActivateWindow(Window *window) { + KMutexAssertLocked(&mutex); + + if (window && (window->style == ES_WINDOW_TIP || window->style == ES_WINDOW_MENU || window->closed)) { + return false; + } + + Window *oldWindow = activeWindow; + + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + + bool result = CloseMenus(); + + // Set the active window, unless it hasn't changed. + + if (activeWindow == window && (!window || !window->hidden)) { + // Bring the window to the front anyway. + if (window && !window->noBringToFront) ChangeWindowDepth(window, false, -1); + return result; + } + + activeWindow = window; + if (window) window->hidden = false; + + if (window) { + // Bring the window to the front. + if (!window->noBringToFront) ChangeWindowDepth(window, true, -1); + + // Activate the new window. + message.type = ES_MSG_WINDOW_ACTIVATED; + SendMessageToWindow(window, &message); + } else { + // No window is active. + } + + if (oldWindow && oldWindow != window) { + // Deactivate the old window. + + if (oldWindow != FindWindowAtPosition(cursorX, cursorY)) { + message.type = ES_MSG_MOUSE_EXIT; + SendMessageToWindow(oldWindow, &message); + } + + message.type = ES_MSG_WINDOW_DEACTIVATED; + SendMessageToWindow(oldWindow, &message); + } + + return result; +} + +void WindowManager::ClickCursor(unsigned buttons) { + KMutexAcquire(&mutex); + + unsigned delta = lastButtons ^ buttons; + lastButtons = buttons; + + bool moveCursorNone = false; + + if (eyedropping && delta) { + if ((delta & K_LEFT_BUTTON) && (~buttons & K_LEFT_BUTTON)) { + EndEyedrop(false); + moveCursorNone = true; + } + } else if (delta) { + // Send a mouse pressed message to the window the cursor is over. + Window *window = FindWindowAtPosition(cursorX, cursorY); + + bool activationClick = false, activationClickFromMenu = false; + + if (buttons == delta) { + if (activeWindow != window) { + activationClick = true; + } + + if (window && window->noClickActivate) { + if (!window->noBringToFront) { + ChangeWindowDepth(window, false, -1); + } + + if (window->style != ES_WINDOW_MENU) { + activationClickFromMenu = CloseMenus(); + } + } else { + activationClickFromMenu = ActivateWindow(window); + } + } + + { + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + + if (delta & K_LEFT_BUTTON) message.type = (buttons & K_LEFT_BUTTON) ? ES_MSG_MOUSE_LEFT_DOWN : ES_MSG_MOUSE_LEFT_UP; + if (delta & K_RIGHT_BUTTON) message.type = (buttons & K_RIGHT_BUTTON) ? ES_MSG_MOUSE_RIGHT_DOWN : ES_MSG_MOUSE_RIGHT_UP; + if (delta & K_MIDDLE_BUTTON) message.type = (buttons & K_MIDDLE_BUTTON) ? ES_MSG_MOUSE_MIDDLE_DOWN : ES_MSG_MOUSE_MIDDLE_UP; + + if (message.type == ES_MSG_MOUSE_LEFT_DOWN) { + pressedWindow = window; + } else if (message.type == ES_MSG_MOUSE_LEFT_UP) { + if (pressedWindow) { + // Always send the messages to the pressed window, if there is one. + window = pressedWindow; + } + + pressedWindow = nullptr; + moveCursorNone = true; // We might have moved outside the window. + } + + if (window) { + message.mouseDown.positionX = cursorX - window->position.x; + message.mouseDown.positionY = cursorY - window->position.y; + window->activationClick = activationClick || activationClickFromMenu; + SendMessageToWindow(window, &message); + } + } + } + + if (moveCursorNone) { + MoveCursor(0, 0); + } else { + GraphicsUpdateScreen(); + } + + KMutexRelease(&mutex); +} + +void WindowManager::MoveCursor(int xMovement, int yMovement) { + KMutexAssertLocked(&mutex); + + xMovement *= alt ? 2 : 10; + yMovement *= alt ? 2 : 10; + + int oldCursorX = cursorXPrecise; + int oldCursorY = cursorYPrecise; + int _cursorX = oldCursorX + xMovement; + int _cursorY = oldCursorY + yMovement; + + // if (!lastButtons) { + if (_cursorX < 0) { + _cursorX = 0; + } + + if (_cursorY < 0) { + _cursorY = 0; + } + + if (_cursorX >= (int) graphics.width * 10) { + _cursorX = graphics.width * 10 - 1; + } + + if (_cursorY >= (int) graphics.height * 10) { + _cursorY = graphics.height * 10 - 1; + } + // } + + cursorXPrecise = _cursorX; + cursorYPrecise = _cursorY; + cursorX = _cursorX / 10; + cursorY = _cursorY / 10; + oldCursorX /= 10; + oldCursorY /= 10; + + if (eyedropping) { + EsMessage m = { ES_MSG_EYEDROP_REPORT }; + uint32_t color = *(uint32_t *) ((uint8_t *) graphics.frameBuffer.bits + 4 * cursorX + graphics.frameBuffer.stride * cursorY); + m.eyedrop.color = color; + m.eyedrop.cancelled = false; + eyedropProcess->messageQueue.SendMessage((void *) eyedropObject, &m); + } else { + Window *window = pressedWindow; + + if (!window) { + // Work out which window the mouse is now over. + window = FindWindowAtPosition(cursorX, cursorY); + + if (hoverWindow != window && hoverWindow) { + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_MOUSE_EXIT; + SendMessageToWindow(hoverWindow, &message); + } + + hoverWindow = window; + } + + if (window) { + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_MOUSE_MOVED; + message.mouseMoved.newPositionX = cursorX - window->position.x; + message.mouseMoved.newPositionY = cursorY - window->position.y; + SendMessageToWindow(window, &message); + } + } + + GraphicsUpdateScreen(); +} + +void _CloseWindows(uintptr_t) { + while (true) { + KEventWait(&windowManager.windowsToCloseEvent); + KMutexAcquire(&windowManager.mutex); + + for (uintptr_t i = 0; i < windowManager.windows.Length(); i++) { + Window *window = windowManager.windows[i]; + + if (window->handles > 1) { + continue; + } + + // Remove the window from the array. + windowManager.windows.Delete(i); + + if (!window->closed) { + // Only the window manager's handle to the window remains, + // but the window has not been closed. + // This probably means the process crashed before it could close its windows; + // we should close the window ourselves. + window->Close(); + } + + // Close the window manager's handle to the window. + CloseHandleToObject(window, KERNEL_OBJECT_WINDOW); + + i--; + } + + for (uintptr_t i = 0; i < windowManager.embeddedWindows.Length(); i++) { + // Apply a similar set of operations to embedded windows. + EmbeddedWindow *window = windowManager.embeddedWindows[i]; + if (window->handles > 1) continue; + if (!window->closed) window->Close(); + windowManager.embeddedWindows.Delete(i); + CloseHandleToObject(window, KERNEL_OBJECT_EMBEDDED_WINDOW); + i--; + } + + KMutexRelease(&windowManager.mutex); + } +} + +void WindowManager::Initialise() { + windowManager.windowsToCloseEvent.autoReset = true; + KThreadCreate("CloseWindows", _CloseWindows); + KMutexAcquire(&mutex); + MoveCursor(graphics.width / 2, graphics.height / 2); + GraphicsUpdateScreen(); + initialised = true; + KMutexRelease(&mutex); +} + +void *WindowManager::CreateEmbeddedWindow(Process *process, void *apiWindow) { + EmbeddedWindow *window = (EmbeddedWindow *) EsHeapAllocate(sizeof(EmbeddedWindow), true, K_PAGED); + if (!window) return nullptr; + + if (!embeddedWindows.Add(window)) { + EsHeapFree(window, sizeof(EmbeddedWindow), K_PAGED); + return nullptr; + } + + window->apiWindow = apiWindow; + window->owner = process; + window->handles = 2; // One handle for the window manager, and one handle for the calling process. + + KMutexAcquire(&mutex); + window->id = ++currentWindowID; + KMutexRelease(&mutex); + + OpenHandleToObject(window->owner, KERNEL_OBJECT_PROCESS); + + return window; +} + +void *WindowManager::CreateWindow(Process *process, void *apiWindow, EsWindowStyle style) { + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + // Allocate and initialise the window object. + + Window *window = (Window *) EsHeapAllocate(sizeof(Window), true, K_PAGED); + if (!window) return nullptr; + + window->style = style; + window->apiWindow = apiWindow; + window->alpha = 0xFF; + window->position = ES_POINT(-8, -8); + window->owner = process; + window->handles = 2; // One handle for the window manager, and one handle for the calling process. + window->hidden = true; + window->id = ++currentWindowID; + + if (style == ES_WINDOW_INSPECTOR) windowManager.inspectorWindowCount++; + + // Insert the window into the window array. + + uintptr_t insertionPoint = GetActivationZIndex(); + + if (!windows.Insert(window, insertionPoint)) { + EsHeapFree(window->surface.bits, 0, K_PAGED); + EsHeapFree(window, sizeof(Window), K_PAGED); + return nullptr; + } + + // Get a handle to the owner process. + + OpenHandleToObject(window->owner, KERNEL_OBJECT_PROCESS); + + MoveCursor(0, 0); + return window; +} + +bool Window::Move(EsRectangle rectangle, uint32_t flags) { + KMutexAssertLocked(&windowManager.mutex); + + if (closed) { + return false; + } + + if ((flags & ES_WINDOW_MOVE_DYNAMIC) + && windowManager.resizeWindow == this + && windowManager.resizeStartTimeStampMs + RESIZE_FLICKER_TIMEOUT_MS > KGetTimeInMs()) { + windowManager.resizeQueued = true; + windowManager.resizeQueuedRectangle = rectangle; + return false; + } + + bool result = true; + + isMaximised = flags & ES_WINDOW_MOVE_MAXIMISED; + alwaysOnTop = flags & ES_WINDOW_MOVE_ALWAYS_ON_TOP; + + // TS("Move window\n"); + + if (flags & ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN) { + if (rectangle.r > (int32_t) graphics.frameBuffer.width) { + rectangle.l -= rectangle.r - graphics.frameBuffer.width; + rectangle.r -= rectangle.r - graphics.frameBuffer.width; + } + + if (rectangle.b > (int32_t) graphics.frameBuffer.height) { + rectangle.t -= rectangle.b - graphics.frameBuffer.height; + rectangle.b -= rectangle.b - graphics.frameBuffer.height; + } + + if (rectangle.l < 0) { + rectangle.r -= rectangle.l - 0; + rectangle.l = 0; + } + + if (rectangle.t < 0) { + rectangle.b -= rectangle.t - 0; + rectangle.t = 0; + } + } + + size_t newWidth = rectangle.r - rectangle.l; + size_t newHeight = rectangle.b - rectangle.t; + + if (newWidth < 4 || newHeight < 4 + || rectangle.l > rectangle.r + || rectangle.t > rectangle.b + || newWidth > graphics.width * 2 + || newHeight > graphics.height * 2) { + return false; + } + + if (!hidden) { + // TS("Clear previous image\n"); + windowManager.Redraw(ES_POINT(position.x, position.y), width, height, this); + } + + hidden = false; + position = ES_POINT(rectangle.l, rectangle.t); + bool changedSize = width != newWidth || height != newHeight; + width = newWidth, height = newHeight; + + if (changedSize) { + if (style == ES_WINDOW_CONTAINER && embed) { + surface.Resize(width, height, 0, windowManager.resizeSlow); + } else { + surface.Resize(width, height); + } + + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_WINDOW_RESIZED; + message.windowResized.content = ES_RECT_4(0, width, 0, height); + SendMessageToWindow(this, &message); + + if (flags & ES_WINDOW_MOVE_DYNAMIC) { + // Don't redraw the screen until both the container and embedded window have painted + // (or the timeout completes). + windowManager.resizeWindow = this; + windowManager.resizeReceivedBitsFromContainer = false; + windowManager.resizeReceivedBitsFromEmbed = embed == nullptr; + windowManager.resizeStartTimeStampMs = KGetTimeInMs(); + } + } + + if (flags & ES_WINDOW_MOVE_AT_BOTTOM) { + windowManager.ChangeWindowDepth(this, false, 0); + } + + if ((flags & ES_WINDOW_MOVE_DYNAMIC) && changedSize && style == ES_WINDOW_CONTAINER && !windowManager.resizeSlow) { + windowManager.Redraw(ES_POINT(position.x, position.y), WINDOW_INSET, height, nullptr); + windowManager.Redraw(ES_POINT(position.x + width - WINDOW_INSET, position.y), WINDOW_INSET, height, nullptr); + windowManager.Redraw(ES_POINT(position.x + WINDOW_INSET, position.y), width - WINDOW_INSET * 2, WINDOW_INSET, nullptr); + windowManager.Redraw(ES_POINT(position.x + WINDOW_INSET, position.y + height - WINDOW_INSET), width - WINDOW_INSET * 2, WINDOW_INSET, nullptr); + } else { + windowManager.Redraw(position, width, height, nullptr); + } + + return result; +} + +void EmbeddedWindow::Destroy() { + KernelLog(LOG_VERBOSE, "Window Manager", "destroy embedded window", "EmbeddedWindow::Destroy - Destroying embedded window.\n"); + EsHeapFree(this, sizeof(EmbeddedWindow), K_PAGED); +} + +void EmbeddedWindow::Close() { + KMutexAssertLocked(&windowManager.mutex); + + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_WINDOW_DESTROYED; + owner->messageQueue.SendMessage(apiWindow, &message); + SetEmbedOwner(nullptr); + + if (!scheduler.shutdown) { + message.type = ES_MSG_EMBEDDED_WINDOW_DESTROYED; + message.desktop.windowID = id; + desktopProcess->messageQueue.SendMessage(nullptr, &message); + } + + if (container && container->embed == this) { + container->SetEmbed(nullptr); + } + + closed = true; +} + +void Window::Destroy() { + if (!closed) { + KernelPanic("Window::Destroy - Window %x has not been closed.\n", this); + } + + EsHeapFree(this, sizeof(Window), K_PAGED); +} + +void Window::Close() { + KMutexAssertLocked(&windowManager.mutex); + + SetEmbed(nullptr); + + // Send the destroy message - the last message sent to the window. + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_WINDOW_DESTROYED; + owner->messageQueue.SendMessage(apiWindow, &message); + + Process *_owner = owner; + owner = nullptr; + CloseHandleToObject(_owner, KERNEL_OBJECT_PROCESS); + + hidden = true; + solid = false; + + bool findActiveWindow = false; + + if (windowManager.pressedWindow == this) windowManager.pressedWindow = nullptr; + if (windowManager.hoverWindow == this) windowManager.hoverWindow = nullptr; + if (windowManager.resizeWindow == this) windowManager.resizeWindow = nullptr; + if (windowManager.activeWindow == this) windowManager.activeWindow = nullptr, findActiveWindow = true; + + if (style == ES_WINDOW_INSPECTOR) windowManager.inspectorWindowCount--; + + windowManager.Redraw(ES_POINT(position.x, position.y), width, height); + + if (findActiveWindow) { + windowManager.ActivateWindow(windowManager.FindWindowToActivate()); + } + + windowManager.MoveCursor(0, 0); + GraphicsUpdateScreen(); + + __sync_fetch_and_sub(&graphics.totalSurfaceBytes, surface.width * surface.height * 4); + EsHeapFree(surface.bits, 0, K_PAGED); + surface.bits = nullptr; + + __sync_synchronize(); + closed = true; +} + +void WindowManager::Redraw(EsPoint position, int width, int height, Window *except, int startingAt, bool addToModifiedRegion) { + // TS("Window manager redraw at [%d, %d] with size [%d, %d]\n", position.x, position.y, width, height); + + KMutexAssertLocked(&mutex); + + if (!width || !height) return; + if (scheduler.shutdown) return; + + for (int index = startingAt; index < (int) windows.Length(); index++) { + Window *window = windows[index]; + + if (!window->IsVisible() || window == except) { + continue; + } + + if (position.x >= window->position.x + window->opaqueBounds.l + && position.x + width <= window->position.x + window->opaqueBounds.r + && position.y >= window->position.y + window->opaqueBounds.t + && position.y + height <= window->position.y + window->opaqueBounds.b) { + startingAt = index; + } + } + + for (int index = startingAt; index < (int) windows.Length(); index++) { + Window *window = windows[index]; + + if (!window->IsVisible() || window == except) continue; + + EsRectangle rectangle = ES_RECT_4PD(window->position.x, window->position.y, window->width, window->height); + rectangle = EsRectangleIntersection(rectangle, ES_RECT_2S(graphics.frameBuffer.width, graphics.frameBuffer.height)); + rectangle = EsRectangleIntersection(rectangle, ES_RECT_4PD(position.x, position.y, width, height)); + if (window->isMaximised) rectangle = EsRectangleIntersection(rectangle, workArea); + rectangle = Translate(rectangle, -window->position.x, -window->position.y); + + if (!ES_RECT_VALID(rectangle)) continue; + + EsPoint point = ES_POINT(window->position.x + rectangle.l, window->position.y + rectangle.t); + Surface *surface = &window->surface; + + if (window->opaqueBounds.l <= rectangle.l && window->opaqueBounds.r >= rectangle.r + && window->opaqueBounds.t <= rectangle.t && window->opaqueBounds.b >= rectangle.b) { + graphics.frameBuffer.Copy(surface, point, rectangle, addToModifiedRegion); + } else { + EsRectangle blurRegion = Translate(EsRectangleIntersection(window->blurBounds, rectangle), window->position.x, window->position.y); + graphics.frameBuffer.BlendWindow(surface, point, rectangle, window->material, window->alpha, blurRegion); + } + } +} + +bool Window::UpdateDirect(K_USER_BUFFER void *bits, uintptr_t stride, EsRectangle region) { + KMutexAssertLocked(&windowManager.mutex); + + intptr_t z = windowManager.FindWindowDepth(this); + + if (z == -1) { + return false; + } + + if (hidden) { + return false; + } + + if (windowManager.changedCursorImage) { + // The entire cursor needs to be redrawn about its image changes, + // which might not happen with a direct update. + return false; + } + + if (region.l + position.x < 0) { + bits = (K_USER_BUFFER uint8_t *) bits + 4 * (-position.x - region.l); + region.l = -position.x; + } + + if (region.t + position.y < 0) { + bits = (K_USER_BUFFER uint8_t *) bits + stride * (-position.y - region.t); + region.t = -position.y; + } + + if ((uint32_t) (region.r + position.x) > graphics.width) { + region.r = graphics.width - position.x; + } + + if ((uint32_t) (region.b + position.y) > graphics.height) { + region.b = graphics.height - position.y; + } + + // If the update region is completely obscured, then we don't need to update. + + for (uintptr_t i = z + 1; i < windowManager.windows.Length(); i++) { + Window *other = windowManager.windows[i]; + EsRectangle otherBounds = Translate(other->opaqueBounds, other->position.x, other->position.y); + + if (region.l + position.x > otherBounds.l && region.r + position.x < otherBounds.r + && region.t + position.y > otherBounds.t && region.b + position.y < otherBounds.b + && other->alpha == 0xFF && other->IsVisible()) { + return true; + } + } + + // If the update region isn't opaque, we cannot do a direct update. + + if (region.l < opaqueBounds.l || region.r > opaqueBounds.r || region.t < opaqueBounds.t || region.b > opaqueBounds.b + || alpha != 0xFF) { + return false; + } + + // If any window overlaps the update region, we cannot do a direct update. + + EsRectangle thisBounds = ES_RECT_4(position.x, position.x + width, position.y, position.y + height); + + for (uintptr_t i = z + 1; i < windowManager.windows.Length(); i++) { + Window *other = windowManager.windows[i]; + EsRectangle otherBounds = ES_RECT_4(other->position.x, other->position.x + other->width, + other->position.y, other->position.y + other->height); + + if (EsRectangleClip(thisBounds, otherBounds, nullptr)) { + return false; + } + } + + region = Translate(region, position.x, position.y); + + // Write the updated bits directly to the frame buffer! + GraphicsUpdateScreen(bits, ®ion, stride); + return true; +} + +void Window::Update(EsRectangle *_region, bool addToModifiedRegion) { + KMutexAssertLocked(&windowManager.mutex); + + intptr_t z = windowManager.FindWindowDepth(this); + + if (z == -1) { + return; + } + + // TS("Update window %x within %R\n", this, _region ? *_region : ES_RECT_1(0)); + + EsRectangle region = _region ? *_region : ES_RECT_4(0, width, 0, height); + + // Is this updated region completely obscured? + for (uintptr_t i = z + 1; i < windowManager.windows.Length(); i++) { + Window *other = windowManager.windows[i]; + EsRectangle otherBounds = Translate(other->opaqueBounds, other->position.x, other->position.y); + + if (region.l + position.x > otherBounds.l && region.r + position.x < otherBounds.r + && region.t + position.y > otherBounds.t && region.b + position.y < otherBounds.b + && other->alpha == 0xFF && other->IsVisible()) { + return; + } + } + + EsRectangle r; + // EsPrint("Update window width region %d/%d/%d/%d\n", region.left, region.right, region.top, region.bottom); + + if (alpha == 0xFF) { + EsRectangle translucentBorder = opaqueBounds; + + // Draw the opaque region, then everything above it. + EsRectangleClip(region, ES_RECT_4(translucentBorder.l, translucentBorder.r, translucentBorder.t, translucentBorder.b), &r); + windowManager.Redraw(ES_POINT(position.x + r.l, position.y + r.t), r.r - r.l, r.b - r.t, nullptr, z, addToModifiedRegion); + + // Draw the transparent regions after everything below them, then everything above them. + EsRectangleClip(region, ES_RECT_4(0, translucentBorder.l, 0, height), &r); + windowManager.Redraw(ES_POINT(position.x + r.l, position.y + r.t), r.r - r.l, r.b - r.t, nullptr, 0, addToModifiedRegion); + EsRectangleClip(region, ES_RECT_4(translucentBorder.r, width, 0, height), &r); + windowManager.Redraw(ES_POINT(position.x + r.l, position.y + r.t), r.r - r.l, r.b - r.t, nullptr, 0, addToModifiedRegion); + EsRectangleClip(region, ES_RECT_4(translucentBorder.l, translucentBorder.r, 0, translucentBorder.t), &r); + windowManager.Redraw(ES_POINT(position.x + r.l, position.y + r.t), r.r - r.l, r.b - r.t, nullptr, 0, addToModifiedRegion); + EsRectangleClip(region, ES_RECT_4(translucentBorder.l, translucentBorder.r, translucentBorder.b, height), &r); + windowManager.Redraw(ES_POINT(position.x + r.l, position.y + r.t), r.r - r.l, r.b - r.t, nullptr, 0, addToModifiedRegion); + } else { + // The whole window is translucent; draw it. + EsRectangleClip(region, ES_RECT_4(0, width, 0, height), &r); + windowManager.Redraw(ES_POINT(position.x + r.l, position.y + r.t), r.r - r.l, r.b - r.t, nullptr, 0, addToModifiedRegion); + } +} + +void EmbeddedWindow::SetEmbedOwner(Process *process) { + KMutexAssertLocked(&windowManager.mutex); + + apiWindow = nullptr; + + if (process) { + OpenHandleToObject(process, KERNEL_OBJECT_PROCESS); + } + + if (owner) { + CloseHandleToObject(owner, KERNEL_OBJECT_PROCESS); + } + + owner = process; +} + +void Window::SetEmbed(EmbeddedWindow *newEmbed) { + KMutexAssertLocked(&windowManager.mutex); + + if (newEmbed && (newEmbed->container || newEmbed->closed)) { + return; + } + + if (newEmbed == embed) { + return; + } + + if (newEmbed) { + newEmbed->container = this; + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_WINDOW_RESIZED; + int embedWidth = width - WINDOW_INSET * 2; + int embedHeight = height - WINDOW_INSET * 2 - CONTAINER_TAB_BAND_HEIGHT; + message.windowResized.content = ES_RECT_4(0, embedWidth, 0, embedHeight); + newEmbed->owner->messageQueue.SendMessage(newEmbed->apiWindow, &message); + } + + if (embed) { + if (embed->closed) { + KernelPanic("Window::SetEmbed - Previous embed %x was closed.\n"); + } + + embed->container = nullptr; + + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_WINDOW_RESIZED; + message.windowResized.content = ES_RECT_4(0, 0, 0, 0); + message.windowResized.hidden = true; + + if (embed->owner) { + embed->owner->messageQueue.SendMessage(embed->apiWindow, &message); + } + } + + embed = newEmbed; +} + +void WindowManager::StartEyedrop(uintptr_t object, Window *avoid, uint32_t cancelColor) { + KMutexAcquire(&mutex); + + if (!eyedropping) { + eyedropObject = object; + eyedropping = true; + eyedropAvoidID = avoid->id; + eyedropCancelColor = cancelColor; + Redraw(avoid->position, avoid->width, avoid->height); + + if (hoverWindow) { + EsMessage message; + EsMemoryZero(&message, sizeof(EsMessage)); + message.type = ES_MSG_MOUSE_EXIT; + SendMessageToWindow(hoverWindow, &message); + } + + hoverWindow = pressedWindow = nullptr; + + eyedropProcess = GetCurrentThread()->process; + OpenHandleToObject(eyedropProcess, KERNEL_OBJECT_PROCESS); + } + + GraphicsUpdateScreen(); + KMutexRelease(&mutex); +} + +void KCursorUpdate(int xMovement, int yMovement, unsigned buttons) { + windowManager.UpdateCursor(xMovement, yMovement, buttons); +} + +void KKeyPress(unsigned scancode) { + windowManager.PressKey(scancode); +} + +void KKeyboardUpdate(uint16_t *keysDown, size_t keysDownCount) { + // TODO Key repeat. + + static uint16_t previousKeysDown[32] = {}; + static size_t previousKeysDownCount = 0; + static KMutex mutex = {}; + + KMutexAcquire(&mutex); + EsDefer(KMutexRelease(&mutex)); + + if (keysDownCount > 32) { + keysDownCount = 32; + } + + for (uintptr_t i = 0; i < keysDownCount; i++) { + bool found = false; + + for (uintptr_t j = 0; j < previousKeysDownCount; j++) { + if (keysDown[i] == previousKeysDown[j]) { + found = true; + break; + } + } + + if (!found && keysDown[i]) { + if (keysDown[i] == ES_SCANCODE_PAUSE) { + KDebugKeyPressed(); // TODO Doesn't work if scheduler not functioning correctly. + } + + KKeyPress(keysDown[i] | K_SCANCODE_KEY_PRESSED); + } + } + + for (uintptr_t i = 0; i < previousKeysDownCount; i++) { + bool found = false; + + for (uintptr_t j = 0; j < keysDownCount; j++) { + if (keysDown[j] == previousKeysDown[i]) { + found = true; + break; + } + } + + if (!found) { + KKeyPress(previousKeysDown[i] | K_SCANCODE_KEY_RELEASED); + } + } + + previousKeysDownCount = keysDownCount; + EsMemoryCopy(previousKeysDown, keysDown, sizeof(uint16_t) * keysDownCount); +} + +uint64_t KGameControllerConnect() { + KMutexAcquire(&windowManager.gameControllersMutex); + + uint64_t id = ++windowManager.gameControllerID; + + if (windowManager.gameControllerCount != ES_GAME_CONTROLLER_MAX_COUNT) { + windowManager.gameControllers[windowManager.gameControllerCount++].id = id; + } else { + id = 0; + } + + KMutexRelease(&windowManager.gameControllersMutex); + + return id; +} + +void KGameControllerDisconnect(uint64_t id) { + KMutexAcquire(&windowManager.gameControllersMutex); + + for (uintptr_t i = 0; i < windowManager.gameControllerCount; i++) { + if (windowManager.gameControllers[i].id == id) { + EsMemoryMove(windowManager.gameControllers + i + 1, + windowManager.gameControllers + windowManager.gameControllerCount, + -sizeof(EsGameControllerState), false); + windowManager.gameControllerCount--; + break; + } + } + + KMutexRelease(&windowManager.gameControllersMutex); +} + +void KGameControllerUpdateState(EsGameControllerState *state) { + KMutexAcquire(&windowManager.gameControllersMutex); + + for (uintptr_t i = 0; i < windowManager.gameControllerCount; i++) { + if (windowManager.gameControllers[i].id == state->id) { + windowManager.gameControllers[i] = *state; +#if 0 + EsPrint("game controller %d: buttons %x analog %d %d %d %d %d %d dpad %d\n", + state->id, state->buttons, state->analog[0].x, state->analog[0].y, state->analog[0].z, + state->analog[1].x, state->analog[1].y, state->analog[1].z, state->directionalPad); +#endif + break; + } + } + + KMutexRelease(&windowManager.gameControllersMutex); +} + +EsError Clipboard::Add(uint64_t format, const void *data, size_t dataBytes) { + if (dataBytes > CLIPBOARD_ITEM_SIZE_LIMIT) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + ClipboardItem item = {}; + item.buffer = MakeConstantBuffer(data, dataBytes); + item.format = format; + + if (!item.buffer) { + return ES_ERROR_INSUFFICIENT_RESOURCES; + } + + KMutexAcquire(&mutex); + + if (items[CLIPBOARD_ITEM_COUNT - 1].buffer) { + CloseHandleToObject(items[CLIPBOARD_ITEM_COUNT - 1].buffer, KERNEL_OBJECT_CONSTANT_BUFFER); + } + + EsMemoryMove(items, items + CLIPBOARD_ITEM_COUNT - 1, sizeof(ClipboardItem), false); + items[0] = item; + + KMutexRelease(&mutex); + + if (this == &primaryClipboard) { + KMutexAcquire(&windowManager.mutex); + + if (windowManager.activeWindow) { + EsMessage m; + EsMemoryZero(&m, sizeof(EsMessage)); + m.type = ES_MSG_PRIMARY_CLIPBOARD_UPDATED; + SendMessageToWindow(windowManager.activeWindow, &m); + } + + KMutexRelease(&windowManager.mutex); + } + + return ES_SUCCESS; +} + +bool Clipboard::Has(uint64_t format) { + KMutexAcquire(&mutex); + bool result = items[0].format == format; + KMutexRelease(&mutex); + return result; +} + +EsHandle Clipboard::Read(uint64_t format, K_USER_BUFFER size_t *_bytes, Process *process) { + ConstantBuffer *buffer = nullptr; + KMutexAcquire(&mutex); + + if (items[0].format == format) { + buffer = items[0].buffer; + OpenHandleToObject(buffer, KERNEL_OBJECT_CONSTANT_BUFFER); + } + + KMutexRelease(&mutex); + + if (buffer) { + *_bytes = buffer->bytes; + return process->handleTable.OpenHandle(buffer, 0, KERNEL_OBJECT_CONSTANT_BUFFER); + } else { + return ES_INVALID_HANDLE; + } +} + +#endif diff --git a/kernel/x86_64.cpp b/kernel/x86_64.cpp new file mode 100644 index 0000000..20863f3 --- /dev/null +++ b/kernel/x86_64.cpp @@ -0,0 +1,1166 @@ +#ifndef IMPLEMENTATION + +typedef struct ACPIProcessor ArchCPU; + +// Interrupt vectors: +// 0x00 - 0x1F: CPU exceptions +// 0x20 - 0x2F: PIC (disabled, spurious) +// 0x30 - 0x4F: Timers and low-priority IPIs. +// 0x50 - 0x6F: APIC (standard) +// 0x70 - 0xAF: MSI +// 0xF0 - 0xFE: High-priority IPIs +// 0xFF: APIC (spurious interrupt) + +#define TIMER_INTERRUPT (0x40) +#define YIELD_IPI (0x41) +// Note: IRQ_BASE is currently 0x50. +#define CALL_FUNCTION_ON_ALL_PROCESSORS_IPI (0xF0) +#define KERNEL_PANIC_IPI (0) // NMIs ignore the interrupt vector. + +#define INTERRUPT_VECTOR_MSI_START (0x70) +#define INTERRUPT_VECTOR_MSI_COUNT (0x40) + +struct InterruptContext { + uint64_t cr2, ds; + uint8_t fxsave[512 + 16]; + uint64_t _check, cr8; + uint64_t r15, r14, r13, r12, r11, r10, r9, r8; + uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax; + uint64_t interruptNumber, errorCode; + uint64_t rip, cs, flags, rsp, ss; +}; + +struct VirtualAddressSpaceData { + uintptr_t cr3; + + // Each process has a 47-bit address space. + // That's 2^35 pages. + // That's 2^26 L1 page tables. 2^23 bytes of bitset. + // That's 2^17 L2 page tables. 2^14 bytes of bitset. + // That's 2^ 8 L3 page tables. 2^ 5 bytes of bitset. + // Tracking of the committed L1 tables is done in l1Commit, a region of coreMMSpace. + // (This array is committed as needed, tracked using l1CommitCommit.) + // Tracking of the committed L2 tables is done in l2Commit. + // Tracking of the committed L3 tables is done in l3Commit. +#define L1_COMMIT_SIZE_BYTES (1 << 23) +#define L1_COMMIT_COMMIT_SIZE_BYTES (1 << 8) +#define L2_COMMIT_SIZE_BYTES (1 << 14) +#define L3_COMMIT_SIZE_BYTES (1 << 5) + uint8_t *l1Commit; + uint8_t l1CommitCommit[L1_COMMIT_COMMIT_SIZE_BYTES]; + uint8_t l2Commit[L2_COMMIT_SIZE_BYTES]; + uint8_t l3Commit[L3_COMMIT_SIZE_BYTES]; + size_t pageTablesCommitted; + + // TODO Consider core/kernel mutex consistency? I think it's fine, but... + KMutex mutex; // Acquire to modify the page tables. +}; + +#define VIRTUAL_ADDRESS_SPACE_DATA() VirtualAddressSpaceData data +#define VIRTUAL_ADDRESS_SPACE_IDENTIFIER(x) ((x)->data.cr3) + +#define MM_CORE_SPACE_START (0xFFFF800100000000) +#define MM_CORE_SPACE_SIZE (0xFFFF8001F0000000 - 0xFFFF800100000000) +#define MM_CORE_REGIONS_START (0xFFFF8001F0000000) +#define MM_CORE_REGIONS_COUNT ((0xFFFF800200000000 - 0xFFFF8001F0000000) / sizeof(MMRegion)) +#define MM_KERNEL_SPACE_START (0xFFFF900000000000) +#define MM_KERNEL_SPACE_SIZE (0xFFFFF00000000000 - 0xFFFF900000000000) +#define MM_MODULES_START (0xFFFFFFFF90000000) +#define MM_MODULES_SIZE (0xFFFFFFFFC0000000 - 0xFFFFFFFF90000000) +#define MM_USER_SPACE_START (0x100000000000) +#define MM_USER_SPACE_SIZE (0xF00000000000 - 0x100000000000) + +#define ArchIsAddressInKernelSpace(x) ((uintptr_t) (x) >= 0xFFFF800000000000) + +uint8_t coreL1Commit[(0xFFFF800200000000 - 0xFFFF800100000000) >> (/* ENTRIES_PER_PAGE_TABLE_BITS */ 9 + K_PAGE_BITS + 3)]; + +#endif + +#ifdef IMPLEMENTATION + +extern uintptr_t bootloaderInformationOffset; +extern "C" bool simdSSE3Support; +extern "C" bool simdSSSE3Support; + +volatile uintptr_t tlbShootdownVirtualAddress; +volatile size_t tlbShootdownPageCount; + +extern "C" uintptr_t _KThreadTerminate; + +typedef void (*CallFunctionOnAllProcessorsCallbackFunction)(); +volatile CallFunctionOnAllProcessorsCallbackFunction callFunctionOnAllProcessorsCallback; +volatile uintptr_t callFunctionOnAllProcessorsRemaining; + +// Recursive page table mapping in slot 0x1FE, so that the top 2GB are available for mcmodel kernel. +#define PAGE_TABLE_L4 ((volatile uint64_t *) 0xFFFFFF7FBFDFE000) +#define PAGE_TABLE_L3 ((volatile uint64_t *) 0xFFFFFF7FBFC00000) +#define PAGE_TABLE_L2 ((volatile uint64_t *) 0xFFFFFF7F80000000) +#define PAGE_TABLE_L1 ((volatile uint64_t *) 0xFFFFFF0000000000) +#define ENTRIES_PER_PAGE_TABLE (512) +#define ENTRIES_PER_PAGE_TABLE_BITS (9) + +bool MMArchCommitPageTables(MMSpace *space, MMRegion *region) { + KMutexAssertLocked(&space->reserveMutex); + + VirtualAddressSpaceData *data = &space->data; + + uintptr_t base = (region->baseAddress - (space == coreMMSpace ? MM_CORE_SPACE_START : 0)) & 0x7FFFFFFFF000; + uintptr_t end = base + (region->pageCount << K_PAGE_BITS); + uintptr_t needed = 0; + + for (uintptr_t i = base; i < end; i += 1L << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3)) { + uintptr_t indexL4 = i >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3); + if (!(data->l3Commit[indexL4 >> 3] & (1 << (indexL4 & 7)))) needed++; + i = indexL4 << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3); + } + + for (uintptr_t i = base; i < end; i += 1L << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2)) { + uintptr_t indexL3 = i >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2); + if (!(data->l2Commit[indexL3 >> 3] & (1 << (indexL3 & 7)))) needed++; + i = indexL3 << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2); + } + + uintptr_t previousIndexL2I = -1; + + for (uintptr_t i = base; i < end; i += 1L << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1)) { + uintptr_t indexL2 = i >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1); + uintptr_t indexL2I = indexL2 >> 15; + if (!(data->l1CommitCommit[indexL2I >> 3] & (1 << (indexL2I & 7)))) needed += previousIndexL2I != indexL2I ? 2 : 1; + else if (!(data->l1Commit[indexL2 >> 3] & (1 << (indexL2 & 7)))) needed++; + previousIndexL2I = indexL2I; + i = indexL2 << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1); + } + + if (needed) { + if (!MMCommit(needed * K_PAGE_SIZE, true)) { + return false; + } + + data->pageTablesCommitted += needed; + } + + for (uintptr_t i = base; i < end; i += 1L << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3)) { + uintptr_t indexL4 = i >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3); + data->l3Commit[indexL4 >> 3] |= (1 << (indexL4 & 7)); + i = indexL4 << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3); + } + + for (uintptr_t i = base; i < end; i += 1L << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2)) { + uintptr_t indexL3 = i >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2); + data->l2Commit[indexL3 >> 3] |= (1 << (indexL3 & 7)); + i = indexL3 << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2); + } + + for (uintptr_t i = base; i < end; i += 1L << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1)) { + uintptr_t indexL2 = i >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1); + uintptr_t indexL2I = indexL2 >> 15; + data->l1CommitCommit[indexL2I >> 3] |= (1 << (indexL2I & 7)); + data->l1Commit[indexL2 >> 3] |= (1 << (indexL2 & 7)); + i = indexL2 << (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1); + } + + return true; +} + +bool MMArchMakePageWritable(MMSpace *space, uintptr_t virtualAddress) { + KMutexAcquire(&space->data.mutex); + EsDefer(KMutexRelease(&space->data.mutex)); + + virtualAddress &= 0x0000FFFFFFFFF000; + + uintptr_t indexL4 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3); + uintptr_t indexL3 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2); + uintptr_t indexL2 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1); + uintptr_t indexL1 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 0); + + if ((PAGE_TABLE_L4[indexL4] & 1) == 0) return false; + if ((PAGE_TABLE_L3[indexL3] & 1) == 0) return false; + if ((PAGE_TABLE_L2[indexL2] & 1) == 0) return false; + if ((PAGE_TABLE_L1[indexL1] & 1) == 0) return false; + + PAGE_TABLE_L1[indexL1] |= 2; + return true; +} + +void MMArchMapPage(MMSpace *space, uintptr_t physicalAddress, uintptr_t virtualAddress, unsigned flags) { + // TODO Use the no-execute bit. + + if (physicalAddress & (K_PAGE_SIZE - 1)) { + KernelPanic("MMArchMapPage - Physical address not page aligned.\n"); + } + + bool acquireFrameLock = !(flags & (MM_MAP_PAGE_NO_NEW_TABLES | MM_MAP_PAGE_FRAME_LOCK_ACQUIRED)); + if (acquireFrameLock) KMutexAcquire(&pmm.pageFrameMutex); + EsDefer(if (acquireFrameLock) KMutexRelease(&pmm.pageFrameMutex);); + + bool acquireSpaceLock = ~flags & MM_MAP_PAGE_NO_NEW_TABLES; + if (acquireSpaceLock) KMutexAcquire(&space->data.mutex); + EsDefer(if (acquireSpaceLock) KMutexRelease(&space->data.mutex)); + + uintptr_t cr3 = space->data.cr3; + + if (!ArchIsAddressInKernelSpace(virtualAddress) + && ProcessorReadCR3() != cr3) { + KernelPanic("MMArchMapPage - Attempt to map page into other address space.\n"); + } else if (!physicalAddress) { + KernelPanic("MMArchMapPage - Attempt to map physical page 0.\n"); + } else if (!virtualAddress) { + KernelPanic("MMArchMapPage - Attempt to map virtual page 0.\n"); + } + + // EsPrint("\tMap, %x -> %x\n", virtualAddress, physicalAddress); + + uintptr_t oldVirtualAddress = virtualAddress; + physicalAddress &= 0xFFFFFFFFFFFFF000; + virtualAddress &= 0x0000FFFFFFFFF000; + + uintptr_t indexL4 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3); + uintptr_t indexL3 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2); + uintptr_t indexL2 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1); + uintptr_t indexL1 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 0); + + if (space != coreMMSpace && space != kernelMMSpace /* Don't check the kernel's space since the bootloader's tables won't be committed. */) { + if (!(space->data.l3Commit[indexL4 >> 3] & (1 << (indexL4 & 7)))) KernelPanic("MMArchMapPage - Attempt to map using uncommitted L3 page table.\n"); + if (!(space->data.l2Commit[indexL3 >> 3] & (1 << (indexL3 & 7)))) KernelPanic("MMArchMapPage - Attempt to map using uncommitted L2 page table.\n"); + if (!(space->data.l1Commit[indexL2 >> 3] & (1 << (indexL2 & 7)))) KernelPanic("MMArchMapPage - Attempt to map using uncommitted L1 page table.\n"); + } + + if ((PAGE_TABLE_L4[indexL4] & 1) == 0) { + if (flags & MM_MAP_PAGE_NO_NEW_TABLES) KernelPanic("MMArchMapPage - NO_NEW_TABLES flag set, but a table was missing.\n"); + PAGE_TABLE_L4[indexL4] = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_LOCK_ACQUIRED) | 7; + ProcessorInvalidatePage((uintptr_t) (PAGE_TABLE_L3 + indexL3)); // Not strictly necessary. + EsMemoryZero((void *) ((uintptr_t) (PAGE_TABLE_L3 + indexL3) & ~(K_PAGE_SIZE - 1)), K_PAGE_SIZE); + } + + if ((PAGE_TABLE_L3[indexL3] & 1) == 0) { + if (flags & MM_MAP_PAGE_NO_NEW_TABLES) KernelPanic("MMArchMapPage - NO_NEW_TABLES flag set, but a table was missing.\n"); + PAGE_TABLE_L3[indexL3] = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_LOCK_ACQUIRED) | 7; + ProcessorInvalidatePage((uintptr_t) (PAGE_TABLE_L2 + indexL2)); // Not strictly necessary. + EsMemoryZero((void *) ((uintptr_t) (PAGE_TABLE_L2 + indexL2) & ~(K_PAGE_SIZE - 1)), K_PAGE_SIZE); + } + + if ((PAGE_TABLE_L2[indexL2] & 1) == 0) { + if (flags & MM_MAP_PAGE_NO_NEW_TABLES) KernelPanic("MMArchMapPage - NO_NEW_TABLES flag set, but a table was missing.\n"); + PAGE_TABLE_L2[indexL2] = MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_LOCK_ACQUIRED) | 7; + ProcessorInvalidatePage((uintptr_t) (PAGE_TABLE_L1 + indexL1)); // Not strictly necessary. + EsMemoryZero((void *) ((uintptr_t) (PAGE_TABLE_L1 + indexL1) & ~(K_PAGE_SIZE - 1)), K_PAGE_SIZE); + } + + uintptr_t oldValue = PAGE_TABLE_L1[indexL1]; + uintptr_t value = physicalAddress | 3; + + if (flags & MM_MAP_PAGE_WRITE_COMBINING) value |= 16; // This only works because we modified the PAT in SetupProcessor1. + if (flags & MM_MAP_PAGE_NOT_CACHEABLE) value |= 24; + if (flags & MM_MAP_PAGE_USER) value |= 7; else value |= 0x100; + if (flags & MM_MAP_PAGE_READ_ONLY) value &= ~2; + if (flags & MM_MAP_PAGE_COPIED) value |= 1 << 9; + + if ((oldValue & 1) && !(flags & MM_MAP_PAGE_OVERWRITE)) { + if (flags & MM_MAP_PAGE_IGNORE_IF_MAPPED) { + return; + } + + if ((oldValue & ~(K_PAGE_SIZE - 1)) != physicalAddress) { + KernelPanic("MMArchMapPage - Attempt to map %x to %x that has already been mapped to %x.\n", + virtualAddress, physicalAddress, oldValue & (~(K_PAGE_SIZE - 1))); + } + + if (oldValue == value) { + KernelPanic("MMArchMapPage - Attempt to rewrite page translation.\n", + physicalAddress, virtualAddress, oldValue & (K_PAGE_SIZE - 1), value & (K_PAGE_SIZE - 1)); + } else if (!(oldValue & 2) && (value & 2)) { + // The page has become writable. + } else { + KernelPanic("MMArchMapPage - Attempt to change flags mapping %x address %x from %x to %x.\n", + physicalAddress, virtualAddress, oldValue & (K_PAGE_SIZE - 1), value & (K_PAGE_SIZE - 1)); + } + } + + PAGE_TABLE_L1[indexL1] = value; + + // We rely on this page being invalidated on this CPU in some places. + ProcessorInvalidatePage(oldVirtualAddress); +} + +bool MMArchHandlePageFault(uintptr_t address, uint32_t flags) { + // EsPrint("Fault %x\n", address); + address &= ~(K_PAGE_SIZE - 1); + bool forSupervisor = flags & MM_HANDLE_PAGE_FAULT_FOR_SUPERVISOR; + + if (!ProcessorAreInterruptsEnabled()) { + KernelPanic("MMArchHandlePageFault - Page fault with interrupts disabled.\n"); + } + + if (address < K_PAGE_SIZE) { + } else if (address >= LOW_MEMORY_MAP_START && address < LOW_MEMORY_MAP_START + 0x100000000 && forSupervisor) { + // We want to access a physical page within the first 4GB. + // This is used for device IO, so the page can't be cacheable. + MMArchMapPage(kernelMMSpace, address - LOW_MEMORY_MAP_START, address, MM_MAP_PAGE_NOT_CACHEABLE | MM_MAP_PAGE_COMMIT_TABLES_NOW); + return true; + } else if (address >= MM_CORE_REGIONS_START && address < MM_CORE_REGIONS_START + MM_CORE_REGIONS_COUNT * sizeof(MMRegion) && forSupervisor) { + // This is where coreMMSpace stores its regions. + // Allocate physical memory and map it. + MMArchMapPage(kernelMMSpace, MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_ZEROED), address, MM_MAP_PAGE_COMMIT_TABLES_NOW); + return true; + } else if (address >= MM_CORE_SPACE_START && address < MM_CORE_SPACE_START + MM_CORE_SPACE_SIZE && forSupervisor) { + return MMHandlePageFault(coreMMSpace, address, flags); + } else if (address >= MM_KERNEL_SPACE_START && address < MM_KERNEL_SPACE_START + MM_KERNEL_SPACE_SIZE && forSupervisor) { + return MMHandlePageFault(kernelMMSpace, address, flags); + } else if (address >= MM_MODULES_START && address < MM_MODULES_START + MM_MODULES_SIZE && forSupervisor) { + return MMHandlePageFault(kernelMMSpace, address, flags); + } else { + Thread *thread = GetCurrentThread(); + MMSpace *space = thread->temporaryAddressSpace; + if (!space) space = thread->process->vmm; + return MMHandlePageFault(space, address, flags); + } + + return false; +} + +void MMArchInitialiseVAS() { + coreMMSpace->data.cr3 = kernelMMSpace->data.cr3 = ProcessorReadCR3(); + coreMMSpace->data.l1Commit = coreL1Commit; + + for (uintptr_t i = 0x100; i < 0x200; i++) { + if (PAGE_TABLE_L4[i] == 0) { + // We don't need to commit anything because the PMM isn't ready yet. + PAGE_TABLE_L4[i] = MMPhysicalAllocate(ES_FLAGS_DEFAULT) | 3; + EsMemoryZero((void *) (PAGE_TABLE_L3 + i * 0x200), K_PAGE_SIZE); + } + } +} + +uintptr_t MMArchTranslateAddress(MMSpace *, uintptr_t virtualAddress, bool writeAccess) { + // TODO I don't think this mutex was ever necessary? + // space->data.mutex.Acquire(); + // EsDefer(space->data.mutex.Release()); + + virtualAddress &= 0x0000FFFFFFFFF000; + if ((PAGE_TABLE_L4[virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3)] & 1) == 0) return 0; + if ((PAGE_TABLE_L3[virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2)] & 1) == 0) return 0; + if ((PAGE_TABLE_L2[virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1)] & 1) == 0) return 0; + uintptr_t physicalAddress = PAGE_TABLE_L1[virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 0)]; + if (writeAccess && !(physicalAddress & 2)) return 0; + return (physicalAddress & 1) ? (physicalAddress & 0x0000FFFFFFFFF000) : 0; +} + +void ArchCallFunctionOnAllProcessors(CallFunctionOnAllProcessorsCallbackFunction callback, bool includingThisProcessor) { + KSpinlockAssertLocked(&ipiLock); + + if (KGetCPUCount() > 1) { + callFunctionOnAllProcessorsCallback = callback; + callFunctionOnAllProcessorsRemaining = KGetCPUCount(); + size_t ignored = ProcessorSendIPI(CALL_FUNCTION_ON_ALL_PROCESSORS_IPI); + __sync_fetch_and_sub(&callFunctionOnAllProcessorsRemaining, ignored); + while (callFunctionOnAllProcessorsRemaining); + static volatile size_t totalIgnored = 0; + totalIgnored += ignored; + } + + if (includingThisProcessor) callback(); +} + +// TODO How should this be determined? +#define INVALIDATE_ALL_PAGES_THRESHOLD (1024) + +void TLBShootdownCallback() { + uintptr_t page = tlbShootdownVirtualAddress; + + if (tlbShootdownPageCount > INVALIDATE_ALL_PAGES_THRESHOLD) { + ProcessorInvalidateAllPages(); + } else { + for (uintptr_t i = 0; i < tlbShootdownPageCount; i++, page += K_PAGE_SIZE) { + ProcessorInvalidatePage(page); + } + } +} + +void MMArchInvalidatePages(uintptr_t virtualAddressStart, uintptr_t pageCount) { + // This must be done with spinlock acquired, otherwise this processor could change. + + // TODO Only send the IPI to the processors that are actually executing threads with the virtual address space. + // Currently we only support the kernel's virtual address space, so this'll apply to all processors. + // If we use Intel's PCID then we may have to send this to all processors anyway. + // And we'll probably also have to be careful with shared memory regions. + // ...actually I think we might not bother doing this. + + KSpinlockAcquire(&ipiLock); + tlbShootdownVirtualAddress = virtualAddressStart; + tlbShootdownPageCount = pageCount; + ArchCallFunctionOnAllProcessors(TLBShootdownCallback, true); + KSpinlockRelease(&ipiLock); +} + +void MMArchUnmapPages(MMSpace *space, uintptr_t virtualAddressStart, uintptr_t pageCount, unsigned flags, size_t unmapMaximum, uintptr_t *resumePosition) { + // We can't let anyone use the unmapped pages until they've been invalidated on all processors. + // This also synchronises modified bit updating. + KMutexAcquire(&pmm.pageFrameMutex); + EsDefer(KMutexRelease(&pmm.pageFrameMutex)); + + KMutexAcquire(&space->data.mutex); + EsDefer(KMutexRelease(&space->data.mutex)); + + uintptr_t tableBase = virtualAddressStart & 0x0000FFFFFFFFF000; + uintptr_t start = resumePosition ? *resumePosition : 0; + + // TODO Freeing newly empty page tables. + // - What do we need to invalidate when we do this? + + for (uintptr_t i = start; i < pageCount; i++) { + // if (flags & MM_UNMAP_PAGES_BALANCE_FILE) EsPrint(",%d", i); + + uintptr_t virtualAddress = (i << K_PAGE_BITS) + tableBase; + + if ((PAGE_TABLE_L4[virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3)] & 1) == 0) { + i -= (virtualAddress >> K_PAGE_BITS) % (1 << (ENTRIES_PER_PAGE_TABLE_BITS * 3)); + i += (1 << (ENTRIES_PER_PAGE_TABLE_BITS * 3)); + continue; + } + + if ((PAGE_TABLE_L3[virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2)] & 1) == 0) { + i -= (virtualAddress >> K_PAGE_BITS) % (1 << (ENTRIES_PER_PAGE_TABLE_BITS * 2)); + i += (1 << (ENTRIES_PER_PAGE_TABLE_BITS * 2)); + continue; + } + + if ((PAGE_TABLE_L2[virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1)] & 1) == 0) { + i -= (virtualAddress >> K_PAGE_BITS) % (1 << (ENTRIES_PER_PAGE_TABLE_BITS * 1)); + i += (1 << (ENTRIES_PER_PAGE_TABLE_BITS * 1)); + continue; + } + + uintptr_t indexL1 = virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 0); + + uintptr_t translation = PAGE_TABLE_L1[indexL1]; + if (!(translation & 1)) continue; + bool copy = translation & (1 << 9); + + if (copy && (flags & MM_UNMAP_PAGES_BALANCE_FILE)) { + // Ignore copied pages when balancing file mappings. + // EsPrint("Ignore copied page %x\n", virtualAddress); + } else { + PAGE_TABLE_L1[indexL1] = 0; + + // NOTE MMArchInvalidatePages invalidates the page on all processors now, + // which I think makes this unnecessary? + // uint64_t invalidateAddress = (i << K_PAGE_BITS) + virtualAddressStart; + // ProcessorInvalidatePage(invalidateAddress); + + if ((flags & MM_UNMAP_PAGES_FREE) || ((flags & MM_UNMAP_PAGES_FREE_COPIED) && copy)) { + MMPhysicalFree(translation & 0x0000FFFFFFFFF000, true); + } else if (flags & MM_UNMAP_PAGES_BALANCE_FILE) { + // EsPrint("Balance %x\n", virtualAddress); + + // It's safe to do this before invalidation, + // because the page fault handler is synchronisation with mutexes acquired above. + + if (MMUnmapFilePage((translation & 0x0000FFFFFFFFF000) >> K_PAGE_BITS)) { + if (resumePosition) { + if (!unmapMaximum--) { + *resumePosition = i; + break; + } + } + } + } + } + } + + MMArchInvalidatePages(virtualAddressStart, pageCount); +} + +InterruptContext *ArchInitialiseThread(uintptr_t kernelStack, uintptr_t kernelStackSize, Thread *thread, + uintptr_t startAddress, uintptr_t argument1, uintptr_t argument2, + bool userland, uintptr_t stack, uintptr_t userStackSize) { + InterruptContext *context = ((InterruptContext *) (kernelStack + kernelStackSize - 8)) - 1; + thread->kernelStack = kernelStack + kernelStackSize - 8; + + // Terminate the thread when the outermost function exists. + *((uintptr_t *) (kernelStack + kernelStackSize - 8)) = (uintptr_t) &_KThreadTerminate; + + context->fxsave[32] = 0x80; + context->fxsave[33] = 0x1F; + + if (userland) { + context->cs = 0x5B; + context->ds = 0x63; + context->ss = 0x63; + } else { + context->cs = 0x48; + context->ds = 0x50; + context->ss = 0x50; + } + + context->_check = 0x123456789ABCDEF; // Stack corruption detection. + context->flags = 1 << 9; // Interrupt flag + context->rip = startAddress; + context->rsp = stack + userStackSize - 8; // The stack should be 16-byte aligned before the call instruction. + context->rdi = argument1; + context->rsi = argument2; + + return context; +} + +bool MMArchInitialiseUserSpace(MMSpace *space) { + if (!MMCommit(K_PAGE_SIZE, true)) { + return false; + } + + space->data.cr3 = MMPhysicalAllocate(ES_FLAGS_DEFAULT); + + KMutexAcquire(&coreMMSpace->reserveMutex); + MMRegion *l1Region = MMReserve(coreMMSpace, L1_COMMIT_SIZE_BYTES, MM_REGION_NORMAL | MM_REGION_NO_COMMIT_TRACKING | MM_REGION_FIXED); + if (l1Region) space->data.l1Commit = (uint8_t *) l1Region->baseAddress; + KMutexRelease(&coreMMSpace->reserveMutex); + + if (!space->data.l1Commit) { + return false; + } + + uint64_t *pageTable = (uint64_t *) MMMapPhysical(kernelMMSpace, (uintptr_t) space->data.cr3, K_PAGE_SIZE, ES_FLAGS_DEFAULT); + EsMemoryZero(pageTable + 0x000, K_PAGE_SIZE / 2); + EsMemoryCopy(pageTable + 0x100, (uint64_t *) (PAGE_TABLE_L4 + 0x100), K_PAGE_SIZE / 2); + pageTable[512 - 2] = space->data.cr3 | 3; + MMFree(kernelMMSpace, pageTable); + + return true; +} + +void ArchCleanupVirtualAddressSpace(void *argument) { + KernelLog(LOG_VERBOSE, "Arch", "remove virtual address space page", "Removing virtual address space page %x...\n", argument); + MMPhysicalFree((uintptr_t) argument); + MMDecommit(K_PAGE_SIZE, true); +} + +void MMFreeVAS(MMSpace *space) { + for (uintptr_t i = 0; i < 256; i++) { + if (!PAGE_TABLE_L4[i]) continue; + + for (uintptr_t j = i * 512; j < (i + 1) * 512; j++) { + if (!PAGE_TABLE_L3[j]) continue; + + for (uintptr_t k = j * 512; k < (j + 1) * 512; k++) { + if (!PAGE_TABLE_L2[k]) continue; + MMPhysicalFree(PAGE_TABLE_L2[k] & (~0xFFF)); + } + + MMPhysicalFree(PAGE_TABLE_L3[j] & (~0xFFF)); + } + + MMPhysicalFree(PAGE_TABLE_L4[i] & (~0xFFF)); + } + + KMutexAcquire(&coreMMSpace->reserveMutex); + MMUnreserve(coreMMSpace, MMFindRegion(coreMMSpace, (uintptr_t) space->data.l1Commit), true); + KMutexRelease(&coreMMSpace->reserveMutex); + MMDecommit(space->data.pageTablesCommitted * K_PAGE_SIZE, true); +} + +void MMFinalizeVAS(MMSpace *space) { + // Freeing the L4 page table has to be done in the kernel process, since it's the page CR3 currently points to!! + // This function is called in an async task. + MMPhysicalFree(space->data.cr3); + MMDecommit(K_PAGE_SIZE, true); +} + +void ArchCheckAddressInRange(int type, uintptr_t address) { + if (type == 1) { + if ((uintptr_t) address < 0xFFFF900000000000) { + KernelPanic("ArchCheckAddressInRange - Address out of expected range.\n"); + } + } else if (type == 2) { + if ((uintptr_t) address < 0xFFFF8F8000000000 || (uintptr_t) address >= 0xFFFF900000000000) { + KernelPanic("ArchCheckAddressInRange - Address out of expected range.\n"); + } + } else { + if ((uintptr_t) address >= 0xFFFF800000000000) { + KernelPanic("ArchCheckAddressInRange - Address out of expected range.\n"); + } + } +} + +void ArchDelay1Ms() { + ProcessorOut8(0x43, 0x30); + ProcessorOut8(0x40, 0xA9); + ProcessorOut8(0x40, 0x04); + + while (true) { + ProcessorOut8(0x43, 0xE2); + + if (ProcessorIn8(0x40) & (1 << 7)) { + break; + } + } +} + +struct MSIHandler { + KIRQHandler callback; + void *context; +}; + +MSIHandler msiHandlers[INTERRUPT_VECTOR_MSI_COUNT]; + +void KUnregisterMSI(uintptr_t tag) { + KSpinlockAcquire(&scheduler.lock); + EsDefer(KSpinlockRelease(&scheduler.lock)); + msiHandlers[tag].callback = nullptr; +} + +KMSIInformation KRegisterMSI(KIRQHandler handler, void *context, const char *cOwnerName) { + KSpinlockAcquire(&scheduler.lock); + EsDefer(KSpinlockRelease(&scheduler.lock)); + + for (uintptr_t i = 0; i < INTERRUPT_VECTOR_MSI_COUNT; i++) { + if (msiHandlers[i].callback) continue; + msiHandlers[i] = { handler, context }; + + // TODO Selecting the best target processor. + // Currently this sends everything to processor 0. + + KernelLog(LOG_INFO, "Arch", "register MSI", "Register MSI with vector %X for '%z'.\n", + INTERRUPT_VECTOR_MSI_START + i, cOwnerName); + + return { + .address = 0xFEE00000, + .data = INTERRUPT_VECTOR_MSI_START + i, + .tag = i, + }; + } + + return {}; +} + +#define IRQ_BASE 0x50 +KIRQHandler irqHandlers[0x20][0x10]; +void *irqHandlerContext[0x20][0x10]; +size_t usedIrqHandlers[0x20]; + +bool KRegisterIRQ(uintptr_t interrupt, KIRQHandler handler, void *context, const char *cOwnerName) { + KSpinlockAcquire(&scheduler.lock); + EsDefer(KSpinlockRelease(&scheduler.lock)); + + // Work out which interrupt the IoApic will sent to the processor. + // TODO Use the upper 4 bits for IRQ priority. + uintptr_t thisProcessorIRQ = interrupt + IRQ_BASE; + + // Register the IRQ handler. + if (interrupt > 0x20) KernelPanic("KRegisterIRQ - Unexpected IRQ %d\n", interrupt); + if (usedIrqHandlers[interrupt] == 0x10) { + // There are too many overloaded interrupts. + return false; + } + irqHandlers[interrupt][usedIrqHandlers[interrupt]] = handler; + irqHandlerContext[interrupt][usedIrqHandlers[interrupt]] = context; + + KernelLog(LOG_INFO, "Arch", "register IRQ", "KRegisterIRQ - Registering IRQ %d to '%z'.\n", + interrupt, cOwnerName); + + if (usedIrqHandlers[interrupt]) { + // IRQ already registered. + usedIrqHandlers[interrupt]++; + return true; + } + + usedIrqHandlers[interrupt]++; + + bool activeLow = false; + bool levelTriggered = true; + + // If there was an interrupt override entry in the MADT table, + // then we'll have to use that number instead. + for (uintptr_t i = 0; i < acpi.interruptOverrideCount; i++) { + ACPIInterruptOverride *interruptOverride = acpi.interruptOverrides + i; + if (interruptOverride->sourceIRQ == interrupt) { + interrupt = interruptOverride->gsiNumber; + activeLow = interruptOverride->activeLow; + levelTriggered = interruptOverride->levelTriggered; + break; + } + } + + KernelLog(LOG_INFO, "Arch", "IRQ flags", "KRegisterIRQ - IRQ %d is active %z, %z triggered.\n", + interrupt, activeLow ? "low" : "high", levelTriggered ? "level" : "edge"); + + ACPIIoApic *ioApic; + bool foundIoApic = false; + + // Look for the IoApic to which this interrupt is sent. + for (uintptr_t i = 0; i < acpi.ioapicCount; i++) { + ioApic = acpi.ioApics + i; + if (interrupt >= ioApic->gsiBase + && interrupt < (ioApic->gsiBase + (0xFF & (ioApic->ReadRegister(1) >> 16)))) { + foundIoApic = true; + interrupt -= ioApic->gsiBase; + break; + } + } + + // We couldn't find the IoApic that handles this interrupt. + if (!foundIoApic) { + return false; + } + + // A normal priority interrupt. + uintptr_t redirectionTableIndex = interrupt * 2 + 0x10; + uint32_t redirectionEntry = thisProcessorIRQ; + if (activeLow) redirectionEntry |= (1 << 13); + if (levelTriggered) redirectionEntry |= (1 << 15); + + // Mask the interrupt while we modify the entry. + ioApic->WriteRegister(redirectionTableIndex, 1 << 16); + + // Send the interrupt to the processor that registered the interrupt. + ioApic->WriteRegister(redirectionTableIndex + 1, GetLocalStorage()->archCPU->apicID << 24); + ioApic->WriteRegister(redirectionTableIndex, redirectionEntry); + + return true; +} + +size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi, int processorID) { + // It's possible that another CPU is trying to send an IPI at the same time we want to send the panic IPI. + // TODO What should we do in this case? + if (interrupt != KERNEL_PANIC_IPI) KSpinlockAssertLocked(&ipiLock); + + // Note: We send IPIs at a special priority that ProcessorDisableInterrupts doesn't mask. + + size_t ignored = 0; + + for (uintptr_t i = 0; i < acpi.processorCount; i++) { + ACPIProcessor *processor = acpi.processors + i; + + if (processorID != -1) { + if (processorID != processor->kernelProcessorID) { + ignored++; + continue; + } + } else { + if (processor == GetLocalStorage()->archCPU || !processor->local || !processor->local->schedulerReady) { + ignored++; + continue; + } + } + + uint32_t destination = acpi.processors[i].apicID << 24; + uint32_t command = interrupt | (1 << 14) | (nmi ? 0x400 : 0); + acpi.lapic.WriteRegister(0x310 >> 2, destination); + acpi.lapic.WriteRegister(0x300 >> 2, command); + + // Wait for the interrupt to be sent. + while (acpi.lapic.ReadRegister(0x300 >> 2) & (1 << 12)); + } + + return ignored; +} + +void ArchNextTimer(size_t ms) { + while (!scheduler.started); // Wait until the scheduler is ready. + GetLocalStorage()->schedulerReady = true; // Make sure this CPU can be scheduled. + acpi.lapic.ArchNextTimer(ms); // Set the next timer. +} + +NewProcessorStorage AllocateNewProcessorStorage(ACPIProcessor *archCPU) { + NewProcessorStorage storage = {}; + storage.local = (CPULocalStorage *) EsHeapAllocate(sizeof(CPULocalStorage), true, K_FIXED); + storage.gdt = (uint32_t *) MMMapPhysical(kernelMMSpace, MMPhysicalAllocate(MM_PHYSICAL_ALLOCATE_COMMIT_NOW), K_PAGE_SIZE, ES_FLAGS_DEFAULT); + storage.local->archCPU = archCPU; + archCPU->local = storage.local; + scheduler.CreateProcessorThreads(storage.local); + archCPU->kernelProcessorID = storage.local->processorID; + return storage; +} + +extern "C" void SetupProcessor2(NewProcessorStorage *storage) { + // Setup the local interrupts for the current processor. + + for (uintptr_t i = 0; i < acpi.lapicNMICount; i++) { + if (acpi.lapicNMIs[i].processor == 0xFF + || acpi.lapicNMIs[i].processor == storage->local->archCPU->processorID) { + uint32_t registerIndex = (0x350 + (acpi.lapicNMIs[i].lintIndex << 4)) >> 2; + uint32_t value = 2 | (1 << 10); // NMI exception interrupt vector. + if (acpi.lapicNMIs[i].activeLow) value |= 1 << 13; + if (acpi.lapicNMIs[i].levelTriggered) value |= 1 << 15; + acpi.lapic.WriteRegister(registerIndex, value); + } + } + + acpi.lapic.WriteRegister(0x350 >> 2, acpi.lapic.ReadRegister(0x350 >> 2) & ~(1 << 16)); + acpi.lapic.WriteRegister(0x360 >> 2, acpi.lapic.ReadRegister(0x360 >> 2) & ~(1 << 16)); + acpi.lapic.WriteRegister(0x080 >> 2, 0); + if (acpi.lapic.ReadRegister(0x30 >> 2) & 0x80000000) acpi.lapic.WriteRegister(0x410 >> 2, 0); + acpi.lapic.EndOfInterrupt(); + + // Configure the LAPIC's timer. + + acpi.lapic.WriteRegister(0x3E0 >> 2, 2); // Divisor = 16 + + // Create the processor's local storage. + + ProcessorSetLocalStorage(storage->local); + + // Setup a GDT and TSS for the processor. + + uint32_t *gdt = storage->gdt; + void *bootstrapGDT = (void *) (((uint64_t *) ((uint16_t *) processorGDTR + 1))[0]); + EsMemoryCopy(gdt, bootstrapGDT, 2048); + uint32_t *tss = (uint32_t *) ((uint8_t *) storage->gdt + 2048); + storage->local->archCPU->kernelStack = (void **) (tss + 1); + ProcessorInstallTSS(gdt, tss); +} + +const char *exceptionInformation[] = { + "0x00: Divide Error (Fault)", + "0x01: Debug Exception (Fault/Trap)", + "0x02: Non-Maskable External Interrupt (Interrupt)", + "0x03: Breakpoint (Trap)", + "0x04: Overflow (Trap)", + "0x05: BOUND Range Exceeded (Fault)", + "0x06: Invalid Opcode (Fault)", + "0x07: x87 Coprocessor Unavailable (Fault)", + "0x08: Double Fault (Abort)", + "0x09: x87 Coprocessor Segment Overrun (Fault)", + "0x0A: Invalid TSS (Fault)", + "0x0B: Segment Not Present (Fault)", + "0x0C: Stack Protection (Fault)", + "0x0D: General Protection (Fault)", + "0x0E: Page Fault (Fault)", + "0x0F: Reserved/Unknown", + "0x10: x87 FPU Floating-Point Error (Fault)", + "0x11: Alignment Check (Fault)", + "0x12: Machine Check (Abort)", + "0x13: SIMD Floating-Point Exception (Fault)", + "0x14: Virtualization Exception (Fault)", + "0x15: Reserved/Unknown", + "0x16: Reserved/Unknown", + "0x17: Reserved/Unknown", + "0x18: Reserved/Unknown", + "0x19: Reserved/Unknown", + "0x1A: Reserved/Unknown", + "0x1B: Reserved/Unknown", + "0x1C: Reserved/Unknown", + "0x1D: Reserved/Unknown", + "0x1E: Reserved/Unknown", + "0x1F: Reserved/Unknown", +}; + +void ContextSanityCheck(InterruptContext *context) { + if (!context || context->cs > 0x100 || context->ds > 0x100 || context->ss > 0x100 + || (context->rip >= 0x1000000000000 && context->rip < 0xFFFF000000000000) + || (context->rip < 0xFFFF800000000000 && context->cs == 0x48)) { + KernelPanic("ContextSanityCheck - Corrupt context (%x/%x/%x/%x)\nRIP = %x, RSP = %x\n", context, context->cs, context->ds, context->ss, context->rip, context->rsp); + } +} + +extern "C" void InterruptHandler(InterruptContext *context) { + if (scheduler.panic && context->interruptNumber != 2) { + return; + } + + if (ProcessorAreInterruptsEnabled()) { + KernelPanic("InterruptHandler - Interrupts were enabled at the start of an interrupt handler.\n"); + } + + CPULocalStorage *local = GetLocalStorage(); + uintptr_t interrupt = context->interruptNumber; + +#if 0 +#ifdef EARLY_DEBUGGING +#ifdef VGA_TEXT_MODE + if (local) { + TERMINAL_ADDRESS[local->processorID] += 0x1000; + } +#else + if (graphics.target && graphics.target->debugPutBlock) { + graphics.target->debugPutBlock(local->processorID * 3 + 3, 3, true); + graphics.target->debugPutBlock(local->processorID * 3 + 4, 3, true); + graphics.target->debugPutBlock(local->processorID * 3 + 3, 4, true); + graphics.target->debugPutBlock(local->processorID * 3 + 4, 4, true); + } +#endif +#endif +#endif + + if (interrupt < 0x20) { + // If we received a non-maskable interrupt, halt execution. + if (interrupt == 2) { + GetLocalStorage()->panicContext = context; + ProcessorHalt(); + } + + bool supervisor = (context->cs & 3) == 0; + + if (!supervisor) { + // EsPrint("User interrupt: %x/%x/%x\n", interrupt, context->cr2, context->errorCode); + + if (context->cs != 0x5B && context->cs != 0x6B) { + KernelPanic("InterruptHandler - Unexpected value of CS 0x%X\n", context->cs); + } + + if (GetCurrentThread()->isKernelThread) { + KernelPanic("InterruptHandler - Kernel thread executing user code. (1)\n"); + } + + // User-code exceptions are *basically* the same thing as system calls. + Thread *currentThread = GetCurrentThread(); + ThreadTerminatableState previousTerminatableState; + previousTerminatableState = currentThread->terminatableState; + currentThread->terminatableState = THREAD_IN_SYSCALL; + + if (local && local->spinlockCount) { + KernelPanic("InterruptHandler - User exception occurred with spinlock acquired.\n"); + } + + // Re-enable interrupts during exception handling. + ProcessorEnableInterrupts(); + + if (interrupt == 14) { + bool success = MMArchHandlePageFault(context->cr2, (context->errorCode & 2) ? MM_HANDLE_PAGE_FAULT_WRITE : 0); + + if (success) { + goto resolved; + } + } + + if (interrupt == 0x13) { + EsPrint("ProcessorReadMXCSR() = %x\n", ProcessorReadMXCSR()); + } + + // TODO Usermode exceptions and debugging. + KernelLog(LOG_ERROR, "Arch", "unhandled userland exception", + "InterruptHandler - Exception (%z) in userland process (%z).\nRIP = %x (CPU %d)\nRSP = %x\nX86_64 error codes: [err] %x, [cr2] %x\n", + exceptionInformation[interrupt], + currentThread->process->cExecutableName, + context->rip, local->processorID, context->rsp, context->errorCode, context->cr2); + +#ifndef __OPTIMIZE__ + EsPrint("Attempting to make a stack trace...\n"); + + { + // TODO Temporary, may crash kernel. + // Attempt to make a stack trace. + + uint64_t *rbp = (uint64_t *) context->rbp; + int i = 0; + + while (rbp && i < 32) { + EsPrint("\t%d: %x\n", ++i, rbp[1]); + if (!rbp[1]) break; + rbp = (uint64_t *) (rbp[0]); + } + } + + EsPrint("Stack trace complete.\n"); +#else + EsPrint("Disable optimisations to get a stack trace.\n"); +#endif + + EsCrashReason crashReason; + EsMemoryZero(&crashReason, sizeof(EsCrashReason)); + crashReason.errorCode = ES_FATAL_ERROR_PROCESSOR_EXCEPTION; + crashReason.duringSystemCall = (EsSyscallType) -1; + scheduler.CrashProcess(currentThread->process, &crashReason); + + resolved:; + + if (currentThread->terminatableState != THREAD_IN_SYSCALL) { + KernelPanic("InterruptHandler - Thread changed terminatable status during interrupt.\n"); + } + + currentThread->terminatableState = previousTerminatableState; + + if (currentThread->terminating || currentThread->paused) { + ProcessorFakeTimerInterrupt(); + } + + // Disable interrupts when we're done. + ProcessorDisableInterrupts(); + + // EsPrint("User interrupt complete.\n", interrupt, context->cr2); + } else { + if (context->cs != 0x48) { + KernelPanic("InterruptHandler - Unexpected value of CS 0x%X\n", context->cs); + } + + if (interrupt == 14) { + // EsPrint("PF: %x\n", context->cr2); + + if ((context->errorCode & (1 << 3))) { + goto fault; + } + + if ((context->flags & 0x200) && context->cr8 != 0xE) { + ProcessorEnableInterrupts(); + } + + { + CPULocalStorage *storage = GetLocalStorage(); + + if (storage && storage->spinlockCount && ((context->cr2 >= 0xFFFF900000000000 && context->cr2 < 0xFFFFF00000000000) + || context->cr2 < 0x8000000000000000)) { + KernelPanic("HandlePageFault - Page fault occurred in critical section at %x (S = %x, B = %x, LG = %x) (CR2 = %x).\n", + context->rip, context->rsp, context->rbp, storage->currentThread->lastKnownExecutionAddress, context->cr2); + } + } + + + if (!MMArchHandlePageFault(context->cr2, MM_HANDLE_PAGE_FAULT_FOR_SUPERVISOR + | ((context->errorCode & 2) ? MM_HANDLE_PAGE_FAULT_WRITE : 0))) { + goto fault; + } + + ProcessorDisableInterrupts(); + } else { + fault: + KernelPanic("Unresolvable processor exception encountered in supervisor mode.\n%z\nRIP = %x (CPU %d)\nX86_64 error codes: [err] %x, [cr2] %x\n" + "Stack: [rsp] %x, [rbp] %x\nRegisters: [rax] %x, [rbx] %x, [rsi] %x, [rdi] %x.\nThread ID = %d\n", + exceptionInformation[interrupt], context->rip, local ? local->processorID : -1, context->errorCode, context->cr2, + context->rsp, context->rbp, context->rax, context->rbx, context->rsi, context->rdi, + local && local->currentThread ? local->currentThread->id : -1); + } + } + } else if (interrupt == 0xFF) { + // Spurious interrupt (APIC), ignore. + } else if (interrupt >= 0x20 && interrupt < 0x30) { + // Spurious interrupt (PIC), ignore. + } else if (interrupt >= 0xF0 && interrupt < 0xFE) { + // IPI. + // Warning: This code executes at a special IRQL! Do not acquire spinlocks!! + + if (interrupt == CALL_FUNCTION_ON_ALL_PROCESSORS_IPI) { + if (!callFunctionOnAllProcessorsRemaining) KernelPanic("InterruptHandler - callFunctionOnAllProcessorsRemaining is 0 (a).\n"); + callFunctionOnAllProcessorsCallback(); + if (!callFunctionOnAllProcessorsRemaining) KernelPanic("InterruptHandler - callFunctionOnAllProcessorsRemaining is 0 (b).\n"); + __sync_fetch_and_sub(&callFunctionOnAllProcessorsRemaining, 1); + } + + acpi.lapic.EndOfInterrupt(); + } else if (interrupt >= INTERRUPT_VECTOR_MSI_START && interrupt < INTERRUPT_VECTOR_MSI_START + INTERRUPT_VECTOR_MSI_COUNT && local) { + MSIHandler handler = msiHandlers[interrupt - INTERRUPT_VECTOR_MSI_START]; + local->irqSwitchThread = false; + + if (!handler.callback) { + KernelLog(LOG_ERROR, "Arch", "unexpected MSI", "Unexpected MSI vector %X (no handler).\n", interrupt); + } else { + handler.callback(interrupt - INTERRUPT_VECTOR_MSI_START, handler.context); + } + + + acpi.lapic.EndOfInterrupt(); + + if (local->irqSwitchThread && scheduler.started && local->schedulerReady) { + scheduler.Yield(context); + KernelPanic("InterruptHandler - Returned from Scheduler::Yield.\n"); + } + } else if (local) { + // IRQ. + + local->irqSwitchThread = false; + + if (interrupt == TIMER_INTERRUPT) { + local->irqSwitchThread = true; + } else if (interrupt == YIELD_IPI) { + local->irqSwitchThread = true; + GetCurrentThread()->receivedYieldIPI = true; + } else if (interrupt >= IRQ_BASE && interrupt < IRQ_BASE + 0x20) { + GetLocalStorage()->inIRQ = true; + + size_t overloads = usedIrqHandlers[interrupt - IRQ_BASE]; + bool handledInterrupt = false; + + KernelLog(LOG_VERBOSE, "Arch", "IRQ start", "IRQ start %d.\n", interrupt - IRQ_BASE); + + for (uintptr_t i = 0; i < overloads; i++) { + KIRQHandler handler = irqHandlers[interrupt - IRQ_BASE][i]; + + if (handler(interrupt - IRQ_BASE, irqHandlerContext[interrupt - IRQ_BASE][i])) { + handledInterrupt = true; + } + } + + KernelLog(LOG_VERBOSE, "Arch", "IRQ end", "IRQ end %d.\n", interrupt - IRQ_BASE); + + bool rejectedByAll = !handledInterrupt; + + if (rejectedByAll) { + // TODO Now what? + // KernelLog(LOG_ERROR, "Arch", "unhandled IRQ", + // "InterruptHandler - Unhandled IRQ %d, rejected by %d %z\n", + // interrupt, overloads, (overloads != 1) ? "overloads" : "overload"); + } + + GetLocalStorage()->inIRQ = false; + } + + acpi.lapic.EndOfInterrupt(); + + if (local->irqSwitchThread && scheduler.started && local->schedulerReady) { + scheduler.Yield(context); + KernelPanic("InterruptHandler - Returned from Scheduler::Yield.\n"); + } + } + + // Sanity check. + ContextSanityCheck(context); + + if (ProcessorAreInterruptsEnabled()) { + KernelPanic("InterruptHandler - Interrupts were enabled while returning from an interrupt handler.\n"); + } +} + +extern "C" bool PostContextSwitch(InterruptContext *context) { + CPULocalStorage *local = GetLocalStorage(); + Thread *currentThread = GetCurrentThread(); + + void *kernelStack = (void *) currentThread->kernelStack; + *local->archCPU->kernelStack = kernelStack; + + bool newThread = currentThread->cpuTimeSlices == 1; + + KernelLog(LOG_VERBOSE, "Arch", "context switch", "Context switch to thread %x at %x\n", currentThread, context->rip); + + if (newThread) { + ContextSanityCheck(context); + KernelLog(LOG_VERBOSE, "Arch", "executing new thread", "Executing new thread %x at %x\n", currentThread, context->rip); + } + + acpi.lapic.EndOfInterrupt(); + ContextSanityCheck(context); + + if (ProcessorAreInterruptsEnabled()) { + KernelPanic("PostContextSwitch - Interrupts were enabled. (1)\n"); + } + + currentThread->lastKnownExecutionAddress = context->rip; + + if (scheduler.lock.interruptsEnabled) { + KernelPanic("PostContextSwitch - Interrupts were enabled. (3)\n"); + } + + ProcessorSetThreadStorage(currentThread->tlsAddress); + + // We can only free the scheduler's spinlock when we are no longer using the stack + // from the previous thread. See DoContextSwitch in x86_64.s. + KSpinlockRelease(&scheduler.lock, true); + + if (ProcessorAreInterruptsEnabled()) { + KernelPanic("PostContextSwitch - Interrupts were enabled. (2)\n"); + } + + return newThread; +} + +extern "C" uintptr_t Syscall(uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, + uintptr_t returnAddress, uintptr_t argument3, uintptr_t argument4, uintptr_t *userStackPointer) { + (void) returnAddress; + return DoSyscall((EsSyscallType) argument0, argument1, argument2, argument3, argument4, false, nullptr, userStackPointer); +} + +bool HasSSSE3Support() { + return simdSSSE3Support; +} + +uintptr_t GetBootloaderInformationOffset() { + return bootloaderInformationOffset; +} + +#endif diff --git a/kernel/x86_64.h b/kernel/x86_64.h new file mode 100644 index 0000000..d97e9f7 --- /dev/null +++ b/kernel/x86_64.h @@ -0,0 +1,33 @@ +#ifndef ARCH_X86_64_HEADER +#define ARCH_X86_64_HEADER + +#define LOW_MEMORY_MAP_START (0xFFFFFE0000000000) +#define LOW_MEMORY_LIMIT (0x100000) // The first 1MB is mapped here. + +extern "C" uint64_t ProcessorReadCR3(); +extern "C" void gdt_data(); + +extern "C" void SSSE3Framebuffer32To24Copy(volatile uint8_t *destination, volatile uint8_t *source, size_t pixelGroups); + +extern bool pagingNXESupport; +extern bool pagingPCIDSupport; +extern bool pagingSMEPSupport; +extern bool pagingTCESupport; + +extern "C" void processorGDTR(); +extern "C" void SetupProcessor2(struct NewProcessorStorage *); +extern "C" void ProcessorInstallTSS(uint32_t *gdt, uint32_t *tss); + +bool HasSSSE3Support(); +uintptr_t GetBootloaderInformationOffset(); + +void ArchDelay1Ms(); // Spin for approximately 1ms. Use only during initialisation. Not thread-safe. + +struct NewProcessorStorage { + struct CPULocalStorage *local; + uint32_t *gdt; +}; + +NewProcessorStorage AllocateNewProcessorStorage(struct ACPIProcessor *archCPU); + +#endif diff --git a/kernel/x86_64.s b/kernel/x86_64.s new file mode 100644 index 0000000..34780fd --- /dev/null +++ b/kernel/x86_64.s @@ -0,0 +1,1078 @@ +[bits 64] + +[section .bss] + +[extern ArchNextTimer] + +align 16 + +%define stack_size 16384 +stack: resb stack_size + +%define idt_size 4096 +idt_data: resb idt_size + +%define cpu_local_storage_size 8192 +; Array of pointers to the CPU local states +[global cpu_local_storage] +cpu_local_storage: resb cpu_local_storage_size + +[section .data] + +idt: + .limit: dw idt_size - 1 + .base: dq idt_data + +cpu_local_storage_index: + dq 0 + +[global physicalMemoryRegions] +physicalMemoryRegions: + dq 0xFFFFFE0000060000 +[global physicalMemoryRegionsCount] +physicalMemoryRegionsCount: + dq 0 +[global physicalMemoryRegionsPagesCount] +physicalMemoryRegionsPagesCount: + dq 0 +[global physicalMemoryOriginalPagesCount] +physicalMemoryOriginalPagesCount: + dq 0 +[global physicalMemoryRegionsIndex] +physicalMemoryRegionsIndex: + dq 0 +[global physicalMemoryHighest] +physicalMemoryHighest: + dq 0 + +[global pagingNXESupport] +pagingNXESupport: + dd 1 +[global pagingPCIDSupport] +pagingPCIDSupport: + dd 1 +[global pagingSMEPSupport] +pagingSMEPSupport: + dd 1 +[global pagingTCESupport] +pagingTCESupport: + dd 1 +[global simdSSE3Support] +simdSSE3Support: + dd 1 +[global simdSSSE3Support] +simdSSSE3Support: + dd 1 + +[global bootloaderID] +bootloaderID: + dd 0 +[global bootloaderInformationOffset] +bootloaderInformationOffset: + dq 0 + +align 16 +[global processorGDTR] +processorGDTR: + dq 0 + dq 0 + +[section .text] + +[global _start] +_start: + cli + mov rax,0x63 + mov fs,ax + mov gs,ax + + ; Save the bootloader ID. + mov rax,bootloaderID + mov [rax],rsi + + cmp rdi,0 + jne .standard_acpi + mov [0x7FE8],rdi + .standard_acpi: + + ; Install a stack + mov rsp,stack + stack_size + + ; Save the bootloader information offset. + mov rax,bootloaderInformationOffset + mov [rax],rdi + + ; Load the installation ID. +[extern installationID] + mov rbx,installationID + mov rax,[rdi + 0x7FF0] + mov [rbx],rax + mov rax,[rdi + 0x7FF8] + mov [rbx + 8],rax + + ; Unmap the identity paging the bootloader used + mov rax,0xFFFFFF7FBFDFE000 + mov qword [rax],0 + mov rax,cr3 + mov cr3,rax + +SetupCOM1: + ; Setup the serial COM1 port for debug output. +%ifdef COM_OUTPUT + mov dx,0x3F8 + 1 + mov al,0x00 + out dx,al + mov dx,0x3F8 + 3 + mov al,0x80 + out dx,al + mov dx,0x3F8 + 0 + mov al,0x03 + out dx,al + mov dx,0x3F8 + 1 + mov al,0x00 + out dx,al + mov dx,0x3F8 + 3 + mov al,0x03 + out dx,al + mov dx,0x3F8 + 2 + mov al,0xC7 + out dx,al + mov dx,0x3F8 + 4 + mov al,0x0B + out dx,al +%endif + +InstallIDT: + ; Remap the ISRs sent by the PIC to 0x20 - 0x2F + ; Even though we'll mask the PIC to use the APIC, + ; we have to do this so that the spurious interrupts + ; are set to a sane vector range. + mov al,0x11 + out 0x20,al + mov al,0x11 + out 0xA0,al + mov al,0x20 + out 0x21,al + mov al,0x28 + out 0xA1,al + mov al,0x04 + out 0x21,al + mov al,0x02 + out 0xA1,al + mov al,0x01 + out 0x21,al + mov al,0x01 + out 0xA1,al + mov al,0x00 + out 0x21,al + mov al,0x00 + out 0xA1,al + + ; Install the interrupt handlers +%macro INSTALL_INTERRUPT_HANDLER 1 + mov rbx,(%1 * 16) + idt_data + mov rdx,InterruptHandler%1 + call InstallInterruptHandler +%endmacro +%assign i 0 +%rep 256 + INSTALL_INTERRUPT_HANDLER i +%assign i i+1 +%endrep + + ; Save the location of the bootstrap GDT + mov rcx,processorGDTR + sgdt [rcx] + +MemoryCalculations: + ; Work out basic information about the physical memory map we got from the bootloader + mov rax,bootloaderInformationOffset + mov rax,[rax] + mov rbx,physicalMemoryRegions + add [rbx],rax + mov rdi,0xFFFFFE0000060000 - 0x10 + add rdi,rax + mov rsi,0xFFFFFE0000060000 + add rsi,rax + xor rax,rax + xor r8,r8 + .loop: + add rdi,0x10 + mov r9,[rdi + 8] + shl r9,12 + add r9,[rdi] + cmp r9,r8 + jb .lower + mov r8,r9 + .lower: + add rax,[rdi + 8] + cmp qword [rdi],0 + jne .loop + mov rbx,[rdi + 8] + sub rax,rbx + sub rdi,rsi + shr rdi,4 + mov rsi,physicalMemoryRegionsCount + mov [rsi],rdi + mov rsi,physicalMemoryRegionsPagesCount + mov [rsi],rax + mov rsi,physicalMemoryOriginalPagesCount + mov [rsi],rbx + mov rsi,physicalMemoryHighest + mov [rsi],r8 + +DisablePIC: + ; Disable the PIC by masking all its interrupts, as we're going to use the APIC instead. + ; For some reason, it'll still generate spurious interrupts, so we'll have to ignore those. + mov al,0xFF + out 0xA1,al + out 0x21,al + +StartKernel: + ; First stage of processor initilisation + call SetupProcessor1 + + ; Print a divider line. + mov rdi,'-' + mov rcx,10 + .line: call ProcessorDebugOutputByte + loop .line + mov rdi,10 + call ProcessorDebugOutputByte + mov rdi,13 + call ProcessorDebugOutputByte + + ; Call the KernelMain function + and rsp,~0xF + extern KernelMain + call KernelMain + +ProcessorReady: + ; Set the timer and become this CPU's idle thread. + mov rdi,1 + call ArchNextTimer + jmp ProcessorIdle + +SetupProcessor1: +EnableCPUFeatures: + ; Enable no-execute support, if available + mov eax,0x80000001 + cpuid + and edx,1 << 20 + shr edx,20 + mov rax,pagingNXESupport + and [rax],edx + cmp edx,0 + je .no_paging_nxe_support + mov ecx,0xC0000080 + rdmsr + or eax,1 << 11 + wrmsr + .no_paging_nxe_support: + + ; x87 FPU + fninit + mov rax,.cw + fldcw [rax] + jmp .cwa + .cw: dw 0x037A + .cwa: + + ; Enable SMEP support, if available + ; This prevents the kernel from executing userland pages + ; TODO Test this: neither Bochs or Qemu seem to support it? + xor eax,eax + cpuid + cmp eax,7 + jb .no_smep_support + mov eax,7 + xor ecx,ecx + cpuid + and ebx,1 << 7 + shr ebx,7 + mov rax,pagingSMEPSupport + and [rax],ebx + cmp ebx,0 + je .no_smep_support + mov word [rax],2 + mov rax,cr4 + or rax,1 << 20 + mov cr4,rax + .no_smep_support: + + ; Enable PCID support, if available + mov eax,1 + xor ecx,ecx + cpuid + and ecx,1 << 17 + shr ecx,17 + mov rax,pagingPCIDSupport + and [rax],ecx + cmp ecx,0 + je .no_pcid_support + mov rax,cr4 + or rax,1 << 17 + mov cr4,rax + .no_pcid_support: + + ; Enable global pages + mov rax,cr4 + or rax,1 << 7 + mov cr4,rax + + ; Enable TCE support, if available + mov eax,0x80000001 + xor ecx,ecx + cpuid + and ecx,1 << 17 + shr ecx,17 + mov rax,pagingTCESupport + and [rax],ecx + cmp ecx,0 + je .no_tce_support + mov ecx,0xC0000080 + rdmsr + or eax,1 << 15 + wrmsr + .no_tce_support: + + ; Enable write protect, so copy-on-write works in the kernel. + mov rax,cr0 + or rax,1 << 16 + mov cr0,rax + + ; Enable MMX, SSE and SSE2 + ; These features are all guaranteed to be present on a x86_64 CPU + mov rax,cr0 + mov rbx,cr4 + and rax,~4 + or rax,2 + or rbx,512 + 1024 + mov cr0,rax + mov cr4,rbx + + ; Detect SSE3 and SSSE3, if available. + mov eax,1 + cpuid + test ecx,1 << 0 + jnz .has_sse3 + mov rax,simdSSE3Support + and byte [rax],0 + .has_sse3: + test ecx,1 << 9 + jnz .has_ssse3 + mov rax,simdSSSE3Support + and byte [rax],0 + .has_ssse3: + + ; Enable system-call extensions (SYSCALL and SYSRET). + mov ecx,0xC0000080 + rdmsr + or eax,1 + wrmsr + add ecx,1 + rdmsr + mov edx,0x005B0048 + wrmsr + add ecx,1 + mov rdx,SyscallEntry + mov rax,rdx + shr rdx,32 + wrmsr + add ecx,2 + rdmsr + mov eax,(1 << 10) | (1 << 9) ; Clear direction and interrupt flag when we enter ring 0. + wrmsr + + ; Assign PAT2 to WC. + mov ecx,0x277 + xor rax,rax + xor rdx,rdx + rdmsr + and eax,0xFFF8FFFF + or eax,0x00010000 + wrmsr + +SetupCPULocalStorage: + mov ecx,0xC0000101 + mov rax,cpu_local_storage + mov rdx,cpu_local_storage + shr rdx,32 + mov rdi,cpu_local_storage_index + add rax,[rdi] + add qword [rdi],32 ; Space for 4 8-byte values at gs:0 - gs:31 + wrmsr + +LoadIDTR: + ; Load the IDTR + mov rax,idt + lidt [rax] + sti + +EnableAPIC: + ; Enable the APIC! + ; Since we're on AMD64, we know that the APIC will be present. + mov ecx,0x1B + rdmsr + and eax,~0xFFF + mov edi,eax + test eax,1 << 8 + jne $ + or eax,0x900 + wrmsr + + ; Set the spurious interrupt vector to 0xFF + mov rax,0xFFFFFE00000000F0 + add rax,rdi + mov ebx,[rax] + or ebx,0x1FF + mov [rax],ebx + + ; Use the flat processor addressing model + mov rax,0xFFFFFE00000000E0 + add rax,rdi + mov dword [rax],0xFFFFFFFF + + ; Make sure that no external interrupts are masked + xor rax,rax + mov cr8,rax + + ret + +SyscallEntry: + mov rsp,[gs:8] + sti + + mov ax,0x50 + mov ds,ax + mov es,ax + + ; Preserve RCX, R11, R12 and RBX. + push rcx + push r11 + push r12 + mov rax,rsp + push rbx + push rax + + ; Arguments in RDI, RSI, RDX, R8, R9. (RCX contains return address). + ; Return value in RAX. + [extern Syscall] + mov rbx,rsp + and rsp,~0xF + call Syscall + mov rsp,rbx + + ; Disable maskable interrupts. + cli + + ; Return to long mode. (Address in RCX). + add rsp,8 + push rax + mov ax,0x63 + mov ds,ax + mov es,ax + pop rax + pop rbx + pop r12 ; User RSP + pop r11 + pop rcx ; Return address + db 0x48 + sysret + +[global ProcessorFakeTimerInterrupt] +ProcessorFakeTimerInterrupt: + int 0x40 + ret + +[global ProcessorDisableInterrupts] +ProcessorDisableInterrupts: + mov rax,14 ; Still allow important IPIs to go through. + mov cr8,rax + sti ; TODO Where is this necessary? Is is a performance issue? + ret + +[global ProcessorEnableInterrupts] +ProcessorEnableInterrupts: + ; WARNING: Changing this mechanism also requires update in x86_64.cpp, when deciding if we should re-enable interrupts on exception. + mov rax,0 + mov cr8,rax + sti ; TODO Where is this necessary? Is is a performance issue? + ret + +[global ProcessorAreInterruptsEnabled] +ProcessorAreInterruptsEnabled: + pushf + pop rax + and rax,0x200 + shr rax,9 + + mov rdx,cr8 + cmp rdx,0 + je .done + mov rax,0 + .done: + + ; pushf + ; pop rax + ; and rax,0x200 + ; shr rax,9 + ret + +[global ProcessorHalt] +ProcessorHalt: + cli + hlt + jmp ProcessorHalt + +[global ProcessorOut8] +ProcessorOut8: + mov rdx,rdi + mov rax,rsi + out dx,al + ret + +[global ProcessorIn8] +ProcessorIn8: + mov rdx,rdi + xor rax,rax + in al,dx + ret + +[global ProcessorOut16] +ProcessorOut16: + mov rdx,rdi + mov rax,rsi + out dx,ax + ret + +[global ProcessorIn16] +ProcessorIn16: + mov rdx,rdi + xor rax,rax + in ax,dx + ret + +[global ProcessorOut32] +ProcessorOut32: + mov rdx,rdi + mov rax,rsi + out dx,eax + ret + +[global ProcessorIn32] +ProcessorIn32: + mov rdx,rdi + xor rax,rax + in eax,dx + ret + +[global ProcessorInvalidatePage] +ProcessorInvalidatePage: + invlpg [rdi] + ret + +[global ProcessorInvalidateAllPages] +ProcessorInvalidateAllPages: + ; Toggle CR4.PGE to invalidate all TLB entries, including global entries. + mov rax,cr4 + and rax,~(1 << 7) + mov cr4,rax + or rax,1 << 7 + mov cr4,rax + ret + +[global ProcessorIdle] +ProcessorIdle: + sti + hlt + jmp ProcessorIdle + +[global GetLocalStorage] +GetLocalStorage: + mov rax,[gs:0] + ret + +[global GetCurrentThread] +GetCurrentThread: + mov rax,[gs:16] + ret + +[global ProcessorSetLocalStorage] +ProcessorSetLocalStorage: + mov [gs:0],rdi + ret + +[global ProcessorSetThreadStorage] +ProcessorSetThreadStorage: + push rdx + push rcx + mov rcx,0xC0000100 ; set fs base + mov rdx,rdi + mov rax,rdi + shr rdx,32 + wrmsr ; to edx:eax (from rdi) + pop rcx + pop rdx + ret + +InstallInterruptHandler: + mov word [rbx + 0],dx + mov word [rbx + 2],0x48 + mov word [rbx + 4],0x8E00 + shr rdx,16 + mov word [rbx + 6],dx + shr rdx,16 + mov qword [rbx + 8],rdx + + ret + +%macro INTERRUPT_HANDLER 1 +InterruptHandler%1: + push dword 0 ; A fake error code + push dword %1 ; The interrupt number + jmp ASMInterruptHandler +%endmacro + +%macro INTERRUPT_HANDLER_EC 1 +InterruptHandler%1: + ; The CPU already pushed an error code + push dword %1 ; The interrupt number + jmp ASMInterruptHandler +%endmacro + +INTERRUPT_HANDLER 0 +INTERRUPT_HANDLER 1 +INTERRUPT_HANDLER 2 +INTERRUPT_HANDLER 3 +INTERRUPT_HANDLER 4 +INTERRUPT_HANDLER 5 +INTERRUPT_HANDLER 6 +INTERRUPT_HANDLER 7 +INTERRUPT_HANDLER_EC 8 +INTERRUPT_HANDLER 9 +INTERRUPT_HANDLER_EC 10 +INTERRUPT_HANDLER_EC 11 +INTERRUPT_HANDLER_EC 12 +INTERRUPT_HANDLER_EC 13 +INTERRUPT_HANDLER_EC 14 +INTERRUPT_HANDLER 15 +INTERRUPT_HANDLER 16 +INTERRUPT_HANDLER_EC 17 +INTERRUPT_HANDLER 18 +INTERRUPT_HANDLER 19 +INTERRUPT_HANDLER 20 +INTERRUPT_HANDLER 21 +INTERRUPT_HANDLER 22 +INTERRUPT_HANDLER 23 +INTERRUPT_HANDLER 24 +INTERRUPT_HANDLER 25 +INTERRUPT_HANDLER 26 +INTERRUPT_HANDLER 27 +INTERRUPT_HANDLER 28 +INTERRUPT_HANDLER 29 +INTERRUPT_HANDLER 30 +INTERRUPT_HANDLER 31 + +%assign i 32 +%rep 224 +INTERRUPT_HANDLER i +%assign i i+1 +%endrep + +ASMInterruptHandler: + cld + + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + + mov rax,cr8 + push rax + + mov rax,0x123456789ABCDEF + push rax + + mov rbx,rsp + and rsp,~0xF + fxsave [rsp - 512] + mov rsp,rbx + sub rsp,512 + 16 + + xor rax,rax + mov ax,ds + push rax + mov ax,0x10 + mov ds,ax + mov es,ax + mov rax,cr2 + push rax + + mov rdi,rsp + mov rbx,rsp + and rsp,~0xF + extern InterruptHandler + call InterruptHandler + mov rsp,rbx + xor rax,rax + +ReturnFromInterruptHandler: + add rsp,8 + pop rbx + mov ds,bx + mov es,bx + + add rsp,512 + 16 + mov rbx,rsp + and rbx,~0xF + fxrstor [rbx - 512] + + cmp al,0 + je .oldThread + fninit ; New thread - initialise FPU. + .oldThread: + + pop rax + mov rbx,0x123456789ABCDEF + cmp rax,rbx + jne $ + + cli + pop rax + mov cr8,rax + + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax + + add rsp,16 + iretq + +[global ProcessorSetAddressSpace] +ProcessorSetAddressSpace: + mov rax,cr3 + cmp rax,rdi + je .cont + mov cr3,rdi + .cont: + ret + +[global ProcessorGetAddressSpace] +ProcessorGetAddressSpace: + mov rax,cr3 + ret + +[global ProcessorGetRSP] +ProcessorGetRSP: + mov rax,rsp + ret + +[global ProcessorGetRBP] +ProcessorGetRBP: + mov rax,rbp + ret + +[extern PostContextSwitch] +[global DoContextSwitch] +DoContextSwitch: + cli + mov [gs:16],rcx + mov [gs:8],rdx + mov rax,cr3 + cmp rax,rsi + je .cont + mov cr3,rsi + .cont: + mov rsp,rdi + call PostContextSwitch + jmp ReturnFromInterruptHandler + +[global ProcessorMagicBreakpoint] +ProcessorMagicBreakpoint: + xchg bx,bx +[global ProcessorBreakpointHelper] +ProcessorBreakpointHelper: + ret + +[global ProcessorReadCR3] +ProcessorReadCR3: + mov rax,cr3 + ret + +[global ArchSpeakerBeep] +ArchSpeakerBeep: + ; Beep!!! + mov rdi,0x43 + mov rsi,0xB6 + call ProcessorOut8 + mov rdi,0x42 + mov rsi,0x97 + call ProcessorOut8 + mov rdi,0x42 + mov rsi,0x0A + call ProcessorOut8 + mov rdi,0x61 + call ProcessorIn8 + mov rsi,rax + or rsi,3 + mov rdi,0x61 + call ProcessorOut8 + ret + +[global ProcessorDebugOutputByte] +ProcessorDebugOutputByte: +%ifdef COM_OUTPUT + mov dx,0x3F8 + 5 + .WaitRead: + in al,dx + and al,0x20 + cmp al,0 + je .WaitRead + mov dx,0x3F8 + 0 + mov rax,rdi + out dx,al +%endif + ret + +[global ProcessorReadTimeStamp] +ProcessorReadTimeStamp: + rdtsc + shl rdx,32 + or rax,rdx + ret + +[global ProcessorFlushCodeCache] +ProcessorFlushCodeCache: + wbinvd + ret + +[global ProcessorReadMXCSR] +ProcessorReadMXCSR: + mov rax,.buffer + stmxcsr [rax] + mov rax,.buffer + mov rax,[rax] + ret + .buffer: dq 0 + +[global ProcessorInstallTSS] +ProcessorInstallTSS: + push rbx + + ; Set the location of the TSS in the GDT. + mov rax,rdi + mov rbx,rsi + mov [rax + 56 + 2],bx + shr rbx,16 + mov [rax + 56 + 4],bl + shr rbx,8 + mov [rax + 56 + 7],bl + shr rbx,8 + mov [rax + 56 + 8],rbx + + ; Flush the GDT. + mov rax,gdt_data.gdt2 + mov rdx,[rax] + mov [rax],rdi + mov rdi,gdt_data.gdt + lgdt [rdi] + mov [rax],rdx + + ; Flush the TSS. + mov ax,0x38 + ltr ax + + pop rbx + ret + +[global ArchResetCPU] +ArchResetCPU: + in al,0x64 + test al,2 + jne ArchResetCPU + mov al,0xFE + out 0x64,al + jmp $ + +[global _KThreadTerminate] +[extern KThreadTerminate] +_KThreadTerminate: + sub rsp,8 + jmp KThreadTerminate + +SynchronizeTimeStampCounter: + mov rdx,[timeStampCounterSynchronizationValue] + mov rcx,0x8000000000000000 + .loop: + mov rbx,rdx + mov rax,[timeStampCounterSynchronizationValue] + xor rbx,rax + test rbx,rcx + jz .loop + sub rcx,1 + and rax,rcx + mov ecx,0x10 + mov rdx,rax + shr rdx,32 + wrmsr + ret +[global timeStampCounterSynchronizationValue] + timeStampCounterSynchronizationValue: dq 0 + +[global ProcessorAPStartup] +[bits 16] +ProcessorAPStartup: ; This function must be less than 4KB in length (see drivers/acpi.cpp) + mov ax,0x1000 + mov ds,ax + mov byte [0xFC0],1 ; Indicate we've started. + mov eax,[0xFF0] + mov cr3,eax + lgdt [0x1000 + gdt_data.gdt - gdt_data] + mov eax,cr0 + or eax,1 + mov cr0,eax + jmp 0x8:dword (.pmode - ProcessorAPStartup + 0x10000) +[bits 32] + .pmode: + mov eax,cr4 + or eax,32 + mov cr4,eax + mov ecx,0xC0000080 + rdmsr + or eax,256 + wrmsr + mov eax,cr0 + or eax,0x80000000 + mov cr0,eax + jmp 0x48:(.start_64_bit_mode - ProcessorAPStartup + 0x10000) +[bits 64] + .start_64_bit_mode: + mov rax,.start_64_bit_mode2 + jmp rax + .start_64_bit_mode2: + mov rax,0x50 + mov ds,rax + mov es,rax + mov ss,rax + mov rax,0x63 + mov fs,rax + mov gs,rax + lgdt [0x10FE0] + mov rsp,[0x10FD0] + call SetupProcessor1 + call SynchronizeTimeStampCounter + [extern SetupProcessor2] + mov rdi,[0x10FB0] + call SetupProcessor2 + mov byte [0x10FC0],2 ; Indicate the BSP can start the next processor. + and rsp,~0xF + jmp ProcessorReady + +[global gdt_data] +gdt_data: + .null_entry: dq 0 + .code_entry: dd 0xFFFF ; 0x08 + db 0 + dw 0xCF9A + db 0 + .data_entry: dd 0xFFFF ; 0x10 + db 0 + dw 0xCF92 + db 0 + .code_entry_16: dd 0xFFFF ; 0x18 + db 0 + dw 0x0F9A + db 0 + .data_entry_16: dd 0xFFFF ; 0x20 + db 0 + dw 0x0F92 + db 0 + .user_code: dd 0xFFFF ; 0x2B + db 0 + dw 0xCFFA + db 0 + .user_data: dd 0xFFFF ; 0x33 + db 0 + dw 0xCFF2 + db 0 + .tss: dd 0x68 ; 0x38 + db 0 + dw 0xE9 + db 0 + dq 0 + .code_entry64: dd 0xFFFF ; 0x48 + db 0 + dw 0xAF9A + db 0 + .data_entry64: dd 0xFFFF ; 0x50 + db 0 + dw 0xAF92 + db 0 + .user_code64: dd 0xFFFF ; 0x5B + db 0 + dw 0xAFFA + db 0 + .user_data64: dd 0xFFFF ; 0x63 + db 0 + dw 0xAFF2 + db 0 + .user_code64c: dd 0xFFFF ; 0x6B + db 0 + dw 0xAFFA + db 0 + .gdt: dw (gdt_data.gdt - gdt_data - 1) + .gdt2: dq 0x11000 + +%macro CALL_REGISTER_INDIRECT 1 +[global __x86_indirect_thunk_%1] +__x86_indirect_thunk_%1: + jmp %1 +%endmacro + +CALL_REGISTER_INDIRECT rax +CALL_REGISTER_INDIRECT rbx +CALL_REGISTER_INDIRECT rcx +CALL_REGISTER_INDIRECT rdx +CALL_REGISTER_INDIRECT rsi +CALL_REGISTER_INDIRECT rdi +CALL_REGISTER_INDIRECT rbp +CALL_REGISTER_INDIRECT r8 +CALL_REGISTER_INDIRECT r9 +CALL_REGISTER_INDIRECT r10 +CALL_REGISTER_INDIRECT r11 +CALL_REGISTER_INDIRECT r12 +CALL_REGISTER_INDIRECT r13 +CALL_REGISTER_INDIRECT r14 +CALL_REGISTER_INDIRECT r15 + +[global __cyg_profile_func_enter] +__cyg_profile_func_enter: + ret + +[global __cyg_profile_func_exit] +__cyg_profile_func_exit: + ret diff --git a/ports/acpica/build.sh b/ports/acpica/build.sh new file mode 100755 index 0000000..64005cb --- /dev/null +++ b/ports/acpica/build.sh @@ -0,0 +1,165 @@ +CC=x86_64-elf-gcc +CFLAGS=-I. -O0 -D_ACPICA_ESSENCE -D_GNU_SOURCE -std=c99 -Wall -Wextra -ffreestanding -mcmodel=large -g -Wno-unused-parameter -mno-red-zone + +$CC -c dsargs.c $CFLAGS +$CC -c dscontrol.c $CFLAGS +$CC -c dsdebug.c $CFLAGS +$CC -c dsfield.c $CFLAGS +$CC -c dsinit.c $CFLAGS +$CC -c dsmethod.c $CFLAGS +$CC -c dsmthdat.c $CFLAGS +$CC -c dsobject.c $CFLAGS +$CC -c dsopcode.c $CFLAGS +$CC -c dspkginit.c $CFLAGS +$CC -c dsutils.c $CFLAGS +$CC -c dswexec.c $CFLAGS +$CC -c dswload.c $CFLAGS +$CC -c dswload2.c $CFLAGS +$CC -c dswscope.c $CFLAGS +$CC -c dswstate.c $CFLAGS +$CC -c evevent.c $CFLAGS +$CC -c evglock.c $CFLAGS +$CC -c evgpe.c $CFLAGS +$CC -c evgpeblk.c $CFLAGS +$CC -c evgpeinit.c $CFLAGS +$CC -c evgpeutil.c $CFLAGS +$CC -c evhandler.c $CFLAGS +$CC -c evmisc.c $CFLAGS +$CC -c evregion.c $CFLAGS +$CC -c evrgnini.c $CFLAGS +$CC -c evsci.c $CFLAGS +$CC -c evxface.c $CFLAGS +$CC -c evxfevnt.c $CFLAGS +$CC -c evxfgpe.c $CFLAGS +$CC -c evxfregn.c $CFLAGS +$CC -c exconcat.c $CFLAGS +$CC -c exconfig.c $CFLAGS +$CC -c exconvrt.c $CFLAGS +$CC -c excreate.c $CFLAGS +$CC -c exdebug.c $CFLAGS +$CC -c exdump.c $CFLAGS +$CC -c exfield.c $CFLAGS +$CC -c exfldio.c $CFLAGS +$CC -c exmisc.c $CFLAGS +$CC -c exmutex.c $CFLAGS +$CC -c exnames.c $CFLAGS +$CC -c exoparg1.c $CFLAGS +$CC -c exoparg2.c $CFLAGS +$CC -c exoparg3.c $CFLAGS +$CC -c exoparg6.c $CFLAGS +$CC -c exprep.c $CFLAGS +$CC -c exregion.c $CFLAGS +$CC -c exresnte.c $CFLAGS +$CC -c exresolv.c $CFLAGS +$CC -c exresop.c $CFLAGS +$CC -c exstore.c $CFLAGS +$CC -c exstoren.c $CFLAGS +$CC -c exstorob.c $CFLAGS +$CC -c exsystem.c $CFLAGS +$CC -c extrace.c $CFLAGS +$CC -c exutils.c $CFLAGS +$CC -c hwacpi.c $CFLAGS +$CC -c hwesleep.c $CFLAGS +$CC -c hwgpe.c $CFLAGS +$CC -c hwpci.c $CFLAGS +$CC -c hwregs.c $CFLAGS +$CC -c hwsleep.c $CFLAGS +$CC -c hwtimer.c $CFLAGS +$CC -c hwvalid.c $CFLAGS +$CC -c hwxface.c $CFLAGS +$CC -c hwxfsleep.c $CFLAGS +$CC -c nsaccess.c $CFLAGS +$CC -c nsalloc.c $CFLAGS +$CC -c nsarguments.c $CFLAGS +$CC -c nsconvert.c $CFLAGS +$CC -c nsdump.c $CFLAGS +$CC -c nsdumpdv.c $CFLAGS +$CC -c nseval.c $CFLAGS +$CC -c nsinit.c $CFLAGS +$CC -c nsload.c $CFLAGS +$CC -c nsnames.c $CFLAGS +$CC -c nsobject.c $CFLAGS +$CC -c nsparse.c $CFLAGS +$CC -c nspredef.c $CFLAGS +$CC -c nsprepkg.c $CFLAGS +$CC -c nsrepair.c $CFLAGS +$CC -c nsrepair2.c $CFLAGS +$CC -c nssearch.c $CFLAGS +$CC -c nsutils.c $CFLAGS +$CC -c nswalk.c $CFLAGS +$CC -c nsxfeval.c $CFLAGS +$CC -c nsxfname.c $CFLAGS +$CC -c nsxfobj.c $CFLAGS +$CC -c psargs.c $CFLAGS +$CC -c psloop.c $CFLAGS +$CC -c psobject.c $CFLAGS +$CC -c psopcode.c $CFLAGS +$CC -c psopinfo.c $CFLAGS +$CC -c psparse.c $CFLAGS +$CC -c psscope.c $CFLAGS +$CC -c pstree.c $CFLAGS +$CC -c psutils.c $CFLAGS +$CC -c pswalk.c $CFLAGS +$CC -c psxface.c $CFLAGS +$CC -c rsaddr.c $CFLAGS +$CC -c rscalc.c $CFLAGS +$CC -c rscreate.c $CFLAGS +$CC -c rsinfo.c $CFLAGS +$CC -c rsio.c $CFLAGS +$CC -c rsirq.c $CFLAGS +$CC -c rslist.c $CFLAGS +$CC -c rsmemory.c $CFLAGS +$CC -c rsmisc.c $CFLAGS +$CC -c rsserial.c $CFLAGS +$CC -c rsutils.c $CFLAGS +$CC -c rsxface.c $CFLAGS +$CC -c tbdata.c $CFLAGS +$CC -c tbfadt.c $CFLAGS +$CC -c tbfind.c $CFLAGS +$CC -c tbinstal.c $CFLAGS +$CC -c tbprint.c $CFLAGS +$CC -c tbutils.c $CFLAGS +$CC -c tbxface.c $CFLAGS +$CC -c tbxfload.c $CFLAGS +$CC -c tbxfroot.c $CFLAGS +$CC -c utaddress.c $CFLAGS +$CC -c utalloc.c $CFLAGS +$CC -c utascii.c $CFLAGS +$CC -c utbuffer.c $CFLAGS +$CC -c utcache.c $CFLAGS +$CC -c utclib.c $CFLAGS +$CC -c utcopy.c $CFLAGS +$CC -c utdebug.c $CFLAGS +$CC -c utdecode.c $CFLAGS +$CC -c utdelete.c $CFLAGS +$CC -c uterror.c $CFLAGS +$CC -c uteval.c $CFLAGS +$CC -c utexcep.c $CFLAGS +$CC -c utglobal.c $CFLAGS +$CC -c uthex.c $CFLAGS +$CC -c utids.c $CFLAGS +$CC -c utinit.c $CFLAGS +$CC -c utlock.c $CFLAGS +$CC -c utmath.c $CFLAGS +$CC -c utmisc.c $CFLAGS +$CC -c utmutex.c $CFLAGS +$CC -c utnonansi.c $CFLAGS +$CC -c utobject.c $CFLAGS +$CC -c utosi.c $CFLAGS +$CC -c utownerid.c $CFLAGS +$CC -c utpredef.c $CFLAGS +$CC -c utprint.c $CFLAGS +$CC -c utresdecode.c $CFLAGS +$CC -c utresrc.c $CFLAGS +$CC -c utstate.c $CFLAGS +$CC -c utstring.c $CFLAGS +$CC -c utstrsuppt.c $CFLAGS +$CC -c utstrtoul64.c $CFLAGS +$CC -c uttrack.c $CFLAGS +$CC -c utuuid.c $CFLAGS +$CC -c utxface.c $CFLAGS +$CC -c utxferror.c $CFLAGS +$CC -c utxfinit.c $CFLAGS +$CC -c utxfmutex.c $CFLAGS + +x86_64-elf-ar -rcs libacpica.a dsargs.o dscontrol.o dsdebug.o dsfield.o dsinit.o dsmethod.o dsmthdat.o dsobject.o dsopcode.o dspkginit.o dsutils.o dswexec.o dswload.o dswload2.o dswscope.o dswstate.o evevent.o evglock.o evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o evhandler.o evmisc.o evregion.o evrgnini.o evsci.o evxface.o evxfevnt.o evxfgpe.o evxfregn.o exconcat.o exconfig.o exconvrt.o excreate.o exdebug.o exdump.o exfield.o exfldio.o exmisc.o exmutex.o exnames.o exoparg1.o exoparg2.o exoparg3.o exoparg6.o exprep.o exregion.o exresnte.o exresolv.o exresop.o exstore.o exstoren.o exstorob.o exsystem.o extrace.o exutils.o hwacpi.o hwesleep.o hwgpe.o hwpci.o hwregs.o hwsleep.o hwtimer.o hwvalid.o hwxface.o hwxfsleep.o nsaccess.o nsalloc.o nsarguments.o nsconvert.o nsdump.o nsdumpdv.o nseval.o nsinit.o nsload.o nsnames.o nsobject.o nsparse.o nspredef.o nsprepkg.o nsrepair.o nsrepair2.o nssearch.o nsutils.o nswalk.o nsxfeval.o nsxfname.o nsxfobj.o psargs.o psloop.o psobject.o psopcode.o psopinfo.o psparse.o psscope.o pstree.o psutils.o pswalk.o psxface.o rsaddr.o rscalc.o rscreate.o rsinfo.o rsio.o rsirq.o rslist.o rsmemory.o rsmisc.o rsserial.o rsutils.o rsxface.o tbdata.o tbfadt.o tbfind.o tbinstal.o tbprint.o tbutils.o tbxface.o tbxfload.o tbxfroot.o utaddress.o utalloc.o utascii.o utbuffer.o utcache.o utclib.o utcopy.o utdebug.o utdecode.o utdelete.o uterror.o uteval.o utexcep.o utglobal.o uthex.o utids.o utinit.o utlock.o utmath.o utmisc.o utmutex.o utnonansi.o utobject.o utosi.o utownerid.o utpredef.o utprint.o utresdecode.o utresrc.o utstate.o utstring.o utstrsuppt.o utstrtoul64.o uttrack.o utuuid.o utxface.o utxferror.o utxfinit.o utxfmutex.o diff --git a/ports/acpica/include/acapps.h b/ports/acpica/include/acapps.h new file mode 100644 index 0000000..dcaebd7 --- /dev/null +++ b/ports/acpica/include/acapps.h @@ -0,0 +1,343 @@ +/****************************************************************************** + * + * Module Name: acapps - common include for ACPI applications/tools + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef _ACAPPS +#define _ACAPPS + +#ifdef ACPI_USE_STANDARD_HEADERS +#include +#endif /* ACPI_USE_STANDARD_HEADERS */ + +/* Common info for tool signons */ + +#define ACPICA_NAME "Intel ACPI Component Architecture" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2018 Intel Corporation" + +#if ACPI_MACHINE_WIDTH == 64 +#define ACPI_WIDTH " (64-bit version)" + +#elif ACPI_MACHINE_WIDTH == 32 +#define ACPI_WIDTH " (32-bit version)" + +#else +#error unknown ACPI_MACHINE_WIDTH +#define ACPI_WIDTH " (unknown bit width, not 32 or 64)" + +#endif + +/* Macros for signons and file headers */ + +#define ACPI_COMMON_SIGNON(UtilityName) \ + "\n%s\n%s version %8.8X\n%s\n\n", \ + ACPICA_NAME, \ + UtilityName, ((UINT32) ACPI_CA_VERSION), \ + ACPICA_COPYRIGHT + +#define ACPI_COMMON_HEADER(UtilityName, Prefix) \ + "%s%s\n%s%s version %8.8X%s\n%s%s\n%s\n", \ + Prefix, ACPICA_NAME, \ + Prefix, UtilityName, ((UINT32) ACPI_CA_VERSION), ACPI_WIDTH, \ + Prefix, ACPICA_COPYRIGHT, \ + Prefix + +#define ACPI_COMMON_BUILD_TIME \ + "Build date/time: %s %s\n", __DATE__, __TIME__ + +/* Macros for usage messages */ + +#define ACPI_USAGE_HEADER(Usage) \ + printf ("Usage: %s\nOptions:\n", Usage); + +#define ACPI_USAGE_TEXT(Description) \ + printf (Description); + +#define ACPI_OPTION(Name, Description) \ + printf (" %-20s%s\n", Name, Description); + + +/* Check for unexpected exceptions */ + +#define ACPI_CHECK_STATUS(Name, Status, Expected) \ + if (Status != Expected) \ + { \ + AcpiOsPrintf ("Unexpected %s from %s (%s-%d)\n", \ + AcpiFormatException (Status), #Name, _AcpiModuleName, __LINE__); \ + } + +/* Check for unexpected non-AE_OK errors */ + + +#define ACPI_CHECK_OK(Name, Status) ACPI_CHECK_STATUS (Name, Status, AE_OK); + +#define FILE_SUFFIX_DISASSEMBLY "dsl" +#define FILE_SUFFIX_BINARY_TABLE ".dat" /* Needs the dot */ + + +/* acfileio */ + +ACPI_STATUS +AcGetAllTablesFromFile ( + char *Filename, + UINT8 GetOnlyAmlTables, + ACPI_NEW_TABLE_DESC **ReturnListHead); + +void +AcDeleteTableList ( + ACPI_NEW_TABLE_DESC *ListHead); + +BOOLEAN +AcIsFileBinary ( + FILE *File); + +ACPI_STATUS +AcValidateTableHeader ( + FILE *File, + long TableOffset); + + +/* Values for GetOnlyAmlTables */ + +#define ACPI_GET_ONLY_AML_TABLES TRUE +#define ACPI_GET_ALL_TABLES FALSE + + +/* + * getopt + */ +int +AcpiGetopt( + int argc, + char **argv, + char *opts); + +int +AcpiGetoptArgument ( + int argc, + char **argv); + +extern int AcpiGbl_Optind; +extern int AcpiGbl_Opterr; +extern int AcpiGbl_SubOptChar; +extern char *AcpiGbl_Optarg; + + +/* + * cmfsize - Common get file size function + */ +UINT32 +CmGetFileSize ( + ACPI_FILE File); + + +/* + * adwalk + */ +void +AcpiDmCrossReferenceNamespace ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot, + ACPI_OWNER_ID OwnerId); + +void +AcpiDmDumpTree ( + ACPI_PARSE_OBJECT *Origin); + +void +AcpiDmFindOrphanMethods ( + ACPI_PARSE_OBJECT *Origin); + +void +AcpiDmFinishNamespaceLoad ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot, + ACPI_OWNER_ID OwnerId); + +void +AcpiDmConvertParseObjects ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot); + + +/* + * adfile + */ +ACPI_STATUS +AdInitialize ( + void); + +char * +FlGenerateFilename ( + char *InputFilename, + char *Suffix); + +ACPI_STATUS +FlSplitInputPathname ( + char *InputPath, + char **OutDirectoryPath, + char **OutFilename); + +char * +FlGetFileBasename ( + char *FilePathname); + +char * +AdGenerateFilename ( + char *Prefix, + char *TableId); + +void +AdWriteTable ( + ACPI_TABLE_HEADER *Table, + UINT32 Length, + char *TableName, + char *OemTableId); + +#endif /* _ACAPPS */ diff --git a/ports/acpica/include/acbuffer.h b/ports/acpica/include/acbuffer.h new file mode 100644 index 0000000..857d8bc --- /dev/null +++ b/ports/acpica/include/acbuffer.h @@ -0,0 +1,363 @@ +/****************************************************************************** + * + * Name: acbuffer.h - Support for buffers returned by ACPI predefined names + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACBUFFER_H__ +#define __ACBUFFER_H__ + +/* + * Contains buffer structures for these predefined names: + * _FDE, _GRT, _GTM, _PLD, _SRT + */ + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/* _FDE return value */ + +typedef struct acpi_fde_info +{ + UINT32 Floppy0; + UINT32 Floppy1; + UINT32 Floppy2; + UINT32 Floppy3; + UINT32 Tape; + +} ACPI_FDE_INFO; + +/* + * _GRT return value + * _SRT input value + */ +typedef struct acpi_grt_info +{ + UINT16 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 Valid; + UINT16 Milliseconds; + UINT16 Timezone; + UINT8 Daylight; + UINT8 Reserved[3]; + +} ACPI_GRT_INFO; + +/* _GTM return value */ + +typedef struct acpi_gtm_info +{ + UINT32 PioSpeed0; + UINT32 DmaSpeed0; + UINT32 PioSpeed1; + UINT32 DmaSpeed1; + UINT32 Flags; + +} ACPI_GTM_INFO; + +/* + * Formatted _PLD return value. The minimum size is a package containing + * one buffer. + * Revision 1: Buffer is 16 bytes (128 bits) + * Revision 2: Buffer is 20 bytes (160 bits) + * + * Note: This structure is returned from the AcpiDecodePldBuffer + * interface. + */ +typedef struct acpi_pld_info +{ + UINT8 Revision; + UINT8 IgnoreColor; + UINT8 Red; + UINT8 Green; + UINT8 Blue; + UINT16 Width; + UINT16 Height; + UINT8 UserVisible; + UINT8 Dock; + UINT8 Lid; + UINT8 Panel; + UINT8 VerticalPosition; + UINT8 HorizontalPosition; + UINT8 Shape; + UINT8 GroupOrientation; + UINT8 GroupToken; + UINT8 GroupPosition; + UINT8 Bay; + UINT8 Ejectable; + UINT8 OspmEjectRequired; + UINT8 CabinetNumber; + UINT8 CardCageNumber; + UINT8 Reference; + UINT8 Rotation; + UINT8 Order; + UINT8 Reserved; + UINT16 VerticalOffset; + UINT16 HorizontalOffset; + +} ACPI_PLD_INFO; + + +/* + * Macros to: + * 1) Convert a _PLD buffer to internal ACPI_PLD_INFO format - ACPI_PLD_GET* + * (Used by AcpiDecodePldBuffer) + * 2) Construct a _PLD buffer - ACPI_PLD_SET* + * (Intended for BIOS use only) + */ +#define ACPI_PLD_REV1_BUFFER_SIZE 16 /* For Revision 1 of the buffer (From ACPI spec) */ +#define ACPI_PLD_REV2_BUFFER_SIZE 20 /* For Revision 2 of the buffer (From ACPI spec) */ +#define ACPI_PLD_BUFFER_SIZE 20 /* For Revision 2 of the buffer (From ACPI spec) */ + +/* First 32-bit dword, bits 0:32 */ + +#define ACPI_PLD_GET_REVISION(dword) ACPI_GET_BITS (dword, 0, ACPI_7BIT_MASK) +#define ACPI_PLD_SET_REVISION(dword,value) ACPI_SET_BITS (dword, 0, ACPI_7BIT_MASK, value) /* Offset 0, Len 7 */ + +#define ACPI_PLD_GET_IGNORE_COLOR(dword) ACPI_GET_BITS (dword, 7, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_IGNORE_COLOR(dword,value) ACPI_SET_BITS (dword, 7, ACPI_1BIT_MASK, value) /* Offset 7, Len 1 */ + +#define ACPI_PLD_GET_RED(dword) ACPI_GET_BITS (dword, 8, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_RED(dword,value) ACPI_SET_BITS (dword, 8, ACPI_8BIT_MASK, value) /* Offset 8, Len 8 */ + +#define ACPI_PLD_GET_GREEN(dword) ACPI_GET_BITS (dword, 16, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_GREEN(dword,value) ACPI_SET_BITS (dword, 16, ACPI_8BIT_MASK, value) /* Offset 16, Len 8 */ + +#define ACPI_PLD_GET_BLUE(dword) ACPI_GET_BITS (dword, 24, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_BLUE(dword,value) ACPI_SET_BITS (dword, 24, ACPI_8BIT_MASK, value) /* Offset 24, Len 8 */ + +/* Second 32-bit dword, bits 33:63 */ + +#define ACPI_PLD_GET_WIDTH(dword) ACPI_GET_BITS (dword, 0, ACPI_16BIT_MASK) +#define ACPI_PLD_SET_WIDTH(dword,value) ACPI_SET_BITS (dword, 0, ACPI_16BIT_MASK, value) /* Offset 32+0=32, Len 16 */ + +#define ACPI_PLD_GET_HEIGHT(dword) ACPI_GET_BITS (dword, 16, ACPI_16BIT_MASK) +#define ACPI_PLD_SET_HEIGHT(dword,value) ACPI_SET_BITS (dword, 16, ACPI_16BIT_MASK, value) /* Offset 32+16=48, Len 16 */ + +/* Third 32-bit dword, bits 64:95 */ + +#define ACPI_PLD_GET_USER_VISIBLE(dword) ACPI_GET_BITS (dword, 0, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_USER_VISIBLE(dword,value) ACPI_SET_BITS (dword, 0, ACPI_1BIT_MASK, value) /* Offset 64+0=64, Len 1 */ + +#define ACPI_PLD_GET_DOCK(dword) ACPI_GET_BITS (dword, 1, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_DOCK(dword,value) ACPI_SET_BITS (dword, 1, ACPI_1BIT_MASK, value) /* Offset 64+1=65, Len 1 */ + +#define ACPI_PLD_GET_LID(dword) ACPI_GET_BITS (dword, 2, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_LID(dword,value) ACPI_SET_BITS (dword, 2, ACPI_1BIT_MASK, value) /* Offset 64+2=66, Len 1 */ + +#define ACPI_PLD_GET_PANEL(dword) ACPI_GET_BITS (dword, 3, ACPI_3BIT_MASK) +#define ACPI_PLD_SET_PANEL(dword,value) ACPI_SET_BITS (dword, 3, ACPI_3BIT_MASK, value) /* Offset 64+3=67, Len 3 */ + +#define ACPI_PLD_GET_VERTICAL(dword) ACPI_GET_BITS (dword, 6, ACPI_2BIT_MASK) +#define ACPI_PLD_SET_VERTICAL(dword,value) ACPI_SET_BITS (dword, 6, ACPI_2BIT_MASK, value) /* Offset 64+6=70, Len 2 */ + +#define ACPI_PLD_GET_HORIZONTAL(dword) ACPI_GET_BITS (dword, 8, ACPI_2BIT_MASK) +#define ACPI_PLD_SET_HORIZONTAL(dword,value) ACPI_SET_BITS (dword, 8, ACPI_2BIT_MASK, value) /* Offset 64+8=72, Len 2 */ + +#define ACPI_PLD_GET_SHAPE(dword) ACPI_GET_BITS (dword, 10, ACPI_4BIT_MASK) +#define ACPI_PLD_SET_SHAPE(dword,value) ACPI_SET_BITS (dword, 10, ACPI_4BIT_MASK, value) /* Offset 64+10=74, Len 4 */ + +#define ACPI_PLD_GET_ORIENTATION(dword) ACPI_GET_BITS (dword, 14, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_ORIENTATION(dword,value) ACPI_SET_BITS (dword, 14, ACPI_1BIT_MASK, value) /* Offset 64+14=78, Len 1 */ + +#define ACPI_PLD_GET_TOKEN(dword) ACPI_GET_BITS (dword, 15, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_TOKEN(dword,value) ACPI_SET_BITS (dword, 15, ACPI_8BIT_MASK, value) /* Offset 64+15=79, Len 8 */ + +#define ACPI_PLD_GET_POSITION(dword) ACPI_GET_BITS (dword, 23, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_POSITION(dword,value) ACPI_SET_BITS (dword, 23, ACPI_8BIT_MASK, value) /* Offset 64+23=87, Len 8 */ + +#define ACPI_PLD_GET_BAY(dword) ACPI_GET_BITS (dword, 31, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_BAY(dword,value) ACPI_SET_BITS (dword, 31, ACPI_1BIT_MASK, value) /* Offset 64+31=95, Len 1 */ + +/* Fourth 32-bit dword, bits 96:127 */ + +#define ACPI_PLD_GET_EJECTABLE(dword) ACPI_GET_BITS (dword, 0, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_EJECTABLE(dword,value) ACPI_SET_BITS (dword, 0, ACPI_1BIT_MASK, value) /* Offset 96+0=96, Len 1 */ + +#define ACPI_PLD_GET_OSPM_EJECT(dword) ACPI_GET_BITS (dword, 1, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_OSPM_EJECT(dword,value) ACPI_SET_BITS (dword, 1, ACPI_1BIT_MASK, value) /* Offset 96+1=97, Len 1 */ + +#define ACPI_PLD_GET_CABINET(dword) ACPI_GET_BITS (dword, 2, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_CABINET(dword,value) ACPI_SET_BITS (dword, 2, ACPI_8BIT_MASK, value) /* Offset 96+2=98, Len 8 */ + +#define ACPI_PLD_GET_CARD_CAGE(dword) ACPI_GET_BITS (dword, 10, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_CARD_CAGE(dword,value) ACPI_SET_BITS (dword, 10, ACPI_8BIT_MASK, value) /* Offset 96+10=106, Len 8 */ + +#define ACPI_PLD_GET_REFERENCE(dword) ACPI_GET_BITS (dword, 18, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_REFERENCE(dword,value) ACPI_SET_BITS (dword, 18, ACPI_1BIT_MASK, value) /* Offset 96+18=114, Len 1 */ + +#define ACPI_PLD_GET_ROTATION(dword) ACPI_GET_BITS (dword, 19, ACPI_4BIT_MASK) +#define ACPI_PLD_SET_ROTATION(dword,value) ACPI_SET_BITS (dword, 19, ACPI_4BIT_MASK, value) /* Offset 96+19=115, Len 4 */ + +#define ACPI_PLD_GET_ORDER(dword) ACPI_GET_BITS (dword, 23, ACPI_5BIT_MASK) +#define ACPI_PLD_SET_ORDER(dword,value) ACPI_SET_BITS (dword, 23, ACPI_5BIT_MASK, value) /* Offset 96+23=119, Len 5 */ + +/* Fifth 32-bit dword, bits 128:159 (Revision 2 of _PLD only) */ + +#define ACPI_PLD_GET_VERT_OFFSET(dword) ACPI_GET_BITS (dword, 0, ACPI_16BIT_MASK) +#define ACPI_PLD_SET_VERT_OFFSET(dword,value) ACPI_SET_BITS (dword, 0, ACPI_16BIT_MASK, value) /* Offset 128+0=128, Len 16 */ + +#define ACPI_PLD_GET_HORIZ_OFFSET(dword) ACPI_GET_BITS (dword, 16, ACPI_16BIT_MASK) +#define ACPI_PLD_SET_HORIZ_OFFSET(dword,value) ACPI_SET_BITS (dword, 16, ACPI_16BIT_MASK, value) /* Offset 128+16=144, Len 16 */ + + +#endif /* ACBUFFER_H */ diff --git a/ports/acpica/include/acclib.h b/ports/acpica/include/acclib.h new file mode 100644 index 0000000..7c4c9a2 --- /dev/null +++ b/ports/acpica/include/acclib.h @@ -0,0 +1,431 @@ +/****************************************************************************** + * + * Name: acclib.h -- C library support. Prototypes for the (optional) local + * implementations of required C library functions. + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef _ACCLIB_H +#define _ACCLIB_H + + +/* + * Prototypes and macros for local implementations of C library functions + */ + +/* is* functions. The AcpiGbl_Ctypes array is defined in utclib.c */ + +extern const UINT8 AcpiGbl_Ctypes[]; + +#define _ACPI_XA 0x00 /* extra alphabetic - not supported */ +#define _ACPI_XS 0x40 /* extra space */ +#define _ACPI_BB 0x00 /* BEL, BS, etc. - not supported */ +#define _ACPI_CN 0x20 /* CR, FF, HT, NL, VT */ +#define _ACPI_DI 0x04 /* '0'-'9' */ +#define _ACPI_LO 0x02 /* 'a'-'z' */ +#define _ACPI_PU 0x10 /* punctuation */ +#define _ACPI_SP 0x08 /* space, tab, CR, LF, VT, FF */ +#define _ACPI_UP 0x01 /* 'A'-'Z' */ +#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ + +#define isdigit(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_DI)) +#define isspace(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_SP)) +#define isxdigit(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_XD)) +#define isupper(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_UP)) +#define islower(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_LO)) +#define isprint(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_XS | _ACPI_PU)) +#define isalpha(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) + +/* Error code */ + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define EBADF 9 /* Bad file number */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define ENODEV 19 /* No such device */ +#define EINVAL 22 /* Invalid argument */ +#define EPIPE 32 /* Broken pipe */ +#define ERANGE 34 /* Math result not representable */ + +/* Strings */ + +char * +strcat ( + char *DstString, + const char *SrcString); + +char * +strchr ( + const char *String, + int ch); + +char * +strpbrk ( + const char *String, + const char *Delimiters); + +char * +strtok ( + char *String, + const char *Delimiters); + +char * +strcpy ( + char *DstString, + const char *SrcString); + +int +strcmp ( + const char *String1, + const char *String2); + +ACPI_SIZE +strlen ( + const char *String); + +char * +strncat ( + char *DstString, + const char *SrcString, + ACPI_SIZE Count); + +int +strncmp ( + const char *String1, + const char *String2, + ACPI_SIZE Count); + +char * +strncpy ( + char *DstString, + const char *SrcString, + ACPI_SIZE Count); + +char * +strstr ( + char *String1, + char *String2); + + +/* Conversion */ + +UINT32 +strtoul ( + const char *String, + char **Terminator, + UINT32 Base); + + +/* Memory */ + +int +memcmp ( + void *Buffer1, + void *Buffer2, + ACPI_SIZE Count); + +void * +memcpy ( + void *Dest, + const void *Src, + ACPI_SIZE Count); + +void * +memmove ( + void *Dest, + const void *Src, + ACPI_SIZE Count); + +void * +memset ( + void *Dest, + int Value, + ACPI_SIZE Count); + + +/* upper/lower case */ + +int +tolower ( + int c); + +int +toupper ( + int c); + +/* + * utprint - printf/vprintf output functions + */ +const char * +AcpiUtScanNumber ( + const char *String, + UINT64 *NumberPtr); + +const char * +AcpiUtPrintNumber ( + char *String, + UINT64 Number); + +int +vsnprintf ( + char *String, + ACPI_SIZE Size, + const char *Format, + va_list Args); + +int +snprintf ( + char *String, + ACPI_SIZE Size, + const char *Format, + ...); + +int +sprintf ( + char *String, + const char *Format, + ...); + +#ifdef ACPI_APPLICATION +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/* + * NOTE: Currently we only need to update errno for file IOs. Other + * Clibrary invocations in ACPICA do not make descisions according to + * the errno. + */ +extern int errno; + +#ifndef EOF +#define EOF (-1) +#endif + +#define putchar(c) fputc(stdout, c) +#define getchar(c) fgetc(stdin) + +int +vprintf ( + const char *Format, + va_list Args); + +int +printf ( + const char *Format, + ...); + +int +vfprintf ( + FILE *File, + const char *Format, + va_list Args); + +int +fprintf ( + FILE *File, + const char *Format, + ...); + +FILE * +fopen ( + const char *Path, + const char *Modes); + +void +fclose ( + FILE *File); + +int +fread ( + void *Buffer, + ACPI_SIZE Size, + ACPI_SIZE Count, + FILE *File); + +int +fwrite ( + void *Buffer, + ACPI_SIZE Size, + ACPI_SIZE Count, + FILE *File); + +int +fseek ( + FILE *File, + long Offset, + int From); + +long +ftell ( + FILE *File); + +int +fgetc ( + FILE *File); + +int +fputc ( + FILE *File, + char c); + +char * +fgets ( + char *s, + ACPI_SIZE Size, + FILE *File); +#endif + +#endif /* _ACCLIB_H */ diff --git a/ports/acpica/include/accommon.h b/ports/acpica/include/accommon.h new file mode 100644 index 0000000..357df16 --- /dev/null +++ b/ports/acpica/include/accommon.h @@ -0,0 +1,175 @@ +/****************************************************************************** + * + * Name: accommon.h - Common include files for generation of ACPICA source + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACCOMMON_H__ +#define __ACCOMMON_H__ + +/* + * Common set of includes for all ACPICA source files. + * We put them here because we don't want to duplicate them + * in the the source code again and again. + * + * Note: The order of these include files is important. + */ +#include "acconfig.h" /* Global configuration constants */ +#include "acmacros.h" /* C macros */ +#include "aclocal.h" /* Internal data types */ +#include "acobject.h" /* ACPI internal object */ +#include "acstruct.h" /* Common structures */ +#include "acglobal.h" /* All global variables */ +#include "achware.h" /* Hardware defines and interfaces */ +#include "acutils.h" /* Utility interfaces */ +#ifndef ACPI_USE_SYSTEM_CLIBRARY +#include "acclib.h" /* C library interfaces */ +#endif /* !ACPI_USE_SYSTEM_CLIBRARY */ + + +#endif /* __ACCOMMON_H__ */ diff --git a/ports/acpica/include/acconfig.h b/ports/acpica/include/acconfig.h new file mode 100644 index 0000000..c5a67ca --- /dev/null +++ b/ports/acpica/include/acconfig.h @@ -0,0 +1,365 @@ +/****************************************************************************** + * + * Name: acconfig.h - Global configuration constants + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef _ACCONFIG_H +#define _ACCONFIG_H + + +/****************************************************************************** + * + * Configuration options + * + *****************************************************************************/ + +/* + * ACPI_DEBUG_OUTPUT - This switch enables all the debug facilities of the + * ACPI subsystem. This includes the DEBUG_PRINT output + * statements. When disabled, all DEBUG_PRINT + * statements are compiled out. + * + * ACPI_APPLICATION - Use this switch if the subsystem is going to be run + * at the application level. + * + */ + +/* + * OS name, used for the _OS object. The _OS object is essentially obsolete, + * but there is a large base of ASL/AML code in existing machines that check + * for the string below. The use of this string usually guarantees that + * the ASL will execute down the most tested code path. Also, there is some + * code that will not execute the _OSI method unless _OS matches the string + * below. Therefore, change this string at your own risk. + */ +#define ACPI_OS_NAME "Microsoft Windows NT" + +/* Maximum objects in the various object caches */ + +#define ACPI_MAX_STATE_CACHE_DEPTH 96 /* State objects */ +#define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ +#define ACPI_MAX_EXTPARSE_CACHE_DEPTH 96 /* Parse tree objects */ +#define ACPI_MAX_OBJECT_CACHE_DEPTH 96 /* Interpreter operand objects */ +#define ACPI_MAX_NAMESPACE_CACHE_DEPTH 96 /* Namespace objects */ +#define ACPI_MAX_COMMENT_CACHE_DEPTH 96 /* Comments for the -ca option */ + +/* + * Should the subsystem abort the loading of an ACPI table if the + * table checksum is incorrect? + */ +#ifndef ACPI_CHECKSUM_ABORT +#define ACPI_CHECKSUM_ABORT FALSE +#endif + +/* + * Generate a version of ACPICA that only supports "reduced hardware" + * platforms (as defined in ACPI 5.0). Set to TRUE to generate a specialized + * version of ACPICA that ONLY supports the ACPI 5.0 "reduced hardware" + * model. In other words, no ACPI hardware is supported. + * + * If TRUE, this means no support for the following: + * PM Event and Control registers + * SCI interrupt (and handler) + * Fixed Events + * General Purpose Events (GPEs) + * Global Lock + * ACPI PM timer + * FACS table (Waking vectors and Global Lock) + */ +#ifndef ACPI_REDUCED_HARDWARE +#define ACPI_REDUCED_HARDWARE FALSE +#endif + + +/****************************************************************************** + * + * Subsystem Constants + * + *****************************************************************************/ + +/* Version of ACPI supported */ + +#define ACPI_CA_SUPPORT_LEVEL 5 + +/* Maximum count for a semaphore object */ + +#define ACPI_MAX_SEMAPHORE_COUNT 256 + +/* Maximum object reference count (detects object deletion issues) */ + +#define ACPI_MAX_REFERENCE_COUNT 0x800 + +/* Default page size for use in mapping memory for operation regions */ + +#define ACPI_DEFAULT_PAGE_SIZE 4096 /* Must be power of 2 */ + +/* OwnerId tracking. 8 entries allows for 255 OwnerIds */ + +#define ACPI_NUM_OWNERID_MASKS 8 + +/* Size of the root table array is increased by this increment */ + +#define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 + +/* Maximum sleep allowed via Sleep() operator */ + +#define ACPI_MAX_SLEEP 2000 /* 2000 millisec == two seconds */ + +/* Address Range lists are per-SpaceId (Memory and I/O only) */ + +#define ACPI_ADDRESS_RANGE_MAX 2 + +/* Maximum time (default 30s) of While() loops before abort */ + +#define ACPI_MAX_LOOP_TIMEOUT 30 + + +/****************************************************************************** + * + * ACPI Specification constants (Do not change unless the specification changes) + * + *****************************************************************************/ + +/* Method info (in WALK_STATE), containing local variables and argumetns */ + +#define ACPI_METHOD_NUM_LOCALS 8 +#define ACPI_METHOD_MAX_LOCAL 7 + +#define ACPI_METHOD_NUM_ARGS 7 +#define ACPI_METHOD_MAX_ARG 6 + +/* + * Operand Stack (in WALK_STATE), Must be large enough to contain METHOD_MAX_ARG + */ +#define ACPI_OBJ_NUM_OPERANDS 8 +#define ACPI_OBJ_MAX_OPERAND 7 + +/* Number of elements in the Result Stack frame, can be an arbitrary value */ + +#define ACPI_RESULTS_FRAME_OBJ_NUM 8 + +/* + * Maximal number of elements the Result Stack can contain, + * it may be an arbitray value not exceeding the types of + * ResultSize and ResultCount (now UINT8). + */ +#define ACPI_RESULTS_OBJ_NUM_MAX 255 + +/* Constants used in searching for the RSDP in low memory */ + +#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */ +#define ACPI_EBDA_PTR_LENGTH 2 +#define ACPI_EBDA_WINDOW_SIZE 1024 +#define ACPI_HI_RSDP_WINDOW_BASE 0x000E0000 /* Physical Address */ +#define ACPI_HI_RSDP_WINDOW_SIZE 0x00020000 +#define ACPI_RSDP_SCAN_STEP 16 + +/* Operation regions */ + +#define ACPI_USER_REGION_BEGIN 0x80 + +/* Maximum SpaceIds for Operation Regions */ + +#define ACPI_MAX_ADDRESS_SPACE 255 +#define ACPI_NUM_DEFAULT_SPACES 4 + +/* Array sizes. Used for range checking also */ + +#define ACPI_MAX_MATCH_OPCODE 5 + +/* RSDP checksums */ + +#define ACPI_RSDP_CHECKSUM_LENGTH 20 +#define ACPI_RSDP_XCHECKSUM_LENGTH 36 + +/* SMBus, GSBus and IPMI bidirectional buffer size */ + +#define ACPI_SMBUS_BUFFER_SIZE 34 +#define ACPI_GSBUS_BUFFER_SIZE 34 +#define ACPI_IPMI_BUFFER_SIZE 66 + +/* _SxD and _SxW control methods */ + +#define ACPI_NUM_SxD_METHODS 4 +#define ACPI_NUM_SxW_METHODS 5 + + +/****************************************************************************** + * + * Miscellaneous constants + * + *****************************************************************************/ + +/* UUID constants */ + +#define UUID_BUFFER_LENGTH 16 /* Length of UUID in memory */ +#define UUID_STRING_LENGTH 36 /* Total length of a UUID string */ + +/* Positions for required hyphens (dashes) in UUID strings */ + +#define UUID_HYPHEN1_OFFSET 8 +#define UUID_HYPHEN2_OFFSET 13 +#define UUID_HYPHEN3_OFFSET 18 +#define UUID_HYPHEN4_OFFSET 23 + + +/****************************************************************************** + * + * ACPI AML Debugger + * + *****************************************************************************/ + +#define ACPI_DEBUGGER_MAX_ARGS ACPI_METHOD_NUM_ARGS + 4 /* Max command line arguments */ +#define ACPI_DB_LINE_BUFFER_SIZE 512 + +#define ACPI_DEBUGGER_COMMAND_PROMPT '-' +#define ACPI_DEBUGGER_EXECUTE_PROMPT '%' + + +#endif /* _ACCONFIG_H */ diff --git a/ports/acpica/include/acconvert.h b/ports/acpica/include/acconvert.h new file mode 100644 index 0000000..cdefc68 --- /dev/null +++ b/ports/acpica/include/acconvert.h @@ -0,0 +1,312 @@ +/****************************************************************************** + * + * Module Name: acapps - common include for ACPI applications/tools + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef _ACCONVERT +#define _ACCONVERT + +/* Definitions for comment state */ + +#define ASL_COMMENT_STANDARD 1 +#define ASLCOMMENT_INLINE 2 +#define ASL_COMMENT_OPEN_PAREN 3 +#define ASL_COMMENT_CLOSE_PAREN 4 +#define ASL_COMMENT_CLOSE_BRACE 5 + +/* Definitions for comment print function*/ + +#define AML_COMMENT_STANDARD 1 +#define AMLCOMMENT_INLINE 2 +#define AML_COMMENT_END_NODE 3 +#define AML_NAMECOMMENT 4 +#define AML_COMMENT_CLOSE_BRACE 5 +#define AML_COMMENT_ENDBLK 6 +#define AML_COMMENT_INCLUDE 7 + + +#ifdef ACPI_ASL_COMPILER +/* + * cvcompiler + */ +void +CvProcessComment ( + ASL_COMMENT_STATE CurrentState, + char *StringBuffer, + int c1); + +void +CvProcessCommentType2 ( + ASL_COMMENT_STATE CurrentState, + char *StringBuffer); + +UINT32 +CvCalculateCommentLengths( + ACPI_PARSE_OBJECT *Op); + +void +CvProcessCommentState ( + char input); + +char* +CvAppendInlineComment ( + char *InlineComment, + char *ToAdd); + +void +CvAddToCommentList ( + char* ToAdd); + +void +CvPlaceComment ( + UINT8 Type, + char *CommentString); + +UINT32 +CvParseOpBlockType ( + ACPI_PARSE_OBJECT *Op); + +ACPI_COMMENT_NODE* +CvCommentNodeCalloc ( + void); + +void +CgWriteAmlDefBlockComment ( + ACPI_PARSE_OBJECT *Op); + +void +CgWriteOneAmlComment ( + ACPI_PARSE_OBJECT *Op, + char* CommentToPrint, + UINT8 InputOption); + +void +CgWriteAmlComment ( + ACPI_PARSE_OBJECT *Op); + + +/* + * cvparser + */ +void +CvInitFileTree ( + ACPI_TABLE_HEADER *Table, + UINT8 *AmlStart, + UINT32 AmlLength); + +void +CvClearOpComments ( + ACPI_PARSE_OBJECT *Op); + +ACPI_FILE_NODE* +CvFilenameExists ( + char *Filename, + ACPI_FILE_NODE *Head); + +void +CvLabelFileNode ( + ACPI_PARSE_OBJECT *Op); + +void +CvCaptureListComments ( + ACPI_PARSE_STATE *ParserState, + ACPI_COMMENT_NODE *ListHead, + ACPI_COMMENT_NODE *ListTail); + +void +CvCaptureCommentsOnly ( + ACPI_PARSE_STATE *ParserState); + +void +CvCaptureComments ( + ACPI_WALK_STATE *WalkState); + +void +CvTransferComments ( + ACPI_PARSE_OBJECT *Op); + +/* + * cvdisasm + */ +void +CvSwitchFiles ( + UINT32 level, + ACPI_PARSE_OBJECT *op); + +BOOLEAN +CvFileHasSwitched ( + ACPI_PARSE_OBJECT *Op); + + +void +CvCloseParenWriteComment ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level); + +void +CvCloseBraceWriteComment ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level); + +void +CvPrintOneCommentList ( + ACPI_COMMENT_NODE *CommentList, + UINT32 Level); + +void +CvPrintOneCommentType ( + ACPI_PARSE_OBJECT *Op, + UINT8 CommentType, + char* EndStr, + UINT32 Level); + + +#endif + +#endif /* _ACCONVERT */ diff --git a/ports/acpica/include/acdebug.h b/ports/acpica/include/acdebug.h new file mode 100644 index 0000000..51a85f3 --- /dev/null +++ b/ports/acpica/include/acdebug.h @@ -0,0 +1,611 @@ +/****************************************************************************** + * + * Name: acdebug.h - ACPI/AML debugger + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACDEBUG_H__ +#define __ACDEBUG_H__ + +/* The debugger is used in conjunction with the disassembler most of time */ + +#ifdef ACPI_DISASSEMBLER +#include "acdisasm.h" +#endif + + +#define ACPI_DEBUG_BUFFER_SIZE 0x4000 /* 16K buffer for return objects */ + +typedef struct acpi_db_command_info +{ + const char *Name; /* Command Name */ + UINT8 MinArgs; /* Minimum arguments required */ + +} ACPI_DB_COMMAND_INFO; + +typedef struct acpi_db_command_help +{ + UINT8 LineCount; /* Number of help lines */ + char *Invocation; /* Command Invocation */ + char *Description; /* Command Description */ + +} ACPI_DB_COMMAND_HELP; + +typedef struct acpi_db_argument_info +{ + const char *Name; /* Argument Name */ + +} ACPI_DB_ARGUMENT_INFO; + +typedef struct acpi_db_execute_walk +{ + UINT32 Count; + UINT32 MaxCount; + +} ACPI_DB_EXECUTE_WALK; + + +#define PARAM_LIST(pl) pl + +#define EX_NO_SINGLE_STEP 1 +#define EX_SINGLE_STEP 2 + + +/* + * dbxface - external debugger interfaces + */ +ACPI_DBR_DEPENDENT_RETURN_OK ( +ACPI_STATUS +AcpiDbSingleStep ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT32 OpType)) + +ACPI_DBR_DEPENDENT_RETURN_VOID ( +void +AcpiDbSignalBreakPoint ( + ACPI_WALK_STATE *WalkState)) + + +/* + * dbcmds - debug commands and output routines + */ +ACPI_NAMESPACE_NODE * +AcpiDbConvertToNode ( + char *InString); + +void +AcpiDbDisplayTableInfo ( + char *TableArg); + +void +AcpiDbDisplayTemplate ( + char *BufferArg); + +void +AcpiDbUnloadAcpiTable ( + char *Name); + +void +AcpiDbSendNotify ( + char *Name, + UINT32 Value); + +void +AcpiDbDisplayInterfaces ( + char *ActionArg, + char *InterfaceNameArg); + +ACPI_STATUS +AcpiDbSleep ( + char *ObjectArg); + +void +AcpiDbTrace ( + char *EnableArg, + char *MethodArg, + char *OnceArg); + +void +AcpiDbDisplayLocks ( + void); + +void +AcpiDbDisplayResources ( + char *ObjectArg); + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiDbDisplayGpes ( + void)) + +void +AcpiDbDisplayHandlers ( + void); + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiDbGenerateGpe ( + char *GpeArg, + char *BlockArg)) + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiDbGenerateSci ( + void)) + +void +AcpiDbExecuteTest ( + char *TypeArg); + + +/* + * dbconvert - miscellaneous conversion routines + */ +ACPI_STATUS +AcpiDbHexCharToValue ( + int HexChar, + UINT8 *ReturnValue); + +ACPI_STATUS +AcpiDbConvertToPackage ( + char *String, + ACPI_OBJECT *Object); + +ACPI_STATUS +AcpiDbConvertToObject ( + ACPI_OBJECT_TYPE Type, + char *String, + ACPI_OBJECT *Object); + +UINT8 * +AcpiDbEncodePldBuffer ( + ACPI_PLD_INFO *PldInfo); + +void +AcpiDbDumpPldBuffer ( + ACPI_OBJECT *ObjDesc); + + +/* + * dbmethod - control method commands + */ +void +AcpiDbSetMethodBreakpoint ( + char *Location, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDbSetMethodCallBreakpoint ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDbSetMethodData ( + char *TypeArg, + char *IndexArg, + char *ValueArg); + +ACPI_STATUS +AcpiDbDisassembleMethod ( + char *Name); + +void +AcpiDbDisassembleAml ( + char *Statements, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDbEvaluatePredefinedNames ( + void); + + +/* + * dbnames - namespace commands + */ +void +AcpiDbSetScope ( + char *Name); + +void +AcpiDbDumpNamespace ( + char *StartArg, + char *DepthArg); + +void +AcpiDbDumpNamespacePaths ( + void); + +void +AcpiDbDumpNamespaceByOwner ( + char *OwnerArg, + char *DepthArg); + +ACPI_STATUS +AcpiDbFindNameInNamespace ( + char *NameArg); + +void +AcpiDbCheckPredefinedNames ( + void); + +ACPI_STATUS +AcpiDbDisplayObjects ( + char *ObjTypeArg, + char *DisplayCountArg); + +void +AcpiDbCheckIntegrity ( + void); + +void +AcpiDbFindReferences ( + char *ObjectArg); + +void +AcpiDbGetBusInfo ( + void); + + +/* + * dbdisply - debug display commands + */ +void +AcpiDbDisplayMethodInfo ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDbDecodeAndDisplayObject ( + char *Target, + char *OutputType); + +ACPI_DBR_DEPENDENT_RETURN_VOID ( +void +AcpiDbDisplayResultObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState)) + +ACPI_STATUS +AcpiDbDisplayAllMethods ( + char *DisplayCountArg); + +void +AcpiDbDisplayArguments ( + void); + +void +AcpiDbDisplayLocals ( + void); + +void +AcpiDbDisplayResults ( + void); + +void +AcpiDbDisplayCallingTree ( + void); + +void +AcpiDbDisplayObjectType ( + char *ObjectArg); + +ACPI_DBR_DEPENDENT_RETURN_VOID ( +void +AcpiDbDisplayArgumentObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState)) + + +/* + * dbexec - debugger control method execution + */ +void +AcpiDbExecute ( + char *Name, + char **Args, + ACPI_OBJECT_TYPE *Types, + UINT32 Flags); + +void +AcpiDbCreateExecutionThread ( + char *MethodNameArg, + char **Arguments, + ACPI_OBJECT_TYPE *Types); + +void +AcpiDbCreateExecutionThreads ( + char *NumThreadsArg, + char *NumLoopsArg, + char *MethodNameArg); + +void +AcpiDbDeleteObjects ( + UINT32 Count, + ACPI_OBJECT *Objects); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +UINT32 +AcpiDbGetCacheInfo ( + ACPI_MEMORY_LIST *Cache); +#endif + + +/* + * dbfileio - Debugger file I/O commands + */ +ACPI_OBJECT_TYPE +AcpiDbMatchArgument ( + char *UserArgument, + ACPI_DB_ARGUMENT_INFO *Arguments); + +void +AcpiDbCloseDebugFile ( + void); + +void +AcpiDbOpenDebugFile ( + char *Name); + +ACPI_STATUS +AcpiDbLoadAcpiTable ( + char *Filename); + +ACPI_STATUS +AcpiDbLoadTables ( + ACPI_NEW_TABLE_DESC *ListHead); + + +/* + * dbhistry - debugger HISTORY command + */ +void +AcpiDbAddToHistory ( + char *CommandLine); + +void +AcpiDbDisplayHistory ( + void); + +char * +AcpiDbGetFromHistory ( + char *CommandNumArg); + +char * +AcpiDbGetHistoryByIndex ( + UINT32 CommanddNum); + + +/* + * dbinput - user front-end to the AML debugger + */ +ACPI_STATUS +AcpiDbCommandDispatch ( + char *InputBuffer, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +void ACPI_SYSTEM_XFACE +AcpiDbExecuteThread ( + void *Context); + +ACPI_STATUS +AcpiDbUserCommands ( + void); + +char * +AcpiDbGetNextToken ( + char *String, + char **Next, + ACPI_OBJECT_TYPE *ReturnType); + + +/* + * dbobject + */ +void +AcpiDbDecodeInternalObject ( + ACPI_OPERAND_OBJECT *ObjDesc); + +void +AcpiDbDisplayInternalObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +void +AcpiDbDecodeArguments ( + ACPI_WALK_STATE *WalkState); + +void +AcpiDbDecodeLocals ( + ACPI_WALK_STATE *WalkState); + +void +AcpiDbDumpMethodInfo ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState); + + +/* + * dbstats - Generation and display of ACPI table statistics + */ +void +AcpiDbGenerateStatistics ( + ACPI_PARSE_OBJECT *Root, + BOOLEAN IsMethod); + +ACPI_STATUS +AcpiDbDisplayStatistics ( + char *TypeArg); + + +/* + * dbutils - AML debugger utilities + */ +void +AcpiDbSetOutputDestination ( + UINT32 Where); + +void +AcpiDbDumpExternalObject ( + ACPI_OBJECT *ObjDesc, + UINT32 Level); + +void +AcpiDbPrepNamestring ( + char *Name); + +ACPI_NAMESPACE_NODE * +AcpiDbLocalNsLookup ( + char *Name); + +void +AcpiDbUint32ToHexString ( + UINT32 Value, + char *Buffer); + +#endif /* __ACDEBUG_H__ */ diff --git a/ports/acpica/include/acdisasm.h b/ports/acpica/include/acdisasm.h new file mode 100644 index 0000000..7f7f7bf --- /dev/null +++ b/ports/acpica/include/acdisasm.h @@ -0,0 +1,1343 @@ +/****************************************************************************** + * + * Name: acdisasm.h - AML disassembler + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACDISASM_H__ +#define __ACDISASM_H__ + +#include "amlresrc.h" + + +#define BLOCK_NONE 0 +#define BLOCK_PAREN 1 +#define BLOCK_BRACE 2 +#define BLOCK_COMMA_LIST 4 +#define ACPI_DEFAULT_RESNAME *(UINT32 *) "__RD" + +/* + * Raw table data header. Used by disassembler and data table compiler. + * Do not change. + */ +#define ACPI_RAW_TABLE_DATA_HEADER "Raw Table Data" + + +typedef struct acpi_dmtable_info +{ + UINT8 Opcode; + UINT16 Offset; + char *Name; + UINT8 Flags; + +} ACPI_DMTABLE_INFO; + +/* Values for Flags field above */ + +#define DT_LENGTH 0x01 /* Field is a subtable length */ +#define DT_FLAG 0x02 /* Field is a flag value */ +#define DT_NON_ZERO 0x04 /* Field must be non-zero */ +#define DT_OPTIONAL 0x08 /* Field is optional */ +#define DT_DESCRIBES_OPTIONAL 0x10 /* Field describes an optional field (length, etc.) */ +#define DT_COUNT 0x20 /* Currently not used */ + +/* + * Values for Opcode above. + * Note: 0-7 must not change, they are used as a flag shift value. Other + * than those, new values can be added wherever appropriate. + */ +typedef enum +{ + /* Simple Data Types */ + + ACPI_DMT_FLAG0 = 0, + ACPI_DMT_FLAG1 = 1, + ACPI_DMT_FLAG2 = 2, + ACPI_DMT_FLAG3 = 3, + ACPI_DMT_FLAG4 = 4, + ACPI_DMT_FLAG5 = 5, + ACPI_DMT_FLAG6 = 6, + ACPI_DMT_FLAG7 = 7, + ACPI_DMT_FLAGS0, + ACPI_DMT_FLAGS1, + ACPI_DMT_FLAGS2, + ACPI_DMT_FLAGS4, + ACPI_DMT_FLAGS4_0, + ACPI_DMT_FLAGS4_4, + ACPI_DMT_FLAGS4_8, + ACPI_DMT_FLAGS4_12, + ACPI_DMT_FLAGS16_16, + ACPI_DMT_UINT8, + ACPI_DMT_UINT16, + ACPI_DMT_UINT24, + ACPI_DMT_UINT32, + ACPI_DMT_UINT40, + ACPI_DMT_UINT48, + ACPI_DMT_UINT56, + ACPI_DMT_UINT64, + ACPI_DMT_BUF7, + ACPI_DMT_BUF10, + ACPI_DMT_BUF12, + ACPI_DMT_BUF16, + ACPI_DMT_BUF128, + ACPI_DMT_SIG, + ACPI_DMT_STRING, + ACPI_DMT_NAME4, + ACPI_DMT_NAME6, + ACPI_DMT_NAME8, + + /* Types that are decoded to strings and miscellaneous */ + + ACPI_DMT_ACCWIDTH, + ACPI_DMT_CHKSUM, + ACPI_DMT_GAS, + ACPI_DMT_SPACEID, + ACPI_DMT_UNICODE, + ACPI_DMT_UUID, + + /* Types used only for the Data Table Compiler */ + + ACPI_DMT_BUFFER, + ACPI_DMT_RAW_BUFFER, /* Large, multiple line buffer */ + ACPI_DMT_DEVICE_PATH, + ACPI_DMT_LABEL, + ACPI_DMT_PCI_PATH, + + /* Types that are specific to particular ACPI tables */ + + ACPI_DMT_ASF, + ACPI_DMT_DMAR, + ACPI_DMT_DMAR_SCOPE, + ACPI_DMT_EINJACT, + ACPI_DMT_EINJINST, + ACPI_DMT_ERSTACT, + ACPI_DMT_ERSTINST, + ACPI_DMT_FADTPM, + ACPI_DMT_GTDT, + ACPI_DMT_HEST, + ACPI_DMT_HESTNTFY, + ACPI_DMT_HESTNTYP, + ACPI_DMT_HMAT, + ACPI_DMT_IORTMEM, + ACPI_DMT_IVRS, + ACPI_DMT_LPIT, + ACPI_DMT_MADT, + ACPI_DMT_NFIT, + ACPI_DMT_PCCT, + ACPI_DMT_PMTT, + ACPI_DMT_PPTT, + ACPI_DMT_SDEI, + ACPI_DMT_SDEV, + ACPI_DMT_SLIC, + ACPI_DMT_SRAT, + ACPI_DMT_TPM2, + + /* Special opcodes */ + + ACPI_DMT_EXTRA_TEXT, + ACPI_DMT_EXIT + +} ACPI_ENTRY_TYPES; + +typedef +void (*ACPI_DMTABLE_HANDLER) ( + ACPI_TABLE_HEADER *Table); + +typedef +ACPI_STATUS (*ACPI_CMTABLE_HANDLER) ( + void **PFieldList); + +typedef struct acpi_dmtable_data +{ + char *Signature; + ACPI_DMTABLE_INFO *TableInfo; + ACPI_DMTABLE_HANDLER TableHandler; + ACPI_CMTABLE_HANDLER CmTableHandler; + const unsigned char *Template; + +} ACPI_DMTABLE_DATA; + + +typedef struct acpi_op_walk_info +{ + ACPI_WALK_STATE *WalkState; + ACPI_PARSE_OBJECT *MappingOp; + UINT8 *PreviousAml; + UINT8 *StartAml; + UINT32 Level; + UINT32 LastLevel; + UINT32 Count; + UINT32 BitOffset; + UINT32 Flags; + UINT32 AmlOffset; + +} ACPI_OP_WALK_INFO; + +/* + * TBD - another copy of this is in asltypes.h, fix + */ +#ifndef ASL_WALK_CALLBACK_DEFINED +typedef +ACPI_STATUS (*ASL_WALK_CALLBACK) ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); +#define ASL_WALK_CALLBACK_DEFINED +#endif + +typedef +void (*ACPI_RESOURCE_HANDLER) ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +typedef struct acpi_resource_tag +{ + UINT32 BitIndex; + char *Tag; + +} ACPI_RESOURCE_TAG; + +/* Strings used for decoding flags to ASL keywords */ + +extern const char *AcpiGbl_WordDecode[]; +extern const char *AcpiGbl_IrqDecode[]; +extern const char *AcpiGbl_LockRule[]; +extern const char *AcpiGbl_AccessTypes[]; +extern const char *AcpiGbl_UpdateRules[]; +extern const char *AcpiGbl_MatchOps[]; + +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf2a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsfHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoBoot[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoBert[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoBgrt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCpep[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCpep0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt2a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Device[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Addr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Size[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Name[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2OemData[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbgp[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmarHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmarScope[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm0a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoEcdt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoEinj[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoEinj0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoErst[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoErst0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFacs[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt5[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt6[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFpdt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFpdtHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFpdt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFpdt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGas[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdtHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt0a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHeader[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest6[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest7[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest8[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest9[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest10[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest11[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHestNotify[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHestBank[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHpet[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoLpitHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoLpit0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoLpit1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmat[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmat0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmat1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmat1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmat1b[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmat1c[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmat2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmat2a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHmatHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort0a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort3a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort3b[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort3c[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIortAcc[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIortHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIortMap[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIortPad[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8b[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8c[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrsHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt5[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt6[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt7[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt8[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt9[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt10[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt11[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt12[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt13[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt14[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt15[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadtHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMcfg[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMcfg0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMchi[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0A[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0B[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMsct[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMsct0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMtmr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMtmr0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfitHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit2a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit3a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit5[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit6[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit6a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit7[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPdtt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmttHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcctHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPdtt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPptt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPptt0a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPptt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPptt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPpttHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoRasf[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoRsdp1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoRsdp2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3ptHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSbst[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSdei[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSdev[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSdevHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSdev0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSdev0a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSdev1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSdev1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSdev1b[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlic[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlit[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSpcr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSpmi[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSratHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoStao[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoStaoStr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaClient[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaServer[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTpm2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTpm2a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTpm211[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoUefi[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoVrtc[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoVrtc0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWaet[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWdat[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWdat0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWddt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWdrt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWpbt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWpbt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWsmt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoXenv[]; + +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGeneric[][2]; + +/* + * dmtable and ahtable + */ +extern const ACPI_DMTABLE_DATA AcpiDmTableData[]; +extern const AH_TABLE Gbl_AcpiSupportedTables[]; + +UINT8 +AcpiDmGenerateChecksum ( + void *Table, + UINT32 Length, + UINT8 OriginalChecksum); + +const ACPI_DMTABLE_DATA * +AcpiDmGetTableData ( + char *Signature); + +void +AcpiDmDumpDataTable ( + ACPI_TABLE_HEADER *Table); + +ACPI_STATUS +AcpiDmDumpTable ( + UINT32 TableLength, + UINT32 TableOffset, + void *Table, + UINT32 SubtableLength, + ACPI_DMTABLE_INFO *Info); + +void +AcpiDmLineHeader ( + UINT32 Offset, + UINT32 ByteLength, + char *Name); + +void +AcpiDmLineHeader2 ( + UINT32 Offset, + UINT32 ByteLength, + char *Name, + UINT32 Value); + + +/* + * dmtbdump + */ +void +AcpiDmDumpBuffer ( + void *Table, + UINT32 BufferOffset, + UINT32 Length, + UINT32 AbsoluteOffset, + char *Header); + +void +AcpiDmDumpUnicode ( + void *Table, + UINT32 BufferOffset, + UINT32 ByteLength); + +void +AcpiDmDumpAsf ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpCpep ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpCsrt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpDbg2 ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpDmar ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpDrtm ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpEinj ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpErst ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpFadt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpFpdt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpGtdt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpHest ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpHmat ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpIort ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpIvrs ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpLpit ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMadt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMcfg ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMpst ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMsct ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMtmr ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpNfit ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpPcct ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpPdtt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpPmtt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpPptt ( + ACPI_TABLE_HEADER *Table); + +UINT32 +AcpiDmDumpRsdp ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpRsdt ( + ACPI_TABLE_HEADER *Table); + +UINT32 +AcpiDmDumpS3pt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpSdev ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpSlic ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpSlit ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpSrat ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpStao ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpTcpa ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpTpm2 ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpVrtc ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpWdat ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpWpbt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpXsdt ( + ACPI_TABLE_HEADER *Table); + + +/* + * dmwalk + */ +void +AcpiDmDisassemble ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Origin, + UINT32 NumOpcodes); + +void +AcpiDmWalkParseTree ( + ACPI_PARSE_OBJECT *Op, + ASL_WALK_CALLBACK DescendingCallback, + ASL_WALK_CALLBACK AscendingCallback, + void *Context); + + +/* + * dmopcode + */ +void +AcpiDmDisassembleOneOp ( + ACPI_WALK_STATE *WalkState, + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op); + +UINT32 +AcpiDmListType ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmMethodFlags ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmDisplayTargetPathname ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmNotifyDescription ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmPredefinedDescription ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmFieldPredefinedDescription ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmFieldFlags ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmAddressSpace ( + UINT8 SpaceId); + +void +AcpiDmRegionFlags ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmMatchOp ( + ACPI_PARSE_OBJECT *Op); + + +/* + * dmnames + */ +UINT32 +AcpiDmDumpName ( + UINT32 Name); + +ACPI_STATUS +AcpiPsDisplayObjectPathname ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmNamestring ( + char *Name); + + +/* + * dmbuffer + */ +void +AcpiDmDisasmByteList ( + UINT32 Level, + UINT8 *ByteData, + UINT32 ByteCount); + +void +AcpiDmByteList ( + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmCheckForHardwareId ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmDecompressEisaId ( + UINT32 EncodedId); + +BOOLEAN +AcpiDmIsUuidBuffer ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AcpiDmIsUnicodeBuffer ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AcpiDmIsStringBuffer ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AcpiDmIsPldBuffer ( + ACPI_PARSE_OBJECT *Op); + + +/* + * dmdeferred + */ +ACPI_STATUS +AcpiDmParseDeferredOps ( + ACPI_PARSE_OBJECT *Root); + + +/* + * dmextern + */ +ACPI_STATUS +AcpiDmAddToExternalFileList ( + char *PathList); + +void +AcpiDmClearExternalFileList ( + void); + +void +AcpiDmAddOpToExternalList ( + ACPI_PARSE_OBJECT *Op, + char *Path, + UINT8 Type, + UINT32 Value, + UINT16 Flags); + +void +AcpiDmCreateSubobjectForExternal ( + UINT8 Type, + ACPI_NAMESPACE_NODE **Node, + UINT32 Value); + +void +AcpiDmAddNodeToExternalList ( + ACPI_NAMESPACE_NODE *Node, + UINT8 Type, + UINT32 Value, + UINT16 Flags); + +void +AcpiDmAddExternalListToNamespace ( + void); + +void +AcpiDmAddOneExternalToNamespace ( + char *Path, + UINT8 Type, + UINT32 Value); + +UINT32 +AcpiDmGetUnresolvedExternalMethodCount ( + void); + +void +AcpiDmClearExternalList ( + void); + +void +AcpiDmEmitExternals ( + void); + +void +AcpiDmEmitExternal ( + ACPI_PARSE_OBJECT *NameOp, + ACPI_PARSE_OBJECT *TypeOp); + +void +AcpiDmUnresolvedWarning ( + UINT8 Type); + +void +AcpiDmGetExternalsFromFile ( + void); + +void +AcpiDmMarkExternalConflict ( + ACPI_NAMESPACE_NODE *Node); + + +/* + * dmresrc + */ +void +AcpiDmDumpInteger8 ( + UINT8 Value, + const char *Name); + +void +AcpiDmDumpInteger16 ( + UINT16 Value, + const char *Name); + +void +AcpiDmDumpInteger32 ( + UINT32 Value, + const char *Name); + +void +AcpiDmDumpInteger64 ( + UINT64 Value, + const char *Name); + +void +AcpiDmResourceTemplate ( + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op, + UINT8 *ByteData, + UINT32 ByteCount); + +ACPI_STATUS +AcpiDmIsResourceTemplate ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmBitList ( + UINT16 Mask); + +void +AcpiDmDescriptorName ( + void); + + +/* + * dmresrcl + */ +void +AcpiDmWordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmDwordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmExtendedDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmQwordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmMemory24Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmMemory32Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmFixedMemory32Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmGenericRegisterDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmInterruptDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmVendorLargeDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmGpioDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmPinFunctionDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmPinConfigDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmPinGroupDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmPinGroupFunctionDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmPinGroupConfigDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmVendorCommon ( + const char *Name, + UINT8 *ByteData, + UINT32 Length, + UINT32 Level); + + +/* + * dmresrcs + */ +void +AcpiDmIrqDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmDmaDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmFixedDmaDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmIoDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmFixedIoDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmStartDependentDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmEndDependentDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmVendorSmallDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + + +/* + * dmutils + */ +void +AcpiDmDecodeAttribute ( + UINT8 Attribute); + +void +AcpiDmIndent ( + UINT32 Level); + +BOOLEAN +AcpiDmCommaIfListMember ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmCommaIfFieldMember ( + ACPI_PARSE_OBJECT *Op); + + +/* + * dmrestag + */ +void +AcpiDmFindResources ( + ACPI_PARSE_OBJECT *Root); + +void +AcpiDmCheckResourceReference ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + + +/* + * dmcstyle + */ +BOOLEAN +AcpiDmCheckForSymbolicOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_OP_WALK_INFO *Info); + +void +AcpiDmCloseOperator ( + ACPI_PARSE_OBJECT *Op); + + +/* + * dmtables + */ +ACPI_STATUS +AcpiDmProcessSwitch ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmClearTempList( + void); + +/* + * dmtables + */ +void +AdDisassemblerHeader ( + char *Filename, + UINT8 TableType); + +#define ACPI_IS_AML_TABLE 0 +#define ACPI_IS_DATA_TABLE 1 + + +/* + * adisasm + */ +ACPI_STATUS +AdAmlDisassemble ( + BOOLEAN OutToFile, + char *Filename, + char *Prefix, + char **OutFilename); + +ACPI_STATUS +AdGetLocalTables ( + void); + +ACPI_STATUS +AdParseTable ( + ACPI_TABLE_HEADER *Table, + ACPI_OWNER_ID *OwnerId, + BOOLEAN LoadTable, + BOOLEAN External); + +ACPI_STATUS +AdDisplayTables ( + char *Filename, + ACPI_TABLE_HEADER *Table); + +ACPI_STATUS +AdDisplayStatistics ( + void); + + +/* + * dmwalk + */ +UINT32 +AcpiDmBlockType ( + ACPI_PARSE_OBJECT *Op); + + +#endif /* __ACDISASM_H__ */ diff --git a/ports/acpica/include/acdispat.h b/ports/acpica/include/acdispat.h new file mode 100644 index 0000000..fd6a1e8 --- /dev/null +++ b/ports/acpica/include/acdispat.h @@ -0,0 +1,599 @@ +/****************************************************************************** + * + * Name: acdispat.h - dispatcher (parser to interpreter interface) + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef _ACDISPAT_H_ +#define _ACDISPAT_H_ + + +#define NAMEOF_LOCAL_NTE "__L0" +#define NAMEOF_ARG_NTE "__A0" + + +/* + * dsargs - execution of dynamic arguments for static objects + */ +ACPI_STATUS +AcpiDsGetBufferFieldArguments ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsGetBankFieldArguments ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsGetRegionArguments ( + ACPI_OPERAND_OBJECT *RgnDesc); + +ACPI_STATUS +AcpiDsGetBufferArguments ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsGetPackageArguments ( + ACPI_OPERAND_OBJECT *ObjDesc); + + +/* + * dscontrol - support for execution control opcodes + */ +ACPI_STATUS +AcpiDsExecBeginControlOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsExecEndControlOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + + +/* + * dsopcode - support for late operand evaluation + */ +ACPI_STATUS +AcpiDsEvalBufferFieldOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsEvalRegionOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsEvalTableRegionOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsEvalDataObjectOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsEvalBankFieldOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsInitializeRegion ( + ACPI_HANDLE ObjHandle); + + +/* + * dsexec - Parser/Interpreter interface, method execution callbacks + */ +ACPI_STATUS +AcpiDsGetPredicateValue ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ResultObj); + +ACPI_STATUS +AcpiDsExecBeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp); + +ACPI_STATUS +AcpiDsExecEndOp ( + ACPI_WALK_STATE *State); + + +/* + * dsfield - Parser/Interpreter interface for AML fields + */ +ACPI_STATUS +AcpiDsCreateField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsCreateBankField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsCreateIndexField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsCreateBufferField ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsInitFieldObjects ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + + +/* + * dsload - Parser/Interpreter interface + */ +ACPI_STATUS +AcpiDsInitCallbacks ( + ACPI_WALK_STATE *WalkState, + UINT32 PassNumber); + +/* dsload - pass 1 namespace load callbacks */ + +ACPI_STATUS +AcpiDsLoad1BeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp); + +ACPI_STATUS +AcpiDsLoad1EndOp ( + ACPI_WALK_STATE *WalkState); + + +/* dsload - pass 2 namespace load callbacks */ + +ACPI_STATUS +AcpiDsLoad2BeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp); + +ACPI_STATUS +AcpiDsLoad2EndOp ( + ACPI_WALK_STATE *WalkState); + + +/* + * dsmthdat - method data (locals/args) + */ +ACPI_STATUS +AcpiDsStoreObjectToLocal ( + UINT8 Type, + UINT32 Index, + ACPI_OPERAND_OBJECT *SrcDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsMethodDataGetEntry ( + UINT16 Opcode, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT ***Node); + +void +AcpiDsMethodDataDeleteAll ( + ACPI_WALK_STATE *WalkState); + +BOOLEAN +AcpiDsIsMethodValue ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsMethodDataGetValue ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT **DestDesc); + +ACPI_STATUS +AcpiDsMethodDataInitArgs ( + ACPI_OPERAND_OBJECT **Params, + UINT32 MaxParamCount, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsMethodDataGetNode ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **Node); + +void +AcpiDsMethodDataInit ( + ACPI_WALK_STATE *WalkState); + + +/* + * dsmethod - Parser/Interpreter interface - control method parsing + */ +ACPI_STATUS +AcpiDsAutoSerializeMethod ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsCallControlMethod ( + ACPI_THREAD_STATE *Thread, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsRestartControlMethod ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ReturnDesc); + +void +AcpiDsTerminateControlMethod ( + ACPI_OPERAND_OBJECT *MethodDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsBeginMethodExecution ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsMethodError ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState); + +/* + * dsinit + */ +ACPI_STATUS +AcpiDsInitializeObjects ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode); + + +/* + * dsobject - Parser/Interpreter interface - object initialization and conversion + */ +ACPI_STATUS +AcpiDsBuildInternalObject ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT **ObjDescPtr); + +ACPI_STATUS +AcpiDsBuildInternalBufferObj ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT32 BufferLength, + ACPI_OPERAND_OBJECT **ObjDescPtr); + +ACPI_STATUS +AcpiDsBuildInternalPackageObj ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *op, + UINT32 PackageLength, + ACPI_OPERAND_OBJECT **ObjDesc); + +ACPI_STATUS +AcpiDsInitObjectFromOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT16 Opcode, + ACPI_OPERAND_OBJECT **ObjDesc); + +ACPI_STATUS +AcpiDsCreateNode ( + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *Node, + ACPI_PARSE_OBJECT *Op); + + +/* + * dspkginit - Package object initialization + */ +ACPI_STATUS +AcpiDsInitPackageElement ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context); + + +/* + * dsutils - Parser/Interpreter interface utility routines + */ +void +AcpiDsClearImplicitReturn ( + ACPI_WALK_STATE *WalkState); + +BOOLEAN +AcpiDsDoImplicitReturn ( + ACPI_OPERAND_OBJECT *ReturnDesc, + ACPI_WALK_STATE *WalkState, + BOOLEAN AddReference); + +BOOLEAN +AcpiDsIsResultUsed ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +void +AcpiDsDeleteResultIfNotUsed ( + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT *ResultObj, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsCreateOperand ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Arg, + UINT32 ArgsRemaining); + +ACPI_STATUS +AcpiDsCreateOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *FirstArg); + +ACPI_STATUS +AcpiDsResolveOperands ( + ACPI_WALK_STATE *WalkState); + +void +AcpiDsClearOperands ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsEvaluateNamePath ( + ACPI_WALK_STATE *WalkState); + + +/* + * dswscope - Scope Stack manipulation + */ +ACPI_STATUS +AcpiDsScopeStackPush ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type, + ACPI_WALK_STATE *WalkState); + + +ACPI_STATUS +AcpiDsScopeStackPop ( + ACPI_WALK_STATE *WalkState); + +void +AcpiDsScopeStackClear ( + ACPI_WALK_STATE *WalkState); + + +/* + * dswstate - parser WALK_STATE management routines + */ +ACPI_STATUS +AcpiDsObjStackPush ( + void *Object, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsObjStackPop ( + UINT32 PopCount, + ACPI_WALK_STATE *WalkState); + +ACPI_WALK_STATE * +AcpiDsCreateWalkState ( + ACPI_OWNER_ID OwnerId, + ACPI_PARSE_OBJECT *Origin, + ACPI_OPERAND_OBJECT *MthDesc, + ACPI_THREAD_STATE *Thread); + +ACPI_STATUS +AcpiDsInitAmlWalk ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *MethodNode, + UINT8 *AmlStart, + UINT32 AmlLength, + ACPI_EVALUATE_INFO *Info, + UINT8 PassNumber); + +void +AcpiDsObjStackPopAndDelete ( + UINT32 PopCount, + ACPI_WALK_STATE *WalkState); + +void +AcpiDsDeleteWalkState ( + ACPI_WALK_STATE *WalkState); + +ACPI_WALK_STATE * +AcpiDsPopWalkState ( + ACPI_THREAD_STATE *Thread); + +void +AcpiDsPushWalkState ( + ACPI_WALK_STATE *WalkState, + ACPI_THREAD_STATE *Thread); + +ACPI_STATUS +AcpiDsResultStackClear ( + ACPI_WALK_STATE *WalkState); + +ACPI_WALK_STATE * +AcpiDsGetCurrentWalkState ( + ACPI_THREAD_STATE *Thread); + +ACPI_STATUS +AcpiDsResultPop ( + ACPI_OPERAND_OBJECT **Object, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsResultPush ( + ACPI_OPERAND_OBJECT *Object, + ACPI_WALK_STATE *WalkState); + + +/* + * dsdebug - parser debugging routines + */ +void +AcpiDsDumpMethodStack ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +#endif /* _ACDISPAT_H_ */ diff --git a/ports/acpica/include/acevents.h b/ports/acpica/include/acevents.h new file mode 100644 index 0000000..3dc3660 --- /dev/null +++ b/ports/acpica/include/acevents.h @@ -0,0 +1,495 @@ +/****************************************************************************** + * + * Name: acevents.h - Event subcomponent prototypes and defines + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACEVENTS_H__ +#define __ACEVENTS_H__ + + +/* + * Conditions to trigger post enabling GPE polling: + * It is not sufficient to trigger edge-triggered GPE with specific GPE + * chips, software need to poll once after enabling. + */ +#ifdef ACPI_USE_GPE_POLLING +#define ACPI_GPE_IS_POLLING_NEEDED(__gpe__) \ + ((__gpe__)->RuntimeCount == 1 && \ + (__gpe__)->Flags & ACPI_GPE_INITIALIZED && \ + ((__gpe__)->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) +#else +#define ACPI_GPE_IS_POLLING_NEEDED(__gpe__) FALSE +#endif + + +/* + * evevent + */ +ACPI_STATUS +AcpiEvInitializeEvents ( + void); + +ACPI_STATUS +AcpiEvInstallXruptHandlers ( + void); + +UINT32 +AcpiEvFixedEventDetect ( + void); + + +/* + * evmisc + */ +BOOLEAN +AcpiEvIsNotifyObject ( + ACPI_NAMESPACE_NODE *Node); + +UINT32 +AcpiEvGetGpeNumberIndex ( + UINT32 GpeNumber); + +ACPI_STATUS +AcpiEvQueueNotifyRequest ( + ACPI_NAMESPACE_NODE *Node, + UINT32 NotifyValue); + + +/* + * evglock - Global Lock support + */ +ACPI_STATUS +AcpiEvInitGlobalLockHandler ( + void); + +ACPI_HW_DEPENDENT_RETURN_OK ( +ACPI_STATUS +AcpiEvAcquireGlobalLock( + UINT16 Timeout)) + +ACPI_HW_DEPENDENT_RETURN_OK ( +ACPI_STATUS +AcpiEvReleaseGlobalLock( + void)) + +ACPI_STATUS +AcpiEvRemoveGlobalLockHandler ( + void); + + +/* + * evgpe - Low-level GPE support + */ +UINT32 +AcpiEvGpeDetect ( + ACPI_GPE_XRUPT_INFO *GpeXruptList); + +ACPI_STATUS +AcpiEvUpdateGpeEnableMask ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiEvEnableGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiEvMaskGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + BOOLEAN IsMasked); + +ACPI_STATUS +AcpiEvAddGpeReference ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiEvRemoveGpeReference ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_GPE_EVENT_INFO * +AcpiEvGetGpeEventInfo ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber); + +ACPI_GPE_EVENT_INFO * +AcpiEvLowGetGpeInfo ( + UINT32 GpeNumber, + ACPI_GPE_BLOCK_INFO *GpeBlock); + +ACPI_STATUS +AcpiEvFinishGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +UINT32 +AcpiEvDetectGpe ( + ACPI_NAMESPACE_NODE *GpeDevice, + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 GpeNumber); + + +/* + * evgpeblk - Upper-level GPE block support + */ +ACPI_STATUS +AcpiEvCreateGpeBlock ( + ACPI_NAMESPACE_NODE *GpeDevice, + UINT64 Address, + UINT8 SpaceId, + UINT32 RegisterCount, + UINT16 GpeBlockBaseNumber, + UINT32 InterruptNumber, + ACPI_GPE_BLOCK_INFO **ReturnGpeBlock); + +ACPI_STATUS +AcpiEvInitializeGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +ACPI_HW_DEPENDENT_RETURN_OK ( +ACPI_STATUS +AcpiEvDeleteGpeBlock ( + ACPI_GPE_BLOCK_INFO *GpeBlock)) + +UINT32 +AcpiEvGpeDispatch ( + ACPI_NAMESPACE_NODE *GpeDevice, + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 GpeNumber); + + +/* + * evgpeinit - GPE initialization and update + */ +ACPI_STATUS +AcpiEvGpeInitialize ( + void); + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiEvUpdateGpes ( + ACPI_OWNER_ID TableOwnerId)) + +ACPI_STATUS +AcpiEvMatchGpeMethod ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + + +/* + * evgpeutil - GPE utilities + */ +ACPI_STATUS +AcpiEvWalkGpeList ( + ACPI_GPE_CALLBACK GpeWalkCallback, + void *Context); + +ACPI_STATUS +AcpiEvGetGpeDevice ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +ACPI_STATUS +AcpiEvGetGpeXruptBlock ( + UINT32 InterruptNumber, + ACPI_GPE_XRUPT_INFO **GpeXruptBlock); + +ACPI_STATUS +AcpiEvDeleteGpeXrupt ( + ACPI_GPE_XRUPT_INFO *GpeXrupt); + +ACPI_STATUS +AcpiEvDeleteGpeHandlers ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + + +/* + * evhandler - Address space handling + */ +ACPI_OPERAND_OBJECT * +AcpiEvFindRegionHandler ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_OPERAND_OBJECT *HandlerObj); + +BOOLEAN +AcpiEvHasDefaultHandler ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId); + +ACPI_STATUS +AcpiEvInstallRegionHandlers ( + void); + +ACPI_STATUS +AcpiEvInstallSpaceHandler ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context); + + +/* + * evregion - Operation region support + */ +ACPI_STATUS +AcpiEvInitializeOpRegions ( + void); + +ACPI_STATUS +AcpiEvAddressSpaceDispatch ( + ACPI_OPERAND_OBJECT *RegionObj, + ACPI_OPERAND_OBJECT *FieldObj, + UINT32 Function, + UINT32 RegionOffset, + UINT32 BitWidth, + UINT64 *Value); + +ACPI_STATUS +AcpiEvAttachRegion ( + ACPI_OPERAND_OBJECT *HandlerObj, + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsIsLocked); + +void +AcpiEvDetachRegion ( + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsIsLocked); + +void +AcpiEvExecuteRegMethods ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId, + UINT32 Function); + +ACPI_STATUS +AcpiEvExecuteRegMethod ( + ACPI_OPERAND_OBJECT *RegionObj, + UINT32 Function); + + +/* + * evregini - Region initialization and setup + */ +ACPI_STATUS +AcpiEvSystemMemoryRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvIoSpaceRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvPciConfigRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvCmosRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvPciBarRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvDefaultRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvInitializeRegion ( + ACPI_OPERAND_OBJECT *RegionObj); + + +/* + * evsci - SCI (System Control Interrupt) handling/dispatch + */ +UINT32 ACPI_SYSTEM_XFACE +AcpiEvGpeXruptHandler ( + void *Context); + +UINT32 +AcpiEvSciDispatch ( + void); + +UINT32 +AcpiEvInstallSciHandler ( + void); + +ACPI_STATUS +AcpiEvRemoveAllSciHandlers ( + void); + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiEvTerminate ( + void)) + +#endif /* __ACEVENTS_H__ */ diff --git a/ports/acpica/include/acexcep.h b/ports/acpica/include/acexcep.h new file mode 100644 index 0000000..828f9fb --- /dev/null +++ b/ports/acpica/include/acexcep.h @@ -0,0 +1,470 @@ +/****************************************************************************** + * + * Name: acexcep.h - Exception codes returned by the ACPI subsystem + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACEXCEP_H__ +#define __ACEXCEP_H__ + + +/* This module contains all possible exception codes for ACPI_STATUS */ + +/* + * Exception code classes + */ +#define AE_CODE_ENVIRONMENTAL 0x0000 /* General ACPICA environment */ +#define AE_CODE_PROGRAMMER 0x1000 /* External ACPICA interface caller */ +#define AE_CODE_ACPI_TABLES 0x2000 /* ACPI tables */ +#define AE_CODE_AML 0x3000 /* From executing AML code */ +#define AE_CODE_CONTROL 0x4000 /* Internal control codes */ + +#define AE_CODE_MAX 0x4000 +#define AE_CODE_MASK 0xF000 + +/* + * Macros to insert the exception code classes + */ +#define EXCEP_ENV(code) ((ACPI_STATUS) (code | AE_CODE_ENVIRONMENTAL)) +#define EXCEP_PGM(code) ((ACPI_STATUS) (code | AE_CODE_PROGRAMMER)) +#define EXCEP_TBL(code) ((ACPI_STATUS) (code | AE_CODE_ACPI_TABLES)) +#define EXCEP_AML(code) ((ACPI_STATUS) (code | AE_CODE_AML)) +#define EXCEP_CTL(code) ((ACPI_STATUS) (code | AE_CODE_CONTROL)) + +/* + * Exception info table. The "Description" field is used only by the + * ACPICA help application (acpihelp). + */ +typedef struct acpi_exception_info +{ + char *Name; + +#ifdef ACPI_HELP_APP + char *Description; +#endif +} ACPI_EXCEPTION_INFO; + +#ifdef ACPI_HELP_APP +#define EXCEP_TXT(Name,Description) {Name, Description} +#else +#define EXCEP_TXT(Name,Description) {Name} +#endif + + +/* + * Success is always zero, failure is non-zero + */ +#define ACPI_SUCCESS(a) (!(a)) +#define ACPI_FAILURE(a) (a) + +#define AE_OK (ACPI_STATUS) 0x0000 + +/* + * Environmental exceptions + */ +#define AE_ERROR EXCEP_ENV (0x0001) +#define AE_NO_ACPI_TABLES EXCEP_ENV (0x0002) +#define AE_NO_NAMESPACE EXCEP_ENV (0x0003) +#define AE_NO_MEMORY EXCEP_ENV (0x0004) +#define AE_NOT_FOUND EXCEP_ENV (0x0005) +#define AE_NOT_EXIST EXCEP_ENV (0x0006) +#define AE_ALREADY_EXISTS EXCEP_ENV (0x0007) +#define AE_TYPE EXCEP_ENV (0x0008) +#define AE_NULL_OBJECT EXCEP_ENV (0x0009) +#define AE_NULL_ENTRY EXCEP_ENV (0x000A) +#define AE_BUFFER_OVERFLOW EXCEP_ENV (0x000B) +#define AE_STACK_OVERFLOW EXCEP_ENV (0x000C) +#define AE_STACK_UNDERFLOW EXCEP_ENV (0x000D) +#define AE_NOT_IMPLEMENTED EXCEP_ENV (0x000E) +#define AE_SUPPORT EXCEP_ENV (0x000F) +#define AE_LIMIT EXCEP_ENV (0x0010) +#define AE_TIME EXCEP_ENV (0x0011) +#define AE_ACQUIRE_DEADLOCK EXCEP_ENV (0x0012) +#define AE_RELEASE_DEADLOCK EXCEP_ENV (0x0013) +#define AE_NOT_ACQUIRED EXCEP_ENV (0x0014) +#define AE_ALREADY_ACQUIRED EXCEP_ENV (0x0015) +#define AE_NO_HARDWARE_RESPONSE EXCEP_ENV (0x0016) +#define AE_NO_GLOBAL_LOCK EXCEP_ENV (0x0017) +#define AE_ABORT_METHOD EXCEP_ENV (0x0018) +#define AE_SAME_HANDLER EXCEP_ENV (0x0019) +#define AE_NO_HANDLER EXCEP_ENV (0x001A) +#define AE_OWNER_ID_LIMIT EXCEP_ENV (0x001B) +#define AE_NOT_CONFIGURED EXCEP_ENV (0x001C) +#define AE_ACCESS EXCEP_ENV (0x001D) +#define AE_IO_ERROR EXCEP_ENV (0x001E) +#define AE_NUMERIC_OVERFLOW EXCEP_ENV (0x001F) +#define AE_HEX_OVERFLOW EXCEP_ENV (0x0020) +#define AE_DECIMAL_OVERFLOW EXCEP_ENV (0x0021) +#define AE_OCTAL_OVERFLOW EXCEP_ENV (0x0022) +#define AE_END_OF_TABLE EXCEP_ENV (0x0023) + +#define AE_CODE_ENV_MAX 0x0023 + + +/* + * Programmer exceptions + */ +#define AE_BAD_PARAMETER EXCEP_PGM (0x0001) +#define AE_BAD_CHARACTER EXCEP_PGM (0x0002) +#define AE_BAD_PATHNAME EXCEP_PGM (0x0003) +#define AE_BAD_DATA EXCEP_PGM (0x0004) +#define AE_BAD_HEX_CONSTANT EXCEP_PGM (0x0005) +#define AE_BAD_OCTAL_CONSTANT EXCEP_PGM (0x0006) +#define AE_BAD_DECIMAL_CONSTANT EXCEP_PGM (0x0007) +#define AE_MISSING_ARGUMENTS EXCEP_PGM (0x0008) +#define AE_BAD_ADDRESS EXCEP_PGM (0x0009) + +#define AE_CODE_PGM_MAX 0x0009 + + +/* + * Acpi table exceptions + */ +#define AE_BAD_SIGNATURE EXCEP_TBL (0x0001) +#define AE_BAD_HEADER EXCEP_TBL (0x0002) +#define AE_BAD_CHECKSUM EXCEP_TBL (0x0003) +#define AE_BAD_VALUE EXCEP_TBL (0x0004) +#define AE_INVALID_TABLE_LENGTH EXCEP_TBL (0x0005) + +#define AE_CODE_TBL_MAX 0x0005 + + +/* + * AML exceptions. These are caused by problems with + * the actual AML byte stream + */ +#define AE_AML_BAD_OPCODE EXCEP_AML (0x0001) +#define AE_AML_NO_OPERAND EXCEP_AML (0x0002) +#define AE_AML_OPERAND_TYPE EXCEP_AML (0x0003) +#define AE_AML_OPERAND_VALUE EXCEP_AML (0x0004) +#define AE_AML_UNINITIALIZED_LOCAL EXCEP_AML (0x0005) +#define AE_AML_UNINITIALIZED_ARG EXCEP_AML (0x0006) +#define AE_AML_UNINITIALIZED_ELEMENT EXCEP_AML (0x0007) +#define AE_AML_NUMERIC_OVERFLOW EXCEP_AML (0x0008) +#define AE_AML_REGION_LIMIT EXCEP_AML (0x0009) +#define AE_AML_BUFFER_LIMIT EXCEP_AML (0x000A) +#define AE_AML_PACKAGE_LIMIT EXCEP_AML (0x000B) +#define AE_AML_DIVIDE_BY_ZERO EXCEP_AML (0x000C) +#define AE_AML_BAD_NAME EXCEP_AML (0x000D) +#define AE_AML_NAME_NOT_FOUND EXCEP_AML (0x000E) +#define AE_AML_INTERNAL EXCEP_AML (0x000F) +#define AE_AML_INVALID_SPACE_ID EXCEP_AML (0x0010) +#define AE_AML_STRING_LIMIT EXCEP_AML (0x0011) +#define AE_AML_NO_RETURN_VALUE EXCEP_AML (0x0012) +#define AE_AML_METHOD_LIMIT EXCEP_AML (0x0013) +#define AE_AML_NOT_OWNER EXCEP_AML (0x0014) +#define AE_AML_MUTEX_ORDER EXCEP_AML (0x0015) +#define AE_AML_MUTEX_NOT_ACQUIRED EXCEP_AML (0x0016) +#define AE_AML_INVALID_RESOURCE_TYPE EXCEP_AML (0x0017) +#define AE_AML_INVALID_INDEX EXCEP_AML (0x0018) +#define AE_AML_REGISTER_LIMIT EXCEP_AML (0x0019) +#define AE_AML_NO_WHILE EXCEP_AML (0x001A) +#define AE_AML_ALIGNMENT EXCEP_AML (0x001B) +#define AE_AML_NO_RESOURCE_END_TAG EXCEP_AML (0x001C) +#define AE_AML_BAD_RESOURCE_VALUE EXCEP_AML (0x001D) +#define AE_AML_CIRCULAR_REFERENCE EXCEP_AML (0x001E) +#define AE_AML_BAD_RESOURCE_LENGTH EXCEP_AML (0x001F) +#define AE_AML_ILLEGAL_ADDRESS EXCEP_AML (0x0020) +#define AE_AML_LOOP_TIMEOUT EXCEP_AML (0x0021) +#define AE_AML_UNINITIALIZED_NODE EXCEP_AML (0x0022) +#define AE_AML_TARGET_TYPE EXCEP_AML (0x0023) + +#define AE_CODE_AML_MAX 0x0023 + + +/* + * Internal exceptions used for control + */ +#define AE_CTRL_RETURN_VALUE EXCEP_CTL (0x0001) +#define AE_CTRL_PENDING EXCEP_CTL (0x0002) +#define AE_CTRL_TERMINATE EXCEP_CTL (0x0003) +#define AE_CTRL_TRUE EXCEP_CTL (0x0004) +#define AE_CTRL_FALSE EXCEP_CTL (0x0005) +#define AE_CTRL_DEPTH EXCEP_CTL (0x0006) +#define AE_CTRL_END EXCEP_CTL (0x0007) +#define AE_CTRL_TRANSFER EXCEP_CTL (0x0008) +#define AE_CTRL_BREAK EXCEP_CTL (0x0009) +#define AE_CTRL_CONTINUE EXCEP_CTL (0x000A) +#define AE_CTRL_PARSE_CONTINUE EXCEP_CTL (0x000B) +#define AE_CTRL_PARSE_PENDING EXCEP_CTL (0x000C) + +#define AE_CODE_CTRL_MAX 0x000C + + +/* Exception strings for AcpiFormatException */ + +#ifdef ACPI_DEFINE_EXCEPTION_TABLE + +/* + * String versions of the exception codes above + * These strings must match the corresponding defines exactly + */ +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Env[] = +{ + EXCEP_TXT ("AE_OK", "No error"), + EXCEP_TXT ("AE_ERROR", "Unspecified error"), + EXCEP_TXT ("AE_NO_ACPI_TABLES", "ACPI tables could not be found"), + EXCEP_TXT ("AE_NO_NAMESPACE", "A namespace has not been loaded"), + EXCEP_TXT ("AE_NO_MEMORY", "Insufficient dynamic memory"), + EXCEP_TXT ("AE_NOT_FOUND", "A requested entity is not found"), + EXCEP_TXT ("AE_NOT_EXIST", "A required entity does not exist"), + EXCEP_TXT ("AE_ALREADY_EXISTS", "An entity already exists"), + EXCEP_TXT ("AE_TYPE", "The object type is incorrect"), + EXCEP_TXT ("AE_NULL_OBJECT", "A required object was missing"), + EXCEP_TXT ("AE_NULL_ENTRY", "The requested object does not exist"), + EXCEP_TXT ("AE_BUFFER_OVERFLOW", "The buffer provided is too small"), + EXCEP_TXT ("AE_STACK_OVERFLOW", "An internal stack overflowed"), + EXCEP_TXT ("AE_STACK_UNDERFLOW", "An internal stack underflowed"), + EXCEP_TXT ("AE_NOT_IMPLEMENTED", "The feature is not implemented"), + EXCEP_TXT ("AE_SUPPORT", "The feature is not supported"), + EXCEP_TXT ("AE_LIMIT", "A predefined limit was exceeded"), + EXCEP_TXT ("AE_TIME", "A time limit or timeout expired"), + EXCEP_TXT ("AE_ACQUIRE_DEADLOCK", "Internal error, attempt was made to acquire a mutex in improper order"), + EXCEP_TXT ("AE_RELEASE_DEADLOCK", "Internal error, attempt was made to release a mutex in improper order"), + EXCEP_TXT ("AE_NOT_ACQUIRED", "An attempt to release a mutex or Global Lock without a previous acquire"), + EXCEP_TXT ("AE_ALREADY_ACQUIRED", "Internal error, attempt was made to acquire a mutex twice"), + EXCEP_TXT ("AE_NO_HARDWARE_RESPONSE", "Hardware did not respond after an I/O operation"), + EXCEP_TXT ("AE_NO_GLOBAL_LOCK", "There is no FACS Global Lock"), + EXCEP_TXT ("AE_ABORT_METHOD", "A control method was aborted"), + EXCEP_TXT ("AE_SAME_HANDLER", "Attempt was made to install the same handler that is already installed"), + EXCEP_TXT ("AE_NO_HANDLER", "A handler for the operation is not installed"), + EXCEP_TXT ("AE_OWNER_ID_LIMIT", "There are no more Owner IDs available for ACPI tables or control methods"), + EXCEP_TXT ("AE_NOT_CONFIGURED", "The interface is not part of the current subsystem configuration"), + EXCEP_TXT ("AE_ACCESS", "Permission denied for the requested operation"), + EXCEP_TXT ("AE_IO_ERROR", "An I/O error occurred"), + EXCEP_TXT ("AE_NUMERIC_OVERFLOW", "Overflow during string-to-integer conversion"), + EXCEP_TXT ("AE_HEX_OVERFLOW", "Overflow during ASCII hex-to-binary conversion"), + EXCEP_TXT ("AE_DECIMAL_OVERFLOW", "Overflow during ASCII decimal-to-binary conversion"), + EXCEP_TXT ("AE_OCTAL_OVERFLOW", "Overflow during ASCII octal-to-binary conversion"), + EXCEP_TXT ("AE_END_OF_TABLE", "Reached the end of table") +}; + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Pgm[] = +{ + EXCEP_TXT (NULL, NULL), + EXCEP_TXT ("AE_BAD_PARAMETER", "A parameter is out of range or invalid"), + EXCEP_TXT ("AE_BAD_CHARACTER", "An invalid character was found in a name"), + EXCEP_TXT ("AE_BAD_PATHNAME", "An invalid character was found in a pathname"), + EXCEP_TXT ("AE_BAD_DATA", "A package or buffer contained incorrect data"), + EXCEP_TXT ("AE_BAD_HEX_CONSTANT", "Invalid character in a Hex constant"), + EXCEP_TXT ("AE_BAD_OCTAL_CONSTANT", "Invalid character in an Octal constant"), + EXCEP_TXT ("AE_BAD_DECIMAL_CONSTANT", "Invalid character in a Decimal constant"), + EXCEP_TXT ("AE_MISSING_ARGUMENTS", "Too few arguments were passed to a control method"), + EXCEP_TXT ("AE_BAD_ADDRESS", "An illegal null I/O address") +}; + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Tbl[] = +{ + EXCEP_TXT (NULL, NULL), + EXCEP_TXT ("AE_BAD_SIGNATURE", "An ACPI table has an invalid signature"), + EXCEP_TXT ("AE_BAD_HEADER", "Invalid field in an ACPI table header"), + EXCEP_TXT ("AE_BAD_CHECKSUM", "An ACPI table checksum is not correct"), + EXCEP_TXT ("AE_BAD_VALUE", "An invalid value was found in a table"), + EXCEP_TXT ("AE_INVALID_TABLE_LENGTH", "The FADT or FACS has improper length") +}; + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Aml[] = +{ + EXCEP_TXT (NULL, NULL), + EXCEP_TXT ("AE_AML_BAD_OPCODE", "Invalid AML opcode encountered"), + EXCEP_TXT ("AE_AML_NO_OPERAND", "A required operand is missing"), + EXCEP_TXT ("AE_AML_OPERAND_TYPE", "An operand of an incorrect type was encountered"), + EXCEP_TXT ("AE_AML_OPERAND_VALUE", "The operand had an inappropriate or invalid value"), + EXCEP_TXT ("AE_AML_UNINITIALIZED_LOCAL", "Method tried to use an uninitialized local variable"), + EXCEP_TXT ("AE_AML_UNINITIALIZED_ARG", "Method tried to use an uninitialized argument"), + EXCEP_TXT ("AE_AML_UNINITIALIZED_ELEMENT", "Method tried to use an empty package element"), + EXCEP_TXT ("AE_AML_NUMERIC_OVERFLOW", "Overflow during BCD conversion or other"), + EXCEP_TXT ("AE_AML_REGION_LIMIT", "Tried to access beyond the end of an Operation Region"), + EXCEP_TXT ("AE_AML_BUFFER_LIMIT", "Tried to access beyond the end of a buffer"), + EXCEP_TXT ("AE_AML_PACKAGE_LIMIT", "Tried to access beyond the end of a package"), + EXCEP_TXT ("AE_AML_DIVIDE_BY_ZERO", "During execution of AML Divide operator"), + EXCEP_TXT ("AE_AML_BAD_NAME", "An ACPI name contains invalid character(s)"), + EXCEP_TXT ("AE_AML_NAME_NOT_FOUND", "Could not resolve a named reference"), + EXCEP_TXT ("AE_AML_INTERNAL", "An internal error within the interprete"), + EXCEP_TXT ("AE_AML_INVALID_SPACE_ID", "An Operation Region SpaceID is invalid"), + EXCEP_TXT ("AE_AML_STRING_LIMIT", "String is longer than 200 characters"), + EXCEP_TXT ("AE_AML_NO_RETURN_VALUE", "A method did not return a required value"), + EXCEP_TXT ("AE_AML_METHOD_LIMIT", "A control method reached the maximum reentrancy limit of 255"), + EXCEP_TXT ("AE_AML_NOT_OWNER", "A thread tried to release a mutex that it does not own"), + EXCEP_TXT ("AE_AML_MUTEX_ORDER", "Mutex SyncLevel release mismatch"), + EXCEP_TXT ("AE_AML_MUTEX_NOT_ACQUIRED", "Attempt to release a mutex that was not previously acquired"), + EXCEP_TXT ("AE_AML_INVALID_RESOURCE_TYPE", "Invalid resource type in resource list"), + EXCEP_TXT ("AE_AML_INVALID_INDEX", "Invalid Argx or Localx (x too large)"), + EXCEP_TXT ("AE_AML_REGISTER_LIMIT", "Bank value or Index value beyond range of register"), + EXCEP_TXT ("AE_AML_NO_WHILE", "Break or Continue without a While"), + EXCEP_TXT ("AE_AML_ALIGNMENT", "Non-aligned memory transfer on platform that does not support this"), + EXCEP_TXT ("AE_AML_NO_RESOURCE_END_TAG", "No End Tag in a resource list"), + EXCEP_TXT ("AE_AML_BAD_RESOURCE_VALUE", "Invalid value of a resource element"), + EXCEP_TXT ("AE_AML_CIRCULAR_REFERENCE", "Two references refer to each other"), + EXCEP_TXT ("AE_AML_BAD_RESOURCE_LENGTH", "The length of a Resource Descriptor in the AML is incorrect"), + EXCEP_TXT ("AE_AML_ILLEGAL_ADDRESS", "A memory, I/O, or PCI configuration address is invalid"), + EXCEP_TXT ("AE_AML_LOOP_TIMEOUT", "An AML While loop exceeded the maximum execution time"), + EXCEP_TXT ("AE_AML_UNINITIALIZED_NODE", "A namespace node is uninitialized or unresolved"), + EXCEP_TXT ("AE_AML_TARGET_TYPE", "A target operand of an incorrect type was encountered") +}; + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Ctrl[] = +{ + EXCEP_TXT (NULL, NULL), + EXCEP_TXT ("AE_CTRL_RETURN_VALUE", "A Method returned a value"), + EXCEP_TXT ("AE_CTRL_PENDING", "Method is calling another method"), + EXCEP_TXT ("AE_CTRL_TERMINATE", "Terminate the executing method"), + EXCEP_TXT ("AE_CTRL_TRUE", "An If or While predicate result"), + EXCEP_TXT ("AE_CTRL_FALSE", "An If or While predicate result"), + EXCEP_TXT ("AE_CTRL_DEPTH", "Maximum search depth has been reached"), + EXCEP_TXT ("AE_CTRL_END", "An If or While predicate is false"), + EXCEP_TXT ("AE_CTRL_TRANSFER", "Transfer control to called method"), + EXCEP_TXT ("AE_CTRL_BREAK", "A Break has been executed"), + EXCEP_TXT ("AE_CTRL_CONTINUE", "A Continue has been executed"), + EXCEP_TXT ("AE_CTRL_PARSE_CONTINUE", "Used to skip over bad opcodes"), + EXCEP_TXT ("AE_CTRL_PARSE_PENDING", "Used to implement AML While loops") +}; + +#endif /* EXCEPTION_TABLE */ + +#endif /* __ACEXCEP_H__ */ diff --git a/ports/acpica/include/acglobal.h b/ports/acpica/include/acglobal.h new file mode 100644 index 0000000..3c2a4ed --- /dev/null +++ b/ports/acpica/include/acglobal.h @@ -0,0 +1,533 @@ +/****************************************************************************** + * + * Name: acglobal.h - Declarations for global variables + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACGLOBAL_H__ +#define __ACGLOBAL_H__ + + +/***************************************************************************** + * + * Globals related to the incoming ACPI tables + * + ****************************************************************************/ + +/* Master list of all ACPI tables that were found in the RSDT/XSDT */ + +ACPI_GLOBAL (ACPI_TABLE_LIST, AcpiGbl_RootTableList); + +/* DSDT information. Used to check for DSDT corruption */ + +ACPI_GLOBAL (ACPI_TABLE_HEADER *, AcpiGbl_DSDT); +ACPI_GLOBAL (ACPI_TABLE_HEADER, AcpiGbl_OriginalDsdtHeader); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_DsdtIndex, ACPI_INVALID_TABLE_INDEX); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_FacsIndex, ACPI_INVALID_TABLE_INDEX); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_XFacsIndex, ACPI_INVALID_TABLE_INDEX); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_FadtIndex, ACPI_INVALID_TABLE_INDEX); + +#if (!ACPI_REDUCED_HARDWARE) +ACPI_GLOBAL (ACPI_TABLE_FACS *, AcpiGbl_FACS); + +#endif /* !ACPI_REDUCED_HARDWARE */ + +/* These addresses are calculated from the FADT Event Block addresses */ + +ACPI_GLOBAL (ACPI_GENERIC_ADDRESS, AcpiGbl_XPm1aStatus); +ACPI_GLOBAL (ACPI_GENERIC_ADDRESS, AcpiGbl_XPm1aEnable); + +ACPI_GLOBAL (ACPI_GENERIC_ADDRESS, AcpiGbl_XPm1bStatus); +ACPI_GLOBAL (ACPI_GENERIC_ADDRESS, AcpiGbl_XPm1bEnable); + +/* + * Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is + * determined by the revision of the DSDT: If the DSDT revision is less than + * 2, use only the lower 32 bits of the internal 64-bit Integer. + */ +ACPI_GLOBAL (UINT8, AcpiGbl_IntegerBitWidth); +ACPI_GLOBAL (UINT8, AcpiGbl_IntegerByteWidth); +ACPI_GLOBAL (UINT8, AcpiGbl_IntegerNybbleWidth); + + +/***************************************************************************** + * + * Mutual exclusion within the ACPICA subsystem + * + ****************************************************************************/ + +/* + * Predefined mutex objects. This array contains the + * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs. + * (The table maps local handles to the real OS handles) + */ +ACPI_GLOBAL (ACPI_MUTEX_INFO, AcpiGbl_MutexInfo[ACPI_NUM_MUTEX]); + +/* + * Global lock mutex is an actual AML mutex object + * Global lock semaphore works in conjunction with the actual global lock + * Global lock spinlock is used for "pending" handshake + */ +ACPI_GLOBAL (ACPI_OPERAND_OBJECT *, AcpiGbl_GlobalLockMutex); +ACPI_GLOBAL (ACPI_SEMAPHORE, AcpiGbl_GlobalLockSemaphore); +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_GlobalLockPendingLock); +ACPI_GLOBAL (UINT16, AcpiGbl_GlobalLockHandle); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_GlobalLockAcquired); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_GlobalLockPresent); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_GlobalLockPending); + +/* + * Spinlocks are used for interfaces that can be possibly called at + * interrupt level + */ +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_GpeLock); /* For GPE data structs and registers */ +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_HardwareLock); /* For ACPI H/W except GPE registers */ +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_ReferenceCountLock); + +/* Mutex for _OSI support */ + +ACPI_GLOBAL (ACPI_MUTEX, AcpiGbl_OsiMutex); + +/* Reader/Writer lock is used for namespace walk and dynamic table unload */ + +ACPI_GLOBAL (ACPI_RW_LOCK, AcpiGbl_NamespaceRwLock); + + +/***************************************************************************** + * + * Miscellaneous globals + * + ****************************************************************************/ + +/* Object caches */ + +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_NamespaceCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_StateCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_PsNodeCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_PsNodeExtCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_OperandCache); + +/* System */ + +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_StartupFlags, 0); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_Shutdown, TRUE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_EarlyInitialization, TRUE); + +/* Global handlers */ + +ACPI_GLOBAL (ACPI_GLOBAL_NOTIFY_HANDLER,AcpiGbl_GlobalNotify[2]); +ACPI_GLOBAL (ACPI_EXCEPTION_HANDLER, AcpiGbl_ExceptionHandler); +ACPI_GLOBAL (ACPI_INIT_HANDLER, AcpiGbl_InitHandler); +ACPI_GLOBAL (ACPI_TABLE_HANDLER, AcpiGbl_TableHandler); +ACPI_GLOBAL (void *, AcpiGbl_TableHandlerContext); +ACPI_GLOBAL (ACPI_INTERFACE_HANDLER, AcpiGbl_InterfaceHandler); +ACPI_GLOBAL (ACPI_SCI_HANDLER_INFO *, AcpiGbl_SciHandlerList); + +/* Owner ID support */ + +ACPI_GLOBAL (UINT32, AcpiGbl_OwnerIdMask[ACPI_NUM_OWNERID_MASKS]); +ACPI_GLOBAL (UINT8, AcpiGbl_LastOwnerIdIndex); +ACPI_GLOBAL (UINT8, AcpiGbl_NextOwnerIdOffset); + +/* Initialization sequencing */ + +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_NamespaceInitialized, FALSE); + +/* Miscellaneous */ + +ACPI_GLOBAL (UINT32, AcpiGbl_OriginalMode); +ACPI_GLOBAL (UINT32, AcpiGbl_NsLookupCount); +ACPI_GLOBAL (UINT32, AcpiGbl_PsFindCount); +ACPI_GLOBAL (UINT16, AcpiGbl_Pm1EnableRegisterSave); +ACPI_GLOBAL (UINT8, AcpiGbl_DebuggerConfiguration); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_StepToNextCall); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_AcpiHardwarePresent); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_EventsInitialized); +ACPI_GLOBAL (ACPI_INTERFACE_INFO *, AcpiGbl_SupportedInterfaces); +ACPI_GLOBAL (ACPI_ADDRESS_RANGE *, AcpiGbl_AddressRangeList[ACPI_ADDRESS_RANGE_MAX]); + +/* Other miscellaneous, declared and initialized in utglobal */ + +extern const char *AcpiGbl_SleepStateNames[ACPI_S_STATE_COUNT]; +extern const char *AcpiGbl_LowestDstateNames[ACPI_NUM_SxW_METHODS]; +extern const char *AcpiGbl_HighestDstateNames[ACPI_NUM_SxD_METHODS]; +extern const char *AcpiGbl_RegionTypes[ACPI_NUM_PREDEFINED_REGIONS]; +extern const char AcpiGbl_LowerHexDigits[]; +extern const char AcpiGbl_UpperHexDigits[]; +extern const ACPI_OPCODE_INFO AcpiGbl_AmlOpInfo[AML_NUM_OPCODES]; + +/* Lists for tracking memory allocations (debug only) */ + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +ACPI_GLOBAL (ACPI_MEMORY_LIST *, AcpiGbl_GlobalList); +ACPI_GLOBAL (ACPI_MEMORY_LIST *, AcpiGbl_NsNodeList); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DisplayFinalMemStats); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DisableMemTracking); +#endif + + +/***************************************************************************** + * + * ACPI Namespace + * + ****************************************************************************/ + +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#define NUM_PREDEFINED_NAMES 10 +#else +#define NUM_PREDEFINED_NAMES 9 +#endif + +ACPI_GLOBAL (ACPI_NAMESPACE_NODE, AcpiGbl_RootNodeStruct); +ACPI_GLOBAL (ACPI_NAMESPACE_NODE *, AcpiGbl_RootNode); +ACPI_GLOBAL (ACPI_NAMESPACE_NODE *, AcpiGbl_FadtGpeDevice); +ACPI_GLOBAL (ACPI_OPERAND_OBJECT *, AcpiGbl_ModuleCodeList); + +extern const UINT8 AcpiGbl_NsProperties [ACPI_NUM_NS_TYPES]; +extern const ACPI_PREDEFINED_NAMES AcpiGbl_PreDefinedNames [NUM_PREDEFINED_NAMES]; + +#ifdef ACPI_DEBUG_OUTPUT +ACPI_GLOBAL (UINT32, AcpiGbl_CurrentNodeCount); +ACPI_GLOBAL (UINT32, AcpiGbl_CurrentNodeSize); +ACPI_GLOBAL (UINT32, AcpiGbl_MaxConcurrentNodeCount); +ACPI_GLOBAL (ACPI_SIZE *, AcpiGbl_EntryStackPointer); +ACPI_GLOBAL (ACPI_SIZE *, AcpiGbl_LowestStackPointer); +ACPI_GLOBAL (UINT32, AcpiGbl_DeepestNesting); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_NestingLevel, 0); +#endif + + +/***************************************************************************** + * + * Interpreter/Parser globals + * + ****************************************************************************/ + +/* Control method single step flag */ + +ACPI_GLOBAL (UINT8, AcpiGbl_CmSingleStep); +ACPI_GLOBAL (ACPI_THREAD_STATE *, AcpiGbl_CurrentWalkList); +ACPI_INIT_GLOBAL (ACPI_PARSE_OBJECT, *AcpiGbl_CurrentScope, NULL); + +/* ASL/ASL+ converter */ + +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_CaptureComments, FALSE); +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_LastListHead, NULL); + + +/***************************************************************************** + * + * Hardware globals + * + ****************************************************************************/ + +extern ACPI_BIT_REGISTER_INFO AcpiGbl_BitRegisterInfo[ACPI_NUM_BITREG]; +ACPI_GLOBAL (UINT8, AcpiGbl_SleepTypeA); +ACPI_GLOBAL (UINT8, AcpiGbl_SleepTypeB); + + +/***************************************************************************** + * + * Event and GPE globals + * + ****************************************************************************/ + +#if (!ACPI_REDUCED_HARDWARE) +ACPI_GLOBAL (UINT8, AcpiGbl_AllGpesInitialized); +ACPI_GLOBAL (ACPI_GPE_XRUPT_INFO *, AcpiGbl_GpeXruptListHead); +ACPI_GLOBAL (ACPI_GPE_BLOCK_INFO *, AcpiGbl_GpeFadtBlocks[ACPI_MAX_GPE_BLOCKS]); +ACPI_GLOBAL (ACPI_GBL_EVENT_HANDLER, AcpiGbl_GlobalEventHandler); +ACPI_GLOBAL (void *, AcpiGbl_GlobalEventHandlerContext); +ACPI_GLOBAL (ACPI_FIXED_EVENT_HANDLER, AcpiGbl_FixedEventHandlers[ACPI_NUM_FIXED_EVENTS]); +extern ACPI_FIXED_EVENT_INFO AcpiGbl_FixedEventInfo[ACPI_NUM_FIXED_EVENTS]; +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/***************************************************************************** + * + * Debug support + * + ****************************************************************************/ + +/* Event counters */ + +ACPI_GLOBAL (UINT32, AcpiMethodCount); +ACPI_GLOBAL (UINT32, AcpiGpeCount); +ACPI_GLOBAL (UINT32, AcpiSciCount); +ACPI_GLOBAL (UINT32, AcpiFixedEventCount[ACPI_NUM_FIXED_EVENTS]); + +/* Dynamic control method tracing mechanism */ + +ACPI_GLOBAL (UINT32, AcpiGbl_OriginalDbgLevel); +ACPI_GLOBAL (UINT32, AcpiGbl_OriginalDbgLayer); + + +/***************************************************************************** + * + * Debugger and Disassembler + * + ****************************************************************************/ + +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DbOutputFlags, ACPI_DB_CONSOLE_OUTPUT); + + +#ifdef ACPI_DISASSEMBLER + +/* Do not disassemble buffers to resource descriptors */ + +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_NoResourceDisassembly, FALSE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_IgnoreNoopOperator, FALSE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_CstyleDisassembly, TRUE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_ForceAmlDisassembly, FALSE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_DmOpt_Verbose, TRUE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_DmEmitExternalOpcodes, FALSE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_DoDisassemblerOptimizations, TRUE); +ACPI_INIT_GLOBAL (ACPI_PARSE_OBJECT_LIST, *AcpiGbl_TempListHead, NULL); + +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DmOpt_Disasm); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DmOpt_Listing); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_NumExternalMethods); +ACPI_GLOBAL (UINT32, AcpiGbl_ResolvedExternalMethods); +ACPI_GLOBAL (ACPI_EXTERNAL_LIST *, AcpiGbl_ExternalList); +ACPI_GLOBAL (ACPI_EXTERNAL_FILE *, AcpiGbl_ExternalFileList); +#endif + +#ifdef ACPI_DEBUGGER +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_AbortMethod, FALSE); +ACPI_INIT_GLOBAL (ACPI_THREAD_ID, AcpiGbl_DbThreadId, ACPI_INVALID_THREAD_ID); + +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_NoIniMethods); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_NoRegionSupport); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOutputToFile); +ACPI_GLOBAL (char *, AcpiGbl_DbBuffer); +ACPI_GLOBAL (char *, AcpiGbl_DbFilename); +ACPI_GLOBAL (UINT32, AcpiGbl_DbDebugLevel); +ACPI_GLOBAL (UINT32, AcpiGbl_DbConsoleDebugLevel); +ACPI_GLOBAL (ACPI_NAMESPACE_NODE *, AcpiGbl_DbScopeNode); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbTerminateLoop); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbThreadsTerminated); +ACPI_GLOBAL (char *, AcpiGbl_DbArgs[ACPI_DEBUGGER_MAX_ARGS]); +ACPI_GLOBAL (ACPI_OBJECT_TYPE, AcpiGbl_DbArgTypes[ACPI_DEBUGGER_MAX_ARGS]); + +/* These buffers should all be the same size */ + +ACPI_GLOBAL (char, AcpiGbl_DbParsedBuf[ACPI_DB_LINE_BUFFER_SIZE]); +ACPI_GLOBAL (char, AcpiGbl_DbScopeBuf[ACPI_DB_LINE_BUFFER_SIZE]); +ACPI_GLOBAL (char, AcpiGbl_DbDebugFilename[ACPI_DB_LINE_BUFFER_SIZE]); + +/* Statistics globals */ + +ACPI_GLOBAL (UINT16, AcpiGbl_ObjTypeCount[ACPI_TOTAL_TYPES]); +ACPI_GLOBAL (UINT16, AcpiGbl_NodeTypeCount[ACPI_TOTAL_TYPES]); +ACPI_GLOBAL (UINT16, AcpiGbl_ObjTypeCountMisc); +ACPI_GLOBAL (UINT16, AcpiGbl_NodeTypeCountMisc); +ACPI_GLOBAL (UINT32, AcpiGbl_NumNodes); +ACPI_GLOBAL (UINT32, AcpiGbl_NumObjects); +#endif /* ACPI_DEBUGGER */ + +#if defined (ACPI_DISASSEMBLER) || defined (ACPI_ASL_COMPILER) +ACPI_GLOBAL (const char, *AcpiGbl_PldPanelList[]); +ACPI_GLOBAL (const char, *AcpiGbl_PldVerticalPositionList[]); +ACPI_GLOBAL (const char, *AcpiGbl_PldHorizontalPositionList[]); +ACPI_GLOBAL (const char, *AcpiGbl_PldShapeList[]); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_DisasmFlag, FALSE); +#endif + + +/***************************************************************************** + * + * ACPICA application-specific globals + * + ****************************************************************************/ + +/* ASL-to-ASL+ conversion utility (implemented within the iASL compiler) */ + +#ifdef ACPI_ASL_COMPILER +ACPI_INIT_GLOBAL (char *, AcpiGbl_CurrentInlineComment, NULL); +ACPI_INIT_GLOBAL (char *, AcpiGbl_CurrentEndNodeComment, NULL); +ACPI_INIT_GLOBAL (char *, AcpiGbl_CurrentOpenBraceComment, NULL); +ACPI_INIT_GLOBAL (char *, AcpiGbl_CurrentCloseBraceComment, NULL); + +ACPI_INIT_GLOBAL (char *, AcpiGbl_RootFilename, NULL); +ACPI_INIT_GLOBAL (char *, AcpiGbl_CurrentFilename, NULL); +ACPI_INIT_GLOBAL (char *, AcpiGbl_CurrentParentFilename, NULL); +ACPI_INIT_GLOBAL (char *, AcpiGbl_CurrentIncludeFilename, NULL); + +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_DefBlkCommentListHead, NULL); +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_DefBlkCommentListTail, NULL); +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_RegCommentListHead, NULL); +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_RegCommentListTail, NULL); +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_IncCommentListHead, NULL); +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_IncCommentListTail, NULL); +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_EndBlkCommentListHead, NULL); +ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_EndBlkCommentListTail, NULL); + +ACPI_INIT_GLOBAL (ACPI_COMMENT_ADDR_NODE, *AcpiGbl_CommentAddrListHead, NULL); +ACPI_INIT_GLOBAL (ACPI_FILE_NODE, *AcpiGbl_FileTreeRoot, NULL); + +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_RegCommentCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_CommentAddrCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_FileCache); + +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_DebugAslConversion, FALSE); +ACPI_INIT_GLOBAL (ACPI_FILE, AcpiGbl_ConvDebugFile, NULL); +ACPI_GLOBAL (char, AcpiGbl_TableSig[4]); +#endif + +#ifdef ACPI_APPLICATION +ACPI_INIT_GLOBAL (ACPI_FILE, AcpiGbl_DebugFile, NULL); +ACPI_INIT_GLOBAL (ACPI_FILE, AcpiGbl_OutputFile, NULL); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_DebugTimeout, FALSE); + +/* Print buffer */ + +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_PrintLock); /* For print buffer */ +ACPI_GLOBAL (char, AcpiGbl_PrintBuffer[1024]); +#endif /* ACPI_APPLICATION */ + +#endif /* __ACGLOBAL_H__ */ diff --git a/ports/acpica/include/achware.h b/ports/acpica/include/achware.h new file mode 100644 index 0000000..1c43926 --- /dev/null +++ b/ports/acpica/include/achware.h @@ -0,0 +1,335 @@ +/****************************************************************************** + * + * Name: achware.h -- hardware specific interfaces + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACHWARE_H__ +#define __ACHWARE_H__ + + +/* Values for the _SST predefined method */ + +#define ACPI_SST_INDICATOR_OFF 0 +#define ACPI_SST_WORKING 1 +#define ACPI_SST_WAKING 2 +#define ACPI_SST_SLEEPING 3 +#define ACPI_SST_SLEEP_CONTEXT 4 + + +/* + * hwacpi - high level functions + */ +ACPI_STATUS +AcpiHwSetMode ( + UINT32 Mode); + +UINT32 +AcpiHwGetMode ( + void); + + +/* + * hwregs - ACPI Register I/O + */ +ACPI_STATUS +AcpiHwValidateRegister ( + ACPI_GENERIC_ADDRESS *Reg, + UINT8 MaxBitWidth, + UINT64 *Address); + +ACPI_STATUS +AcpiHwRead ( + UINT64 *Value, + ACPI_GENERIC_ADDRESS *Reg); + +ACPI_STATUS +AcpiHwWrite ( + UINT64 Value, + ACPI_GENERIC_ADDRESS *Reg); + +ACPI_BIT_REGISTER_INFO * +AcpiHwGetBitRegisterInfo ( + UINT32 RegisterId); + +ACPI_STATUS +AcpiHwWritePm1Control ( + UINT32 Pm1aControl, + UINT32 Pm1bControl); + +ACPI_STATUS +AcpiHwRegisterRead ( + UINT32 RegisterId, + UINT32 *ReturnValue); + +ACPI_STATUS +AcpiHwRegisterWrite ( + UINT32 RegisterId, + UINT32 Value); + +ACPI_STATUS +AcpiHwClearAcpiStatus ( + void); + + +/* + * hwsleep - sleep/wake support (Legacy sleep registers) + */ +ACPI_STATUS +AcpiHwLegacySleep ( + UINT8 SleepState); + +ACPI_STATUS +AcpiHwLegacyWakePrep ( + UINT8 SleepState); + +ACPI_STATUS +AcpiHwLegacyWake ( + UINT8 SleepState); + + +/* + * hwesleep - sleep/wake support (Extended FADT-V5 sleep registers) + */ +void +AcpiHwExecuteSleepMethod ( + char *MethodName, + UINT32 IntegerArgument); + +ACPI_STATUS +AcpiHwExtendedSleep ( + UINT8 SleepState); + +ACPI_STATUS +AcpiHwExtendedWakePrep ( + UINT8 SleepState); + +ACPI_STATUS +AcpiHwExtendedWake ( + UINT8 SleepState); + + +/* + * hwvalid - Port I/O with validation + */ +ACPI_STATUS +AcpiHwReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width); + +ACPI_STATUS +AcpiHwWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width); + + +/* + * hwgpe - GPE support + */ +UINT32 +AcpiHwGetGpeRegisterBit ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiHwLowSetGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 Action); + +ACPI_STATUS +AcpiHwDisableGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +ACPI_STATUS +AcpiHwClearGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiHwClearGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +ACPI_STATUS +AcpiHwGetGpeStatus ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + ACPI_EVENT_STATUS *EventStatus); + +ACPI_STATUS +AcpiHwDisableAllGpes ( + void); + +ACPI_STATUS +AcpiHwEnableAllRuntimeGpes ( + void); + +ACPI_STATUS +AcpiHwEnableAllWakeupGpes ( + void); + +ACPI_STATUS +AcpiHwEnableRuntimeGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + + +/* + * hwpci - PCI configuration support + */ +ACPI_STATUS +AcpiHwDerivePciId ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion); + + +#endif /* __ACHWARE_H__ */ diff --git a/ports/acpica/include/acinterp.h b/ports/acpica/include/acinterp.h new file mode 100644 index 0000000..fde066d --- /dev/null +++ b/ports/acpica/include/acinterp.h @@ -0,0 +1,861 @@ +/****************************************************************************** + * + * Name: acinterp.h - Interpreter subcomponent prototypes and defines + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACINTERP_H__ +#define __ACINTERP_H__ + + +#define ACPI_WALK_OPERANDS (&(WalkState->Operands [WalkState->NumOperands -1])) + +/* Macros for tables used for debug output */ + +#define ACPI_EXD_OFFSET(f) (UINT8) ACPI_OFFSET (ACPI_OPERAND_OBJECT,f) +#define ACPI_EXD_NSOFFSET(f) (UINT8) ACPI_OFFSET (ACPI_NAMESPACE_NODE,f) +#define ACPI_EXD_TABLE_SIZE(name) (sizeof(name) / sizeof (ACPI_EXDUMP_INFO)) + +/* + * If possible, pack the following structures to byte alignment, since we + * don't care about performance for debug output. Two cases where we cannot + * pack the structures: + * + * 1) Hardware does not support misaligned memory transfers + * 2) Compiler does not support pointers within packed structures + */ +#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) +#pragma pack(1) +#endif + +typedef const struct acpi_exdump_info +{ + UINT8 Opcode; + UINT8 Offset; + const char *Name; + +} ACPI_EXDUMP_INFO; + +/* Values for the Opcode field above */ + +#define ACPI_EXD_INIT 0 +#define ACPI_EXD_TYPE 1 +#define ACPI_EXD_UINT8 2 +#define ACPI_EXD_UINT16 3 +#define ACPI_EXD_UINT32 4 +#define ACPI_EXD_UINT64 5 +#define ACPI_EXD_LITERAL 6 +#define ACPI_EXD_POINTER 7 +#define ACPI_EXD_ADDRESS 8 +#define ACPI_EXD_STRING 9 +#define ACPI_EXD_BUFFER 10 +#define ACPI_EXD_PACKAGE 11 +#define ACPI_EXD_FIELD 12 +#define ACPI_EXD_REFERENCE 13 +#define ACPI_EXD_LIST 14 /* Operand object list */ +#define ACPI_EXD_HDLR_LIST 15 /* Address Handler list */ +#define ACPI_EXD_RGN_LIST 16 /* Region list */ +#define ACPI_EXD_NODE 17 /* Namespace Node */ + +/* restore default alignment */ + +#pragma pack() + + +/* + * exconvrt - object conversion + */ +ACPI_STATUS +AcpiExConvertToInteger ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + UINT32 ImplicitConversion); + +ACPI_STATUS +AcpiExConvertToBuffer ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc); + +ACPI_STATUS +AcpiExConvertToString ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + UINT32 Type); + +/* Types for ->String conversion */ + +#define ACPI_EXPLICIT_BYTE_COPY 0x00000000 +#define ACPI_EXPLICIT_CONVERT_HEX 0x00000001 +#define ACPI_IMPLICIT_CONVERT_HEX 0x00000002 +#define ACPI_EXPLICIT_CONVERT_DECIMAL 0x00000003 + +ACPI_STATUS +AcpiExConvertToTargetType ( + ACPI_OBJECT_TYPE DestinationType, + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + ACPI_WALK_STATE *WalkState); + + +/* + * exdebug - AML debug object + */ +void +AcpiExDoDebugObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + UINT32 Level, + UINT32 Index); + +void +AcpiExStartTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +void +AcpiExStopTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +void +AcpiExStartTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +void +AcpiExStopTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +void +AcpiExTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname); + + +/* + * exfield - ACPI AML (p-code) execution - field manipulation + */ +ACPI_STATUS +AcpiExCommonBufferSetup ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 BufferLength, + UINT32 *DatumCount); + +ACPI_STATUS +AcpiExWriteWithUpdateRule ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT64 Mask, + UINT64 FieldValue, + UINT32 FieldDatumByteOffset); + +void +AcpiExGetBufferDatum( + UINT64 *Datum, + void *Buffer, + UINT32 BufferLength, + UINT32 ByteGranularity, + UINT32 BufferOffset); + +void +AcpiExSetBufferDatum ( + UINT64 MergedDatum, + void *Buffer, + UINT32 BufferLength, + UINT32 ByteGranularity, + UINT32 BufferOffset); + +ACPI_STATUS +AcpiExReadDataFromField ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **RetBufferDesc); + +ACPI_STATUS +AcpiExWriteDataToField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc); + + +/* + * exfldio - low level field I/O + */ +ACPI_STATUS +AcpiExExtractFromField ( + ACPI_OPERAND_OBJECT *ObjDesc, + void *Buffer, + UINT32 BufferLength); + +ACPI_STATUS +AcpiExInsertIntoField ( + ACPI_OPERAND_OBJECT *ObjDesc, + void *Buffer, + UINT32 BufferLength); + +ACPI_STATUS +AcpiExAccessRegion ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset, + UINT64 *Value, + UINT32 ReadWrite); + + +/* + * exmisc - misc support routines + */ +ACPI_STATUS +AcpiExGetObjectReference ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ReturnDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExConcatTemplate ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *ObjDesc2, + ACPI_OPERAND_OBJECT **ActualReturnDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExDoConcatenate ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *ObjDesc2, + ACPI_OPERAND_OBJECT **ActualReturnDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExDoLogicalNumericOp ( + UINT16 Opcode, + UINT64 Integer0, + UINT64 Integer1, + BOOLEAN *LogicalResult); + +ACPI_STATUS +AcpiExDoLogicalOp ( + UINT16 Opcode, + ACPI_OPERAND_OBJECT *Operand0, + ACPI_OPERAND_OBJECT *Operand1, + BOOLEAN *LogicalResult); + +UINT64 +AcpiExDoMathOp ( + UINT16 Opcode, + UINT64 Operand0, + UINT64 Operand1); + +ACPI_STATUS +AcpiExCreateMutex ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateProcessor ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreatePowerResource ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateRegion ( + UINT8 *AmlStart, + UINT32 AmlLength, + UINT8 RegionSpace, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateEvent ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateAlias ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateMethod ( + UINT8 *AmlStart, + UINT32 AmlLength, + ACPI_WALK_STATE *WalkState); + + +/* + * exconfig - dynamic table load/unload + */ +ACPI_STATUS +AcpiExLoadOp ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *Target, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExLoadTableOp ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT **ReturnDesc); + +ACPI_STATUS +AcpiExUnloadTable ( + ACPI_OPERAND_OBJECT *DdbHandle); + + +/* + * exmutex - mutex support + */ +ACPI_STATUS +AcpiExAcquireMutex ( + ACPI_OPERAND_OBJECT *TimeDesc, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExAcquireMutexObject ( + UINT16 Timeout, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_THREAD_ID ThreadId); + +ACPI_STATUS +AcpiExReleaseMutex ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExReleaseMutexObject ( + ACPI_OPERAND_OBJECT *ObjDesc); + +void +AcpiExReleaseAllMutexes ( + ACPI_THREAD_STATE *Thread); + +void +AcpiExUnlinkMutex ( + ACPI_OPERAND_OBJECT *ObjDesc); + + +/* + * exprep - ACPI AML execution - prep utilities + */ +ACPI_STATUS +AcpiExPrepCommonFieldObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT8 FieldFlags, + UINT8 FieldAttribute, + UINT32 FieldBitPosition, + UINT32 FieldBitLength); + +ACPI_STATUS +AcpiExPrepFieldValue ( + ACPI_CREATE_FIELD_INFO *Info); + + +/* + * exsystem - Interface to OS services + */ +ACPI_STATUS +AcpiExSystemDoNotifyOp ( + ACPI_OPERAND_OBJECT *Value, + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiExSystemDoSleep( + UINT64 Time); + +ACPI_STATUS +AcpiExSystemDoStall ( + UINT32 Time); + +ACPI_STATUS +AcpiExSystemSignalEvent( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiExSystemWaitEvent( + ACPI_OPERAND_OBJECT *Time, + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiExSystemResetEvent( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiExSystemWaitSemaphore ( + ACPI_SEMAPHORE Semaphore, + UINT16 Timeout); + +ACPI_STATUS +AcpiExSystemWaitMutex ( + ACPI_MUTEX Mutex, + UINT16 Timeout); + +/* + * exoparg1 - ACPI AML execution, 1 operand + */ +ACPI_STATUS +AcpiExOpcode_0A_0T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_1A_0T_0R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_1A_0T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_1A_1T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_1A_1T_0R ( + ACPI_WALK_STATE *WalkState); + +/* + * exoparg2 - ACPI AML execution, 2 operands + */ +ACPI_STATUS +AcpiExOpcode_2A_0T_0R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_2A_0T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_2A_1T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_2A_2T_1R ( + ACPI_WALK_STATE *WalkState); + + +/* + * exoparg3 - ACPI AML execution, 3 operands + */ +ACPI_STATUS +AcpiExOpcode_3A_0T_0R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_3A_1T_1R ( + ACPI_WALK_STATE *WalkState); + + +/* + * exoparg6 - ACPI AML execution, 6 operands + */ +ACPI_STATUS +AcpiExOpcode_6A_0T_1R ( + ACPI_WALK_STATE *WalkState); + + +/* + * exresolv - Object resolution and get value functions + */ +ACPI_STATUS +AcpiExResolveToValue ( + ACPI_OPERAND_OBJECT **StackPtr, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExResolveMultiple ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *Operand, + ACPI_OBJECT_TYPE *ReturnType, + ACPI_OPERAND_OBJECT **ReturnDesc); + + +/* + * exresnte - resolve namespace node + */ +ACPI_STATUS +AcpiExResolveNodeToValue ( + ACPI_NAMESPACE_NODE **StackPtr, + ACPI_WALK_STATE *WalkState); + + +/* + * exresop - resolve operand to value + */ +ACPI_STATUS +AcpiExResolveOperands ( + UINT16 Opcode, + ACPI_OPERAND_OBJECT **StackPtr, + ACPI_WALK_STATE *WalkState); + + +/* + * exdump - Interpreter debug output routines + */ +void +AcpiExDumpOperand ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Depth); + +void +AcpiExDumpOperands ( + ACPI_OPERAND_OBJECT **Operands, + const char *OpcodeName, + UINT32 NumOpcodes); + +void +AcpiExDumpObjectDescriptor ( + ACPI_OPERAND_OBJECT *Object, + UINT32 Flags); + +void +AcpiExDumpNamespaceNode ( + ACPI_NAMESPACE_NODE *Node, + UINT32 Flags); + + +/* + * exnames - AML namestring support + */ +ACPI_STATUS +AcpiExGetNameString ( + ACPI_OBJECT_TYPE DataType, + UINT8 *InAmlAddress, + char **OutNameString, + UINT32 *OutNameLength); + + +/* + * exstore - Object store support + */ +ACPI_STATUS +AcpiExStore ( + ACPI_OPERAND_OBJECT *ValDesc, + ACPI_OPERAND_OBJECT *DestDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExStoreObjectToNode ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_NAMESPACE_NODE *Node, + ACPI_WALK_STATE *WalkState, + UINT8 ImplicitConversion); + + +/* + * exstoren - resolve/store object + */ +ACPI_STATUS +AcpiExResolveObject ( + ACPI_OPERAND_OBJECT **SourceDescPtr, + ACPI_OBJECT_TYPE TargetType, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExStoreObjectToObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *DestDesc, + ACPI_OPERAND_OBJECT **NewDesc, + ACPI_WALK_STATE *WalkState); + + +/* + * exstorob - store object - buffer/string + */ +ACPI_STATUS +AcpiExStoreBufferToBuffer ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + +ACPI_STATUS +AcpiExStoreStringToString ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + + +/* + * excopy - object copy + */ +ACPI_STATUS +AcpiExCopyIntegerToIndexField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + +ACPI_STATUS +AcpiExCopyIntegerToBankField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + +ACPI_STATUS +AcpiExCopyDataToNamedField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_NAMESPACE_NODE *Node); + +ACPI_STATUS +AcpiExCopyIntegerToBufferField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + + +/* + * exutils - interpreter/scanner utilities + */ +void +AcpiExEnterInterpreter ( + void); + +void +AcpiExExitInterpreter ( + void); + +BOOLEAN +AcpiExTruncateFor32bitTable ( + ACPI_OPERAND_OBJECT *ObjDesc); + +void +AcpiExAcquireGlobalLock ( + UINT32 Rule); + +void +AcpiExReleaseGlobalLock ( + UINT32 Rule); + +void +AcpiExEisaIdToString ( + char *Dest, + UINT64 CompressedId); + +void +AcpiExIntegerToString ( + char *Dest, + UINT64 Value); + +void +AcpiExPciClsToString ( + char *Dest, + UINT8 ClassCode[3]); + +BOOLEAN +AcpiIsValidSpaceId ( + UINT8 SpaceId); + + +/* + * exregion - default OpRegion handlers + */ +ACPI_STATUS +AcpiExSystemMemorySpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExSystemIoSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExPciConfigSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExCmosSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExPciBarSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExEmbeddedControllerSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExSmBusSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + + +ACPI_STATUS +AcpiExDataTableSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +#endif /* __INTERP_H__ */ diff --git a/ports/acpica/include/aclocal.h b/ports/acpica/include/aclocal.h new file mode 100644 index 0000000..f487a4e --- /dev/null +++ b/ports/acpica/include/aclocal.h @@ -0,0 +1,1651 @@ +/****************************************************************************** + * + * Name: aclocal.h - Internal data types used across the ACPI subsystem + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACLOCAL_H__ +#define __ACLOCAL_H__ + + +/* acpisrc:StructDefs -- for acpisrc conversion */ + +#define ACPI_SERIALIZED 0xFF + +typedef UINT32 ACPI_MUTEX_HANDLE; +#define ACPI_GLOBAL_LOCK (ACPI_SEMAPHORE) (-1) + +/* Total number of aml opcodes defined */ + +#define AML_NUM_OPCODES 0x83 + + +/* Forward declarations */ + +struct acpi_walk_state; +struct acpi_obj_mutex; +union acpi_parse_object; + + +/***************************************************************************** + * + * Mutex typedefs and structs + * + ****************************************************************************/ + + +/* + * Predefined handles for the mutex objects used within the subsystem + * All mutex objects are automatically created by AcpiUtMutexInitialize. + * + * The acquire/release ordering protocol is implied via this list. Mutexes + * with a lower value must be acquired before mutexes with a higher value. + * + * NOTE: any changes here must be reflected in the AcpiGbl_MutexNames + * table below also! + */ +#define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */ +#define ACPI_MTX_NAMESPACE 1 /* ACPI Namespace */ +#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */ +#define ACPI_MTX_EVENTS 3 /* Data for ACPI events */ +#define ACPI_MTX_CACHES 4 /* Internal caches, general purposes */ +#define ACPI_MTX_MEMORY 5 /* Debug memory tracking lists */ + +#define ACPI_MAX_MUTEX 5 +#define ACPI_NUM_MUTEX (ACPI_MAX_MUTEX+1) + + +/* Lock structure for reader/writer interfaces */ + +typedef struct acpi_rw_lock +{ + ACPI_MUTEX WriterMutex; + ACPI_MUTEX ReaderMutex; + UINT32 NumReaders; + +} ACPI_RW_LOCK; + + +/* + * Predefined handles for spinlocks used within the subsystem. + * These spinlocks are created by AcpiUtMutexInitialize + */ +#define ACPI_LOCK_GPES 0 +#define ACPI_LOCK_HARDWARE 1 + +#define ACPI_MAX_LOCK 1 +#define ACPI_NUM_LOCK (ACPI_MAX_LOCK+1) + + +/* This Thread ID means that the mutex is not in use (unlocked) */ + +#define ACPI_MUTEX_NOT_ACQUIRED ((ACPI_THREAD_ID) -1) + +/* This Thread ID means an invalid thread ID */ + +#ifdef ACPI_OS_INVALID_THREAD_ID +#define ACPI_INVALID_THREAD_ID ACPI_OS_INVALID_THREAD_ID +#else +#define ACPI_INVALID_THREAD_ID ((ACPI_THREAD_ID) 0xFFFFFFFF) +#endif + +/* Table for the global mutexes */ + +typedef struct acpi_mutex_info +{ + ACPI_MUTEX Mutex; + UINT32 UseCount; + ACPI_THREAD_ID ThreadId; + +} ACPI_MUTEX_INFO; + + +/* Lock flag parameter for various interfaces */ + +#define ACPI_MTX_DO_NOT_LOCK 0 +#define ACPI_MTX_LOCK 1 + + +/* Field access granularities */ + +#define ACPI_FIELD_BYTE_GRANULARITY 1 +#define ACPI_FIELD_WORD_GRANULARITY 2 +#define ACPI_FIELD_DWORD_GRANULARITY 4 +#define ACPI_FIELD_QWORD_GRANULARITY 8 + + +#define ACPI_ENTRY_NOT_FOUND NULL + + +/***************************************************************************** + * + * Namespace typedefs and structs + * + ****************************************************************************/ + +/* Operational modes of the AML interpreter/scanner */ + +typedef enum +{ + ACPI_IMODE_LOAD_PASS1 = 0x01, + ACPI_IMODE_LOAD_PASS2 = 0x02, + ACPI_IMODE_EXECUTE = 0x03 + +} ACPI_INTERPRETER_MODE; + + +/* + * The Namespace Node describes a named object that appears in the AML. + * DescriptorType is used to differentiate between internal descriptors. + * + * The node is optimized for both 32-bit and 64-bit platforms: + * 20 bytes for the 32-bit case, 32 bytes for the 64-bit case. + * + * Note: The DescriptorType and Type fields must appear in the identical + * position in both the ACPI_NAMESPACE_NODE and ACPI_OPERAND_OBJECT + * structures. + */ +typedef struct acpi_namespace_node +{ + union acpi_operand_object *Object; /* Interpreter object */ + UINT8 DescriptorType; /* Differentiate object descriptor types */ + UINT8 Type; /* ACPI Type associated with this name */ + UINT8 Flags; /* Miscellaneous flags */ + ACPI_OWNER_ID OwnerId; /* Node creator */ + ACPI_NAME_UNION Name; /* ACPI Name, always 4 chars per ACPI spec */ + struct acpi_namespace_node *Parent; /* Parent node */ + struct acpi_namespace_node *Child; /* First child */ + struct acpi_namespace_node *Peer; /* First peer */ + + /* + * The following fields are used by the ASL compiler and disassembler only + */ +#ifdef ACPI_LARGE_NAMESPACE_NODE + union acpi_parse_object *Op; + void *MethodLocals; + void *MethodArgs; + UINT32 Value; + UINT32 Length; + UINT8 ArgCount; + +#endif + +} ACPI_NAMESPACE_NODE; + + +/* Namespace Node flags */ + +#define ANOBJ_RESERVED 0x01 /* Available for use */ +#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */ +#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ +#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ +#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ +#define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ +#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (InstallMethod) */ + +#define IMPLICIT_EXTERNAL 0x02 /* iASL only: This object created implicitly via External */ +#define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ +#define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ +#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* iASL only: Method has at least one return value */ +#define ANOBJ_IS_REFERENCED 0x80 /* iASL only: Object was referenced */ + + +/* Internal ACPI table management - master table list */ + +typedef struct acpi_table_list +{ + ACPI_TABLE_DESC *Tables; /* Table descriptor array */ + UINT32 CurrentTableCount; /* Tables currently in the array */ + UINT32 MaxTableCount; /* Max tables array will hold */ + UINT8 Flags; + +} ACPI_TABLE_LIST; + +/* Flags for above */ + +#define ACPI_ROOT_ORIGIN_UNKNOWN (0) /* ~ORIGIN_ALLOCATED */ +#define ACPI_ROOT_ORIGIN_ALLOCATED (1) +#define ACPI_ROOT_ALLOW_RESIZE (2) + + +/* List to manage incoming ACPI tables */ + +typedef struct acpi_new_table_desc +{ + ACPI_TABLE_HEADER *Table; + struct acpi_new_table_desc *Next; + +} ACPI_NEW_TABLE_DESC; + + +/* Predefined table indexes */ + +#define ACPI_INVALID_TABLE_INDEX (0xFFFFFFFF) + + +typedef struct acpi_find_context +{ + char *SearchFor; + ACPI_HANDLE *List; + UINT32 *Count; + +} ACPI_FIND_CONTEXT; + + +typedef struct acpi_ns_search_data +{ + ACPI_NAMESPACE_NODE *Node; + +} ACPI_NS_SEARCH_DATA; + + +/* Object types used during package copies */ + +#define ACPI_COPY_TYPE_SIMPLE 0 +#define ACPI_COPY_TYPE_PACKAGE 1 + + +/* Info structure used to convert external<->internal namestrings */ + +typedef struct acpi_namestring_info +{ + const char *ExternalName; + const char *NextExternalChar; + char *InternalName; + UINT32 Length; + UINT32 NumSegments; + UINT32 NumCarats; + BOOLEAN FullyQualified; + +} ACPI_NAMESTRING_INFO; + + +/* Field creation info */ + +typedef struct acpi_create_field_info +{ + ACPI_NAMESPACE_NODE *RegionNode; + ACPI_NAMESPACE_NODE *FieldNode; + ACPI_NAMESPACE_NODE *RegisterNode; + ACPI_NAMESPACE_NODE *DataRegisterNode; + ACPI_NAMESPACE_NODE *ConnectionNode; + UINT8 *ResourceBuffer; + UINT32 BankValue; + UINT32 FieldBitPosition; + UINT32 FieldBitLength; + UINT16 ResourceLength; + UINT16 PinNumberIndex; + UINT8 FieldFlags; + UINT8 Attribute; + UINT8 FieldType; + UINT8 AccessLength; + +} ACPI_CREATE_FIELD_INFO; + + +typedef +ACPI_STATUS (*ACPI_INTERNAL_METHOD) ( + struct acpi_walk_state *WalkState); + + +/* + * Bitmapped ACPI types. Used internally only + */ +#define ACPI_BTYPE_ANY 0x00000000 +#define ACPI_BTYPE_INTEGER 0x00000001 +#define ACPI_BTYPE_STRING 0x00000002 +#define ACPI_BTYPE_BUFFER 0x00000004 +#define ACPI_BTYPE_PACKAGE 0x00000008 +#define ACPI_BTYPE_FIELD_UNIT 0x00000010 +#define ACPI_BTYPE_DEVICE 0x00000020 +#define ACPI_BTYPE_EVENT 0x00000040 +#define ACPI_BTYPE_METHOD 0x00000080 +#define ACPI_BTYPE_MUTEX 0x00000100 +#define ACPI_BTYPE_REGION 0x00000200 +#define ACPI_BTYPE_POWER 0x00000400 +#define ACPI_BTYPE_PROCESSOR 0x00000800 +#define ACPI_BTYPE_THERMAL 0x00001000 +#define ACPI_BTYPE_BUFFER_FIELD 0x00002000 +#define ACPI_BTYPE_DDB_HANDLE 0x00004000 +#define ACPI_BTYPE_DEBUG_OBJECT 0x00008000 +#define ACPI_BTYPE_REFERENCE_OBJECT 0x00010000 /* From Index(), RefOf(), etc (Type6Opcodes) */ +#define ACPI_BTYPE_RESOURCE 0x00020000 +#define ACPI_BTYPE_NAMED_REFERENCE 0x00040000 /* Generic unresolved Name or Namepath */ + +#define ACPI_BTYPE_COMPUTE_DATA (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER) + +#define ACPI_BTYPE_DATA (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_PACKAGE) + + /* Used by Copy, DeRefOf, Store, Printf, Fprintf */ + +#define ACPI_BTYPE_DATA_REFERENCE (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE_OBJECT | ACPI_BTYPE_DDB_HANDLE) +#define ACPI_BTYPE_DEVICE_OBJECTS (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR) +#define ACPI_BTYPE_OBJECTS_AND_REFS 0x0001FFFF /* ARG or LOCAL */ +#define ACPI_BTYPE_ALL_OBJECTS 0x0000FFFF + +#pragma pack(1) + +/* + * Information structure for ACPI predefined names. + * Each entry in the table contains the following items: + * + * Name - The ACPI reserved name + * ParamCount - Number of arguments to the method + * ExpectedReturnBtypes - Allowed type(s) for the return value + */ +typedef struct acpi_name_info +{ + char Name[ACPI_NAME_SIZE]; + UINT16 ArgumentList; + UINT8 ExpectedBtypes; + +} ACPI_NAME_INFO; + +/* + * Secondary information structures for ACPI predefined objects that return + * package objects. This structure appears as the next entry in the table + * after the NAME_INFO structure above. + * + * The reason for this is to minimize the size of the predefined name table. + */ + +/* + * Used for ACPI_PTYPE1_FIXED, ACPI_PTYPE1_VAR, ACPI_PTYPE2, + * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT, + * ACPI_PTYPE2_FIX_VAR + */ +typedef struct acpi_package_info +{ + UINT8 Type; + UINT8 ObjectType1; + UINT8 Count1; + UINT8 ObjectType2; + UINT8 Count2; + UINT16 Reserved; + +} ACPI_PACKAGE_INFO; + +/* Used for ACPI_PTYPE2_FIXED */ + +typedef struct acpi_package_info2 +{ + UINT8 Type; + UINT8 Count; + UINT8 ObjectType[4]; + UINT8 Reserved; + +} ACPI_PACKAGE_INFO2; + +/* Used for ACPI_PTYPE1_OPTION */ + +typedef struct acpi_package_info3 +{ + UINT8 Type; + UINT8 Count; + UINT8 ObjectType[2]; + UINT8 TailObjectType; + UINT16 Reserved; + +} ACPI_PACKAGE_INFO3; + +typedef struct acpi_package_info4 +{ + UINT8 Type; + UINT8 ObjectType1; + UINT8 Count1; + UINT8 SubObjectTypes; + UINT8 PkgCount; + UINT16 Reserved; + +} ACPI_PACKAGE_INFO4; + +typedef union acpi_predefined_info +{ + ACPI_NAME_INFO Info; + ACPI_PACKAGE_INFO RetInfo; + ACPI_PACKAGE_INFO2 RetInfo2; + ACPI_PACKAGE_INFO3 RetInfo3; + ACPI_PACKAGE_INFO4 RetInfo4; + +} ACPI_PREDEFINED_INFO; + +/* Reset to default packing */ + +#pragma pack() + + +/* Return object auto-repair info */ + +typedef ACPI_STATUS (*ACPI_OBJECT_CONVERTER) ( + struct acpi_namespace_node *Scope, + union acpi_operand_object *OriginalObject, + union acpi_operand_object **ConvertedObject); + +typedef struct acpi_simple_repair_info +{ + char Name[ACPI_NAME_SIZE]; + UINT32 UnexpectedBtypes; + UINT32 PackageIndex; + ACPI_OBJECT_CONVERTER ObjectConverter; + +} ACPI_SIMPLE_REPAIR_INFO; + + +/* + * Bitmapped return value types + * Note: the actual data types must be contiguous, a loop in nspredef.c + * depends on this. + */ +#define ACPI_RTYPE_ANY 0x00 +#define ACPI_RTYPE_NONE 0x01 +#define ACPI_RTYPE_INTEGER 0x02 +#define ACPI_RTYPE_STRING 0x04 +#define ACPI_RTYPE_BUFFER 0x08 +#define ACPI_RTYPE_PACKAGE 0x10 +#define ACPI_RTYPE_REFERENCE 0x20 +#define ACPI_RTYPE_ALL 0x3F + +#define ACPI_NUM_RTYPES 5 /* Number of actual object types */ + + +/* Info for running the _REG methods */ + +typedef struct acpi_reg_walk_info +{ + ACPI_ADR_SPACE_TYPE SpaceId; + UINT32 Function; + UINT32 RegRunCount; + +} ACPI_REG_WALK_INFO; + + +/***************************************************************************** + * + * Event typedefs and structs + * + ****************************************************************************/ + +/* Dispatch info for each host-installed SCI handler */ + +typedef struct acpi_sci_handler_info +{ + struct acpi_sci_handler_info *Next; + ACPI_SCI_HANDLER Address; /* Address of handler */ + void *Context; /* Context to be passed to handler */ + +} ACPI_SCI_HANDLER_INFO; + +/* Dispatch info for each GPE -- either a method or handler, cannot be both */ + +typedef struct acpi_gpe_handler_info +{ + ACPI_GPE_HANDLER Address; /* Address of handler, if any */ + void *Context; /* Context to be passed to handler */ + ACPI_NAMESPACE_NODE *MethodNode; /* Method node for this GPE level (saved) */ + UINT8 OriginalFlags; /* Original (pre-handler) GPE info */ + BOOLEAN OriginallyEnabled; /* True if GPE was originally enabled */ + +} ACPI_GPE_HANDLER_INFO; + +/* Notify info for implicit notify, multiple device objects */ + +typedef struct acpi_gpe_notify_info +{ + ACPI_NAMESPACE_NODE *DeviceNode; /* Device to be notified */ + struct acpi_gpe_notify_info *Next; + +} ACPI_GPE_NOTIFY_INFO; + +/* + * GPE dispatch info. At any time, the GPE can have at most one type + * of dispatch - Method, Handler, or Implicit Notify. + */ +typedef union acpi_gpe_dispatch_info +{ + ACPI_NAMESPACE_NODE *MethodNode; /* Method node for this GPE level */ + ACPI_GPE_HANDLER_INFO *Handler; /* Installed GPE handler */ + ACPI_GPE_NOTIFY_INFO *NotifyList; /* List of _PRW devices for implicit notifies */ + +} ACPI_GPE_DISPATCH_INFO; + +/* + * Information about a GPE, one per each GPE in an array. + * NOTE: Important to keep this struct as small as possible. + */ +typedef struct acpi_gpe_event_info +{ + union acpi_gpe_dispatch_info Dispatch; /* Either Method, Handler, or NotifyList */ + struct acpi_gpe_register_info *RegisterInfo; /* Backpointer to register info */ + UINT8 Flags; /* Misc info about this GPE */ + UINT8 GpeNumber; /* This GPE */ + UINT8 RuntimeCount; /* References to a run GPE */ + BOOLEAN DisableForDispatch; /* Masked during dispatching */ + +} ACPI_GPE_EVENT_INFO; + +/* Information about a GPE register pair, one per each status/enable pair in an array */ + +typedef struct acpi_gpe_register_info +{ + ACPI_GENERIC_ADDRESS StatusAddress; /* Address of status reg */ + ACPI_GENERIC_ADDRESS EnableAddress; /* Address of enable reg */ + UINT16 BaseGpeNumber; /* Base GPE number for this register */ + UINT8 EnableForWake; /* GPEs to keep enabled when sleeping */ + UINT8 EnableForRun; /* GPEs to keep enabled when running */ + UINT8 MaskForRun; /* GPEs to keep masked when running */ + UINT8 EnableMask; /* Current mask of enabled GPEs */ + +} ACPI_GPE_REGISTER_INFO; + +/* + * Information about a GPE register block, one per each installed block -- + * GPE0, GPE1, and one per each installed GPE Block Device. + */ +typedef struct acpi_gpe_block_info +{ + ACPI_NAMESPACE_NODE *Node; + struct acpi_gpe_block_info *Previous; + struct acpi_gpe_block_info *Next; + struct acpi_gpe_xrupt_info *XruptBlock; /* Backpointer to interrupt block */ + ACPI_GPE_REGISTER_INFO *RegisterInfo; /* One per GPE register pair */ + ACPI_GPE_EVENT_INFO *EventInfo; /* One for each GPE */ + UINT64 Address; /* Base address of the block */ + UINT32 RegisterCount; /* Number of register pairs in block */ + UINT16 GpeCount; /* Number of individual GPEs in block */ + UINT16 BlockBaseNumber;/* Base GPE number for this block */ + UINT8 SpaceId; + BOOLEAN Initialized; /* TRUE if this block is initialized */ + +} ACPI_GPE_BLOCK_INFO; + +/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */ + +typedef struct acpi_gpe_xrupt_info +{ + struct acpi_gpe_xrupt_info *Previous; + struct acpi_gpe_xrupt_info *Next; + ACPI_GPE_BLOCK_INFO *GpeBlockListHead; /* List of GPE blocks for this xrupt */ + UINT32 InterruptNumber; /* System interrupt number */ + +} ACPI_GPE_XRUPT_INFO; + +typedef struct acpi_gpe_walk_info +{ + ACPI_NAMESPACE_NODE *GpeDevice; + ACPI_GPE_BLOCK_INFO *GpeBlock; + UINT16 Count; + ACPI_OWNER_ID OwnerId; + BOOLEAN ExecuteByOwnerId; + +} ACPI_GPE_WALK_INFO; + +typedef struct acpi_gpe_device_info +{ + UINT32 Index; + UINT32 NextBlockBaseIndex; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *GpeDevice; + +} ACPI_GPE_DEVICE_INFO; + +typedef ACPI_STATUS (*ACPI_GPE_CALLBACK) ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + + +/* Information about each particular fixed event */ + +typedef struct acpi_fixed_event_handler +{ + ACPI_EVENT_HANDLER Handler; /* Address of handler. */ + void *Context; /* Context to be passed to handler */ + +} ACPI_FIXED_EVENT_HANDLER; + +typedef struct acpi_fixed_event_info +{ + UINT8 StatusRegisterId; + UINT8 EnableRegisterId; + UINT16 StatusBitMask; + UINT16 EnableBitMask; + +} ACPI_FIXED_EVENT_INFO; + +/* Information used during field processing */ + +typedef struct acpi_field_info +{ + UINT8 SkipField; + UINT8 FieldFlag; + UINT32 PkgLength; + +} ACPI_FIELD_INFO; + + +/***************************************************************************** + * + * Generic "state" object for stacks + * + ****************************************************************************/ + +#define ACPI_CONTROL_NORMAL 0xC0 +#define ACPI_CONTROL_CONDITIONAL_EXECUTING 0xC1 +#define ACPI_CONTROL_PREDICATE_EXECUTING 0xC2 +#define ACPI_CONTROL_PREDICATE_FALSE 0xC3 +#define ACPI_CONTROL_PREDICATE_TRUE 0xC4 + + +#define ACPI_STATE_COMMON \ + void *Next; \ + UINT8 DescriptorType; /* To differentiate various internal objs */\ + UINT8 Flags; \ + UINT16 Value; \ + UINT16 State; + + /* There are 2 bytes available here until the next natural alignment boundary */ + +typedef struct acpi_common_state +{ + ACPI_STATE_COMMON +} ACPI_COMMON_STATE; + + +/* + * Update state - used to traverse complex objects such as packages + */ +typedef struct acpi_update_state +{ + ACPI_STATE_COMMON + union acpi_operand_object *Object; + +} ACPI_UPDATE_STATE; + + +/* + * Pkg state - used to traverse nested package structures + */ +typedef struct acpi_pkg_state +{ + ACPI_STATE_COMMON + UINT32 Index; + union acpi_operand_object *SourceObject; + union acpi_operand_object *DestObject; + struct acpi_walk_state *WalkState; + void *ThisTargetObj; + UINT32 NumPackages; + +} ACPI_PKG_STATE; + + +/* + * Control state - one per if/else and while constructs. + * Allows nesting of these constructs + */ +typedef struct acpi_control_state +{ + ACPI_STATE_COMMON + UINT16 Opcode; + union acpi_parse_object *PredicateOp; + UINT8 *AmlPredicateStart; /* Start of if/while predicate */ + UINT8 *PackageEnd; /* End of if/while block */ + UINT64 LoopTimeout; /* While() loop timeout */ + +} ACPI_CONTROL_STATE; + + +/* + * Scope state - current scope during namespace lookups + */ +typedef struct acpi_scope_state +{ + ACPI_STATE_COMMON + ACPI_NAMESPACE_NODE *Node; + +} ACPI_SCOPE_STATE; + + +typedef struct acpi_pscope_state +{ + ACPI_STATE_COMMON + UINT32 ArgCount; /* Number of fixed arguments */ + union acpi_parse_object *Op; /* Current op being parsed */ + UINT8 *ArgEnd; /* Current argument end */ + UINT8 *PkgEnd; /* Current package end */ + UINT32 ArgList; /* Next argument to parse */ + +} ACPI_PSCOPE_STATE; + + +/* + * Thread state - one per thread across multiple walk states. Multiple walk + * states are created when there are nested control methods executing. + */ +typedef struct acpi_thread_state +{ + ACPI_STATE_COMMON + UINT8 CurrentSyncLevel; /* Mutex Sync (nested acquire) level */ + struct acpi_walk_state *WalkStateList; /* Head of list of WalkStates for this thread */ + union acpi_operand_object *AcquiredMutexList; /* List of all currently acquired mutexes */ + ACPI_THREAD_ID ThreadId; /* Running thread ID */ + +} ACPI_THREAD_STATE; + + +/* + * Result values - used to accumulate the results of nested + * AML arguments + */ +typedef struct acpi_result_values +{ + ACPI_STATE_COMMON + union acpi_operand_object *ObjDesc [ACPI_RESULTS_FRAME_OBJ_NUM]; + +} ACPI_RESULT_VALUES; + + +typedef +ACPI_STATUS (*ACPI_PARSE_DOWNWARDS) ( + struct acpi_walk_state *WalkState, + union acpi_parse_object **OutOp); + +typedef +ACPI_STATUS (*ACPI_PARSE_UPWARDS) ( + struct acpi_walk_state *WalkState); + + +/* Global handlers for AML Notifies */ + +typedef struct acpi_global_notify_handler +{ + ACPI_NOTIFY_HANDLER Handler; + void *Context; + +} ACPI_GLOBAL_NOTIFY_HANDLER; + +/* + * Notify info - used to pass info to the deferred notify + * handler/dispatcher. + */ +typedef struct acpi_notify_info +{ + ACPI_STATE_COMMON + UINT8 HandlerListId; + ACPI_NAMESPACE_NODE *Node; + union acpi_operand_object *HandlerListHead; + ACPI_GLOBAL_NOTIFY_HANDLER *Global; + +} ACPI_NOTIFY_INFO; + + +/* Generic state is union of structs above */ + +typedef union acpi_generic_state +{ + ACPI_COMMON_STATE Common; + ACPI_CONTROL_STATE Control; + ACPI_UPDATE_STATE Update; + ACPI_SCOPE_STATE Scope; + ACPI_PSCOPE_STATE ParseScope; + ACPI_PKG_STATE Pkg; + ACPI_THREAD_STATE Thread; + ACPI_RESULT_VALUES Results; + ACPI_NOTIFY_INFO Notify; + +} ACPI_GENERIC_STATE; + + +/***************************************************************************** + * + * Interpreter typedefs and structs + * + ****************************************************************************/ + +typedef +ACPI_STATUS (*ACPI_EXECUTE_OP) ( + struct acpi_walk_state *WalkState); + +/* Address Range info block */ + +typedef struct acpi_address_range +{ + struct acpi_address_range *Next; + ACPI_NAMESPACE_NODE *RegionNode; + ACPI_PHYSICAL_ADDRESS StartAddress; + ACPI_PHYSICAL_ADDRESS EndAddress; + +} ACPI_ADDRESS_RANGE; + + +/***************************************************************************** + * + * Parser typedefs and structs + * + ****************************************************************************/ + +/* + * AML opcode, name, and argument layout + */ +typedef struct acpi_opcode_info +{ +#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) + char *Name; /* Opcode name (disassembler/debug only) */ +#endif + UINT32 ParseArgs; /* Grammar/Parse time arguments */ + UINT32 RuntimeArgs; /* Interpret time arguments */ + UINT16 Flags; /* Misc flags */ + UINT8 ObjectType; /* Corresponding internal object type */ + UINT8 Class; /* Opcode class */ + UINT8 Type; /* Opcode type */ + +} ACPI_OPCODE_INFO; + +/* Structure for Resource Tag information */ + +typedef struct acpi_tag_info +{ + UINT32 BitOffset; + UINT32 BitLength; + +} ACPI_TAG_INFO; + +/* Value associated with the parse object */ + +typedef union acpi_parse_value +{ + UINT64 Integer; /* Integer constant (Up to 64 bits) */ + UINT32 Size; /* bytelist or field size */ + char *String; /* NULL terminated string */ + UINT8 *Buffer; /* buffer or string */ + char *Name; /* NULL terminated string */ + union acpi_parse_object *Arg; /* arguments and contained ops */ + ACPI_TAG_INFO Tag; /* Resource descriptor tag info */ + +} ACPI_PARSE_VALUE; + + +#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) +#define ACPI_DISASM_ONLY_MEMBERS(a) a; +#else +#define ACPI_DISASM_ONLY_MEMBERS(a) +#endif + +#if defined(ACPI_ASL_COMPILER) +#define ACPI_CONVERTER_ONLY_MEMBERS(a) a; +#else +#define ACPI_CONVERTER_ONLY_MEMBERS(a) +#endif + +#define ACPI_PARSE_COMMON \ + union acpi_parse_object *Parent; /* Parent op */\ + UINT8 DescriptorType; /* To differentiate various internal objs */\ + UINT8 Flags; /* Type of Op */\ + UINT16 AmlOpcode; /* AML opcode */\ + UINT8 *Aml; /* Address of declaration in AML */\ + union acpi_parse_object *Next; /* Next op */\ + ACPI_NAMESPACE_NODE *Node; /* For use by interpreter */\ + ACPI_PARSE_VALUE Value; /* Value or args associated with the opcode */\ + UINT8 ArgListLength; /* Number of elements in the arg list */\ + ACPI_DISASM_ONLY_MEMBERS (\ + UINT16 DisasmFlags; /* Used during AML disassembly */\ + UINT8 DisasmOpcode; /* Subtype used for disassembly */\ + char *OperatorSymbol; /* Used for C-style operator name strings */\ + char AmlOpName[16]) /* Op name (debug only) */\ + ACPI_CONVERTER_ONLY_MEMBERS (\ + char *InlineComment; /* Inline comment */\ + char *EndNodeComment; /* End of node comment */\ + char *NameComment; /* Comment associated with the first parameter of the name node */\ + char *CloseBraceComment; /* Comments that come after } on the same as } */\ + ACPI_COMMENT_NODE *CommentList; /* comments that appears before this node */\ + ACPI_COMMENT_NODE *EndBlkComment; /* comments that at the end of a block but before ) or } */\ + char *CvFilename; /* Filename associated with this node. Used for ASL/ASL+ converter */\ + char *CvParentFilename) /* Parent filename associated with this node. Used for ASL/ASL+ converter */ + + +/* categories of comments */ + +typedef enum +{ + STANDARD_COMMENT = 1, + INLINE_COMMENT, + ENDNODE_COMMENT, + OPENBRACE_COMMENT, + CLOSE_BRACE_COMMENT, + STD_DEFBLK_COMMENT, + END_DEFBLK_COMMENT, + FILENAME_COMMENT, + PARENTFILENAME_COMMENT, + ENDBLK_COMMENT, + INCLUDE_COMMENT + +} ASL_COMMENT_TYPES; + + +/* Internal opcodes for DisasmOpcode field above */ + +#define ACPI_DASM_BUFFER 0x00 /* Buffer is a simple data buffer */ +#define ACPI_DASM_RESOURCE 0x01 /* Buffer is a Resource Descriptor */ +#define ACPI_DASM_STRING 0x02 /* Buffer is a ASCII string */ +#define ACPI_DASM_UNICODE 0x03 /* Buffer is a Unicode string */ +#define ACPI_DASM_PLD_METHOD 0x04 /* Buffer is a _PLD method bit-packed buffer */ +#define ACPI_DASM_UUID 0x05 /* Buffer is a UUID/GUID */ +#define ACPI_DASM_EISAID 0x06 /* Integer is an EISAID */ +#define ACPI_DASM_MATCHOP 0x07 /* Parent opcode is a Match() operator */ +#define ACPI_DASM_LNOT_PREFIX 0x08 /* Start of a LNotEqual (etc.) pair of opcodes */ +#define ACPI_DASM_LNOT_SUFFIX 0x09 /* End of a LNotEqual (etc.) pair of opcodes */ +#define ACPI_DASM_HID_STRING 0x0A /* String is a _HID or _CID */ +#define ACPI_DASM_IGNORE_SINGLE 0x0B /* Ignore the opcode but not it's children */ +#define ACPI_DASM_SWITCH 0x0C /* While is a Switch */ +#define ACPI_DASM_SWITCH_PREDICATE 0x0D /* Object is a predicate for a Switch or Case block */ +#define ACPI_DASM_CASE 0x0E /* If/Else is a Case in a Switch/Case block */ +#define ACPI_DASM_DEFAULT 0x0F /* Else is a Default in a Switch/Case block */ + + +/* + * List struct used in the -ca option + */ +typedef struct acpi_comment_node +{ + char *Comment; + struct acpi_comment_node *Next; + +} ACPI_COMMENT_NODE; + + +typedef struct acpi_comment_addr_node +{ + UINT8 *Addr; + struct acpi_comment_addr_node *Next; +} ACPI_COMMENT_ADDR_NODE; + +/* + * File node - used for "Include" operator file stack and + * depdendency tree for the -ca option + */ +typedef struct acpi_file_node +{ + void *File; + char *Filename; + char *FileStart; /* Points to AML and indicates when the AML for this particular file starts. */ + char *FileEnd; /* Points to AML and indicates when the AML for this particular file ends. */ + struct acpi_file_node *Next; + struct acpi_file_node *Parent; + BOOLEAN IncludeWritten; + ACPI_COMMENT_NODE *IncludeComment; + +} ACPI_FILE_NODE; + + +/* + * Generic operation (for example: If, While, Store) + */ +typedef struct acpi_parse_obj_common +{ + ACPI_PARSE_COMMON +} ACPI_PARSE_OBJ_COMMON; + + +/* + * Extended Op for named ops (Scope, Method, etc.), deferred ops (Methods and OpRegions), + * and bytelists. + */ +typedef struct acpi_parse_obj_named +{ + ACPI_PARSE_COMMON + char *Path; + UINT8 *Data; /* AML body or bytelist data */ + UINT32 Length; /* AML length */ + UINT32 Name; /* 4-byte name or zero if no name */ + +} ACPI_PARSE_OBJ_NAMED; + + +/* This version is used by the iASL compiler only */ + +#define ACPI_MAX_PARSEOP_NAME 20 + +typedef struct acpi_parse_obj_asl +{ + ACPI_PARSE_COMMON + union acpi_parse_object *Child; + union acpi_parse_object *ParentMethod; + char *Filename; + BOOLEAN FileChanged; + char *ParentFilename; + char *ExternalName; + char *Namepath; + char NameSeg[4]; + UINT32 ExtraValue; + UINT32 Column; + UINT32 LineNumber; + UINT32 LogicalLineNumber; + UINT32 LogicalByteOffset; + UINT32 EndLine; + UINT32 EndLogicalLine; + UINT32 AcpiBtype; + UINT32 AmlLength; + UINT32 AmlSubtreeLength; + UINT32 FinalAmlLength; + UINT32 FinalAmlOffset; + UINT32 CompileFlags; + UINT16 ParseOpcode; + UINT8 AmlOpcodeLength; + UINT8 AmlPkgLenBytes; + UINT8 Extra; + char ParseOpName[ACPI_MAX_PARSEOP_NAME]; + +} ACPI_PARSE_OBJ_ASL; + +typedef union acpi_parse_object +{ + ACPI_PARSE_OBJ_COMMON Common; + ACPI_PARSE_OBJ_NAMED Named; + ACPI_PARSE_OBJ_ASL Asl; + +} ACPI_PARSE_OBJECT; + +typedef struct asl_comment_state +{ + UINT8 CommentType; + UINT32 SpacesBefore; + ACPI_PARSE_OBJECT *LatestParseOp; + ACPI_PARSE_OBJECT *ParsingParenBraceNode; + BOOLEAN CaptureComments; + +} ASL_COMMENT_STATE; + + +/* + * Parse state - one state per parser invocation and each control + * method. + */ +typedef struct acpi_parse_state +{ + UINT8 *AmlStart; /* First AML byte */ + UINT8 *Aml; /* Next AML byte */ + UINT8 *AmlEnd; /* (last + 1) AML byte */ + UINT8 *PkgStart; /* Current package begin */ + UINT8 *PkgEnd; /* Current package end */ + union acpi_parse_object *StartOp; /* Root of parse tree */ + struct acpi_namespace_node *StartNode; + union acpi_generic_state *Scope; /* Current scope */ + union acpi_parse_object *StartScope; + UINT32 AmlSize; + +} ACPI_PARSE_STATE; + + +/* Parse object flags */ + +#define ACPI_PARSEOP_GENERIC 0x01 +#define ACPI_PARSEOP_NAMED_OBJECT 0x02 +#define ACPI_PARSEOP_DEFERRED 0x04 +#define ACPI_PARSEOP_BYTELIST 0x08 +#define ACPI_PARSEOP_IN_STACK 0x10 +#define ACPI_PARSEOP_TARGET 0x20 +#define ACPI_PARSEOP_IN_CACHE 0x80 + +/* Parse object DisasmFlags */ + +#define ACPI_PARSEOP_IGNORE 0x0001 +#define ACPI_PARSEOP_PARAMETER_LIST 0x0002 +#define ACPI_PARSEOP_EMPTY_TERMLIST 0x0004 +#define ACPI_PARSEOP_PREDEFINED_CHECKED 0x0008 +#define ACPI_PARSEOP_CLOSING_PAREN 0x0010 +#define ACPI_PARSEOP_COMPOUND_ASSIGNMENT 0x0020 +#define ACPI_PARSEOP_ASSIGNMENT 0x0040 +#define ACPI_PARSEOP_ELSEIF 0x0080 +#define ACPI_PARSEOP_LEGACY_ASL_ONLY 0x0100 + + +/***************************************************************************** + * + * Hardware (ACPI registers) and PNP + * + ****************************************************************************/ + +typedef struct acpi_bit_register_info +{ + UINT8 ParentRegister; + UINT8 BitPosition; + UINT16 AccessBitMask; + +} ACPI_BIT_REGISTER_INFO; + + +/* + * Some ACPI registers have bits that must be ignored -- meaning that they + * must be preserved. + */ +#define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */ + +/* Write-only bits must be zeroed by software */ + +#define ACPI_PM1_CONTROL_WRITEONLY_BITS 0x2004 /* Bits 13, 2 */ + +/* For control registers, both ignored and reserved bits must be preserved */ + +/* + * For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the + * ACPI specification to be a "preserved" bit - "OSPM always preserves this + * bit position", section 4.7.3.2.1. However, on some machines the OS must + * write a one to this bit after resume for the machine to work properly. + * To enable this, we no longer attempt to preserve this bit. No machines + * are known to fail if the bit is not preserved. (May 2009) + */ +#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bit 9 */ +#define ACPI_PM1_CONTROL_RESERVED_BITS 0xC1F8 /* Bits 14-15, 3-8 */ +#define ACPI_PM1_CONTROL_PRESERVED_BITS \ + (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS) + +#define ACPI_PM2_CONTROL_PRESERVED_BITS 0xFFFFFFFE /* All except bit 0 */ + +/* + * Register IDs + * These are the full ACPI registers + */ +#define ACPI_REGISTER_PM1_STATUS 0x01 +#define ACPI_REGISTER_PM1_ENABLE 0x02 +#define ACPI_REGISTER_PM1_CONTROL 0x03 +#define ACPI_REGISTER_PM2_CONTROL 0x04 +#define ACPI_REGISTER_PM_TIMER 0x05 +#define ACPI_REGISTER_PROCESSOR_BLOCK 0x06 +#define ACPI_REGISTER_SMI_COMMAND_BLOCK 0x07 + + +/* Masks used to access the BitRegisters */ + +#define ACPI_BITMASK_TIMER_STATUS 0x0001 +#define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010 +#define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020 +#define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100 +#define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200 +#define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400 +#define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */ +#define ACPI_BITMASK_WAKE_STATUS 0x8000 + +#define ACPI_BITMASK_ALL_FIXED_STATUS (\ + ACPI_BITMASK_TIMER_STATUS | \ + ACPI_BITMASK_BUS_MASTER_STATUS | \ + ACPI_BITMASK_GLOBAL_LOCK_STATUS | \ + ACPI_BITMASK_POWER_BUTTON_STATUS | \ + ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ + ACPI_BITMASK_RT_CLOCK_STATUS | \ + ACPI_BITMASK_PCIEXP_WAKE_STATUS | \ + ACPI_BITMASK_WAKE_STATUS) + +#define ACPI_BITMASK_TIMER_ENABLE 0x0001 +#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020 +#define ACPI_BITMASK_POWER_BUTTON_ENABLE 0x0100 +#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE 0x0200 +#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400 +#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE 0x4000 /* ACPI 3.0 */ + +#define ACPI_BITMASK_SCI_ENABLE 0x0001 +#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002 +#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE 0x0004 +#define ACPI_BITMASK_SLEEP_TYPE 0x1C00 +#define ACPI_BITMASK_SLEEP_ENABLE 0x2000 + +#define ACPI_BITMASK_ARB_DISABLE 0x0001 + + +/* Raw bit position of each BitRegister */ + +#define ACPI_BITPOSITION_TIMER_STATUS 0x00 +#define ACPI_BITPOSITION_BUS_MASTER_STATUS 0x04 +#define ACPI_BITPOSITION_GLOBAL_LOCK_STATUS 0x05 +#define ACPI_BITPOSITION_POWER_BUTTON_STATUS 0x08 +#define ACPI_BITPOSITION_SLEEP_BUTTON_STATUS 0x09 +#define ACPI_BITPOSITION_RT_CLOCK_STATUS 0x0A +#define ACPI_BITPOSITION_PCIEXP_WAKE_STATUS 0x0E /* ACPI 3.0 */ +#define ACPI_BITPOSITION_WAKE_STATUS 0x0F + +#define ACPI_BITPOSITION_TIMER_ENABLE 0x00 +#define ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE 0x05 +#define ACPI_BITPOSITION_POWER_BUTTON_ENABLE 0x08 +#define ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE 0x09 +#define ACPI_BITPOSITION_RT_CLOCK_ENABLE 0x0A +#define ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE 0x0E /* ACPI 3.0 */ + +#define ACPI_BITPOSITION_SCI_ENABLE 0x00 +#define ACPI_BITPOSITION_BUS_MASTER_RLD 0x01 +#define ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE 0x02 +#define ACPI_BITPOSITION_SLEEP_TYPE 0x0A +#define ACPI_BITPOSITION_SLEEP_ENABLE 0x0D + +#define ACPI_BITPOSITION_ARB_DISABLE 0x00 + + +/* Structs and definitions for _OSI support and I/O port validation */ + +#define ACPI_ALWAYS_ILLEGAL 0x00 + +typedef struct acpi_interface_info +{ + char *Name; + struct acpi_interface_info *Next; + UINT8 Flags; + UINT8 Value; + +} ACPI_INTERFACE_INFO; + +#define ACPI_OSI_INVALID 0x01 +#define ACPI_OSI_DYNAMIC 0x02 +#define ACPI_OSI_FEATURE 0x04 +#define ACPI_OSI_DEFAULT_INVALID 0x08 +#define ACPI_OSI_OPTIONAL_FEATURE (ACPI_OSI_FEATURE | ACPI_OSI_DEFAULT_INVALID | ACPI_OSI_INVALID) + +typedef struct acpi_port_info +{ + char *Name; + UINT16 Start; + UINT16 End; + UINT8 OsiDependency; + +} ACPI_PORT_INFO; + + +/***************************************************************************** + * + * Resource descriptors + * + ****************************************************************************/ + +/* ResourceType values */ + +#define ACPI_ADDRESS_TYPE_MEMORY_RANGE 0 +#define ACPI_ADDRESS_TYPE_IO_RANGE 1 +#define ACPI_ADDRESS_TYPE_BUS_NUMBER_RANGE 2 + +/* Resource descriptor types and masks */ + +#define ACPI_RESOURCE_NAME_LARGE 0x80 +#define ACPI_RESOURCE_NAME_SMALL 0x00 + +#define ACPI_RESOURCE_NAME_SMALL_MASK 0x78 /* Bits 6:3 contain the type */ +#define ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK 0x07 /* Bits 2:0 contain the length */ +#define ACPI_RESOURCE_NAME_LARGE_MASK 0x7F /* Bits 6:0 contain the type */ + + +/* + * Small resource descriptor "names" as defined by the ACPI specification. + * Note: Bits 2:0 are used for the descriptor length + */ +#define ACPI_RESOURCE_NAME_IRQ 0x20 +#define ACPI_RESOURCE_NAME_DMA 0x28 +#define ACPI_RESOURCE_NAME_START_DEPENDENT 0x30 +#define ACPI_RESOURCE_NAME_END_DEPENDENT 0x38 +#define ACPI_RESOURCE_NAME_IO 0x40 +#define ACPI_RESOURCE_NAME_FIXED_IO 0x48 +#define ACPI_RESOURCE_NAME_FIXED_DMA 0x50 +#define ACPI_RESOURCE_NAME_RESERVED_S2 0x58 +#define ACPI_RESOURCE_NAME_RESERVED_S3 0x60 +#define ACPI_RESOURCE_NAME_RESERVED_S4 0x68 +#define ACPI_RESOURCE_NAME_VENDOR_SMALL 0x70 +#define ACPI_RESOURCE_NAME_END_TAG 0x78 + +/* + * Large resource descriptor "names" as defined by the ACPI specification. + * Note: includes the Large Descriptor bit in bit[7] + */ +#define ACPI_RESOURCE_NAME_MEMORY24 0x81 +#define ACPI_RESOURCE_NAME_GENERIC_REGISTER 0x82 +#define ACPI_RESOURCE_NAME_RESERVED_L1 0x83 +#define ACPI_RESOURCE_NAME_VENDOR_LARGE 0x84 +#define ACPI_RESOURCE_NAME_MEMORY32 0x85 +#define ACPI_RESOURCE_NAME_FIXED_MEMORY32 0x86 +#define ACPI_RESOURCE_NAME_ADDRESS32 0x87 +#define ACPI_RESOURCE_NAME_ADDRESS16 0x88 +#define ACPI_RESOURCE_NAME_EXTENDED_IRQ 0x89 +#define ACPI_RESOURCE_NAME_ADDRESS64 0x8A +#define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 0x8B +#define ACPI_RESOURCE_NAME_GPIO 0x8C +#define ACPI_RESOURCE_NAME_PIN_FUNCTION 0x8D +#define ACPI_RESOURCE_NAME_SERIAL_BUS 0x8E +#define ACPI_RESOURCE_NAME_PIN_CONFIG 0x8F +#define ACPI_RESOURCE_NAME_PIN_GROUP 0x90 +#define ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION 0x91 +#define ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG 0x92 +#define ACPI_RESOURCE_NAME_LARGE_MAX 0x92 + + +/***************************************************************************** + * + * Miscellaneous + * + ****************************************************************************/ + +#define ACPI_ASCII_ZERO 0x30 + + +/***************************************************************************** + * + * Disassembler + * + ****************************************************************************/ + +typedef struct acpi_external_list +{ + char *Path; + char *InternalPath; + struct acpi_external_list *Next; + UINT32 Value; + UINT16 Length; + UINT16 Flags; + UINT8 Type; + +} ACPI_EXTERNAL_LIST; + +/* Values for Flags field above */ + +#define ACPI_EXT_RESOLVED_REFERENCE 0x01 /* Object was resolved during cross ref */ +#define ACPI_EXT_ORIGIN_FROM_FILE 0x02 /* External came from a file */ +#define ACPI_EXT_INTERNAL_PATH_ALLOCATED 0x04 /* Deallocate internal path on completion */ +#define ACPI_EXT_EXTERNAL_EMITTED 0x08 /* External() statement has been emitted */ +#define ACPI_EXT_ORIGIN_FROM_OPCODE 0x10 /* External came from a External() opcode */ +#define ACPI_EXT_CONFLICTING_DECLARATION 0x20 /* External has a conflicting declaration within AML */ + + +typedef struct acpi_external_file +{ + char *Path; + struct acpi_external_file *Next; + +} ACPI_EXTERNAL_FILE; + + +typedef struct acpi_parse_object_list +{ + ACPI_PARSE_OBJECT *Op; + struct acpi_parse_object_list *Next; + +} ACPI_PARSE_OBJECT_LIST; + +/***************************************************************************** + * + * Debugger + * + ****************************************************************************/ + +typedef struct acpi_db_method_info +{ + ACPI_HANDLE Method; + ACPI_HANDLE MainThreadGate; + ACPI_HANDLE ThreadCompleteGate; + ACPI_HANDLE InfoGate; + ACPI_THREAD_ID *Threads; + UINT32 NumThreads; + UINT32 NumCreated; + UINT32 NumCompleted; + + char *Name; + UINT32 Flags; + UINT32 NumLoops; + char Pathname[ACPI_DB_LINE_BUFFER_SIZE]; + char **Args; + ACPI_OBJECT_TYPE *Types; + + /* + * Arguments to be passed to method for the commands Threads and + * Background. Note, ACPI specifies a maximum of 7 arguments (0 - 6). + * + * For the Threads command, the Number of threads, ID of current + * thread and Index of current thread inside all them created. + */ + char InitArgs; +#ifdef ACPI_DEBUGGER + ACPI_OBJECT_TYPE ArgTypes[ACPI_METHOD_NUM_ARGS]; +#endif + char *Arguments[ACPI_METHOD_NUM_ARGS]; + char NumThreadsStr[11]; + char IdOfThreadStr[11]; + char IndexOfThreadStr[11]; + +} ACPI_DB_METHOD_INFO; + +typedef struct acpi_integrity_info +{ + UINT32 Nodes; + UINT32 Objects; + +} ACPI_INTEGRITY_INFO; + + +#define ACPI_DB_DISABLE_OUTPUT 0x00 +#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01 +#define ACPI_DB_CONSOLE_OUTPUT 0x02 +#define ACPI_DB_DUPLICATE_OUTPUT 0x03 + + +typedef struct acpi_object_info +{ + UINT32 Types[ACPI_TOTAL_TYPES]; + +} ACPI_OBJECT_INFO; + + +/***************************************************************************** + * + * Debug + * + ****************************************************************************/ + +/* Entry for a memory allocation (debug only) */ + +#define ACPI_MEM_MALLOC 0 +#define ACPI_MEM_CALLOC 1 +#define ACPI_MAX_MODULE_NAME 16 + +#define ACPI_COMMON_DEBUG_MEM_HEADER \ + struct acpi_debug_mem_block *Previous; \ + struct acpi_debug_mem_block *Next; \ + UINT32 Size; \ + UINT32 Component; \ + UINT32 Line; \ + char Module[ACPI_MAX_MODULE_NAME]; \ + UINT8 AllocType; + +typedef struct acpi_debug_mem_header +{ + ACPI_COMMON_DEBUG_MEM_HEADER + +} ACPI_DEBUG_MEM_HEADER; + +typedef struct acpi_debug_mem_block +{ + ACPI_COMMON_DEBUG_MEM_HEADER + UINT64 UserSpace; + +} ACPI_DEBUG_MEM_BLOCK; + + +#define ACPI_MEM_LIST_GLOBAL 0 +#define ACPI_MEM_LIST_NSNODE 1 +#define ACPI_MEM_LIST_MAX 1 +#define ACPI_NUM_MEM_LISTS 2 + + +/***************************************************************************** + * + * Info/help support + * + ****************************************************************************/ + +typedef struct ah_predefined_name +{ + char *Name; + char *Description; +#ifndef ACPI_ASL_COMPILER + char *Action; +#endif + +} AH_PREDEFINED_NAME; + +typedef struct ah_device_id +{ + char *Name; + char *Description; + +} AH_DEVICE_ID; + +typedef struct ah_uuid +{ + char *Description; + char *String; + +} AH_UUID; + +typedef struct ah_table +{ + char *Signature; + char *Description; + +} AH_TABLE; + +#endif /* __ACLOCAL_H__ */ diff --git a/ports/acpica/include/acmacros.h b/ports/acpica/include/acmacros.h new file mode 100644 index 0000000..f13523a --- /dev/null +++ b/ports/acpica/include/acmacros.h @@ -0,0 +1,647 @@ +/****************************************************************************** + * + * Name: acmacros.h - C macros for the entire subsystem. + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACMACROS_H__ +#define __ACMACROS_H__ + + +/* + * Extract data using a pointer. Any more than a byte and we + * get into potential alignment issues -- see the STORE macros below. + * Use with care. + */ +#define ACPI_CAST8(ptr) ACPI_CAST_PTR (UINT8, (ptr)) +#define ACPI_CAST16(ptr) ACPI_CAST_PTR (UINT16, (ptr)) +#define ACPI_CAST32(ptr) ACPI_CAST_PTR (UINT32, (ptr)) +#define ACPI_CAST64(ptr) ACPI_CAST_PTR (UINT64, (ptr)) +#define ACPI_GET8(ptr) (*ACPI_CAST8 (ptr)) +#define ACPI_GET16(ptr) (*ACPI_CAST16 (ptr)) +#define ACPI_GET32(ptr) (*ACPI_CAST32 (ptr)) +#define ACPI_GET64(ptr) (*ACPI_CAST64 (ptr)) +#define ACPI_SET8(ptr, val) (*ACPI_CAST8 (ptr) = (UINT8) (val)) +#define ACPI_SET16(ptr, val) (*ACPI_CAST16 (ptr) = (UINT16) (val)) +#define ACPI_SET32(ptr, val) (*ACPI_CAST32 (ptr) = (UINT32) (val)) +#define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (UINT64) (val)) + +/* + * printf() format helper. This macro is a workaround for the difficulties + * with emitting 64-bit integers and 64-bit pointers with the same code + * for both 32-bit and 64-bit hosts. + */ +#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i) + + +/* + * Macros for moving data around to/from buffers that are possibly unaligned. + * If the hardware supports the transfer of unaligned data, just do the store. + * Otherwise, we have to move one byte at a time. + */ +#ifdef ACPI_BIG_ENDIAN +/* + * Macros for big-endian machines + */ + +/* These macros reverse the bytes during the move, converting little-endian to big endian */ + + /* Big Endian <== Little Endian */ + /* Hi...Lo Lo...Hi */ +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[0];} + +#define ACPI_MOVE_16_TO_32(d, s) {(*(UINT32 *)(void *)(d))=0;\ + ((UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[1];\ + ((UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[0];} + +#define ACPI_MOVE_16_TO_64(d, s) {(*(UINT64 *)(void *)(d))=0;\ + ((UINT8 *)(void *)(d))[6] = ((UINT8 *)(void *)(s))[1];\ + ((UINT8 *)(void *)(d))[7] = ((UINT8 *)(void *)(s))[0];} + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_32_TO_32(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[3];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[2];\ + (( UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[0];} + +#define ACPI_MOVE_32_TO_64(d, s) {(*(UINT64 *)(void *)(d))=0;\ + ((UINT8 *)(void *)(d))[4] = ((UINT8 *)(void *)(s))[3];\ + ((UINT8 *)(void *)(d))[5] = ((UINT8 *)(void *)(s))[2];\ + ((UINT8 *)(void *)(d))[6] = ((UINT8 *)(void *)(s))[1];\ + ((UINT8 *)(void *)(d))[7] = ((UINT8 *)(void *)(s))[0];} + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ + +#define ACPI_MOVE_64_TO_64(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[7];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[6];\ + (( UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[5];\ + (( UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[4];\ + (( UINT8 *)(void *)(d))[4] = ((UINT8 *)(void *)(s))[3];\ + (( UINT8 *)(void *)(d))[5] = ((UINT8 *)(void *)(s))[2];\ + (( UINT8 *)(void *)(d))[6] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[7] = ((UINT8 *)(void *)(s))[0];} +#else +/* + * Macros for little-endian machines + */ + +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED + +/* The hardware supports unaligned transfers, just do the little-endian move */ + +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) *(UINT16 *)(void *)(d) = *(UINT16 *)(void *)(s) +#define ACPI_MOVE_16_TO_32(d, s) *(UINT32 *)(void *)(d) = *(UINT16 *)(void *)(s) +#define ACPI_MOVE_16_TO_64(d, s) *(UINT64 *)(void *)(d) = *(UINT16 *)(void *)(s) + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_32_TO_32(d, s) *(UINT32 *)(void *)(d) = *(UINT32 *)(void *)(s) +#define ACPI_MOVE_32_TO_64(d, s) *(UINT64 *)(void *)(d) = *(UINT32 *)(void *)(s) + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ +#define ACPI_MOVE_64_TO_64(d, s) *(UINT64 *)(void *)(d) = *(UINT64 *)(void *)(s) + +#else +/* + * The hardware does not support unaligned transfers. We must move the + * data one byte at a time. These macros work whether the source or + * the destination (or both) is/are unaligned. (Little-endian move) + */ + +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[0];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[1];} + +#define ACPI_MOVE_16_TO_32(d, s) {(*(UINT32 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);} +#define ACPI_MOVE_16_TO_64(d, s) {(*(UINT64 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);} + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_32_TO_32(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[0];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[2];\ + (( UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[3];} + +#define ACPI_MOVE_32_TO_64(d, s) {(*(UINT64 *)(void *)(d)) = 0; ACPI_MOVE_32_TO_32(d, s);} + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ +#define ACPI_MOVE_64_TO_64(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[0];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[2];\ + (( UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[3];\ + (( UINT8 *)(void *)(d))[4] = ((UINT8 *)(void *)(s))[4];\ + (( UINT8 *)(void *)(d))[5] = ((UINT8 *)(void *)(s))[5];\ + (( UINT8 *)(void *)(d))[6] = ((UINT8 *)(void *)(s))[6];\ + (( UINT8 *)(void *)(d))[7] = ((UINT8 *)(void *)(s))[7];} +#endif +#endif + + +/* + * Fast power-of-two math macros for non-optimized compilers + */ +#define _ACPI_DIV(value, PowerOf2) ((UINT32) ((value) >> (PowerOf2))) +#define _ACPI_MUL(value, PowerOf2) ((UINT32) ((value) << (PowerOf2))) +#define _ACPI_MOD(value, Divisor) ((UINT32) ((value) & ((Divisor) -1))) + +#define ACPI_DIV_2(a) _ACPI_DIV(a, 1) +#define ACPI_MUL_2(a) _ACPI_MUL(a, 1) +#define ACPI_MOD_2(a) _ACPI_MOD(a, 2) + +#define ACPI_DIV_4(a) _ACPI_DIV(a, 2) +#define ACPI_MUL_4(a) _ACPI_MUL(a, 2) +#define ACPI_MOD_4(a) _ACPI_MOD(a, 4) + +#define ACPI_DIV_8(a) _ACPI_DIV(a, 3) +#define ACPI_MUL_8(a) _ACPI_MUL(a, 3) +#define ACPI_MOD_8(a) _ACPI_MOD(a, 8) + +#define ACPI_DIV_16(a) _ACPI_DIV(a, 4) +#define ACPI_MUL_16(a) _ACPI_MUL(a, 4) +#define ACPI_MOD_16(a) _ACPI_MOD(a, 16) + +#define ACPI_DIV_32(a) _ACPI_DIV(a, 5) +#define ACPI_MUL_32(a) _ACPI_MUL(a, 5) +#define ACPI_MOD_32(a) _ACPI_MOD(a, 32) + +/* Test for ASCII character */ + +#define ACPI_IS_ASCII(c) ((c) < 0x80) + +/* Signed integers */ + +#define ACPI_SIGN_POSITIVE 0 +#define ACPI_SIGN_NEGATIVE 1 + + +/* + * Rounding macros (Power of two boundaries only) + */ +#define ACPI_ROUND_DOWN(value, boundary) (((ACPI_SIZE)(value)) & \ + (~(((ACPI_SIZE) boundary)-1))) + +#define ACPI_ROUND_UP(value, boundary) ((((ACPI_SIZE)(value)) + \ + (((ACPI_SIZE) boundary)-1)) & \ + (~(((ACPI_SIZE) boundary)-1))) + +/* Note: sizeof(ACPI_SIZE) evaluates to either 4 or 8 (32- vs 64-bit mode) */ + +#define ACPI_ROUND_DOWN_TO_32BIT(a) ACPI_ROUND_DOWN(a, 4) +#define ACPI_ROUND_DOWN_TO_64BIT(a) ACPI_ROUND_DOWN(a, 8) +#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a, sizeof(ACPI_SIZE)) + +#define ACPI_ROUND_UP_TO_32BIT(a) ACPI_ROUND_UP(a, 4) +#define ACPI_ROUND_UP_TO_64BIT(a) ACPI_ROUND_UP(a, 8) +#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a, sizeof(ACPI_SIZE)) + +#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7) +#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a)) + +#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10) + +/* Generic (non-power-of-two) rounding */ + +#define ACPI_ROUND_UP_TO(value, boundary) (((value) + ((boundary)-1)) / (boundary)) + +#define ACPI_IS_MISALIGNED(value) (((ACPI_SIZE) value) & (sizeof(ACPI_SIZE)-1)) + +/* Generic bit manipulation */ + +#ifndef ACPI_USE_NATIVE_BIT_FINDER + +#define __ACPI_FIND_LAST_BIT_2(a, r) ((((UINT8) (a)) & 0x02) ? (r)+1 : (r)) +#define __ACPI_FIND_LAST_BIT_4(a, r) ((((UINT8) (a)) & 0x0C) ? \ + __ACPI_FIND_LAST_BIT_2 ((a)>>2, (r)+2) : \ + __ACPI_FIND_LAST_BIT_2 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_8(a, r) ((((UINT8) (a)) & 0xF0) ? \ + __ACPI_FIND_LAST_BIT_4 ((a)>>4, (r)+4) : \ + __ACPI_FIND_LAST_BIT_4 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_16(a, r) ((((UINT16) (a)) & 0xFF00) ? \ + __ACPI_FIND_LAST_BIT_8 ((a)>>8, (r)+8) : \ + __ACPI_FIND_LAST_BIT_8 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_32(a, r) ((((UINT32) (a)) & 0xFFFF0000) ? \ + __ACPI_FIND_LAST_BIT_16 ((a)>>16, (r)+16) : \ + __ACPI_FIND_LAST_BIT_16 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_64(a, r) ((((UINT64) (a)) & 0xFFFFFFFF00000000) ? \ + __ACPI_FIND_LAST_BIT_32 ((a)>>32, (r)+32) : \ + __ACPI_FIND_LAST_BIT_32 ((a), (r))) + +#define ACPI_FIND_LAST_BIT_8(a) ((a) ? __ACPI_FIND_LAST_BIT_8 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_16(a) ((a) ? __ACPI_FIND_LAST_BIT_16 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_32(a) ((a) ? __ACPI_FIND_LAST_BIT_32 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_64(a) ((a) ? __ACPI_FIND_LAST_BIT_64 (a, 1) : 0) + +#define __ACPI_FIND_FIRST_BIT_2(a, r) ((((UINT8) (a)) & 0x01) ? (r) : (r)+1) +#define __ACPI_FIND_FIRST_BIT_4(a, r) ((((UINT8) (a)) & 0x03) ? \ + __ACPI_FIND_FIRST_BIT_2 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_2 ((a)>>2, (r)+2)) +#define __ACPI_FIND_FIRST_BIT_8(a, r) ((((UINT8) (a)) & 0x0F) ? \ + __ACPI_FIND_FIRST_BIT_4 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_4 ((a)>>4, (r)+4)) +#define __ACPI_FIND_FIRST_BIT_16(a, r) ((((UINT16) (a)) & 0x00FF) ? \ + __ACPI_FIND_FIRST_BIT_8 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_8 ((a)>>8, (r)+8)) +#define __ACPI_FIND_FIRST_BIT_32(a, r) ((((UINT32) (a)) & 0x0000FFFF) ? \ + __ACPI_FIND_FIRST_BIT_16 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_16 ((a)>>16, (r)+16)) +#define __ACPI_FIND_FIRST_BIT_64(a, r) ((((UINT64) (a)) & 0x00000000FFFFFFFF) ? \ + __ACPI_FIND_FIRST_BIT_32 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_32 ((a)>>32, (r)+32)) + +#define ACPI_FIND_FIRST_BIT_8(a) ((a) ? __ACPI_FIND_FIRST_BIT_8 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_16(a) ((a) ? __ACPI_FIND_FIRST_BIT_16 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_32(a) ((a) ? __ACPI_FIND_FIRST_BIT_32 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_64(a) ((a) ? __ACPI_FIND_FIRST_BIT_64 (a, 1) : 0) + +#endif /* ACPI_USE_NATIVE_BIT_FINDER */ + +/* Generic (power-of-two) rounding */ + +#define ACPI_ROUND_UP_POWER_OF_TWO_8(a) ((UINT8) \ + (((UINT16) 1) << ACPI_FIND_LAST_BIT_8 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_8(a) ((UINT8) \ + (((UINT16) 1) << (ACPI_FIND_LAST_BIT_8 ((a)) - 1))) +#define ACPI_ROUND_UP_POWER_OF_TWO_16(a) ((UINT16) \ + (((UINT32) 1) << ACPI_FIND_LAST_BIT_16 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_16(a) ((UINT16) \ + (((UINT32) 1) << (ACPI_FIND_LAST_BIT_16 ((a)) - 1))) +#define ACPI_ROUND_UP_POWER_OF_TWO_32(a) ((UINT32) \ + (((UINT64) 1) << ACPI_FIND_LAST_BIT_32 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_32(a) ((UINT32) \ + (((UINT64) 1) << (ACPI_FIND_LAST_BIT_32 ((a)) - 1))) +#define ACPI_IS_ALIGNED(a, s) (((a) & ((s) - 1)) == 0) +#define ACPI_IS_POWER_OF_TWO(a) ACPI_IS_ALIGNED(a, a) + +/* + * Bitmask creation + * Bit positions start at zero. + * MASK_BITS_ABOVE creates a mask starting AT the position and above + * MASK_BITS_BELOW creates a mask starting one bit BELOW the position + * MASK_BITS_ABOVE/BELOW accepts a bit offset to create a mask + * MASK_BITS_ABOVE/BELOW_32/64 accepts a bit width to create a mask + * Note: The ACPI_INTEGER_BIT_SIZE check is used to bypass compiler + * differences with the shift operator + */ +#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_UINT64_MAX) << ((UINT32) (position)))) +#define ACPI_MASK_BITS_BELOW(position) ((ACPI_UINT64_MAX) << ((UINT32) (position))) +#define ACPI_MASK_BITS_ABOVE_32(width) ((UINT32) ACPI_MASK_BITS_ABOVE(width)) +#define ACPI_MASK_BITS_BELOW_32(width) ((UINT32) ACPI_MASK_BITS_BELOW(width)) +#define ACPI_MASK_BITS_ABOVE_64(width) ((width) == ACPI_INTEGER_BIT_SIZE ? \ + ACPI_UINT64_MAX : \ + ACPI_MASK_BITS_ABOVE(width)) +#define ACPI_MASK_BITS_BELOW_64(width) ((width) == ACPI_INTEGER_BIT_SIZE ? \ + (UINT64) 0 : \ + ACPI_MASK_BITS_BELOW(width)) + +/* Bitfields within ACPI registers */ + +#define ACPI_REGISTER_PREPARE_BITS(Val, Pos, Mask) \ + ((Val << Pos) & Mask) + +#define ACPI_REGISTER_INSERT_VALUE(Reg, Pos, Mask, Val) \ + Reg = (Reg & (~(Mask))) | ACPI_REGISTER_PREPARE_BITS(Val, Pos, Mask) + +#define ACPI_INSERT_BITS(Target, Mask, Source) \ + Target = ((Target & (~(Mask))) | (Source & Mask)) + +/* Generic bitfield macros and masks */ + +#define ACPI_GET_BITS(SourcePtr, Position, Mask) \ + ((*(SourcePtr) >> (Position)) & (Mask)) + +#define ACPI_SET_BITS(TargetPtr, Position, Mask, Value) \ + (*(TargetPtr) |= (((Value) & (Mask)) << (Position))) + +#define ACPI_1BIT_MASK 0x00000001 +#define ACPI_2BIT_MASK 0x00000003 +#define ACPI_3BIT_MASK 0x00000007 +#define ACPI_4BIT_MASK 0x0000000F +#define ACPI_5BIT_MASK 0x0000001F +#define ACPI_6BIT_MASK 0x0000003F +#define ACPI_7BIT_MASK 0x0000007F +#define ACPI_8BIT_MASK 0x000000FF +#define ACPI_16BIT_MASK 0x0000FFFF +#define ACPI_24BIT_MASK 0x00FFFFFF + +/* Macros to extract flag bits from position zero */ + +#define ACPI_GET_1BIT_FLAG(Value) ((Value) & ACPI_1BIT_MASK) +#define ACPI_GET_2BIT_FLAG(Value) ((Value) & ACPI_2BIT_MASK) +#define ACPI_GET_3BIT_FLAG(Value) ((Value) & ACPI_3BIT_MASK) +#define ACPI_GET_4BIT_FLAG(Value) ((Value) & ACPI_4BIT_MASK) + +/* Macros to extract flag bits from position one and above */ + +#define ACPI_EXTRACT_1BIT_FLAG(Field, Position) (ACPI_GET_1BIT_FLAG ((Field) >> Position)) +#define ACPI_EXTRACT_2BIT_FLAG(Field, Position) (ACPI_GET_2BIT_FLAG ((Field) >> Position)) +#define ACPI_EXTRACT_3BIT_FLAG(Field, Position) (ACPI_GET_3BIT_FLAG ((Field) >> Position)) +#define ACPI_EXTRACT_4BIT_FLAG(Field, Position) (ACPI_GET_4BIT_FLAG ((Field) >> Position)) + +/* ACPI Pathname helpers */ + +#define ACPI_IS_ROOT_PREFIX(c) ((c) == (UINT8) 0x5C) /* Backslash */ +#define ACPI_IS_PARENT_PREFIX(c) ((c) == (UINT8) 0x5E) /* Carat */ +#define ACPI_IS_PATH_SEPARATOR(c) ((c) == (UINT8) 0x2E) /* Period (dot) */ + +/* + * An object of type ACPI_NAMESPACE_NODE can appear in some contexts + * where a pointer to an object of type ACPI_OPERAND_OBJECT can also + * appear. This macro is used to distinguish them. + * + * The "DescriptorType" field is the second field in both structures. + */ +#define ACPI_GET_DESCRIPTOR_PTR(d) (((ACPI_DESCRIPTOR *)(void *)(d))->Common.CommonPointer) +#define ACPI_SET_DESCRIPTOR_PTR(d, p) (((ACPI_DESCRIPTOR *)(void *)(d))->Common.CommonPointer = (p)) +#define ACPI_GET_DESCRIPTOR_TYPE(d) (((ACPI_DESCRIPTOR *)(void *)(d))->Common.DescriptorType) +#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((ACPI_DESCRIPTOR *)(void *)(d))->Common.DescriptorType = (t)) + +/* + * Macros for the master AML opcode table + */ +#if defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT) +#define ACPI_OP(Name, PArgs, IArgs, ObjType, Class, Type, Flags) \ + {Name, (UINT32)(PArgs), (UINT32)(IArgs), (UINT32)(Flags), ObjType, Class, Type} +#else +#define ACPI_OP(Name, PArgs, IArgs, ObjType, Class, Type, Flags) \ + {(UINT32)(PArgs), (UINT32)(IArgs), (UINT32)(Flags), ObjType, Class, Type} +#endif + +#define ARG_TYPE_WIDTH 5 +#define ARG_1(x) ((UINT32)(x)) +#define ARG_2(x) ((UINT32)(x) << (1 * ARG_TYPE_WIDTH)) +#define ARG_3(x) ((UINT32)(x) << (2 * ARG_TYPE_WIDTH)) +#define ARG_4(x) ((UINT32)(x) << (3 * ARG_TYPE_WIDTH)) +#define ARG_5(x) ((UINT32)(x) << (4 * ARG_TYPE_WIDTH)) +#define ARG_6(x) ((UINT32)(x) << (5 * ARG_TYPE_WIDTH)) + +#define ARGI_LIST1(a) (ARG_1(a)) +#define ARGI_LIST2(a, b) (ARG_1(b)|ARG_2(a)) +#define ARGI_LIST3(a, b, c) (ARG_1(c)|ARG_2(b)|ARG_3(a)) +#define ARGI_LIST4(a, b, c, d) (ARG_1(d)|ARG_2(c)|ARG_3(b)|ARG_4(a)) +#define ARGI_LIST5(a, b, c, d, e) (ARG_1(e)|ARG_2(d)|ARG_3(c)|ARG_4(b)|ARG_5(a)) +#define ARGI_LIST6(a, b, c, d, e, f) (ARG_1(f)|ARG_2(e)|ARG_3(d)|ARG_4(c)|ARG_5(b)|ARG_6(a)) + +#define ARGP_LIST1(a) (ARG_1(a)) +#define ARGP_LIST2(a, b) (ARG_1(a)|ARG_2(b)) +#define ARGP_LIST3(a, b, c) (ARG_1(a)|ARG_2(b)|ARG_3(c)) +#define ARGP_LIST4(a, b, c, d) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)) +#define ARGP_LIST5(a, b, c, d, e) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)) +#define ARGP_LIST6(a, b, c, d, e, f) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)|ARG_6(f)) + +#define GET_CURRENT_ARG_TYPE(List) (List & ((UINT32) 0x1F)) +#define INCREMENT_ARG_LIST(List) (List >>= ((UINT32) ARG_TYPE_WIDTH)) + +/* + * Ascii error messages can be configured out + */ +#ifndef ACPI_NO_ERROR_MESSAGES +/* + * Error reporting. The callers module and line number are inserted by AE_INFO, + * the plist contains a set of parens to allow variable-length lists. + * These macros are used for both the debug and non-debug versions of the code. + */ +#define ACPI_ERROR_NAMESPACE(s, p, e) AcpiUtPrefixedNamespaceError (AE_INFO, s, p, e); +#define ACPI_ERROR_METHOD(s, n, p, e) AcpiUtMethodError (AE_INFO, s, n, p, e); +#define ACPI_WARN_PREDEFINED(plist) AcpiUtPredefinedWarning plist +#define ACPI_INFO_PREDEFINED(plist) AcpiUtPredefinedInfo plist +#define ACPI_BIOS_ERROR_PREDEFINED(plist) AcpiUtPredefinedBiosError plist +#define ACPI_ERROR_ONLY(s) s + +#else + +/* No error messages */ + +#define ACPI_ERROR_NAMESPACE(s, p, e) +#define ACPI_ERROR_METHOD(s, n, p, e) +#define ACPI_WARN_PREDEFINED(plist) +#define ACPI_INFO_PREDEFINED(plist) +#define ACPI_BIOS_ERROR_PREDEFINED(plist) +#define ACPI_ERROR_ONLY(s) + +#endif /* ACPI_NO_ERROR_MESSAGES */ + +#if (!ACPI_REDUCED_HARDWARE) +#define ACPI_HW_OPTIONAL_FUNCTION(addr) addr +#else +#define ACPI_HW_OPTIONAL_FUNCTION(addr) NULL +#endif + + +/* + * Macros used for ACPICA utilities only + */ + +/* Generate a UUID */ + +#define ACPI_INIT_UUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + (a) & 0xFF, ((a) >> 8) & 0xFF, ((a) >> 16) & 0xFF, ((a) >> 24) & 0xFF, \ + (b) & 0xFF, ((b) >> 8) & 0xFF, \ + (c) & 0xFF, ((c) >> 8) & 0xFF, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) + +#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) + + +/* + * Macors used for the ASL-/ASL+ converter utility + */ +#ifdef ACPI_ASL_COMPILER + +#define ASL_CV_LABEL_FILENODE(a) CvLabelFileNode(a); +#define ASL_CV_CAPTURE_COMMENTS_ONLY(a) CvCaptureCommentsOnly (a); +#define ASL_CV_CAPTURE_COMMENTS(a) CvCaptureComments (a); +#define ASL_CV_TRANSFER_COMMENTS(a) CvTransferComments (a); +#define ASL_CV_CLOSE_PAREN(a,b) CvCloseParenWriteComment(a,b); +#define ASL_CV_CLOSE_BRACE(a,b) CvCloseBraceWriteComment(a,b); +#define ASL_CV_SWITCH_FILES(a,b) CvSwitchFiles(a,b); +#define ASL_CV_CLEAR_OP_COMMENTS(a) CvClearOpComments(a); +#define ASL_CV_PRINT_ONE_COMMENT(a,b,c,d) CvPrintOneCommentType (a,b,c,d); +#define ASL_CV_PRINT_ONE_COMMENT_LIST(a,b) CvPrintOneCommentList (a,b); +#define ASL_CV_FILE_HAS_SWITCHED(a) CvFileHasSwitched(a) +#define ASL_CV_INIT_FILETREE(a,b,c) CvInitFileTree(a,b,c); + +#else + +#define ASL_CV_LABEL_FILENODE(a) +#define ASL_CV_CAPTURE_COMMENTS_ONLY(a) +#define ASL_CV_CAPTURE_COMMENTS(a) +#define ASL_CV_TRANSFER_COMMENTS(a) +#define ASL_CV_CLOSE_PAREN(a,b) AcpiOsPrintf (")"); +#define ASL_CV_CLOSE_BRACE(a,b) AcpiOsPrintf ("}"); +#define ASL_CV_SWITCH_FILES(a,b) +#define ASL_CV_CLEAR_OP_COMMENTS(a) +#define ASL_CV_PRINT_ONE_COMMENT(a,b,c,d) +#define ASL_CV_PRINT_ONE_COMMENT_LIST(a,b) +#define ASL_CV_FILE_HAS_SWITCHED(a) 0 +#define ASL_CV_INIT_FILETREE(a,b,c) + +#endif + +#endif /* ACMACROS_H */ diff --git a/ports/acpica/include/acnames.h b/ports/acpica/include/acnames.h new file mode 100644 index 0000000..506ff62 --- /dev/null +++ b/ports/acpica/include/acnames.h @@ -0,0 +1,204 @@ +/****************************************************************************** + * + * Name: acnames.h - Global names and strings + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACNAMES_H__ +#define __ACNAMES_H__ + +/* Method names - these methods can appear anywhere in the namespace */ + +#define METHOD_NAME__ADR "_ADR" +#define METHOD_NAME__AEI "_AEI" +#define METHOD_NAME__BBN "_BBN" +#define METHOD_NAME__CBA "_CBA" +#define METHOD_NAME__CID "_CID" +#define METHOD_NAME__CLS "_CLS" +#define METHOD_NAME__CRS "_CRS" +#define METHOD_NAME__DDN "_DDN" +#define METHOD_NAME__DMA "_DMA" +#define METHOD_NAME__HID "_HID" +#define METHOD_NAME__INI "_INI" +#define METHOD_NAME__PLD "_PLD" +#define METHOD_NAME__DSD "_DSD" +#define METHOD_NAME__PRS "_PRS" +#define METHOD_NAME__PRT "_PRT" +#define METHOD_NAME__PRW "_PRW" +#define METHOD_NAME__PS0 "_PS0" +#define METHOD_NAME__PS1 "_PS1" +#define METHOD_NAME__PS2 "_PS2" +#define METHOD_NAME__PS3 "_PS3" +#define METHOD_NAME__REG "_REG" +#define METHOD_NAME__SB_ "_SB_" +#define METHOD_NAME__SEG "_SEG" +#define METHOD_NAME__SRS "_SRS" +#define METHOD_NAME__STA "_STA" +#define METHOD_NAME__SUB "_SUB" +#define METHOD_NAME__UID "_UID" + +/* Method names - these methods must appear at the namespace root */ + +#define METHOD_PATHNAME__PTS "\\_PTS" +#define METHOD_PATHNAME__SST "\\_SI._SST" +#define METHOD_PATHNAME__WAK "\\_WAK" + +/* Definitions of the predefined namespace names */ + +#define ACPI_UNKNOWN_NAME (UINT32) 0x3F3F3F3F /* Unknown name is "????" */ +#define ACPI_PREFIX_MIXED (UINT32) 0x69706341 /* "Acpi" */ +#define ACPI_PREFIX_LOWER (UINT32) 0x69706361 /* "acpi" */ + +/* Root name stuff */ + +#define ACPI_ROOT_NAME (UINT32) 0x5F5F5F5C /* Root name is "\___" */ +#define ACPI_ROOT_PATHNAME "\\___" +#define ACPI_NAMESPACE_ROOT "Namespace Root" +#define ACPI_NS_ROOT_PATH "\\" + +#endif /* __ACNAMES_H__ */ diff --git a/ports/acpica/include/acnamesp.h b/ports/acpica/include/acnamesp.h new file mode 100644 index 0000000..529fc6e --- /dev/null +++ b/ports/acpica/include/acnamesp.h @@ -0,0 +1,691 @@ +/****************************************************************************** + * + * Name: acnamesp.h - Namespace subcomponent prototypes and defines + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACNAMESP_H__ +#define __ACNAMESP_H__ + + +/* To search the entire name space, pass this as SearchBase */ + +#define ACPI_NS_ALL ((ACPI_HANDLE)0) + +/* + * Elements of AcpiNsProperties are bit significant + * and should be one-to-one with values of ACPI_OBJECT_TYPE + */ +#define ACPI_NS_NORMAL 0 +#define ACPI_NS_NEWSCOPE 1 /* a definition of this type opens a name scope */ +#define ACPI_NS_LOCAL 2 /* suppress search of enclosing scopes */ + +/* Flags for AcpiNsLookup, AcpiNsSearchAndEnter */ + +#define ACPI_NS_NO_UPSEARCH 0 +#define ACPI_NS_SEARCH_PARENT 0x01 +#define ACPI_NS_DONT_OPEN_SCOPE 0x02 +#define ACPI_NS_NO_PEER_SEARCH 0x04 +#define ACPI_NS_ERROR_IF_FOUND 0x08 +#define ACPI_NS_PREFIX_IS_SCOPE 0x10 +#define ACPI_NS_EXTERNAL 0x20 +#define ACPI_NS_TEMPORARY 0x40 +#define ACPI_NS_OVERRIDE_IF_FOUND 0x80 + +/* Flags for AcpiNsWalkNamespace */ + +#define ACPI_NS_WALK_NO_UNLOCK 0 +#define ACPI_NS_WALK_UNLOCK 0x01 +#define ACPI_NS_WALK_TEMP_NODES 0x02 + +/* Object is not a package element */ + +#define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX +#define ACPI_ALL_PACKAGE_ELEMENTS (ACPI_UINT32_MAX-1) + +/* Always emit warning message, not dependent on node flags */ + +#define ACPI_WARN_ALWAYS 0 + + +/* + * nsinit - Namespace initialization + */ +ACPI_STATUS +AcpiNsInitializeObjects ( + void); + +ACPI_STATUS +AcpiNsInitializeDevices ( + UINT32 Flags); + +ACPI_STATUS +AcpiNsInitOnePackage ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +/* + * nsload - Namespace loading + */ +ACPI_STATUS +AcpiNsLoadNamespace ( + void); + +ACPI_STATUS +AcpiNsLoadTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *Node); + + +/* + * nswalk - walk the namespace + */ +ACPI_STATUS +AcpiNsWalkNamespace ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + UINT32 Flags, + ACPI_WALK_CALLBACK DescendingCallback, + ACPI_WALK_CALLBACK AscendingCallback, + void *Context, + void **ReturnValue); + +ACPI_NAMESPACE_NODE * +AcpiNsGetNextNode ( + ACPI_NAMESPACE_NODE *Parent, + ACPI_NAMESPACE_NODE *Child); + +ACPI_NAMESPACE_NODE * +AcpiNsGetNextNodeTyped ( + ACPI_OBJECT_TYPE Type, + ACPI_NAMESPACE_NODE *Parent, + ACPI_NAMESPACE_NODE *Child); + +/* + * nsparse - table parsing + */ +ACPI_STATUS +AcpiNsParseTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode); + +ACPI_STATUS +AcpiNsExecuteTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode); + +ACPI_STATUS +AcpiNsOneCompleteParse ( + UINT32 PassNumber, + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode); + + +/* + * nsaccess - Top-level namespace access + */ +ACPI_STATUS +AcpiNsRootInitialize ( + void); + +ACPI_STATUS +AcpiNsLookup ( + ACPI_GENERIC_STATE *ScopeInfo, + char *Name, + ACPI_OBJECT_TYPE Type, + ACPI_INTERPRETER_MODE InterpreterMode, + UINT32 Flags, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **RetNode); + + +/* + * nsalloc - Named object allocation/deallocation + */ +ACPI_NAMESPACE_NODE * +AcpiNsCreateNode ( + UINT32 Name); + +void +AcpiNsDeleteNode ( + ACPI_NAMESPACE_NODE *Node); + +void +AcpiNsRemoveNode ( + ACPI_NAMESPACE_NODE *Node); + +void +AcpiNsDeleteNamespaceSubtree ( + ACPI_NAMESPACE_NODE *ParentHandle); + +void +AcpiNsDeleteNamespaceByOwner ( + ACPI_OWNER_ID OwnerId); + +void +AcpiNsDetachObject ( + ACPI_NAMESPACE_NODE *Node); + +void +AcpiNsDeleteChildren ( + ACPI_NAMESPACE_NODE *Parent); + +int +AcpiNsCompareNames ( + char *Name1, + char *Name2); + + +/* + * nsconvert - Dynamic object conversion routines + */ +ACPI_STATUS +AcpiNsConvertToInteger ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToString ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToBuffer ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToUnicode ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToResource ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToReference ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + + +/* + * nsdump - Namespace dump/print utilities + */ +void +AcpiNsDumpTables ( + ACPI_HANDLE SearchBase, + UINT32 MaxDepth); + +void +AcpiNsDumpEntry ( + ACPI_HANDLE Handle, + UINT32 DebugLevel); + +void +AcpiNsDumpPathname ( + ACPI_HANDLE Handle, + const char *Msg, + UINT32 Level, + UINT32 Component); + +void +AcpiNsPrintPathname ( + UINT32 NumSegments, + const char *Pathname); + +ACPI_STATUS +AcpiNsDumpOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +void +AcpiNsDumpObjects ( + ACPI_OBJECT_TYPE Type, + UINT8 DisplayType, + UINT32 MaxDepth, + ACPI_OWNER_ID OwnerId, + ACPI_HANDLE StartHandle); + +void +AcpiNsDumpObjectPaths ( + ACPI_OBJECT_TYPE Type, + UINT8 DisplayType, + UINT32 MaxDepth, + ACPI_OWNER_ID OwnerId, + ACPI_HANDLE StartHandle); + + +/* + * nseval - Namespace evaluation functions + */ +ACPI_STATUS +AcpiNsEvaluate ( + ACPI_EVALUATE_INFO *Info); + +void +AcpiNsExecModuleCodeList ( + void); + + +/* + * nsarguments - Argument count/type checking for predefined/reserved names + */ +void +AcpiNsCheckArgumentCount ( + char *Pathname, + ACPI_NAMESPACE_NODE *Node, + UINT32 UserParamCount, + const ACPI_PREDEFINED_INFO *Info); + +void +AcpiNsCheckAcpiCompliance ( + char *Pathname, + ACPI_NAMESPACE_NODE *Node, + const ACPI_PREDEFINED_INFO *Predefined); + +void +AcpiNsCheckArgumentTypes ( + ACPI_EVALUATE_INFO *Info); + + +/* + * nspredef - Return value checking for predefined/reserved names + */ +ACPI_STATUS +AcpiNsCheckReturnValue ( + ACPI_NAMESPACE_NODE *Node, + ACPI_EVALUATE_INFO *Info, + UINT32 UserParamCount, + ACPI_STATUS ReturnStatus, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsCheckObjectType ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr, + UINT32 ExpectedBtypes, + UINT32 PackageIndex); + + +/* + * nsprepkg - Validation of predefined name packages + */ +ACPI_STATUS +AcpiNsCheckPackage ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + + +/* + * nsnames - Name and Scope manipulation + */ +UINT32 +AcpiNsOpensScope ( + ACPI_OBJECT_TYPE Type); + +char * +AcpiNsGetExternalPathname ( + ACPI_NAMESPACE_NODE *Node); + +UINT32 +AcpiNsBuildNormalizedPath ( + ACPI_NAMESPACE_NODE *Node, + char *FullPath, + UINT32 PathSize, + BOOLEAN NoTrailing); + +char * +AcpiNsGetNormalizedPathname ( + ACPI_NAMESPACE_NODE *Node, + BOOLEAN NoTrailing); + +char * +AcpiNsBuildPrefixedPathname ( + ACPI_GENERIC_STATE *PrefixScope, + const char *InternalPath); + +char * +AcpiNsNameOfCurrentScope ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiNsHandleToName ( + ACPI_HANDLE TargetHandle, + ACPI_BUFFER *Buffer); + +ACPI_STATUS +AcpiNsHandleToPathname ( + ACPI_HANDLE TargetHandle, + ACPI_BUFFER *Buffer, + BOOLEAN NoTrailing); + +BOOLEAN +AcpiNsPatternMatch ( + ACPI_NAMESPACE_NODE *ObjNode, + char *SearchFor); + +ACPI_STATUS +AcpiNsGetNodeUnlocked ( + ACPI_NAMESPACE_NODE *PrefixNode, + const char *ExternalPathname, + UINT32 Flags, + ACPI_NAMESPACE_NODE **OutNode); + +ACPI_STATUS +AcpiNsGetNode ( + ACPI_NAMESPACE_NODE *PrefixNode, + const char *ExternalPathname, + UINT32 Flags, + ACPI_NAMESPACE_NODE **OutNode); + +ACPI_SIZE +AcpiNsGetPathnameLength ( + ACPI_NAMESPACE_NODE *Node); + + +/* + * nsobject - Object management for namespace nodes + */ +ACPI_STATUS +AcpiNsAttachObject ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OPERAND_OBJECT *Object, + ACPI_OBJECT_TYPE Type); + +ACPI_OPERAND_OBJECT * +AcpiNsGetAttachedObject ( + ACPI_NAMESPACE_NODE *Node); + +ACPI_OPERAND_OBJECT * +AcpiNsGetSecondaryObject ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiNsAttachData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler, + void *Data); + +ACPI_STATUS +AcpiNsDetachData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler); + +ACPI_STATUS +AcpiNsGetAttachedData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler, + void **Data); + + +/* + * nsrepair - General return object repair for all + * predefined methods/objects + */ +ACPI_STATUS +AcpiNsSimpleRepair ( + ACPI_EVALUATE_INFO *Info, + UINT32 ExpectedBtypes, + UINT32 PackageIndex, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +ACPI_STATUS +AcpiNsWrapWithPackage ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ObjDescPtr); + +ACPI_STATUS +AcpiNsRepairNullElement ( + ACPI_EVALUATE_INFO *Info, + UINT32 ExpectedBtypes, + UINT32 PackageIndex, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +void +AcpiNsRemoveNullElements ( + ACPI_EVALUATE_INFO *Info, + UINT8 PackageType, + ACPI_OPERAND_OBJECT *ObjDesc); + + +/* + * nsrepair2 - Return object repair for specific + * predefined methods/objects + */ +ACPI_STATUS +AcpiNsComplexRepairs ( + ACPI_EVALUATE_INFO *Info, + ACPI_NAMESPACE_NODE *Node, + ACPI_STATUS ValidateStatus, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + + +/* + * nssearch - Namespace searching and entry + */ +ACPI_STATUS +AcpiNsSearchAndEnter ( + UINT32 EntryName, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *Node, + ACPI_INTERPRETER_MODE InterpreterMode, + ACPI_OBJECT_TYPE Type, + UINT32 Flags, + ACPI_NAMESPACE_NODE **RetNode); + +ACPI_STATUS +AcpiNsSearchOneScope ( + UINT32 EntryName, + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type, + ACPI_NAMESPACE_NODE **RetNode); + +void +AcpiNsInstallNode ( + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *ParentNode, + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type); + + +/* + * nsutils - Utility functions + */ +ACPI_OBJECT_TYPE +AcpiNsGetType ( + ACPI_NAMESPACE_NODE *Node); + +UINT32 +AcpiNsLocal ( + ACPI_OBJECT_TYPE Type); + +void +AcpiNsPrintNodePathname ( + ACPI_NAMESPACE_NODE *Node, + const char *Msg); + +ACPI_STATUS +AcpiNsBuildInternalName ( + ACPI_NAMESTRING_INFO *Info); + +void +AcpiNsGetInternalNameLength ( + ACPI_NAMESTRING_INFO *Info); + +ACPI_STATUS +AcpiNsInternalizeName ( + const char *DottedName, + char **ConvertedName); + +ACPI_STATUS +AcpiNsExternalizeName ( + UINT32 InternalNameLength, + const char *InternalName, + UINT32 *ConvertedNameLength, + char **ConvertedName); + +ACPI_NAMESPACE_NODE * +AcpiNsValidateHandle ( + ACPI_HANDLE Handle); + +void +AcpiNsTerminate ( + void); + +#endif /* __ACNAMESP_H__ */ diff --git a/ports/acpica/include/acobject.h b/ports/acpica/include/acobject.h new file mode 100644 index 0000000..824d208 --- /dev/null +++ b/ports/acpica/include/acobject.h @@ -0,0 +1,703 @@ +/****************************************************************************** + * + * Name: acobject.h - Definition of ACPI_OPERAND_OBJECT (Internal object only) + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef _ACOBJECT_H +#define _ACOBJECT_H + +/* acpisrc:StructDefs -- for acpisrc conversion */ + + +/* + * The ACPI_OPERAND_OBJECT is used to pass AML operands from the dispatcher + * to the interpreter, and to keep track of the various handlers such as + * address space handlers and notify handlers. The object is a constant + * size in order to allow it to be cached and reused. + * + * Note: The object is optimized to be aligned and will not work if it is + * byte-packed. + */ +#if ACPI_MACHINE_WIDTH == 64 +#pragma pack(8) +#else +#pragma pack(4) +#endif + +/******************************************************************************* + * + * Common Descriptors + * + ******************************************************************************/ + +/* + * Common area for all objects. + * + * DescriptorType is used to differentiate between internal descriptors, and + * must be in the same place across all descriptors + * + * Note: The DescriptorType and Type fields must appear in the identical + * position in both the ACPI_NAMESPACE_NODE and ACPI_OPERAND_OBJECT + * structures. + */ +#define ACPI_OBJECT_COMMON_HEADER \ + union acpi_operand_object *NextObject; /* Objects linked to parent NS node */\ + UINT8 DescriptorType; /* To differentiate various internal objs */\ + UINT8 Type; /* ACPI_OBJECT_TYPE */\ + UINT16 ReferenceCount; /* For object deletion management */\ + UINT8 Flags; + /* + * Note: There are 3 bytes available here before the + * next natural alignment boundary (for both 32/64 cases) + */ + +/* Values for Flag byte above */ + +#define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */ +#define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */ +#define AOPOBJ_DATA_VALID 0x04 /* Object is initialized and data is valid */ +#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized */ +#define AOPOBJ_REG_CONNECTED 0x10 /* _REG was run */ +#define AOPOBJ_SETUP_COMPLETE 0x20 /* Region setup is complete */ +#define AOPOBJ_INVALID 0x40 /* Host OS won't allow a Region address */ + + +/****************************************************************************** + * + * Basic data types + * + *****************************************************************************/ + +typedef struct acpi_object_common +{ + ACPI_OBJECT_COMMON_HEADER + +} ACPI_OBJECT_COMMON; + + +typedef struct acpi_object_integer +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 Fill[3]; /* Prevent warning on some compilers */ + UINT64 Value; + +} ACPI_OBJECT_INTEGER; + + +/* + * Note: The String and Buffer object must be identical through the + * pointer and length elements. There is code that depends on this. + * + * Fields common to both Strings and Buffers + */ +#define ACPI_COMMON_BUFFER_INFO(_Type) \ + _Type *Pointer; \ + UINT32 Length; + + +/* Null terminated, ASCII characters only */ + +typedef struct acpi_object_string +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_BUFFER_INFO (char) /* String in AML stream or allocated string */ + +} ACPI_OBJECT_STRING; + + +typedef struct acpi_object_buffer +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_BUFFER_INFO (UINT8) /* Buffer in AML stream or allocated buffer */ + UINT32 AmlLength; + UINT8 *AmlStart; + ACPI_NAMESPACE_NODE *Node; /* Link back to parent node */ + +} ACPI_OBJECT_BUFFER; + + +typedef struct acpi_object_package +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_NAMESPACE_NODE *Node; /* Link back to parent node */ + union acpi_operand_object **Elements; /* Array of pointers to AcpiObjects */ + UINT8 *AmlStart; + UINT32 AmlLength; + UINT32 Count; /* # of elements in package */ + +} ACPI_OBJECT_PACKAGE; + + +/****************************************************************************** + * + * Complex data types + * + *****************************************************************************/ + +typedef struct acpi_object_event +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_SEMAPHORE OsSemaphore; /* Actual OS synchronization object */ + +} ACPI_OBJECT_EVENT; + + +typedef struct acpi_object_mutex +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 SyncLevel; /* 0-15, specified in Mutex() call */ + UINT16 AcquisitionDepth; /* Allow multiple Acquires, same thread */ + ACPI_MUTEX OsMutex; /* Actual OS synchronization object */ + ACPI_THREAD_ID ThreadId; /* Current owner of the mutex */ + struct acpi_thread_state *OwnerThread; /* Current owner of the mutex */ + union acpi_operand_object *Prev; /* Link for list of acquired mutexes */ + union acpi_operand_object *Next; /* Link for list of acquired mutexes */ + ACPI_NAMESPACE_NODE *Node; /* Containing namespace node */ + UINT8 OriginalSyncLevel; /* Owner's original sync level (0-15) */ + +} ACPI_OBJECT_MUTEX; + + +typedef struct acpi_object_region +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 SpaceId; + ACPI_NAMESPACE_NODE *Node; /* Containing namespace node */ + union acpi_operand_object *Handler; /* Handler for region access */ + union acpi_operand_object *Next; + ACPI_PHYSICAL_ADDRESS Address; + UINT32 Length; + +} ACPI_OBJECT_REGION; + + +typedef struct acpi_object_method +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 InfoFlags; + UINT8 ParamCount; + UINT8 SyncLevel; + union acpi_operand_object *Mutex; + union acpi_operand_object *Node; + UINT8 *AmlStart; + union + { + ACPI_INTERNAL_METHOD Implementation; + union acpi_operand_object *Handler; + } Dispatch; + + UINT32 AmlLength; + UINT8 ThreadCount; + ACPI_OWNER_ID OwnerId; + +} ACPI_OBJECT_METHOD; + +/* Flags for InfoFlags field above */ + +#define ACPI_METHOD_MODULE_LEVEL 0x01 /* Method is actually module-level code */ +#define ACPI_METHOD_INTERNAL_ONLY 0x02 /* Method is implemented internally (_OSI) */ +#define ACPI_METHOD_SERIALIZED 0x04 /* Method is serialized */ +#define ACPI_METHOD_SERIALIZED_PENDING 0x08 /* Method is to be marked serialized */ +#define ACPI_METHOD_IGNORE_SYNC_LEVEL 0x10 /* Method was auto-serialized at table load time */ +#define ACPI_METHOD_MODIFIED_NAMESPACE 0x20 /* Method modified the namespace */ + + +/****************************************************************************** + * + * Objects that can be notified. All share a common NotifyInfo area. + * + *****************************************************************************/ + +/* + * Common fields for objects that support ASL notifications + */ +#define ACPI_COMMON_NOTIFY_INFO \ + union acpi_operand_object *NotifyList[2]; /* Handlers for system/device notifies */\ + union acpi_operand_object *Handler; /* Handler for Address space */ + +/* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ + +typedef struct acpi_object_notify_common +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + +} ACPI_OBJECT_NOTIFY_COMMON; + + +typedef struct acpi_object_device +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + ACPI_GPE_BLOCK_INFO *GpeBlock; + +} ACPI_OBJECT_DEVICE; + + +typedef struct acpi_object_power_resource +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + UINT32 SystemLevel; + UINT32 ResourceOrder; + +} ACPI_OBJECT_POWER_RESOURCE; + + +typedef struct acpi_object_processor +{ + ACPI_OBJECT_COMMON_HEADER + + /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */ + + UINT8 ProcId; + UINT8 Length; + ACPI_COMMON_NOTIFY_INFO + ACPI_IO_ADDRESS Address; + +} ACPI_OBJECT_PROCESSOR; + + +typedef struct acpi_object_thermal_zone +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + +} ACPI_OBJECT_THERMAL_ZONE; + + +/****************************************************************************** + * + * Fields. All share a common header/info field. + * + *****************************************************************************/ + +/* + * Common bitfield for the field objects + * "Field Datum" -- a datum from the actual field object + * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field + */ +#define ACPI_COMMON_FIELD_INFO \ + UINT8 FieldFlags; /* Access, update, and lock bits */\ + UINT8 Attribute; /* From AccessAs keyword */\ + UINT8 AccessByteWidth; /* Read/Write size in bytes */\ + ACPI_NAMESPACE_NODE *Node; /* Link back to parent node */\ + UINT32 BitLength; /* Length of field in bits */\ + UINT32 BaseByteOffset; /* Byte offset within containing object */\ + UINT32 Value; /* Value to store into the Bank or Index register */\ + UINT8 StartFieldBitOffset;/* Bit offset within first field datum (0-63) */\ + UINT8 AccessLength; /* For serial regions/fields */ + +/* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ + +typedef struct acpi_object_field_common +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + union acpi_operand_object *RegionObj; /* Parent Operation Region object (REGION/BANK fields only) */ + +} ACPI_OBJECT_FIELD_COMMON; + + +typedef struct acpi_object_region_field +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + UINT16 ResourceLength; + union acpi_operand_object *RegionObj; /* Containing OpRegion object */ + UINT8 *ResourceBuffer; /* ResourceTemplate for serial regions/fields */ + UINT16 PinNumberIndex; /* Index relative to previous Connection/Template */ + +} ACPI_OBJECT_REGION_FIELD; + + +typedef struct acpi_object_bank_field +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + union acpi_operand_object *RegionObj; /* Containing OpRegion object */ + union acpi_operand_object *BankObj; /* BankSelect Register object */ + +} ACPI_OBJECT_BANK_FIELD; + + +typedef struct acpi_object_index_field +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + + /* + * No "RegionObj" pointer needed since the Index and Data registers + * are each field definitions unto themselves. + */ + union acpi_operand_object *IndexObj; /* Index register */ + union acpi_operand_object *DataObj; /* Data register */ + +} ACPI_OBJECT_INDEX_FIELD; + + +/* The BufferField is different in that it is part of a Buffer, not an OpRegion */ + +typedef struct acpi_object_buffer_field +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + union acpi_operand_object *BufferObj; /* Containing Buffer object */ + +} ACPI_OBJECT_BUFFER_FIELD; + + +/****************************************************************************** + * + * Objects for handlers + * + *****************************************************************************/ + +typedef struct acpi_object_notify_handler +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_NAMESPACE_NODE *Node; /* Parent device */ + UINT32 HandlerType; /* Type: Device/System/Both */ + ACPI_NOTIFY_HANDLER Handler; /* Handler address */ + void *Context; + union acpi_operand_object *Next[2]; /* Device and System handler lists */ + +} ACPI_OBJECT_NOTIFY_HANDLER; + + +typedef struct acpi_object_addr_handler +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 SpaceId; + UINT8 HandlerFlags; + ACPI_ADR_SPACE_HANDLER Handler; + ACPI_NAMESPACE_NODE *Node; /* Parent device */ + void *Context; + ACPI_ADR_SPACE_SETUP Setup; + union acpi_operand_object *RegionList; /* Regions using this handler */ + union acpi_operand_object *Next; + +} ACPI_OBJECT_ADDR_HANDLER; + +/* Flags for address handler (HandlerFlags) */ + +#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x01 + + +/****************************************************************************** + * + * Special internal objects + * + *****************************************************************************/ + +/* + * The Reference object is used for these opcodes: + * Arg[0-6], Local[0-7], IndexOp, NameOp, RefOfOp, LoadOp, LoadTableOp, DebugOp + * The Reference.Class differentiates these types. + */ +typedef struct acpi_object_reference +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 Class; /* Reference Class */ + UINT8 TargetType; /* Used for Index Op */ + UINT8 Resolved; /* Reference has been resolved to a value */ + void *Object; /* NameOp=>HANDLE to obj, IndexOp=>ACPI_OPERAND_OBJECT */ + ACPI_NAMESPACE_NODE *Node; /* RefOf or Namepath */ + union acpi_operand_object **Where; /* Target of Index */ + UINT8 *IndexPointer; /* Used for Buffers and Strings */ + UINT8 *Aml; /* Used for deferred resolution of the ref */ + UINT32 Value; /* Used for Local/Arg/Index/DdbHandle */ + +} ACPI_OBJECT_REFERENCE; + +/* Values for Reference.Class above */ + +typedef enum +{ + ACPI_REFCLASS_LOCAL = 0, /* Method local */ + ACPI_REFCLASS_ARG = 1, /* Method argument */ + ACPI_REFCLASS_REFOF = 2, /* Result of RefOf() TBD: Split to Ref/Node and Ref/OperandObj? */ + ACPI_REFCLASS_INDEX = 3, /* Result of Index() */ + ACPI_REFCLASS_TABLE = 4, /* DdbHandle - Load(), LoadTable() */ + ACPI_REFCLASS_NAME = 5, /* Reference to a named object */ + ACPI_REFCLASS_DEBUG = 6, /* Debug object */ + + ACPI_REFCLASS_MAX = 6 + +} ACPI_REFERENCE_CLASSES; + +/* + * Extra object is used as additional storage for types that + * have AML code in their declarations (TermArgs) that must be + * evaluated at run time. + * + * Currently: Region and FieldUnit types + */ +typedef struct acpi_object_extra +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_NAMESPACE_NODE *Method_REG; /* _REG method for this region (if any) */ + ACPI_NAMESPACE_NODE *ScopeNode; + void *RegionContext; /* Region-specific data */ + UINT8 *AmlStart; + UINT32 AmlLength; + +} ACPI_OBJECT_EXTRA; + + +/* Additional data that can be attached to namespace nodes */ + +typedef struct acpi_object_data +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_OBJECT_HANDLER Handler; + void *Pointer; + +} ACPI_OBJECT_DATA; + + +/* Structure used when objects are cached for reuse */ + +typedef struct acpi_object_cache_list +{ + ACPI_OBJECT_COMMON_HEADER + union acpi_operand_object *Next; /* Link for object cache and internal lists*/ + +} ACPI_OBJECT_CACHE_LIST; + + +/****************************************************************************** + * + * ACPI_OPERAND_OBJECT Descriptor - a giant union of all of the above + * + *****************************************************************************/ + +typedef union acpi_operand_object +{ + ACPI_OBJECT_COMMON Common; + ACPI_OBJECT_INTEGER Integer; + ACPI_OBJECT_STRING String; + ACPI_OBJECT_BUFFER Buffer; + ACPI_OBJECT_PACKAGE Package; + ACPI_OBJECT_EVENT Event; + ACPI_OBJECT_METHOD Method; + ACPI_OBJECT_MUTEX Mutex; + ACPI_OBJECT_REGION Region; + ACPI_OBJECT_NOTIFY_COMMON CommonNotify; + ACPI_OBJECT_DEVICE Device; + ACPI_OBJECT_POWER_RESOURCE PowerResource; + ACPI_OBJECT_PROCESSOR Processor; + ACPI_OBJECT_THERMAL_ZONE ThermalZone; + ACPI_OBJECT_FIELD_COMMON CommonField; + ACPI_OBJECT_REGION_FIELD Field; + ACPI_OBJECT_BUFFER_FIELD BufferField; + ACPI_OBJECT_BANK_FIELD BankField; + ACPI_OBJECT_INDEX_FIELD IndexField; + ACPI_OBJECT_NOTIFY_HANDLER Notify; + ACPI_OBJECT_ADDR_HANDLER AddressSpace; + ACPI_OBJECT_REFERENCE Reference; + ACPI_OBJECT_EXTRA Extra; + ACPI_OBJECT_DATA Data; + ACPI_OBJECT_CACHE_LIST Cache; + + /* + * Add namespace node to union in order to simplify code that accepts both + * ACPI_OPERAND_OBJECTs and ACPI_NAMESPACE_NODEs. The structures share + * a common DescriptorType field in order to differentiate them. + */ + ACPI_NAMESPACE_NODE Node; + +} ACPI_OPERAND_OBJECT; + + +/****************************************************************************** + * + * ACPI_DESCRIPTOR - objects that share a common descriptor identifier + * + *****************************************************************************/ + +/* Object descriptor types */ + +#define ACPI_DESC_TYPE_CACHED 0x01 /* Used only when object is cached */ +#define ACPI_DESC_TYPE_STATE 0x02 +#define ACPI_DESC_TYPE_STATE_UPDATE 0x03 +#define ACPI_DESC_TYPE_STATE_PACKAGE 0x04 +#define ACPI_DESC_TYPE_STATE_CONTROL 0x05 +#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x06 +#define ACPI_DESC_TYPE_STATE_PSCOPE 0x07 +#define ACPI_DESC_TYPE_STATE_WSCOPE 0x08 +#define ACPI_DESC_TYPE_STATE_RESULT 0x09 +#define ACPI_DESC_TYPE_STATE_NOTIFY 0x0A +#define ACPI_DESC_TYPE_STATE_THREAD 0x0B +#define ACPI_DESC_TYPE_WALK 0x0C +#define ACPI_DESC_TYPE_PARSER 0x0D +#define ACPI_DESC_TYPE_OPERAND 0x0E +#define ACPI_DESC_TYPE_NAMED 0x0F +#define ACPI_DESC_TYPE_MAX 0x0F + + +typedef struct acpi_common_descriptor +{ + void *CommonPointer; + UINT8 DescriptorType; /* To differentiate various internal objs */ + +} ACPI_COMMON_DESCRIPTOR; + +typedef union acpi_descriptor +{ + ACPI_COMMON_DESCRIPTOR Common; + ACPI_OPERAND_OBJECT Object; + ACPI_NAMESPACE_NODE Node; + ACPI_PARSE_OBJECT Op; + +} ACPI_DESCRIPTOR; + +#pragma pack() + +#endif /* _ACOBJECT_H */ diff --git a/ports/acpica/include/acopcode.h b/ports/acpica/include/acopcode.h new file mode 100644 index 0000000..6dbeac6 --- /dev/null +++ b/ports/acpica/include/acopcode.h @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * Name: acopcode.h - AML opcode information for the AML parser and interpreter + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACOPCODE_H__ +#define __ACOPCODE_H__ + +#define MAX_EXTENDED_OPCODE 0x88 +#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1) +#define MAX_INTERNAL_OPCODE +#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1) + +/* Used for non-assigned opcodes */ + +#define _UNK 0x6B + +/* + * Reserved ASCII characters. Do not use any of these for + * internal opcodes, since they are used to differentiate + * name strings from AML opcodes + */ +#define _ASC 0x6C +#define _NAM 0x6C +#define _PFX 0x6D + + +/* + * All AML opcodes and the parse-time arguments for each. Used by the AML + * parser Each list is compressed into a 32-bit number and stored in the + * master opcode table (in psopcode.c). + */ +#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA) +#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME) +#define ARGP_ARG0 ARG_NONE +#define ARGP_ARG1 ARG_NONE +#define ARGP_ARG2 ARG_NONE +#define ARGP_ARG3 ARG_NONE +#define ARGP_ARG4 ARG_NONE +#define ARGP_ARG5 ARG_NONE +#define ARGP_ARG6 ARG_NONE +#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BREAK_OP ARG_NONE +#define ARGP_BREAK_POINT_OP ARG_NONE +#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST) +#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA) +#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_COMMENT_OP ARGP_LIST2 (ARGP_BYTEDATA, ARGP_COMMENT) +#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SIMPLENAME, ARGP_TARGET) +#define ARGP_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_CONTINUE_OP ARG_NONE +#define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) +#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_DEBUG_OP ARG_NONE +#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) +#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET) +#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) +#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) +#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) +#define ARGP_EXTERNAL_OP ARGP_LIST3 (ARGP_NAME, ARGP_BYTEDATA, ARGP_BYTEDATA) +#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) +#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) +#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME) +#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LOCAL0 ARG_NONE +#define ARGP_LOCAL1 ARG_NONE +#define ARGP_LOCAL2 ARG_NONE +#define ARGP_LOCAL3 ARG_NONE +#define ARGP_LOCAL4 ARG_NONE +#define ARGP_LOCAL5 ARG_NONE +#define ARGP_LOCAL6 ARG_NONE +#define ARGP_LOCAL7 ARG_NONE +#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST) +#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA) +#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ) +#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_NOOP_OP ARG_NONE +#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) +#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_SIMPLENAME) +#define ARGP_ONE_OP ARG_NONE +#define ARGP_ONES_OP ARG_NONE +#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) +#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) +#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) +#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) +#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SIMPLENAME) +#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_REVISION_OP ARG_NONE +#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST) +#define ARGP_SERIALFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME) +#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST) +#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) +#define ARGP_TIMER_OP ARG_NONE +#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) +#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) +#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) +#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA) +#define ARGP_ZERO_OP ARG_NONE + + +/* + * All AML opcodes and the runtime arguments for each. Used by the AML + * interpreter Each list is compressed into a 32-bit number and stored + * in the master opcode table (in psopcode.c). + * + * (Used by PrepOperands procedure and the ASL Compiler) + */ +#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER) +#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE +#define ARGI_ARG0 ARG_NONE +#define ARGI_ARG1 ARG_NONE +#define ARGI_ARG2 ARG_NONE +#define ARGI_ARG3 ARG_NONE +#define ARGI_ARG4 ARG_NONE +#define ARGI_ARG5 ARG_NONE +#define ARGI_ARG6 ARG_NONE +#define ARGI_BANK_FIELD_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BREAK_OP ARG_NONE +#define ARGI_BREAK_POINT_OP ARG_NONE +#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_BYTE_OP ARGI_INVALID_OPCODE +#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE +#define ARGI_COMMENT_OP ARGI_INVALID_OPCODE +#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_ANYTYPE, ARGI_ANYTYPE, ARGI_TARGETREF) +#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) +#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) +#define ARGI_CONNECTFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE +#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET) +#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) +#define ARGI_DEBUG_OP ARG_NONE +#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) +#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) +#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE +#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF) +#define ARGI_DWORD_OP ARGI_INVALID_OPCODE +#define ARGI_ELSE_OP ARGI_INVALID_OPCODE +#define ARGI_EVENT_OP ARGI_INVALID_OPCODE +#define ARGI_EXTERNAL_OP ARGI_LIST3 (ARGI_STRING, ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_FIELD_OP ARGI_INVALID_OPCODE +#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_IF_OP ARGI_INVALID_OPCODE +#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) +#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE +#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF) +#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE) +#define ARGI_LOCAL0 ARG_NONE +#define ARGI_LOCAL1 ARG_NONE +#define ARGI_LOCAL2 ARG_NONE +#define ARGI_LOCAL3 ARG_NONE +#define ARGI_LOCAL4 ARG_NONE +#define ARGI_LOCAL5 ARG_NONE +#define ARGI_LOCAL6 ARG_NONE +#define ARGI_LOCAL7 ARG_NONE +#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER) +#define ARGI_METHOD_OP ARGI_INVALID_OPCODE +#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE +#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE +#define ARGI_NAME_OP ARGI_INVALID_OPCODE +#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE +#define ARGI_NOOP_OP ARG_NONE +#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) +#define ARGI_OBJECT_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) +#define ARGI_ONE_OP ARG_NONE +#define ARGI_ONES_OP ARG_NONE +#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE +#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE +#define ARGI_QWORD_OP ARGI_INVALID_OPCODE +#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF) +#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX) +#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT) +#define ARGI_RETURN_OP ARGI_INVALID_OPCODE +#define ARGI_REVISION_OP ARG_NONE +#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE +#define ARGI_SERIALFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT) +#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT) +#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE +#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_STORE_TARGET) +#define ARGI_STRING_OP ARGI_INVALID_OPCODE +#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE +#define ARGI_TIMER_OP ARG_NONE +#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) +#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) +#define ARGI_WHILE_OP ARGI_INVALID_OPCODE +#define ARGI_WORD_OP ARGI_INVALID_OPCODE +#define ARGI_ZERO_OP ARG_NONE + +#endif /* __ACOPCODE_H__ */ diff --git a/ports/acpica/include/acoutput.h b/ports/acpica/include/acoutput.h new file mode 100644 index 0000000..49b8505 --- /dev/null +++ b/ports/acpica/include/acoutput.h @@ -0,0 +1,608 @@ +/****************************************************************************** + * + * Name: acoutput.h -- debug output + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACOUTPUT_H__ +#define __ACOUTPUT_H__ + +/* + * Debug levels and component IDs. These are used to control the + * granularity of the output of the ACPI_DEBUG_PRINT macro -- on a + * per-component basis and a per-exception-type basis. + */ + +/* Component IDs are used in the global "DebugLayer" */ + +#define ACPI_UTILITIES 0x00000001 +#define ACPI_HARDWARE 0x00000002 +#define ACPI_EVENTS 0x00000004 +#define ACPI_TABLES 0x00000008 +#define ACPI_NAMESPACE 0x00000010 +#define ACPI_PARSER 0x00000020 +#define ACPI_DISPATCHER 0x00000040 +#define ACPI_EXECUTER 0x00000080 +#define ACPI_RESOURCES 0x00000100 +#define ACPI_CA_DEBUGGER 0x00000200 +#define ACPI_OS_SERVICES 0x00000400 +#define ACPI_CA_DISASSEMBLER 0x00000800 + +/* Component IDs for ACPI tools and utilities */ + +#define ACPI_COMPILER 0x00001000 +#define ACPI_TOOLS 0x00002000 +#define ACPI_EXAMPLE 0x00004000 +#define ACPI_DRIVER 0x00008000 +#define DT_COMPILER 0x00010000 +#define ASL_PREPROCESSOR 0x00020000 + +#define ACPI_ALL_COMPONENTS 0x0001FFFF +#define ACPI_COMPONENT_DEFAULT (ACPI_ALL_COMPONENTS) + +/* Component IDs reserved for ACPI drivers */ + +#define ACPI_ALL_DRIVERS 0xFFFF0000 + + +/* + * Raw debug output levels, do not use these in the ACPI_DEBUG_PRINT macros + */ +#define ACPI_LV_INIT 0x00000001 +#define ACPI_LV_DEBUG_OBJECT 0x00000002 +#define ACPI_LV_INFO 0x00000004 +#define ACPI_LV_REPAIR 0x00000008 +#define ACPI_LV_TRACE_POINT 0x00000010 +#define ACPI_LV_ALL_EXCEPTIONS 0x0000001F + +/* Trace verbosity level 1 [Standard Trace Level] */ + +#define ACPI_LV_INIT_NAMES 0x00000020 +#define ACPI_LV_PARSE 0x00000040 +#define ACPI_LV_LOAD 0x00000080 +#define ACPI_LV_DISPATCH 0x00000100 +#define ACPI_LV_EXEC 0x00000200 +#define ACPI_LV_NAMES 0x00000400 +#define ACPI_LV_OPREGION 0x00000800 +#define ACPI_LV_BFIELD 0x00001000 +#define ACPI_LV_TABLES 0x00002000 +#define ACPI_LV_VALUES 0x00004000 +#define ACPI_LV_OBJECTS 0x00008000 +#define ACPI_LV_RESOURCES 0x00010000 +#define ACPI_LV_USER_REQUESTS 0x00020000 +#define ACPI_LV_PACKAGE 0x00040000 +#define ACPI_LV_VERBOSITY1 0x0007FF40 | ACPI_LV_ALL_EXCEPTIONS + +/* Trace verbosity level 2 [Function tracing and memory allocation] */ + +#define ACPI_LV_ALLOCATIONS 0x00100000 +#define ACPI_LV_FUNCTIONS 0x00200000 +#define ACPI_LV_OPTIMIZATIONS 0x00400000 +#define ACPI_LV_VERBOSITY2 0x00700000 | ACPI_LV_VERBOSITY1 +#define ACPI_LV_ALL ACPI_LV_VERBOSITY2 + +/* Trace verbosity level 3 [Threading, I/O, and Interrupts] */ + +#define ACPI_LV_MUTEX 0x01000000 +#define ACPI_LV_THREADS 0x02000000 +#define ACPI_LV_IO 0x04000000 +#define ACPI_LV_INTERRUPTS 0x08000000 +#define ACPI_LV_VERBOSITY3 0x0F000000 | ACPI_LV_VERBOSITY2 + +/* Exceptionally verbose output -- also used in the global "DebugLevel" */ + +#define ACPI_LV_AML_DISASSEMBLE 0x10000000 +#define ACPI_LV_VERBOSE_INFO 0x20000000 +#define ACPI_LV_FULL_TABLES 0x40000000 +#define ACPI_LV_EVENTS 0x80000000 +#define ACPI_LV_VERBOSE 0xF0000000 + + +/* + * Debug level macros that are used in the DEBUG_PRINT macros + */ +#define ACPI_DEBUG_LEVEL(dl) (UINT32) dl,ACPI_DEBUG_PARAMETERS + +/* + * Exception level -- used in the global "DebugLevel" + * + * Note: For errors, use the ACPI_ERROR or ACPI_EXCEPTION interfaces. + * For warnings, use ACPI_WARNING. + */ +#define ACPI_DB_INIT ACPI_DEBUG_LEVEL (ACPI_LV_INIT) +#define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT) +#define ACPI_DB_INFO ACPI_DEBUG_LEVEL (ACPI_LV_INFO) +#define ACPI_DB_REPAIR ACPI_DEBUG_LEVEL (ACPI_LV_REPAIR) +#define ACPI_DB_TRACE_POINT ACPI_DEBUG_LEVEL (ACPI_LV_TRACE_POINT) +#define ACPI_DB_ALL_EXCEPTIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALL_EXCEPTIONS) + +/* Trace level -- also used in the global "DebugLevel" */ + +#define ACPI_DB_INIT_NAMES ACPI_DEBUG_LEVEL (ACPI_LV_INIT_NAMES) +#define ACPI_DB_THREADS ACPI_DEBUG_LEVEL (ACPI_LV_THREADS) +#define ACPI_DB_PARSE ACPI_DEBUG_LEVEL (ACPI_LV_PARSE) +#define ACPI_DB_DISPATCH ACPI_DEBUG_LEVEL (ACPI_LV_DISPATCH) +#define ACPI_DB_LOAD ACPI_DEBUG_LEVEL (ACPI_LV_LOAD) +#define ACPI_DB_EXEC ACPI_DEBUG_LEVEL (ACPI_LV_EXEC) +#define ACPI_DB_NAMES ACPI_DEBUG_LEVEL (ACPI_LV_NAMES) +#define ACPI_DB_OPREGION ACPI_DEBUG_LEVEL (ACPI_LV_OPREGION) +#define ACPI_DB_BFIELD ACPI_DEBUG_LEVEL (ACPI_LV_BFIELD) +#define ACPI_DB_TABLES ACPI_DEBUG_LEVEL (ACPI_LV_TABLES) +#define ACPI_DB_FUNCTIONS ACPI_DEBUG_LEVEL (ACPI_LV_FUNCTIONS) +#define ACPI_DB_OPTIMIZATIONS ACPI_DEBUG_LEVEL (ACPI_LV_OPTIMIZATIONS) +#define ACPI_DB_VALUES ACPI_DEBUG_LEVEL (ACPI_LV_VALUES) +#define ACPI_DB_OBJECTS ACPI_DEBUG_LEVEL (ACPI_LV_OBJECTS) +#define ACPI_DB_ALLOCATIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALLOCATIONS) +#define ACPI_DB_RESOURCES ACPI_DEBUG_LEVEL (ACPI_LV_RESOURCES) +#define ACPI_DB_IO ACPI_DEBUG_LEVEL (ACPI_LV_IO) +#define ACPI_DB_INTERRUPTS ACPI_DEBUG_LEVEL (ACPI_LV_INTERRUPTS) +#define ACPI_DB_USER_REQUESTS ACPI_DEBUG_LEVEL (ACPI_LV_USER_REQUESTS) +#define ACPI_DB_PACKAGE ACPI_DEBUG_LEVEL (ACPI_LV_PACKAGE) +#define ACPI_DB_MUTEX ACPI_DEBUG_LEVEL (ACPI_LV_MUTEX) +#define ACPI_DB_EVENTS ACPI_DEBUG_LEVEL (ACPI_LV_EVENTS) + +#define ACPI_DB_ALL ACPI_DEBUG_LEVEL (ACPI_LV_ALL) + +/* Defaults for DebugLevel, debug and normal */ + +#define ACPI_DEBUG_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR) +#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR) +#define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL) + + +/* + * Global trace flags + */ +#define ACPI_TRACE_ENABLED ((UINT32) 4) +#define ACPI_TRACE_ONESHOT ((UINT32) 2) +#define ACPI_TRACE_OPCODE ((UINT32) 1) + +/* Defaults for trace debugging level/layer */ + +#define ACPI_TRACE_LEVEL_ALL ACPI_LV_ALL +#define ACPI_TRACE_LAYER_ALL 0x000001FF +#define ACPI_TRACE_LEVEL_DEFAULT ACPI_LV_TRACE_POINT +#define ACPI_TRACE_LAYER_DEFAULT ACPI_EXECUTER + + +#if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) +/* + * The module name is used primarily for error and debug messages. + * The __FILE__ macro is not very useful for this, because it + * usually includes the entire pathname to the module making the + * debug output difficult to read. + */ +#define ACPI_MODULE_NAME(Name) static const char ACPI_UNUSED_VAR _AcpiModuleName[] = Name; +#else +/* + * For the no-debug and no-error-msg cases, we must at least define + * a null module name. + */ +#define ACPI_MODULE_NAME(Name) +#define _AcpiModuleName "" +#endif + +/* + * Ascii error messages can be configured out + */ +#ifndef ACPI_NO_ERROR_MESSAGES +#define AE_INFO _AcpiModuleName, __LINE__ + +/* + * Error reporting. Callers module and line number are inserted by AE_INFO, + * the plist contains a set of parens to allow variable-length lists. + * These macros are used for both the debug and non-debug versions of the code. + */ +#define ACPI_INFO(plist) AcpiInfo plist +#define ACPI_WARNING(plist) AcpiWarning plist +#define ACPI_EXCEPTION(plist) AcpiException plist +#define ACPI_ERROR(plist) AcpiError plist +#define ACPI_BIOS_WARNING(plist) AcpiBiosWarning plist +#define ACPI_BIOS_ERROR(plist) AcpiBiosError plist +#define ACPI_DEBUG_OBJECT(obj,l,i) AcpiExDoDebugObject(obj,l,i) + +#else + +/* No error messages */ + +#define ACPI_INFO(plist) +#define ACPI_WARNING(plist) +#define ACPI_EXCEPTION(plist) +#define ACPI_ERROR(plist) +#define ACPI_BIOS_WARNING(plist) +#define ACPI_BIOS_ERROR(plist) +#define ACPI_DEBUG_OBJECT(obj,l,i) + +#endif /* ACPI_NO_ERROR_MESSAGES */ + + +/* + * Debug macros that are conditionally compiled + */ +#ifdef ACPI_DEBUG_OUTPUT + +/* + * If ACPI_GET_FUNCTION_NAME was not defined in the compiler-dependent header, + * define it now. This is the case where there the compiler does not support + * a __FUNCTION__ macro or equivalent. + */ +#ifndef ACPI_GET_FUNCTION_NAME +#define ACPI_GET_FUNCTION_NAME _AcpiFunctionName + +/* + * The Name parameter should be the procedure name as a non-quoted string. + * The function name is also used by the function exit macros below. + * Note: (const char) is used to be compatible with the debug interfaces + * and macros such as __FUNCTION__. + */ +#define ACPI_FUNCTION_NAME(Name) static const char _AcpiFunctionName[] = #Name; + +#else +/* Compiler supports __FUNCTION__ (or equivalent) -- Ignore this macro */ + +#define ACPI_FUNCTION_NAME(Name) +#endif /* ACPI_GET_FUNCTION_NAME */ + +/* + * Common parameters used for debug output functions: + * line number, function name, module(file) name, component ID + */ +#define ACPI_DEBUG_PARAMETERS \ + __LINE__, ACPI_GET_FUNCTION_NAME, _AcpiModuleName, _COMPONENT + +/* Check if debug output is currently dynamically enabled */ + +#define ACPI_IS_DEBUG_ENABLED(Level, Component) \ + ((Level & AcpiDbgLevel) && (Component & AcpiDbgLayer)) + +/* + * Master debug print macros + * Print message if and only if: + * 1) Debug print for the current component is enabled + * 2) Debug error level or trace level for the print statement is enabled + * + * November 2012: Moved the runtime check for whether to actually emit the + * debug message outside of the print function itself. This improves overall + * performance at a relatively small code cost. Implementation involves the + * use of variadic macros supported by C99. + * + * Note: the ACPI_DO_WHILE0 macro is used to prevent some compilers from + * complaining about these constructs. On other compilers the do...while + * adds some extra code, so this feature is optional. + */ +#ifdef ACPI_USE_DO_WHILE_0 +#define ACPI_DO_WHILE0(a) do a while(0) +#else +#define ACPI_DO_WHILE0(a) a +#endif + +/* DEBUG_PRINT functions */ + +#ifndef COMPILER_VA_MACRO + +#define ACPI_DEBUG_PRINT(plist) AcpiDebugPrint plist +#define ACPI_DEBUG_PRINT_RAW(plist) AcpiDebugPrintRaw plist + +#else + +/* Helper macros for DEBUG_PRINT */ + +#define ACPI_DO_DEBUG_PRINT(Function, Level, Line, Filename, Modulename, Component, ...) \ + ACPI_DO_WHILE0 ({ \ + if (ACPI_IS_DEBUG_ENABLED (Level, Component)) \ + { \ + Function (Level, Line, Filename, Modulename, Component, __VA_ARGS__); \ + } \ + }) + +#define ACPI_ACTUAL_DEBUG(Level, Line, Filename, Modulename, Component, ...) \ + ACPI_DO_DEBUG_PRINT (AcpiDebugPrint, Level, Line, \ + Filename, Modulename, Component, __VA_ARGS__) + +#define ACPI_ACTUAL_DEBUG_RAW(Level, Line, Filename, Modulename, Component, ...) \ + ACPI_DO_DEBUG_PRINT (AcpiDebugPrintRaw, Level, Line, \ + Filename, Modulename, Component, __VA_ARGS__) + +#define ACPI_DEBUG_PRINT(plist) ACPI_ACTUAL_DEBUG plist +#define ACPI_DEBUG_PRINT_RAW(plist) ACPI_ACTUAL_DEBUG_RAW plist + +#endif + + +/* + * Function entry tracing + * + * The name of the function is emitted as a local variable that is + * intended to be used by both the entry trace and the exit trace. + */ + +/* Helper macro */ + +#define ACPI_TRACE_ENTRY(Name, Function, Type, Param) \ + ACPI_FUNCTION_NAME (Name) \ + Function (ACPI_DEBUG_PARAMETERS, (Type) (Param)) + +/* The actual entry trace macros */ + +#define ACPI_FUNCTION_TRACE(Name) \ + ACPI_FUNCTION_NAME(Name) \ + AcpiUtTrace (ACPI_DEBUG_PARAMETERS) + +#define ACPI_FUNCTION_TRACE_PTR(Name, Pointer) \ + ACPI_TRACE_ENTRY (Name, AcpiUtTracePtr, void *, Pointer) + +#define ACPI_FUNCTION_TRACE_U32(Name, Value) \ + ACPI_TRACE_ENTRY (Name, AcpiUtTraceU32, UINT32, Value) + +#define ACPI_FUNCTION_TRACE_STR(Name, String) \ + ACPI_TRACE_ENTRY (Name, AcpiUtTraceStr, const char *, String) + +#define ACPI_FUNCTION_ENTRY() \ + AcpiUtTrackStackPtr() + + +/* + * Function exit tracing + * + * These macros include a return statement. This is usually considered + * bad form, but having a separate exit macro before the actual return + * is very ugly and difficult to maintain. + * + * One of the FUNCTION_TRACE macros above must be used in conjunction + * with these macros so that "_AcpiFunctionName" is defined. + * + * There are two versions of most of the return macros. The default version is + * safer, since it avoids side-effects by guaranteeing that the argument will + * not be evaluated twice. + * + * A less-safe version of the macros is provided for optional use if the + * compiler uses excessive CPU stack (for example, this may happen in the + * debug case if code optimzation is disabled.) + */ + +/* Exit trace helper macro */ + +#ifndef ACPI_SIMPLE_RETURN_MACROS + +#define ACPI_TRACE_EXIT(Function, Type, Param) \ + ACPI_DO_WHILE0 ({ \ + register Type _Param = (Type) (Param); \ + Function (ACPI_DEBUG_PARAMETERS, _Param); \ + return (_Param); \ + }) + +#else /* Use original less-safe macros */ + +#define ACPI_TRACE_EXIT(Function, Type, Param) \ + ACPI_DO_WHILE0 ({ \ + Function (ACPI_DEBUG_PARAMETERS, (Type) (Param)); \ + return (Param); \ + }) + +#endif /* ACPI_SIMPLE_RETURN_MACROS */ + +/* The actual exit macros */ + +#define return_VOID \ + ACPI_DO_WHILE0 ({ \ + AcpiUtExit (ACPI_DEBUG_PARAMETERS); \ + return; \ + }) + +#define return_ACPI_STATUS(Status) \ + ACPI_TRACE_EXIT (AcpiUtStatusExit, ACPI_STATUS, Status) + +#define return_PTR(Pointer) \ + ACPI_TRACE_EXIT (AcpiUtPtrExit, void *, Pointer) + +#define return_STR(String) \ + ACPI_TRACE_EXIT (AcpiUtStrExit, const char *, String) + +#define return_VALUE(Value) \ + ACPI_TRACE_EXIT (AcpiUtValueExit, UINT64, Value) + +#define return_UINT32(Value) \ + ACPI_TRACE_EXIT (AcpiUtValueExit, UINT32, Value) + +#define return_UINT8(Value) \ + ACPI_TRACE_EXIT (AcpiUtValueExit, UINT8, Value) + +/* Conditional execution */ + +#define ACPI_DEBUG_EXEC(a) a +#define ACPI_DEBUG_ONLY_MEMBERS(a) a; +#define _VERBOSE_STRUCTURES + + +/* Various object display routines for debug */ + +#define ACPI_DUMP_STACK_ENTRY(a) AcpiExDumpOperand((a), 0) +#define ACPI_DUMP_OPERANDS(a, b ,c) AcpiExDumpOperands(a, b, c) +#define ACPI_DUMP_ENTRY(a, b) AcpiNsDumpEntry (a, b) +#define ACPI_DUMP_PATHNAME(a, b, c, d) AcpiNsDumpPathname(a, b, c, d) +#define ACPI_DUMP_BUFFER(a, b) AcpiUtDebugDumpBuffer((UINT8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) + +#define ACPI_TRACE_POINT(a, b, c, d) AcpiTracePoint (a, b, c, d) + +#else /* ACPI_DEBUG_OUTPUT */ +/* + * This is the non-debug case -- make everything go away, + * leaving no executable debug code! + */ +#define ACPI_DEBUG_PRINT(pl) +#define ACPI_DEBUG_PRINT_RAW(pl) +#define ACPI_DEBUG_EXEC(a) +#define ACPI_DEBUG_ONLY_MEMBERS(a) +#define ACPI_FUNCTION_NAME(a) +#define ACPI_FUNCTION_TRACE(a) +#define ACPI_FUNCTION_TRACE_PTR(a, b) +#define ACPI_FUNCTION_TRACE_U32(a, b) +#define ACPI_FUNCTION_TRACE_STR(a, b) +#define ACPI_FUNCTION_ENTRY() +#define ACPI_DUMP_STACK_ENTRY(a) +#define ACPI_DUMP_OPERANDS(a, b, c) +#define ACPI_DUMP_ENTRY(a, b) +#define ACPI_DUMP_PATHNAME(a, b, c, d) +#define ACPI_DUMP_BUFFER(a, b) +#define ACPI_IS_DEBUG_ENABLED(Level, Component) 0 +#define ACPI_TRACE_POINT(a, b, c, d) + +/* Return macros must have a return statement at the minimum */ + +#define return_VOID return +#define return_ACPI_STATUS(s) return(s) +#define return_PTR(s) return(s) +#define return_STR(s) return(s) +#define return_VALUE(s) return(s) +#define return_UINT8(s) return(s) +#define return_UINT32(s) return(s) + +#endif /* ACPI_DEBUG_OUTPUT */ + + +#endif /* __ACOUTPUT_H__ */ diff --git a/ports/acpica/include/acparser.h b/ports/acpica/include/acparser.h new file mode 100644 index 0000000..8acea23 --- /dev/null +++ b/ports/acpica/include/acparser.h @@ -0,0 +1,476 @@ +/****************************************************************************** + * + * Module Name: acparser.h - AML Parser subcomponent prototypes and defines + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACPARSER_H__ +#define __ACPARSER_H__ + + +#define OP_HAS_RETURN_VALUE 1 + +/* Variable number of arguments. This field must be 32 bits */ + +#define ACPI_VAR_ARGS ACPI_UINT32_MAX + + +#define ACPI_PARSE_DELETE_TREE 0x0001 +#define ACPI_PARSE_NO_TREE_DELETE 0x0000 +#define ACPI_PARSE_TREE_MASK 0x0001 + +#define ACPI_PARSE_LOAD_PASS1 0x0010 +#define ACPI_PARSE_LOAD_PASS2 0x0020 +#define ACPI_PARSE_EXECUTE 0x0030 +#define ACPI_PARSE_MODE_MASK 0x0030 + +#define ACPI_PARSE_DEFERRED_OP 0x0100 +#define ACPI_PARSE_DISASSEMBLE 0x0200 + +#define ACPI_PARSE_MODULE_LEVEL 0x0400 + +/****************************************************************************** + * + * Parser interfaces + * + *****************************************************************************/ + +extern const UINT8 AcpiGbl_ShortOpIndex[]; +extern const UINT8 AcpiGbl_LongOpIndex[]; + + +/* + * psxface - Parser external interfaces + */ +ACPI_STATUS +AcpiPsExecuteMethod ( + ACPI_EVALUATE_INFO *Info); + +ACPI_STATUS +AcpiPsExecuteTable ( + ACPI_EVALUATE_INFO *Info); + + +/* + * psargs - Parse AML opcode arguments + */ +UINT8 * +AcpiPsGetNextPackageEnd ( + ACPI_PARSE_STATE *ParserState); + +char * +AcpiPsGetNextNamestring ( + ACPI_PARSE_STATE *ParserState); + +void +AcpiPsGetNextSimpleArg ( + ACPI_PARSE_STATE *ParserState, + UINT32 ArgType, + ACPI_PARSE_OBJECT *Arg); + +ACPI_STATUS +AcpiPsGetNextNamepath ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *Arg, + BOOLEAN PossibleMethodCall); + +/* Values for BOOLEAN above */ + +#define ACPI_NOT_METHOD_CALL FALSE +#define ACPI_POSSIBLE_METHOD_CALL TRUE + +ACPI_STATUS +AcpiPsGetNextArg ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_STATE *ParserState, + UINT32 ArgType, + ACPI_PARSE_OBJECT **ReturnArg); + + +/* + * psfind + */ +ACPI_PARSE_OBJECT * +AcpiPsFindName ( + ACPI_PARSE_OBJECT *Scope, + UINT32 Name, + UINT32 Opcode); + +ACPI_PARSE_OBJECT* +AcpiPsGetParent ( + ACPI_PARSE_OBJECT *Op); + + +/* + * psobject - support for parse object processing + */ +ACPI_STATUS +AcpiPsBuildNamedOp ( + ACPI_WALK_STATE *WalkState, + UINT8 *AmlOpStart, + ACPI_PARSE_OBJECT *UnnamedOp, + ACPI_PARSE_OBJECT **Op); + +ACPI_STATUS +AcpiPsCreateOp ( + ACPI_WALK_STATE *WalkState, + UINT8 *AmlOpStart, + ACPI_PARSE_OBJECT **NewOp); + +ACPI_STATUS +AcpiPsCompleteOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **Op, + ACPI_STATUS Status); + +ACPI_STATUS +AcpiPsCompleteFinalOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_STATUS Status); + + +/* + * psopinfo - AML Opcode information + */ +const ACPI_OPCODE_INFO * +AcpiPsGetOpcodeInfo ( + UINT16 Opcode); + +const char * +AcpiPsGetOpcodeName ( + UINT16 Opcode); + +UINT8 +AcpiPsGetArgumentCount ( + UINT32 OpType); + + +/* + * psparse - top level parsing routines + */ +ACPI_STATUS +AcpiPsParseAml ( + ACPI_WALK_STATE *WalkState); + +UINT32 +AcpiPsGetOpcodeSize ( + UINT32 Opcode); + +UINT16 +AcpiPsPeekOpcode ( + ACPI_PARSE_STATE *state); + +ACPI_STATUS +AcpiPsCompleteThisOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiPsNextParseState ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_STATUS CallbackStatus); + + +/* + * psloop - main parse loop + */ +ACPI_STATUS +AcpiPsParseLoop ( + ACPI_WALK_STATE *WalkState); + + +/* + * psscope - Scope stack management routines + */ +ACPI_STATUS +AcpiPsInitScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *Root); + +ACPI_PARSE_OBJECT * +AcpiPsGetParentScope ( + ACPI_PARSE_STATE *state); + +BOOLEAN +AcpiPsHasCompletedScope ( + ACPI_PARSE_STATE *ParserState); + +void +AcpiPsPopScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT **Op, + UINT32 *ArgList, + UINT32 *ArgCount); + +ACPI_STATUS +AcpiPsPushScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *Op, + UINT32 RemainingArgs, + UINT32 ArgCount); + +void +AcpiPsCleanupScope ( + ACPI_PARSE_STATE *state); + + +/* + * pstree - parse tree manipulation routines + */ +void +AcpiPsAppendArg( + ACPI_PARSE_OBJECT *op, + ACPI_PARSE_OBJECT *arg); + +ACPI_PARSE_OBJECT* +AcpiPsFind ( + ACPI_PARSE_OBJECT *Scope, + char *Path, + UINT16 Opcode, + UINT32 Create); + +ACPI_PARSE_OBJECT * +AcpiPsGetArg( + ACPI_PARSE_OBJECT *op, + UINT32 argn); + +ACPI_PARSE_OBJECT * +AcpiPsGetDepthNext ( + ACPI_PARSE_OBJECT *Origin, + ACPI_PARSE_OBJECT *Op); + + +/* + * pswalk - parse tree walk routines + */ +ACPI_STATUS +AcpiPsWalkParsedAml ( + ACPI_PARSE_OBJECT *StartOp, + ACPI_PARSE_OBJECT *EndOp, + ACPI_OPERAND_OBJECT *MthDesc, + ACPI_NAMESPACE_NODE *StartNode, + ACPI_OPERAND_OBJECT **Params, + ACPI_OPERAND_OBJECT **CallerReturnDesc, + ACPI_OWNER_ID OwnerId, + ACPI_PARSE_DOWNWARDS DescendingCallback, + ACPI_PARSE_UPWARDS AscendingCallback); + +ACPI_STATUS +AcpiPsGetNextWalkOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_UPWARDS AscendingCallback); + +ACPI_STATUS +AcpiPsDeleteCompletedOp ( + ACPI_WALK_STATE *WalkState); + +void +AcpiPsDeleteParseTree ( + ACPI_PARSE_OBJECT *root); + + +/* + * psutils - parser utilities + */ +ACPI_PARSE_OBJECT * +AcpiPsCreateScopeOp ( + UINT8 *Aml); + +void +AcpiPsInitOp ( + ACPI_PARSE_OBJECT *op, + UINT16 opcode); + +ACPI_PARSE_OBJECT * +AcpiPsAllocOp ( + UINT16 Opcode, + UINT8 *Aml); + +void +AcpiPsFreeOp ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AcpiPsIsLeadingChar ( + UINT32 c); + +UINT32 +AcpiPsGetName( + ACPI_PARSE_OBJECT *op); + +void +AcpiPsSetName( + ACPI_PARSE_OBJECT *op, + UINT32 name); + + +/* + * psdump - display parser tree + */ +UINT32 +AcpiPsSprintPath ( + char *BufferStart, + UINT32 BufferSize, + ACPI_PARSE_OBJECT *Op); + +UINT32 +AcpiPsSprintOp ( + char *BufferStart, + UINT32 BufferSize, + ACPI_PARSE_OBJECT *Op); + +void +AcpiPsShow ( + ACPI_PARSE_OBJECT *op); + + +#endif /* __ACPARSER_H__ */ diff --git a/ports/acpica/include/acpi.h b/ports/acpica/include/acpi.h new file mode 100644 index 0000000..69dbedf --- /dev/null +++ b/ports/acpica/include/acpi.h @@ -0,0 +1,175 @@ +/****************************************************************************** + * + * Name: acpi.h - Master public include file used to interface to ACPICA + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACPI_H__ +#define __ACPI_H__ + +/* + * Public include files for use by code that will interface to ACPICA. + * + * Information includes the ACPICA data types, names, exceptions, and + * external interface prototypes. Also included are the definitions for + * all ACPI tables (FADT, MADT, etc.) + * + * Note: The order of these include files is important. + */ +#include "platform/acenv.h" /* Environment-specific items */ +#include "actypes.h" /* ACPICA data types and structures */ +#include "platform/acenvex.h" /* Extra environment-specific items */ +#include "acnames.h" /* Common ACPI names and strings */ +#include "acexcep.h" /* ACPICA exceptions */ +#include "actbl.h" /* ACPI table definitions */ +#include "acoutput.h" /* Error output and Debug macros */ +#include "acrestyp.h" /* Resource Descriptor structs */ +#include "acpiosxf.h" /* OSL interfaces (ACPICA-to-OS) */ +#include "acpixf.h" /* ACPI core subsystem external interfaces */ + +#endif /* __ACPI_H__ */ diff --git a/ports/acpica/include/acpiosxf.h b/ports/acpica/include/acpiosxf.h new file mode 100644 index 0000000..c5bbddf --- /dev/null +++ b/ports/acpica/include/acpiosxf.h @@ -0,0 +1,704 @@ +/****************************************************************************** + * + * Name: acpiosxf.h - All interfaces to the OS Services Layer (OSL). These + * interfaces must be implemented by OSL to interface the + * ACPI components to the host operating system. + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACPIOSXF_H__ +#define __ACPIOSXF_H__ + +#include "platform/acenv.h" +#include "actypes.h" + + +/* Types for AcpiOsExecute */ + +typedef enum +{ + OSL_GLOBAL_LOCK_HANDLER, + OSL_NOTIFY_HANDLER, + OSL_GPE_HANDLER, + OSL_DEBUGGER_MAIN_THREAD, + OSL_DEBUGGER_EXEC_THREAD, + OSL_EC_POLL_HANDLER, + OSL_EC_BURST_HANDLER + +} ACPI_EXECUTE_TYPE; + +#define ACPI_NO_UNIT_LIMIT ((UINT32) -1) +#define ACPI_MUTEX_SEM 1 + + +/* Functions for AcpiOsSignal */ + +#define ACPI_SIGNAL_FATAL 0 +#define ACPI_SIGNAL_BREAKPOINT 1 + +typedef struct acpi_signal_fatal_info +{ + UINT32 Type; + UINT32 Code; + UINT32 Argument; + +} ACPI_SIGNAL_FATAL_INFO; + + +/* + * OSL Initialization and shutdown primitives + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsInitialize +ACPI_STATUS +AcpiOsInitialize ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsTerminate +ACPI_STATUS +AcpiOsTerminate ( + void); +#endif + + +/* + * ACPI Table interfaces + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetRootPointer +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsPredefinedOverride +ACPI_STATUS +AcpiOsPredefinedOverride ( + const ACPI_PREDEFINED_NAMES *InitVal, + ACPI_STRING *NewVal); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsTableOverride +ACPI_STATUS +AcpiOsTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsPhysicalTableOverride +ACPI_STATUS +AcpiOsPhysicalTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_PHYSICAL_ADDRESS *NewAddress, + UINT32 *NewTableLength); +#endif + + +/* + * Spinlock primitives + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateLock +ACPI_STATUS +AcpiOsCreateLock ( + ACPI_SPINLOCK *OutHandle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsDeleteLock +void +AcpiOsDeleteLock ( + ACPI_SPINLOCK Handle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAcquireLock +ACPI_CPU_FLAGS +AcpiOsAcquireLock ( + ACPI_SPINLOCK Handle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReleaseLock +void +AcpiOsReleaseLock ( + ACPI_SPINLOCK Handle, + ACPI_CPU_FLAGS Flags); +#endif + + +/* + * Semaphore primitives + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateSemaphore +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_SEMAPHORE *OutHandle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsDeleteSemaphore +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_SEMAPHORE Handle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWaitSemaphore +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_SEMAPHORE Handle, + UINT32 Units, + UINT16 Timeout); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsSignalSemaphore +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_SEMAPHORE Handle, + UINT32 Units); +#endif + + +/* + * Mutex primitives. May be configured to use semaphores instead via + * ACPI_MUTEX_TYPE (see platform/acenv.h) + */ +#if (ACPI_MUTEX_TYPE != ACPI_BINARY_SEMAPHORE) + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateMutex +ACPI_STATUS +AcpiOsCreateMutex ( + ACPI_MUTEX *OutHandle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsDeleteMutex +void +AcpiOsDeleteMutex ( + ACPI_MUTEX Handle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAcquireMutex +ACPI_STATUS +AcpiOsAcquireMutex ( + ACPI_MUTEX Handle, + UINT16 Timeout); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReleaseMutex +void +AcpiOsReleaseMutex ( + ACPI_MUTEX Handle); +#endif + +#endif + + +/* + * Memory allocation and mapping + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAllocate +void * +AcpiOsAllocate ( + ACPI_SIZE Size); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAllocateZeroed +void * +AcpiOsAllocateZeroed ( + ACPI_SIZE Size); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsFree +void +AcpiOsFree ( + void * Memory); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsMapMemory +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS Where, + ACPI_SIZE Length); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsUnmapMemory +void +AcpiOsUnmapMemory ( + void *LogicalAddress, + ACPI_SIZE Size); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetPhysicalAddress +ACPI_STATUS +AcpiOsGetPhysicalAddress ( + void *LogicalAddress, + ACPI_PHYSICAL_ADDRESS *PhysicalAddress); +#endif + + +/* + * Memory/Object Cache + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateCache +ACPI_STATUS +AcpiOsCreateCache ( + char *CacheName, + UINT16 ObjectSize, + UINT16 MaxDepth, + ACPI_CACHE_T **ReturnCache); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsDeleteCache +ACPI_STATUS +AcpiOsDeleteCache ( + ACPI_CACHE_T *Cache); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsPurgeCache +ACPI_STATUS +AcpiOsPurgeCache ( + ACPI_CACHE_T *Cache); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAcquireObject +void * +AcpiOsAcquireObject ( + ACPI_CACHE_T *Cache); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReleaseObject +ACPI_STATUS +AcpiOsReleaseObject ( + ACPI_CACHE_T *Cache, + void *Object); +#endif + + +/* + * Interrupt handlers + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsInstallInterruptHandler +ACPI_STATUS +AcpiOsInstallInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine, + void *Context); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsRemoveInterruptHandler +ACPI_STATUS +AcpiOsRemoveInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine); +#endif + + +/* + * Threads and Scheduling + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetThreadId +ACPI_THREAD_ID +AcpiOsGetThreadId ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsExecute +ACPI_STATUS +AcpiOsExecute ( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWaitEventsComplete +void +AcpiOsWaitEventsComplete ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsSleep +void +AcpiOsSleep ( + UINT64 Milliseconds); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsStall +void +AcpiOsStall ( + UINT32 Microseconds); +#endif + + +/* + * Platform and hardware-independent I/O interfaces + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadPort +ACPI_STATUS +AcpiOsReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWritePort +ACPI_STATUS +AcpiOsWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width); +#endif + + +/* + * Platform and hardware-independent physical memory interfaces + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadMemory +ACPI_STATUS +AcpiOsReadMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 *Value, + UINT32 Width); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWriteMemory +ACPI_STATUS +AcpiOsWriteMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 Value, + UINT32 Width); +#endif + + +/* + * Platform and hardware-independent PCI configuration space access + * Note: Can't use "Register" as a parameter, changed to "Reg" -- + * certain compilers complain. + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadPciConfiguration +ACPI_STATUS +AcpiOsReadPciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 Reg, + UINT64 *Value, + UINT32 Width); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWritePciConfiguration +ACPI_STATUS +AcpiOsWritePciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 Reg, + UINT64 Value, + UINT32 Width); +#endif + + +/* + * Miscellaneous + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadable +BOOLEAN +AcpiOsReadable ( + void *Pointer, + ACPI_SIZE Length); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWritable +BOOLEAN +AcpiOsWritable ( + void *Pointer, + ACPI_SIZE Length); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTimer +UINT64 +AcpiOsGetTimer ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsSignal +ACPI_STATUS +AcpiOsSignal ( + UINT32 Function, + void *Info); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsEnterSleep +ACPI_STATUS +AcpiOsEnterSleep ( + UINT8 SleepState, + UINT32 RegaValue, + UINT32 RegbValue); +#endif + + +/* + * Debug print routines + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsPrintf +void ACPI_INTERNAL_VAR_XFACE +AcpiOsPrintf ( + const char *Format, + ...); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsVprintf +void +AcpiOsVprintf ( + const char *Format, + va_list Args); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsRedirectOutput +void +AcpiOsRedirectOutput ( + void *Destination); +#endif + + +/* + * Debug IO + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetLine +ACPI_STATUS +AcpiOsGetLine ( + char *Buffer, + UINT32 BufferLength, + UINT32 *BytesRead); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsInitializeDebugger +ACPI_STATUS +AcpiOsInitializeDebugger ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsTerminateDebugger +void +AcpiOsTerminateDebugger ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWaitCommandReady +ACPI_STATUS +AcpiOsWaitCommandReady ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsNotifyCommandComplete +ACPI_STATUS +AcpiOsNotifyCommandComplete ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsTracePoint +void +AcpiOsTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname); +#endif + + +/* + * Obtain ACPI table(s) + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByName +ACPI_STATUS +AcpiOsGetTableByName ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByIndex +ACPI_STATUS +AcpiOsGetTableByIndex ( + UINT32 Index, + ACPI_TABLE_HEADER **Table, + UINT32 *Instance, + ACPI_PHYSICAL_ADDRESS *Address); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByAddress +ACPI_STATUS +AcpiOsGetTableByAddress ( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER **Table); +#endif + + +/* + * Directory manipulation + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsOpenDirectory +void * +AcpiOsOpenDirectory ( + char *Pathname, + char *WildcardSpec, + char RequestedFileType); +#endif + +/* RequesteFileType values */ + +#define REQUEST_FILE_ONLY 0 +#define REQUEST_DIR_ONLY 1 + + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetNextFilename +char * +AcpiOsGetNextFilename ( + void *DirHandle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCloseDirectory +void +AcpiOsCloseDirectory ( + void *DirHandle); +#endif + + +#endif /* __ACPIOSXF_H__ */ diff --git a/ports/acpica/include/acpixf.h b/ports/acpica/include/acpixf.h new file mode 100644 index 0000000..6e10c85 --- /dev/null +++ b/ports/acpica/include/acpixf.h @@ -0,0 +1,1408 @@ +/****************************************************************************** + * + * Name: acpixf.h - External interfaces to the ACPI subsystem + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACXFACE_H__ +#define __ACXFACE_H__ + +/* Current ACPICA subsystem version in YYYYMMDD format */ + +#define ACPI_CA_VERSION 0x20180508 + +#include "acconfig.h" +#include "actypes.h" +#include "actbl.h" +#include "acbuffer.h" + + +/***************************************************************************** + * + * Macros used for ACPICA globals and configuration + * + ****************************************************************************/ + +/* + * Ensure that global variables are defined and initialized only once. + * + * The use of these macros allows for a single list of globals (here) + * in order to simplify maintenance of the code. + */ +#ifdef DEFINE_ACPI_GLOBALS +#define ACPI_GLOBAL(type,name) \ + extern type name; \ + type name + +#define ACPI_INIT_GLOBAL(type,name,value) \ + type name=value + +#else +#ifndef ACPI_GLOBAL +#define ACPI_GLOBAL(type,name) \ + extern type name +#endif + +#ifndef ACPI_INIT_GLOBAL +#define ACPI_INIT_GLOBAL(type,name,value) \ + extern type name +#endif +#endif + +/* + * These macros configure the various ACPICA interfaces. They are + * useful for generating stub inline functions for features that are + * configured out of the current kernel or ACPICA application. + */ +#ifndef ACPI_EXTERNAL_RETURN_STATUS +#define ACPI_EXTERNAL_RETURN_STATUS(Prototype) \ + Prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_OK +#define ACPI_EXTERNAL_RETURN_OK(Prototype) \ + Prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_VOID +#define ACPI_EXTERNAL_RETURN_VOID(Prototype) \ + Prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_UINT32 +#define ACPI_EXTERNAL_RETURN_UINT32(Prototype) \ + Prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_PTR +#define ACPI_EXTERNAL_RETURN_PTR(Prototype) \ + Prototype; +#endif + + +/***************************************************************************** + * + * Public globals and runtime configuration options + * + ****************************************************************************/ + +/* + * Enable "slack mode" of the AML interpreter? Default is FALSE, and the + * interpreter strictly follows the ACPI specification. Setting to TRUE + * allows the interpreter to ignore certain errors and/or bad AML constructs. + * + * Currently, these features are enabled by this flag: + * + * 1) Allow "implicit return" of last value in a control method + * 2) Allow access beyond the end of an operation region + * 3) Allow access to uninitialized locals/args (auto-init to integer 0) + * 4) Allow ANY object type to be a source operand for the Store() operator + * 5) Allow unresolved references (invalid target name) in package objects + * 6) Enable warning messages for behavior that is not ACPI spec compliant + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_EnableInterpreterSlack, FALSE); + +/* + * Automatically serialize all methods that create named objects? Default + * is TRUE, meaning that all NonSerialized methods are scanned once at + * table load time to determine those that create named objects. Methods + * that create named objects are marked Serialized in order to prevent + * possible run-time problems if they are entered by more than one thread. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_AutoSerializeMethods, TRUE); + +/* + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPICA is fully compatible with other ACPI implementations. + * Changing this will revert ACPICA (and machine ASL) to pre-OSI behavior. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_CreateOsiMethod, TRUE); + +/* + * Optionally use default values for the ACPI register widths. Set this to + * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_UseDefaultRegisterWidths, TRUE); + +/* + * Whether or not to validate (map) an entire table to verify + * checksum/duplication in early stage before install. Set this to TRUE to + * allow early table validation before install it to the table manager. + * Note that enabling this option causes errors to happen in some OSPMs + * during early initialization stages. Default behavior is to allow such + * validation. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_EnableTableValidation, TRUE); + +/* + * Optionally enable output from the AML Debug Object. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_EnableAmlDebugObject, FALSE); + +/* + * Optionally copy the entire DSDT to local memory (instead of simply + * mapping it.) There are some BIOSs that corrupt or replace the original + * DSDT, creating the need for this option. Default is FALSE, do not copy + * the DSDT. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_CopyDsdtLocally, FALSE); + +/* + * Optionally ignore an XSDT if present and use the RSDT instead. + * Although the ACPI specification requires that an XSDT be used instead + * of the RSDT, the XSDT has been found to be corrupt or ill-formed on + * some machines. Default behavior is to use the XSDT if present. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DoNotUseXsdt, FALSE); + +/* + * Optionally support group module level code. + * NOTE, this is essentially obsolete and will be removed soon + * (01/2018). + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_GroupModuleLevelCode, FALSE); + +/* + * Optionally support module level code by parsing an entire table as + * a method as it is loaded. Default is TRUE. + * NOTE, this is essentially obsolete and will be removed soon + * (01/2018). + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_ExecuteTablesAsMethods, TRUE); + +/* + * Optionally use 32-bit FADT addresses if and when there is a conflict + * (address mismatch) between the 32-bit and 64-bit versions of the + * address. Although ACPICA adheres to the ACPI specification which + * requires the use of the corresponding 64-bit address if it is non-zero, + * some machines have been found to have a corrupted non-zero 64-bit + * address. Default is FALSE, do not favor the 32-bit addresses. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_Use32BitFadtAddresses, FALSE); + +/* + * Optionally use 32-bit FACS table addresses. + * It is reported that some platforms fail to resume from system suspending + * if 64-bit FACS table address is selected: + * https://bugzilla.kernel.org/show_bug.cgi?id=74021 + * Default is TRUE, favor the 32-bit addresses. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_Use32BitFacsAddresses, TRUE); + +/* + * Optionally truncate I/O addresses to 16 bits. Provides compatibility + * with other ACPI implementations. NOTE: During ACPICA initialization, + * this value is set to TRUE if any Windows OSI strings have been + * requested by the BIOS. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_TruncateIoAddresses, FALSE); + +/* + * Disable runtime checking and repair of values returned by control methods. + * Use only if the repair is causing a problem on a particular machine. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DisableAutoRepair, FALSE); + +/* + * Optionally do not install any SSDTs from the RSDT/XSDT during initialization. + * This can be useful for debugging ACPI problems on some machines. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DisableSsdtTableInstall, FALSE); + +/* + * Optionally enable runtime namespace override. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_RuntimeNamespaceOverride, TRUE); + +/* + * We keep track of the latest version of Windows that has been requested by + * the BIOS. ACPI 5.0. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_OsiData, 0); + +/* + * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning + * that the ACPI hardware is no longer required. A flag in the FADT indicates + * a reduced HW machine, and that flag is duplicated here for convenience. + */ +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_ReducedHardware, FALSE); + +/* + * Maximum timeout for While() loop iterations before forced method abort. + * This mechanism is intended to prevent infinite loops during interpreter + * execution within a host kernel. + */ +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_MaxLoopIterations, ACPI_MAX_LOOP_TIMEOUT); + +/* + * Optionally ignore AE_NOT_FOUND errors from named reference package elements + * during DSDT/SSDT table loading. This reduces error "noise" in platforms + * whose firmware is carrying around a bunch of unused package objects that + * refer to non-existent named objects. However, If the AML actually tries to + * use such a package, the unresolved element(s) will be replaced with NULL + * elements. + */ +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_IgnorePackageResolutionErrors, FALSE); + +/* + * This mechanism is used to trace a specified AML method. The method is + * traced each time it is executed. + */ +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_TraceFlags, 0); +ACPI_INIT_GLOBAL (const char *, AcpiGbl_TraceMethodName, NULL); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_TraceDbgLevel, ACPI_TRACE_LEVEL_DEFAULT); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_TraceDbgLayer, ACPI_TRACE_LAYER_DEFAULT); + +/* + * Runtime configuration of debug output control masks. We want the debug + * switches statically initialized so they are already set when the debugger + * is entered. + */ +#ifdef ACPI_DEBUG_OUTPUT +ACPI_INIT_GLOBAL (UINT32, AcpiDbgLevel, ACPI_DEBUG_DEFAULT); +#else +ACPI_INIT_GLOBAL (UINT32, AcpiDbgLevel, ACPI_NORMAL_DEFAULT); +#endif +ACPI_INIT_GLOBAL (UINT32, AcpiDbgLayer, ACPI_COMPONENT_DEFAULT); + +/* Optionally enable timer output with Debug Object output */ + +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DisplayDebugTimer, FALSE); + +/* + * Debugger command handshake globals. Host OSes need to access these + * variables to implement their own command handshake mechanism. + */ +#ifdef ACPI_DEBUGGER +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_MethodExecuting, FALSE); +ACPI_GLOBAL (char, AcpiGbl_DbLineBuf[ACPI_DB_LINE_BUFFER_SIZE]); +#endif + +/* + * Other miscellaneous globals + */ +ACPI_GLOBAL (ACPI_TABLE_FADT, AcpiGbl_FADT); +ACPI_GLOBAL (UINT32, AcpiCurrentGpeCount); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_SystemAwakeAndRunning); + + +/***************************************************************************** + * + * ACPICA public interface configuration. + * + * Interfaces that are configured out of the ACPICA build are replaced + * by inlined stubs by default. + * + ****************************************************************************/ + +/* + * Hardware-reduced prototypes (default: Not hardware reduced). + * + * All ACPICA hardware-related interfaces that use these macros will be + * configured out of the ACPICA build if the ACPI_REDUCED_HARDWARE flag + * is set to TRUE. + * + * Note: This static build option for reduced hardware is intended to + * reduce ACPICA code size if desired or necessary. However, even if this + * option is not specified, the runtime behavior of ACPICA is dependent + * on the actual FADT reduced hardware flag (HW_REDUCED_ACPI). If set, + * the flag will enable similar behavior -- ACPICA will not attempt + * to access any ACPI-relate hardware (SCI, GPEs, Fixed Events, etc.) + */ +#if (!ACPI_REDUCED_HARDWARE) +#define ACPI_HW_DEPENDENT_RETURN_STATUS(Prototype) \ + ACPI_EXTERNAL_RETURN_STATUS(Prototype) + +#define ACPI_HW_DEPENDENT_RETURN_OK(Prototype) \ + ACPI_EXTERNAL_RETURN_OK(Prototype) + +#define ACPI_HW_DEPENDENT_RETURN_VOID(Prototype) \ + ACPI_EXTERNAL_RETURN_VOID(Prototype) + +#else +#define ACPI_HW_DEPENDENT_RETURN_STATUS(Prototype) \ + static ACPI_INLINE Prototype {return(AE_NOT_CONFIGURED);} + +#define ACPI_HW_DEPENDENT_RETURN_OK(Prototype) \ + static ACPI_INLINE Prototype {return(AE_OK);} + +#define ACPI_HW_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/* + * Error message prototypes (default: error messages enabled). + * + * All interfaces related to error and warning messages + * will be configured out of the ACPICA build if the + * ACPI_NO_ERROR_MESSAGE flag is defined. + */ +#ifndef ACPI_NO_ERROR_MESSAGES +#define ACPI_MSG_DEPENDENT_RETURN_VOID(Prototype) \ + Prototype; + +#else +#define ACPI_MSG_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* ACPI_NO_ERROR_MESSAGES */ + + +/* + * Debugging output prototypes (default: no debug output). + * + * All interfaces related to debug output messages + * will be configured out of the ACPICA build unless the + * ACPI_DEBUG_OUTPUT flag is defined. + */ +#ifdef ACPI_DEBUG_OUTPUT +#define ACPI_DBG_DEPENDENT_RETURN_VOID(Prototype) \ + Prototype; + +#else +#define ACPI_DBG_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* ACPI_DEBUG_OUTPUT */ + + +/* + * Application prototypes + * + * All interfaces used by application will be configured + * out of the ACPICA build unless the ACPI_APPLICATION + * flag is defined. + */ +#ifdef ACPI_APPLICATION +#define ACPI_APP_DEPENDENT_RETURN_VOID(Prototype) \ + Prototype; + +#else +#define ACPI_APP_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* ACPI_APPLICATION */ + + +/* + * Debugger prototypes + * + * All interfaces used by debugger will be configured + * out of the ACPICA build unless the ACPI_DEBUGGER + * flag is defined. + */ +#ifdef ACPI_DEBUGGER +#define ACPI_DBR_DEPENDENT_RETURN_OK(Prototype) \ + ACPI_EXTERNAL_RETURN_OK(Prototype) + +#define ACPI_DBR_DEPENDENT_RETURN_VOID(Prototype) \ + ACPI_EXTERNAL_RETURN_VOID(Prototype) + +#else +#define ACPI_DBR_DEPENDENT_RETURN_OK(Prototype) \ + static ACPI_INLINE Prototype {return(AE_OK);} + +#define ACPI_DBR_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* ACPI_DEBUGGER */ + + +/***************************************************************************** + * + * ACPICA public interface prototypes + * + ****************************************************************************/ + +/* + * Initialization + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiInitializeTables ( + ACPI_TABLE_DESC *InitialStorage, + UINT32 InitialTableCount, + BOOLEAN AllowResize)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiInitializeSubsystem ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiEnableSubsystem ( + UINT32 Flags)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiInitializeObjects ( + UINT32 Flags)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiTerminate ( + void)) + + +/* + * Miscellaneous global interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnable ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiDisable ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiSubsystemStatus ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetSystemInfo ( + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetStatistics ( + ACPI_STATISTICS *Stats)) + +ACPI_EXTERNAL_RETURN_PTR ( +const char * +AcpiFormatException ( + ACPI_STATUS Exception)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiPurgeCachedObjects ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallInterface ( + ACPI_STRING InterfaceName)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveInterface ( + ACPI_STRING InterfaceName)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiUpdateInterfaces ( + UINT8 Action)) + +ACPI_EXTERNAL_RETURN_UINT32 ( +UINT32 +AcpiCheckAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + ACPI_SIZE Length, + BOOLEAN Warn)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiDecodePldBuffer ( + UINT8 *InBuffer, + ACPI_SIZE Length, + ACPI_PLD_INFO **ReturnBuffer)) + + +/* + * ACPI table load/unload interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiInstallTable ( + ACPI_PHYSICAL_ADDRESS Address, + BOOLEAN Physical)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiLoadTable ( + ACPI_TABLE_HEADER *Table)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiUnloadParentTable ( + ACPI_HANDLE Object)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiLoadTables ( + void)) + + +/* + * ACPI table manipulation interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiReallocateRootTable ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS ACPI_INIT_FUNCTION +AcpiFindRootPointer ( + ACPI_PHYSICAL_ADDRESS *RsdpAddress)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTableHeader ( + ACPI_STRING Signature, + UINT32 Instance, + ACPI_TABLE_HEADER *OutTableHeader)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTable ( + ACPI_STRING Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **OutTable)) + +ACPI_EXTERNAL_RETURN_VOID ( +void +AcpiPutTable ( + ACPI_TABLE_HEADER *Table)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTableByIndex ( + UINT32 TableIndex, + ACPI_TABLE_HEADER **OutTable)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallTableHandler ( + ACPI_TABLE_HANDLER Handler, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveTableHandler ( + ACPI_TABLE_HANDLER Handler)) + + +/* + * Namespace and name interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiWalkNamespace ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + ACPI_WALK_CALLBACK DescendingCallback, + ACPI_WALK_CALLBACK AscendingCallback, + void *Context, + void **ReturnValue)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetDevices ( + char *HID, + ACPI_WALK_CALLBACK UserFunction, + void *Context, + void **ReturnValue)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetName ( + ACPI_HANDLE Object, + UINT32 NameType, + ACPI_BUFFER *RetPathPtr)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetHandle ( + ACPI_HANDLE Parent, + ACPI_STRING Pathname, + ACPI_HANDLE *RetHandle)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiAttachData ( + ACPI_HANDLE Object, + ACPI_OBJECT_HANDLER Handler, + void *Data)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiDetachData ( + ACPI_HANDLE Object, + ACPI_OBJECT_HANDLER Handler)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetData ( + ACPI_HANDLE Object, + ACPI_OBJECT_HANDLER Handler, + void **Data)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiDebugTrace ( + const char *Name, + UINT32 DebugLevel, + UINT32 DebugLayer, + UINT32 Flags)) + + +/* + * Object manipulation and enumeration + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEvaluateObject ( + ACPI_HANDLE Object, + ACPI_STRING Pathname, + ACPI_OBJECT_LIST *ParameterObjects, + ACPI_BUFFER *ReturnObjectBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEvaluateObjectTyped ( + ACPI_HANDLE Object, + ACPI_STRING Pathname, + ACPI_OBJECT_LIST *ExternalParams, + ACPI_BUFFER *ReturnBuffer, + ACPI_OBJECT_TYPE ReturnType)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetObjectInfo ( + ACPI_HANDLE Object, + ACPI_DEVICE_INFO **ReturnBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallMethod ( + UINT8 *Buffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetNextObject ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE Parent, + ACPI_HANDLE Child, + ACPI_HANDLE *OutHandle)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetType ( + ACPI_HANDLE Object, + ACPI_OBJECT_TYPE *OutType)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetParent ( + ACPI_HANDLE Object, + ACPI_HANDLE *OutHandle)) + + +/* + * Handler interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallInitializationHandler ( + ACPI_INIT_HANDLER Handler, + UINT32 Function)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallSciHandler ( + ACPI_SCI_HANDLER Address, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveSciHandler ( + ACPI_SCI_HANDLER Address)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallGlobalEventHandler ( + ACPI_GBL_EVENT_HANDLER Handler, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallFixedEventHandler ( + UINT32 AcpiEvent, + ACPI_EVENT_HANDLER Handler, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveFixedEventHandler ( + UINT32 AcpiEvent, + ACPI_EVENT_HANDLER Handler)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT32 Type, + ACPI_GPE_HANDLER Address, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallGpeRawHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT32 Type, + ACPI_GPE_HANDLER Address, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + ACPI_GPE_HANDLER Address)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallNotifyHandler ( + ACPI_HANDLE Device, + UINT32 HandlerType, + ACPI_NOTIFY_HANDLER Handler, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveNotifyHandler ( + ACPI_HANDLE Device, + UINT32 HandlerType, + ACPI_NOTIFY_HANDLER Handler)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallAddressSpaceHandler ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveAddressSpaceHandler ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallExceptionHandler ( + ACPI_EXCEPTION_HANDLER Handler)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallInterfaceHandler ( + ACPI_INTERFACE_HANDLER Handler)) + + +/* + * Global Lock interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiAcquireGlobalLock ( + UINT16 Timeout, + UINT32 *Handle)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiReleaseGlobalLock ( + UINT32 Handle)) + + +/* + * Interfaces to AML mutex objects + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiAcquireMutex ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname, + UINT16 Timeout)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiReleaseMutex ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname)) + + +/* + * Fixed Event interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableEvent ( + UINT32 Event, + UINT32 Flags)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiDisableEvent ( + UINT32 Event, + UINT32 Flags)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiClearEvent ( + UINT32 Event)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetEventStatus ( + UINT32 Event, + ACPI_EVENT_STATUS *EventStatus)) + + +/* + * General Purpose Event (GPE) Interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiUpdateAllGpes ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiDisableGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiClearGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiSetGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT8 Action)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiFinishGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiMaskGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + BOOLEAN IsMasked)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiMarkGpeForWake ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiSetupGpeForWake ( + ACPI_HANDLE ParentDevice, + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiSetGpeWakeMask ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT8 Action)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetGpeStatus ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + ACPI_EVENT_STATUS *EventStatus)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiDisableAllGpes ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableAllRuntimeGpes ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableAllWakeupGpes ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetGpeDevice ( + UINT32 GpeIndex, + ACPI_HANDLE *GpeDevice)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallGpeBlock ( + ACPI_HANDLE GpeDevice, + ACPI_GENERIC_ADDRESS *GpeBlockAddress, + UINT32 RegisterCount, + UINT32 InterruptNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveGpeBlock ( + ACPI_HANDLE GpeDevice)) + + +/* + * Resource interfaces + */ +typedef +ACPI_STATUS (*ACPI_WALK_RESOURCE_CALLBACK) ( + ACPI_RESOURCE *Resource, + void *Context); + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetVendorResource ( + ACPI_HANDLE Device, + char *Name, + ACPI_VENDOR_UUID *Uuid, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetCurrentResources ( + ACPI_HANDLE Device, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetPossibleResources ( + ACPI_HANDLE Device, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetEventResources ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiWalkResourceBuffer ( + ACPI_BUFFER *Buffer, + ACPI_WALK_RESOURCE_CALLBACK UserFunction, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiWalkResources ( + ACPI_HANDLE Device, + char *Name, + ACPI_WALK_RESOURCE_CALLBACK UserFunction, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiSetCurrentResources ( + ACPI_HANDLE Device, + ACPI_BUFFER *InBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetIrqRoutingTable ( + ACPI_HANDLE Device, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiResourceToAddress64 ( + ACPI_RESOURCE *Resource, + ACPI_RESOURCE_ADDRESS64 *Out)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiBufferToResource ( + UINT8 *AmlBuffer, + UINT16 AmlBufferLength, + ACPI_RESOURCE **ResourcePtr)) + + +/* + * Hardware (ACPI device) interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiReset ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRead ( + UINT64 *Value, + ACPI_GENERIC_ADDRESS *Reg)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiWrite ( + UINT64 Value, + ACPI_GENERIC_ADDRESS *Reg)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiReadBitRegister ( + UINT32 RegisterId, + UINT32 *ReturnValue)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiWriteBitRegister ( + UINT32 RegisterId, + UINT32 Value)) + + +/* + * Sleep/Wake interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetSleepTypeData ( + UINT8 SleepState, + UINT8 *Slp_TypA, + UINT8 *Slp_TypB)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEnterSleepStatePrep ( + UINT8 SleepState)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEnterSleepState ( + UINT8 SleepState)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnterSleepStateS4bios ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiLeaveSleepStatePrep ( + UINT8 SleepState)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiLeaveSleepState ( + UINT8 SleepState)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiSetFirmwareWakingVector ( + ACPI_PHYSICAL_ADDRESS PhysicalAddress, + ACPI_PHYSICAL_ADDRESS PhysicalAddress64)) + + +/* + * ACPI Timer interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTimerResolution ( + UINT32 *Resolution)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTimer ( + UINT32 *Ticks)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTimerDuration ( + UINT32 StartTicks, + UINT32 EndTicks, + UINT32 *TimeElapsed)) + + +/* + * Error/Warning output + */ +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(4) +void ACPI_INTERNAL_VAR_XFACE +AcpiException ( + const char *ModuleName, + UINT32 LineNumber, + ACPI_STATUS Status, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiWarning ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(1) +void ACPI_INTERNAL_VAR_XFACE +AcpiInfo ( + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiBiosError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiBiosWarning ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + + +/* + * Debug output + */ +ACPI_DBG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(6) +void ACPI_INTERNAL_VAR_XFACE +AcpiDebugPrint ( + UINT32 RequestedDebugLevel, + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const char *Format, + ...)) + +ACPI_DBG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(6) +void ACPI_INTERNAL_VAR_XFACE +AcpiDebugPrintRaw ( + UINT32 RequestedDebugLevel, + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const char *Format, + ...)) + +ACPI_DBG_DEPENDENT_RETURN_VOID ( +void +AcpiTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname)) + +ACPI_STATUS +AcpiInitializeDebugger ( + void); + +void +AcpiTerminateDebugger ( + void); + +void +AcpiRunDebugger ( + char *BatchBuffer); + +void +AcpiSetDebuggerThreadId ( + ACPI_THREAD_ID ThreadId); + +#endif /* __ACXFACE_H__ */ diff --git a/ports/acpica/include/acpredef.h b/ports/acpica/include/acpredef.h new file mode 100644 index 0000000..cd674d2 --- /dev/null +++ b/ports/acpica/include/acpredef.h @@ -0,0 +1,1251 @@ +/****************************************************************************** + * + * Name: acpredef - Information table for ACPI predefined methods and objects + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACPREDEF_H__ +#define __ACPREDEF_H__ + + +/****************************************************************************** + * + * Return Package types + * + * 1) PTYPE1 packages do not contain subpackages. + * + * ACPI_PTYPE1_FIXED: Fixed-length length, 1 or 2 object types: + * object type + * count + * object type + * count + * + * ACPI_PTYPE1_VAR: Variable-length length. Zero-length package is allowed: + * object type (Int/Buf/Ref) + * + * ACPI_PTYPE1_OPTION: Package has some required and some optional elements + * (Used for _PRW) + * + * + * 2) PTYPE2 packages contain a Variable-length number of subpackages. Each + * of the different types describe the contents of each of the subpackages. + * + * ACPI_PTYPE2: Each subpackage contains 1 or 2 object types. Zero-length + * parent package is allowed: + * object type + * count + * object type + * count + * (Used for _ALR,_MLS,_PSS,_TRT,_TSS) + * + * ACPI_PTYPE2_COUNT: Each subpackage has a count as first element. + * Zero-length parent package is allowed: + * object type + * (Used for _CSD,_PSD,_TSD) + * + * ACPI_PTYPE2_PKG_COUNT: Count of subpackages at start, 1 or 2 object types: + * object type + * count + * object type + * count + * (Used for _CST) + * + * ACPI_PTYPE2_FIXED: Each subpackage is of Fixed-length. Zero-length + * parent package is allowed. + * (Used for _PRT) + * + * ACPI_PTYPE2_MIN: Each subpackage has a Variable-length but minimum length. + * Zero-length parent package is allowed: + * (Used for _HPX) + * + * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length + * (Used for _ART, _FPS) + * + * ACPI_PTYPE2_FIX_VAR: Each subpackage consists of some fixed-length elements + * followed by an optional element. Zero-length parent package is allowed. + * object type + * count + * object type + * count = 0 (optional) + * (Used for _DLM) + * + * ACPI_PTYPE2_VAR_VAR: Variable number of subpackages, each of either a + * constant or variable length. The subpackages are preceded by a + * constant number of objects. + * (Used for _LPI, _RDI) + * + * ACPI_PTYPE2_UUID_PAIR: Each subpackage is preceded by a UUID Buffer. The UUID + * defines the format of the package. Zero-length parent package is + * allowed. + * (Used for _DSD) + * + *****************************************************************************/ + +enum AcpiReturnPackageTypes +{ + ACPI_PTYPE1_FIXED = 1, + ACPI_PTYPE1_VAR = 2, + ACPI_PTYPE1_OPTION = 3, + ACPI_PTYPE2 = 4, + ACPI_PTYPE2_COUNT = 5, + ACPI_PTYPE2_PKG_COUNT = 6, + ACPI_PTYPE2_FIXED = 7, + ACPI_PTYPE2_MIN = 8, + ACPI_PTYPE2_REV_FIXED = 9, + ACPI_PTYPE2_FIX_VAR = 10, + ACPI_PTYPE2_VAR_VAR = 11, + ACPI_PTYPE2_UUID_PAIR = 12, + ACPI_PTYPE_CUSTOM = 13 +}; + + +/* Support macros for users of the predefined info table */ + +#define METHOD_PREDEF_ARGS_MAX 4 +#define METHOD_ARG_BIT_WIDTH 3 +#define METHOD_ARG_MASK 0x0007 +#define ARG_COUNT_IS_MINIMUM 0x8000 +#define METHOD_MAX_ARG_TYPE ACPI_TYPE_PACKAGE + +#define METHOD_GET_ARG_COUNT(ArgList) ((ArgList) & METHOD_ARG_MASK) +#define METHOD_GET_NEXT_TYPE(ArgList) (((ArgList) >>= METHOD_ARG_BIT_WIDTH) & METHOD_ARG_MASK) + +/* Macros used to build the predefined info table */ + +#define METHOD_0ARGS 0 +#define METHOD_1ARGS(a1) (1 | (a1 << 3)) +#define METHOD_2ARGS(a1,a2) (2 | (a1 << 3) | (a2 << 6)) +#define METHOD_3ARGS(a1,a2,a3) (3 | (a1 << 3) | (a2 << 6) | (a3 << 9)) +#define METHOD_4ARGS(a1,a2,a3,a4) (4 | (a1 << 3) | (a2 << 6) | (a3 << 9) | (a4 << 12)) + +#define METHOD_RETURNS(type) (type) +#define METHOD_NO_RETURN_VALUE 0 + +#define PACKAGE_INFO(a,b,c,d,e,f) {{{(a),(b),(c),(d)}, ((((UINT16)(f)) << 8) | (e)), 0}} + + +/* Support macros for the resource descriptor info table */ + +#define WIDTH_1 0x0001 +#define WIDTH_2 0x0002 +#define WIDTH_3 0x0004 +#define WIDTH_8 0x0008 +#define WIDTH_16 0x0010 +#define WIDTH_32 0x0020 +#define WIDTH_64 0x0040 +#define VARIABLE_DATA 0x0080 +#define NUM_RESOURCE_WIDTHS 8 + +#define WIDTH_ADDRESS WIDTH_16 | WIDTH_32 | WIDTH_64 + + +#ifdef ACPI_CREATE_PREDEFINED_TABLE +/****************************************************************************** + * + * Predefined method/object information table. + * + * These are the names that can actually be evaluated via AcpiEvaluateObject. + * Not present in this table are the following: + * + * 1) Predefined/Reserved names that are not usually evaluated via + * AcpiEvaluateObject: + * _Lxx and _Exx GPE methods + * _Qxx EC methods + * _T_x compiler temporary variables + * _Wxx wake events + * + * 2) Predefined names that never actually exist within the AML code: + * Predefined resource descriptor field names + * + * 3) Predefined names that are implemented within ACPICA: + * _OSI + * + * The main entries in the table each contain the following items: + * + * Name - The ACPI reserved name + * ArgumentList - Contains (in 16 bits), the number of required + * arguments to the method (3 bits), and a 3-bit type + * field for each argument (up to 4 arguments). The + * METHOD_?ARGS macros generate the correct packed data. + * ExpectedBtypes - Allowed type(s) for the return value. + * 0 means that no return value is expected. + * + * For methods that return packages, the next entry in the table contains + * information about the expected structure of the package. This information + * is saved here (rather than in a separate table) in order to minimize the + * overall size of the stored data. + * + * Note: The additional braces are intended to promote portability. + * + * Note2: Table is used by the kernel-resident subsystem, the iASL compiler, + * and the AcpiHelp utility. + * + * TBD: _PRT - currently ignore reversed entries. Attempt to fix in nsrepair. + * Possibly fixing package elements like _BIF, etc. + * + *****************************************************************************/ + +const ACPI_PREDEFINED_INFO AcpiGbl_PredefinedMethods[] = +{ + {{"_AC0", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC1", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC2", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC3", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC4", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC5", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC6", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC7", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC8", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC9", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ADR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AEI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_AL0", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL1", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL2", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL3", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL4", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL5", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL6", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL7", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL8", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL9", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_ALC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ALI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ALP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ALR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 2 (Ints) */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2,0,0,0), + + {{"_ALT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ART", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Ref/11 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER, 11,0), + + {{"_BBN", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BCL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_BCM", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_BCT", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BDN", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BFS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_BIF", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (9 Int),(4 Str) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, ACPI_RTYPE_STRING, 4,0), + + {{"_BIX", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (16 Int),(4 Str) */ + PACKAGE_INFO (ACPI_PTYPE_CUSTOM, ACPI_RTYPE_INTEGER, 16, ACPI_RTYPE_STRING, 4,0), + + {{"_BLT", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_BMA", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BMC", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_BMD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (5 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5,0,0,0), + + {{"_BMS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BQC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BST", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0,0,0), + + {{"_BTH", METHOD_1ARGS (ACPI_TYPE_INTEGER), /* ACPI 6.0 */ + METHOD_NO_RETURN_VALUE}}, + + {{"_BTM", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BTP", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_CBA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* See PCI firmware spec 3.0 */ + + {{"_CCA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* ACPI 5.1 */ + + {{"_CDM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_CID", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Strs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0,0,0), + + {{"_CLS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3,0,0,0), + + {{"_CPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Bufs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0,0,0,0), + + {{"_CR3", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_CRS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_CRT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_CSD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(n), n-1 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_CST", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER, 3,0), + + {{"_CWS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_DCK", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_DCS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_DDC", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER)}}, + + {{"_DDN", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_STRING)}}, + + {{"_DEP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_DGS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_DIS", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_DLM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (1 Ref, 0/1 Optional Buf/Ref) */ + PACKAGE_INFO (ACPI_PTYPE2_FIX_VAR, ACPI_RTYPE_REFERENCE, 1, ACPI_RTYPE_REFERENCE | ACPI_RTYPE_BUFFER, 0,0), + + {{"_DMA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_DOD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_DOS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_DSD", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Buf, 1 Pkg */ + PACKAGE_INFO (ACPI_PTYPE2_UUID_PAIR, ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_PACKAGE, 1,0), + + {{"_DSM", METHOD_4ARGS (ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_PACKAGE), + METHOD_RETURNS (ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */ + + {{"_DSS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_DSW", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_DTI", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EC_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_EDL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs)*/ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_EJ0", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJ1", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJ2", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJ3", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJ4", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_STRING)}}, + + {{"_ERR", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_STRING, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* Internal use only, used by ACPICA test suites */ + + {{"_EVT", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_FDE", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_FDI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (16 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0,0,0), + + {{"_FDM", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_FIF", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0,0,0), + + {{"_FIT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, /* ACPI 6.0 */ + + {{"_FIX", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_FPS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (5 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_REV_FIXED,ACPI_RTYPE_INTEGER, 5, 0,0,0), + + {{"_FSL", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_FST", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3,0,0,0), + + {{"_GAI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GCP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GHL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GLK", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GPD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GPE", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* _GPE method, not _GPE scope */ + + {{"_GRT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_GSB", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GTF", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_GTM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_GTS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_GWS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_HID", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}}, + + {{"_HMA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_HOT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_HPP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0,0,0), + + /* + * For _HPX, a single package is returned, containing a variable-length number + * of subpackages. Each subpackage contains a PCI record setting. + * There are several different type of record settings, of different + * lengths, but all elements of all settings are Integers. + */ + {{"_HPX", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (var Ints) */ + PACKAGE_INFO (ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5,0,0,0), + + {{"_HRV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_IFT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* See IPMI spec */ + + {{"_INI", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_IRC", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_LCK", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_LID", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_LPD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2,0,0,0), + + {{"_LPI", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (3 Int, n Pkg (10 Int/Buf) */ + PACKAGE_INFO (ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 3, + ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER | ACPI_RTYPE_STRING, 10,0), + + {{"_LSI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3,0,0,0), + + {{"_LSR", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 1, ACPI_RTYPE_BUFFER, 1,0), + + {{"_LSW", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_MAT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_MBM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (8 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8,0,0,0), + + {{"_MLS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (1 Str/1 Buf) */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_STRING, 1, ACPI_RTYPE_BUFFER, 1,0), + + {{"_MSG", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_MSM", METHOD_4ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_MTL", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_NTT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_OFF", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_ON_", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_OS_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_STRING)}}, + + {{"_OSC", METHOD_4ARGS (ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER), + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_OST", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PAI", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PCL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PCT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Buf) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0,0,0), + + {{"_PDC", METHOD_1ARGS (ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PDL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PIC", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PIF", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int),(3 Str) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, ACPI_RTYPE_STRING, 3,0), + + {{"_PLD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Bufs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0,0,0,0), + + {{"_PMC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (11 Int),(3 Str) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 11, ACPI_RTYPE_STRING, 3,0), + + {{"_PMD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PMM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PPE", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* See dig64 spec */ + + {{"_PR0", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PR1", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PR2", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PR3", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PRE", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PRL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PRR", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Ref) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_REFERENCE, 1,0,0,0), + + {{"_PRS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + /* + * For _PRT, many BIOSs reverse the 3rd and 4th Package elements (Source + * and SourceIndex). This bug is so prevalent that there is code in the + * ACPICA Resource Manager to detect this and switch them back. For now, + * do not allow and issue a warning. To allow this and eliminate the + * warning, add the ACPI_RTYPE_REFERENCE type to the 4th element (index 3) + * in the statement below. + */ + {{"_PRT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (4): Int,Int,Int/Ref,Int */ + PACKAGE_INFO (ACPI_PTYPE2_FIXED, 4, ACPI_RTYPE_INTEGER, ACPI_RTYPE_INTEGER, + ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE, ACPI_RTYPE_INTEGER), + + {{"_PRW", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: Pkg/Int,Int,[Variable-length Refs] (Pkg is Ref/Int) */ + PACKAGE_INFO (ACPI_PTYPE1_OPTION, 2, ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE, + ACPI_RTYPE_INTEGER, ACPI_RTYPE_REFERENCE, 0), + + {{"_PS0", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_PS1", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_PS2", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_PS3", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_PSC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PSD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (5 Int) with count */ + PACKAGE_INFO (ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_PSE", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PSL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PSR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PSS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (6 Int) */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6,0,0,0), + + {{"_PSV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PSW", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PTC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Buf) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0,0,0), + + {{"_PTP", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PTS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PUR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0,0,0), + + {{"_PXM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_RDI", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int, n Pkg (m Ref)) */ + PACKAGE_INFO (ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 1, + ACPI_RTYPE_REFERENCE,0,0), + + {{"_REG", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_REV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_RMV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ROM", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_RST", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_NO_RETURN_VALUE}}, + + {{"_RTV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + /* + * For _S0_ through _S5_, the ACPI spec defines a return Package + * containing 1 Integer, but most DSDTs have it wrong - 2,3, or 4 integers. + * Allow this by making the objects "Variable-length length", but all elements + * must be Integers. + */ + {{"_S0_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S1_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S2_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S3_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S4_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S5_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S1D", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S2D", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S3D", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S4D", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S0W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S1W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S2W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S3W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S4W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SBS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SCP", METHOD_1ARGS (ACPI_TYPE_INTEGER) | ARG_COUNT_IS_MINIMUM, + METHOD_NO_RETURN_VALUE}}, /* Acpi 1.0 allowed 1 integer arg. Acpi 3.0 expanded to 3 args. Allow both. */ + + {{"_SDD", METHOD_1ARGS (ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_SEG", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SHL", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SLI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_SPD", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SRS", METHOD_1ARGS (ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_SRT", METHOD_1ARGS (ACPI_TYPE_BUFFER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SRV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* See IPMI spec */ + + {{"_SST", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_STA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_STM", METHOD_3ARGS (ACPI_TYPE_BUFFER, ACPI_TYPE_BUFFER, ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_STP", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_STR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_STV", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SUB", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_STRING)}}, + + {{"_SUN", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SWS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TC1", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TC2", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TDL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TFP", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TIP", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TIV", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TMP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TPT", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_TRT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 2 Ref/6 Int */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER, 6, 0), + + {{"_TSD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int with count */ + PACKAGE_INFO (ACPI_PTYPE2_COUNT,ACPI_RTYPE_INTEGER, 5,0,0,0), + + {{"_TSN", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_REFERENCE)}}, + + {{"_TSP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TSS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5,0,0,0), + + {{"_TST", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TTS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_TZD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_TZM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_REFERENCE)}}, + + {{"_TZP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_UID", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}}, + + {{"_UPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0,0,0), + + {{"_UPD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_UPP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_VPO", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + /* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */ + + {{"_WAK", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE)}}, + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0,0,0), /* Fixed-length (2 Int), but is optional */ + + /* _WDG/_WED are MS extensions defined by "Windows Instrumentation" */ + + {{"_WDG", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_WED", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER)}}, + + {{"_WPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* ACPI 6.1 */ + + {{"_WPP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* ACPI 6.1 */ + + PACKAGE_INFO (0,0,0,0,0,0) /* Table terminator */ +}; +#else +extern const ACPI_PREDEFINED_INFO AcpiGbl_PredefinedMethods[]; +#endif + + +#if (defined ACPI_CREATE_RESOURCE_TABLE && defined ACPI_APPLICATION) +/****************************************************************************** + * + * Predefined names for use in Resource Descriptors. These names do not + * appear in the global Predefined Name table (since these names never + * appear in actual AML byte code, only in the original ASL) + * + * Note: Used by iASL compiler and AcpiHelp utility only. + * + *****************************************************************************/ + +const ACPI_PREDEFINED_INFO AcpiGbl_ResourceNames[] = +{ + {{"_ADR", WIDTH_16 | WIDTH_64, 0}}, + {{"_ALN", WIDTH_8 | WIDTH_16 | WIDTH_32, 0}}, + {{"_ASI", WIDTH_8, 0}}, + {{"_ASZ", WIDTH_8, 0}}, + {{"_ATT", WIDTH_64, 0}}, + {{"_BAS", WIDTH_16 | WIDTH_32, 0}}, + {{"_BM_", WIDTH_1, 0}}, + {{"_DBT", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_DEC", WIDTH_1, 0}}, + {{"_DMA", WIDTH_8, 0}}, + {{"_DPL", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_DRS", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_END", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_FLC", WIDTH_2, 0}}, /* Acpi 5.0 */ + {{"_GRA", WIDTH_ADDRESS, 0}}, + {{"_HE_", WIDTH_1, 0}}, + {{"_INT", WIDTH_16 | WIDTH_32, 0}}, + {{"_IOR", WIDTH_2, 0}}, /* Acpi 5.0 */ + {{"_LEN", WIDTH_8 | WIDTH_ADDRESS, 0}}, + {{"_LIN", WIDTH_8, 0}}, /* Acpi 5.0 */ + {{"_LL_", WIDTH_1, 0}}, + {{"_MAF", WIDTH_1, 0}}, + {{"_MAX", WIDTH_ADDRESS, 0}}, + {{"_MEM", WIDTH_2, 0}}, + {{"_MIF", WIDTH_1, 0}}, + {{"_MIN", WIDTH_ADDRESS, 0}}, + {{"_MOD", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_MTP", WIDTH_2, 0}}, + {{"_PAR", WIDTH_8, 0}}, /* Acpi 5.0 */ + {{"_PHA", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_PIN", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_PPI", WIDTH_8, 0}}, /* Acpi 5.0 */ + {{"_POL", WIDTH_1 | WIDTH_2, 0}}, /* Acpi 5.0 */ + {{"_RBO", WIDTH_8, 0}}, + {{"_RBW", WIDTH_8, 0}}, + {{"_RNG", WIDTH_1, 0}}, + {{"_RT_", WIDTH_8, 0}}, /* Acpi 3.0 */ + {{"_RW_", WIDTH_1, 0}}, + {{"_RXL", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_SHR", WIDTH_2, 0}}, + {{"_SIZ", WIDTH_2, 0}}, + {{"_SLV", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_SPE", WIDTH_32, 0}}, /* Acpi 5.0 */ + {{"_STB", WIDTH_2, 0}}, /* Acpi 5.0 */ + {{"_TRA", WIDTH_ADDRESS, 0}}, + {{"_TRS", WIDTH_1, 0}}, + {{"_TSF", WIDTH_8, 0}}, /* Acpi 3.0 */ + {{"_TTP", WIDTH_1, 0}}, + {{"_TXL", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_TYP", WIDTH_2 | WIDTH_16, 0}}, + {{"_VEN", VARIABLE_DATA, 0}}, /* Acpi 5.0 */ + PACKAGE_INFO (0,0,0,0,0,0) /* Table terminator */ +}; + +const ACPI_PREDEFINED_INFO AcpiGbl_ScopeNames[] = { + {{"_GPE", 0, 0}}, + {{"_PR_", 0, 0}}, + {{"_SB_", 0, 0}}, + {{"_SI_", 0, 0}}, + {{"_TZ_", 0, 0}}, + PACKAGE_INFO (0,0,0,0,0,0) /* Table terminator */ +}; +#else +extern const ACPI_PREDEFINED_INFO AcpiGbl_ResourceNames[]; +#endif + +#endif diff --git a/ports/acpica/include/acresrc.h b/ports/acpica/include/acresrc.h new file mode 100644 index 0000000..ebcc110 --- /dev/null +++ b/ports/acpica/include/acresrc.h @@ -0,0 +1,563 @@ +/****************************************************************************** + * + * Name: acresrc.h - Resource Manager function prototypes + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACRESRC_H__ +#define __ACRESRC_H__ + +/* Need the AML resource descriptor structs */ + +#include "amlresrc.h" + + +/* + * If possible, pack the following structures to byte alignment, since we + * don't care about performance for debug output. Two cases where we cannot + * pack the structures: + * + * 1) Hardware does not support misaligned memory transfers + * 2) Compiler does not support pointers within packed structures + */ +#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) +#pragma pack(1) +#endif + +/* + * Individual entry for the resource conversion tables + */ +typedef const struct acpi_rsconvert_info +{ + UINT8 Opcode; + UINT8 ResourceOffset; + UINT8 AmlOffset; + UINT8 Value; + +} ACPI_RSCONVERT_INFO; + +/* Resource conversion opcodes */ + +typedef enum +{ + ACPI_RSC_INITGET = 0, + ACPI_RSC_INITSET, + ACPI_RSC_FLAGINIT, + ACPI_RSC_1BITFLAG, + ACPI_RSC_2BITFLAG, + ACPI_RSC_3BITFLAG, + ACPI_RSC_ADDRESS, + ACPI_RSC_BITMASK, + ACPI_RSC_BITMASK16, + ACPI_RSC_COUNT, + ACPI_RSC_COUNT16, + ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RSC_COUNT_GPIO_RES, + ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RSC_DATA8, + ACPI_RSC_EXIT_EQ, + ACPI_RSC_EXIT_LE, + ACPI_RSC_EXIT_NE, + ACPI_RSC_LENGTH, + ACPI_RSC_MOVE_GPIO_PIN, + ACPI_RSC_MOVE_GPIO_RES, + ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RSC_MOVE8, + ACPI_RSC_MOVE16, + ACPI_RSC_MOVE32, + ACPI_RSC_MOVE64, + ACPI_RSC_SET8, + ACPI_RSC_SOURCE, + ACPI_RSC_SOURCEX + +} ACPI_RSCONVERT_OPCODES; + +/* Resource Conversion sub-opcodes */ + +#define ACPI_RSC_COMPARE_AML_LENGTH 0 +#define ACPI_RSC_COMPARE_VALUE 1 + +#define ACPI_RSC_TABLE_SIZE(d) (sizeof (d) / sizeof (ACPI_RSCONVERT_INFO)) + +#define ACPI_RS_OFFSET(f) (UINT8) ACPI_OFFSET (ACPI_RESOURCE,f) +#define AML_OFFSET(f) (UINT8) ACPI_OFFSET (AML_RESOURCE,f) + + +/* + * Individual entry for the resource dump tables + */ +typedef const struct acpi_rsdump_info +{ + UINT8 Opcode; + UINT8 Offset; + const char *Name; + const char **Pointer; + +} ACPI_RSDUMP_INFO; + +/* Values for the Opcode field above */ + +typedef enum +{ + ACPI_RSD_TITLE = 0, + ACPI_RSD_1BITFLAG, + ACPI_RSD_2BITFLAG, + ACPI_RSD_3BITFLAG, + ACPI_RSD_ADDRESS, + ACPI_RSD_DWORDLIST, + ACPI_RSD_LITERAL, + ACPI_RSD_LONGLIST, + ACPI_RSD_SHORTLIST, + ACPI_RSD_SHORTLISTX, + ACPI_RSD_SOURCE, + ACPI_RSD_STRING, + ACPI_RSD_UINT8, + ACPI_RSD_UINT16, + ACPI_RSD_UINT32, + ACPI_RSD_UINT64, + ACPI_RSD_WORDLIST, + ACPI_RSD_LABEL, + ACPI_RSD_SOURCE_LABEL, + +} ACPI_RSDUMP_OPCODES; + +/* restore default alignment */ + +#pragma pack() + + +/* Resource tables indexed by internal resource type */ + +extern const UINT8 AcpiGbl_AmlResourceSizes[]; +extern const UINT8 AcpiGbl_AmlResourceSerialBusSizes[]; +extern ACPI_RSCONVERT_INFO *AcpiGbl_SetResourceDispatch[]; + +/* Resource tables indexed by raw AML resource descriptor type */ + +extern const UINT8 AcpiGbl_ResourceStructSizes[]; +extern const UINT8 AcpiGbl_ResourceStructSerialBusSizes[]; +extern ACPI_RSCONVERT_INFO *AcpiGbl_GetResourceDispatch[]; + +extern ACPI_RSCONVERT_INFO *AcpiGbl_ConvertResourceSerialBusDispatch[]; + +typedef struct acpi_vendor_walk_info +{ + ACPI_VENDOR_UUID *Uuid; + ACPI_BUFFER *Buffer; + ACPI_STATUS Status; + +} ACPI_VENDOR_WALK_INFO; + + +/* + * rscreate + */ +ACPI_STATUS +AcpiRsCreateResourceList ( + ACPI_OPERAND_OBJECT *AmlBuffer, + ACPI_BUFFER *OutputBuffer); + +ACPI_STATUS +AcpiRsCreateAmlResources ( + ACPI_BUFFER *ResourceList, + ACPI_BUFFER *OutputBuffer); + +ACPI_STATUS +AcpiRsCreatePciRoutingTable ( + ACPI_OPERAND_OBJECT *PackageObject, + ACPI_BUFFER *OutputBuffer); + + +/* + * rsutils + */ +ACPI_STATUS +AcpiRsGetPrtMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsGetCrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsGetPrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsGetMethodData ( + ACPI_HANDLE Handle, + const char *Path, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsSetSrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsGetAeiMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +/* + * rscalc + */ +ACPI_STATUS +AcpiRsGetListLength ( + UINT8 *AmlBuffer, + UINT32 AmlBufferLength, + ACPI_SIZE *SizeNeeded); + +ACPI_STATUS +AcpiRsGetAmlLength ( + ACPI_RESOURCE *ResourceList, + ACPI_SIZE ResourceListSize, + ACPI_SIZE *SizeNeeded); + +ACPI_STATUS +AcpiRsGetPciRoutingTableLength ( + ACPI_OPERAND_OBJECT *PackageObject, + ACPI_SIZE *BufferSizeNeeded); + +ACPI_STATUS +AcpiRsConvertAmlToResources ( + UINT8 *Aml, + UINT32 Length, + UINT32 Offset, + UINT8 ResourceIndex, + void **Context); + +ACPI_STATUS +AcpiRsConvertResourcesToAml ( + ACPI_RESOURCE *Resource, + ACPI_SIZE AmlSizeNeeded, + UINT8 *OutputBuffer); + + +/* + * rsaddr + */ +void +AcpiRsSetAddressCommon ( + AML_RESOURCE *Aml, + ACPI_RESOURCE *Resource); + +BOOLEAN +AcpiRsGetAddressCommon ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml); + + +/* + * rsmisc + */ +ACPI_STATUS +AcpiRsConvertAmlToResource ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml, + ACPI_RSCONVERT_INFO *Info); + +ACPI_STATUS +AcpiRsConvertResourceToAml ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml, + ACPI_RSCONVERT_INFO *Info); + + +/* + * rsutils + */ +void +AcpiRsMoveData ( + void *Destination, + void *Source, + UINT16 ItemCount, + UINT8 MoveType); + +UINT8 +AcpiRsDecodeBitmask ( + UINT16 Mask, + UINT8 *List); + +UINT16 +AcpiRsEncodeBitmask ( + UINT8 *List, + UINT8 Count); + +ACPI_RS_LENGTH +AcpiRsGetResourceSource ( + ACPI_RS_LENGTH ResourceLength, + ACPI_RS_LENGTH MinimumLength, + ACPI_RESOURCE_SOURCE *ResourceSource, + AML_RESOURCE *Aml, + char *StringPtr); + +ACPI_RSDESC_SIZE +AcpiRsSetResourceSource ( + AML_RESOURCE *Aml, + ACPI_RS_LENGTH MinimumLength, + ACPI_RESOURCE_SOURCE *ResourceSource); + +void +AcpiRsSetResourceHeader ( + UINT8 DescriptorType, + ACPI_RSDESC_SIZE TotalLength, + AML_RESOURCE *Aml); + +void +AcpiRsSetResourceLength ( + ACPI_RSDESC_SIZE TotalLength, + AML_RESOURCE *Aml); + + +/* + * rsdump - Debugger support + */ +#ifdef ACPI_DEBUGGER +void +AcpiRsDumpResourceList ( + ACPI_RESOURCE *Resource); + +void +AcpiRsDumpIrqList ( + UINT8 *RouteTable); +#endif + + +/* + * Resource conversion tables + */ +extern ACPI_RSCONVERT_INFO AcpiRsConvertDma[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertEndDpf[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertIo[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertFixedIo[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertEndTag[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertMemory24[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertGenericReg[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertMemory32[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertFixedMemory32[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertAddress32[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertAddress16[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertExtIrq[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertAddress64[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertExtAddress64[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertGpio[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertFixedDma[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertI2cSerialBus[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertSpiSerialBus[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertUartSerialBus[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertPinFunction[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertPinConfig[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertPinGroup[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertPinGroupFunction[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertPinGroupConfig[]; + +/* These resources require separate get/set tables */ + +extern ACPI_RSCONVERT_INFO AcpiRsGetIrq[]; +extern ACPI_RSCONVERT_INFO AcpiRsGetStartDpf[]; +extern ACPI_RSCONVERT_INFO AcpiRsGetVendorSmall[]; +extern ACPI_RSCONVERT_INFO AcpiRsGetVendorLarge[]; + +extern ACPI_RSCONVERT_INFO AcpiRsSetIrq[]; +extern ACPI_RSCONVERT_INFO AcpiRsSetStartDpf[]; +extern ACPI_RSCONVERT_INFO AcpiRsSetVendor[]; + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* + * rsinfo + */ +extern ACPI_RSDUMP_INFO *AcpiGbl_DumpResourceDispatch[]; +extern ACPI_RSDUMP_INFO *AcpiGbl_DumpSerialBusDispatch[]; + +/* + * rsdumpinfo + */ +extern ACPI_RSDUMP_INFO AcpiRsDumpIrq[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpPrt[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpDma[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpStartDpf[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpEndDpf[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpIo[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpIoFlags[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpFixedIo[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpVendor[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpEndTag[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpMemory24[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpMemory32[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpMemoryFlags[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpFixedMemory32[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpAddress16[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpAddress32[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpAddress64[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpExtAddress64[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpExtIrq[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpGenericReg[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpGpio[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpPinFunction[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpFixedDma[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpCommonSerialBus[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpI2cSerialBus[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpSpiSerialBus[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpUartSerialBus[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpGeneralFlags[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpPinConfig[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpPinGroup[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpPinGroupFunction[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpPinGroupConfig[]; +#endif + +#endif /* __ACRESRC_H__ */ diff --git a/ports/acpica/include/acrestyp.h b/ports/acpica/include/acrestyp.h new file mode 100644 index 0000000..2d485f7 --- /dev/null +++ b/ports/acpica/include/acrestyp.h @@ -0,0 +1,924 @@ +/****************************************************************************** + * + * Name: acrestyp.h - Defines, types, and structures for resource descriptors + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACRESTYP_H__ +#define __ACRESTYP_H__ + + +/* + * Definitions for Resource Attributes + */ +typedef UINT16 ACPI_RS_LENGTH; /* Resource Length field is fixed at 16 bits */ +typedef UINT32 ACPI_RSDESC_SIZE; /* Max Resource Descriptor size is (Length+3) = (64K-1)+3 */ + +/* + * Memory Attributes + */ +#define ACPI_READ_ONLY_MEMORY (UINT8) 0x00 +#define ACPI_READ_WRITE_MEMORY (UINT8) 0x01 + +#define ACPI_NON_CACHEABLE_MEMORY (UINT8) 0x00 +#define ACPI_CACHABLE_MEMORY (UINT8) 0x01 +#define ACPI_WRITE_COMBINING_MEMORY (UINT8) 0x02 +#define ACPI_PREFETCHABLE_MEMORY (UINT8) 0x03 + +/*! [Begin] no source code translation */ +/* + * IO Attributes + * The ISA IO ranges are: n000-n0FFh, n400-n4FFh, n800-n8FFh, nC00-nCFFh. + * The non-ISA IO ranges are: n100-n3FFh, n500-n7FFh, n900-nBFFh, nCD0-nFFFh. + */ +/*! [End] no source code translation !*/ + +#define ACPI_NON_ISA_ONLY_RANGES (UINT8) 0x01 +#define ACPI_ISA_ONLY_RANGES (UINT8) 0x02 +#define ACPI_ENTIRE_RANGE (ACPI_NON_ISA_ONLY_RANGES | ACPI_ISA_ONLY_RANGES) + +/* Type of translation - 1=Sparse, 0=Dense */ + +#define ACPI_SPARSE_TRANSLATION (UINT8) 0x01 + +/* + * IO Port Descriptor Decode + */ +#define ACPI_DECODE_10 (UINT8) 0x00 /* 10-bit IO address decode */ +#define ACPI_DECODE_16 (UINT8) 0x01 /* 16-bit IO address decode */ + +/* + * Interrupt attributes - used in multiple descriptors + */ + +/* Triggering */ + +#define ACPI_LEVEL_SENSITIVE (UINT8) 0x00 +#define ACPI_EDGE_SENSITIVE (UINT8) 0x01 + +/* Polarity */ + +#define ACPI_ACTIVE_HIGH (UINT8) 0x00 +#define ACPI_ACTIVE_LOW (UINT8) 0x01 +#define ACPI_ACTIVE_BOTH (UINT8) 0x02 + +/* Sharing */ + +#define ACPI_EXCLUSIVE (UINT8) 0x00 +#define ACPI_SHARED (UINT8) 0x01 + +/* Wake */ + +#define ACPI_NOT_WAKE_CAPABLE (UINT8) 0x00 +#define ACPI_WAKE_CAPABLE (UINT8) 0x01 + +/* + * DMA Attributes + */ +#define ACPI_COMPATIBILITY (UINT8) 0x00 +#define ACPI_TYPE_A (UINT8) 0x01 +#define ACPI_TYPE_B (UINT8) 0x02 +#define ACPI_TYPE_F (UINT8) 0x03 + +#define ACPI_NOT_BUS_MASTER (UINT8) 0x00 +#define ACPI_BUS_MASTER (UINT8) 0x01 + +#define ACPI_TRANSFER_8 (UINT8) 0x00 +#define ACPI_TRANSFER_8_16 (UINT8) 0x01 +#define ACPI_TRANSFER_16 (UINT8) 0x02 + +/* + * Start Dependent Functions Priority definitions + */ +#define ACPI_GOOD_CONFIGURATION (UINT8) 0x00 +#define ACPI_ACCEPTABLE_CONFIGURATION (UINT8) 0x01 +#define ACPI_SUB_OPTIMAL_CONFIGURATION (UINT8) 0x02 + +/* + * 16, 32 and 64-bit Address Descriptor resource types + */ +#define ACPI_MEMORY_RANGE (UINT8) 0x00 +#define ACPI_IO_RANGE (UINT8) 0x01 +#define ACPI_BUS_NUMBER_RANGE (UINT8) 0x02 + +#define ACPI_ADDRESS_NOT_FIXED (UINT8) 0x00 +#define ACPI_ADDRESS_FIXED (UINT8) 0x01 + +#define ACPI_POS_DECODE (UINT8) 0x00 +#define ACPI_SUB_DECODE (UINT8) 0x01 + +/* Producer/Consumer */ + +#define ACPI_PRODUCER (UINT8) 0x00 +#define ACPI_CONSUMER (UINT8) 0x01 + + +/* + * If possible, pack the following structures to byte alignment + */ +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#pragma pack(1) +#endif + +/* UUID data structures for use in vendor-defined resource descriptors */ + +typedef struct acpi_uuid +{ + UINT8 Data[ACPI_UUID_LENGTH]; +} ACPI_UUID; + +typedef struct acpi_vendor_uuid +{ + UINT8 Subtype; + UINT8 Data[ACPI_UUID_LENGTH]; + +} ACPI_VENDOR_UUID; + +/* + * Structures used to describe device resources + */ +typedef struct acpi_resource_irq +{ + UINT8 DescriptorLength; + UINT8 Triggering; + UINT8 Polarity; + UINT8 Sharable; + UINT8 WakeCapable; + UINT8 InterruptCount; + UINT8 Interrupts[1]; + +} ACPI_RESOURCE_IRQ; + +typedef struct acpi_resource_dma +{ + UINT8 Type; + UINT8 BusMaster; + UINT8 Transfer; + UINT8 ChannelCount; + UINT8 Channels[1]; + +} ACPI_RESOURCE_DMA; + +typedef struct acpi_resource_start_dependent +{ + UINT8 DescriptorLength; + UINT8 CompatibilityPriority; + UINT8 PerformanceRobustness; + +} ACPI_RESOURCE_START_DEPENDENT; + + +/* + * The END_DEPENDENT_FUNCTIONS_RESOURCE struct is not + * needed because it has no fields + */ + + +typedef struct acpi_resource_io +{ + UINT8 IoDecode; + UINT8 Alignment; + UINT8 AddressLength; + UINT16 Minimum; + UINT16 Maximum; + +} ACPI_RESOURCE_IO; + +typedef struct acpi_resource_fixed_io +{ + UINT16 Address; + UINT8 AddressLength; + +} ACPI_RESOURCE_FIXED_IO; + +typedef struct acpi_resource_fixed_dma +{ + UINT16 RequestLines; + UINT16 Channels; + UINT8 Width; + +} ACPI_RESOURCE_FIXED_DMA; + +/* Values for Width field above */ + +#define ACPI_DMA_WIDTH8 0 +#define ACPI_DMA_WIDTH16 1 +#define ACPI_DMA_WIDTH32 2 +#define ACPI_DMA_WIDTH64 3 +#define ACPI_DMA_WIDTH128 4 +#define ACPI_DMA_WIDTH256 5 + + +typedef struct acpi_resource_vendor +{ + UINT16 ByteLength; + UINT8 ByteData[1]; + +} ACPI_RESOURCE_VENDOR; + +/* Vendor resource with UUID info (introduced in ACPI 3.0) */ + +typedef struct acpi_resource_vendor_typed +{ + UINT16 ByteLength; + UINT8 UuidSubtype; + UINT8 Uuid[ACPI_UUID_LENGTH]; + UINT8 ByteData[1]; + +} ACPI_RESOURCE_VENDOR_TYPED; + +typedef struct acpi_resource_end_tag +{ + UINT8 Checksum; + +} ACPI_RESOURCE_END_TAG; + +typedef struct acpi_resource_memory24 +{ + UINT8 WriteProtect; + UINT16 Minimum; + UINT16 Maximum; + UINT16 Alignment; + UINT16 AddressLength; + +} ACPI_RESOURCE_MEMORY24; + +typedef struct acpi_resource_memory32 +{ + UINT8 WriteProtect; + UINT32 Minimum; + UINT32 Maximum; + UINT32 Alignment; + UINT32 AddressLength; + +} ACPI_RESOURCE_MEMORY32; + +typedef struct acpi_resource_fixed_memory32 +{ + UINT8 WriteProtect; + UINT32 Address; + UINT32 AddressLength; + +} ACPI_RESOURCE_FIXED_MEMORY32; + +typedef struct acpi_memory_attribute +{ + UINT8 WriteProtect; + UINT8 Caching; + UINT8 RangeType; + UINT8 Translation; + +} ACPI_MEMORY_ATTRIBUTE; + +typedef struct acpi_io_attribute +{ + UINT8 RangeType; + UINT8 Translation; + UINT8 TranslationType; + UINT8 Reserved1; + +} ACPI_IO_ATTRIBUTE; + +typedef union acpi_resource_attribute +{ + ACPI_MEMORY_ATTRIBUTE Mem; + ACPI_IO_ATTRIBUTE Io; + + /* Used for the *WordSpace macros */ + + UINT8 TypeSpecific; + +} ACPI_RESOURCE_ATTRIBUTE; + +typedef struct acpi_resource_label +{ + UINT16 StringLength; + char *StringPtr; + +} ACPI_RESOURCE_LABEL; + +typedef struct acpi_resource_source +{ + UINT8 Index; + UINT16 StringLength; + char *StringPtr; + +} ACPI_RESOURCE_SOURCE; + +/* Fields common to all address descriptors, 16/32/64 bit */ + +#define ACPI_RESOURCE_ADDRESS_COMMON \ + UINT8 ResourceType; \ + UINT8 ProducerConsumer; \ + UINT8 Decode; \ + UINT8 MinAddressFixed; \ + UINT8 MaxAddressFixed; \ + ACPI_RESOURCE_ATTRIBUTE Info; + +typedef struct acpi_address16_attribute +{ + UINT16 Granularity; + UINT16 Minimum; + UINT16 Maximum; + UINT16 TranslationOffset; + UINT16 AddressLength; + +} ACPI_ADDRESS16_ATTRIBUTE; + +typedef struct acpi_address32_attribute +{ + UINT32 Granularity; + UINT32 Minimum; + UINT32 Maximum; + UINT32 TranslationOffset; + UINT32 AddressLength; + +} ACPI_ADDRESS32_ATTRIBUTE; + +typedef struct acpi_address64_attribute +{ + UINT64 Granularity; + UINT64 Minimum; + UINT64 Maximum; + UINT64 TranslationOffset; + UINT64 AddressLength; + +} ACPI_ADDRESS64_ATTRIBUTE; + +typedef struct acpi_resource_address +{ + ACPI_RESOURCE_ADDRESS_COMMON + +} ACPI_RESOURCE_ADDRESS; + +typedef struct acpi_resource_address16 +{ + ACPI_RESOURCE_ADDRESS_COMMON + ACPI_ADDRESS16_ATTRIBUTE Address; + ACPI_RESOURCE_SOURCE ResourceSource; + +} ACPI_RESOURCE_ADDRESS16; + +typedef struct acpi_resource_address32 +{ + ACPI_RESOURCE_ADDRESS_COMMON + ACPI_ADDRESS32_ATTRIBUTE Address; + ACPI_RESOURCE_SOURCE ResourceSource; + +} ACPI_RESOURCE_ADDRESS32; + +typedef struct acpi_resource_address64 +{ + ACPI_RESOURCE_ADDRESS_COMMON + ACPI_ADDRESS64_ATTRIBUTE Address; + ACPI_RESOURCE_SOURCE ResourceSource; + +} ACPI_RESOURCE_ADDRESS64; + +typedef struct acpi_resource_extended_address64 +{ + ACPI_RESOURCE_ADDRESS_COMMON + UINT8 RevisionID; + ACPI_ADDRESS64_ATTRIBUTE Address; + UINT64 TypeSpecific; + +} ACPI_RESOURCE_EXTENDED_ADDRESS64; + +typedef struct acpi_resource_extended_irq +{ + UINT8 ProducerConsumer; + UINT8 Triggering; + UINT8 Polarity; + UINT8 Sharable; + UINT8 WakeCapable; + UINT8 InterruptCount; + ACPI_RESOURCE_SOURCE ResourceSource; + UINT32 Interrupts[1]; + +} ACPI_RESOURCE_EXTENDED_IRQ; + +typedef struct acpi_resource_generic_register +{ + UINT8 SpaceId; + UINT8 BitWidth; + UINT8 BitOffset; + UINT8 AccessSize; + UINT64 Address; + +} ACPI_RESOURCE_GENERIC_REGISTER; + +typedef struct acpi_resource_gpio +{ + UINT8 RevisionId; + UINT8 ConnectionType; + UINT8 ProducerConsumer; /* For values, see Producer/Consumer above */ + UINT8 PinConfig; + UINT8 Sharable; /* For values, see Interrupt Attributes above */ + UINT8 WakeCapable; /* For values, see Interrupt Attributes above */ + UINT8 IoRestriction; + UINT8 Triggering; /* For values, see Interrupt Attributes above */ + UINT8 Polarity; /* For values, see Interrupt Attributes above */ + UINT16 DriveStrength; + UINT16 DebounceTimeout; + UINT16 PinTableLength; + UINT16 VendorLength; + ACPI_RESOURCE_SOURCE ResourceSource; + UINT16 *PinTable; + UINT8 *VendorData; + +} ACPI_RESOURCE_GPIO; + +/* Values for GPIO ConnectionType field above */ + +#define ACPI_RESOURCE_GPIO_TYPE_INT 0 +#define ACPI_RESOURCE_GPIO_TYPE_IO 1 + +/* Values for PinConfig field above */ + +#define ACPI_PIN_CONFIG_DEFAULT 0 +#define ACPI_PIN_CONFIG_PULLUP 1 +#define ACPI_PIN_CONFIG_PULLDOWN 2 +#define ACPI_PIN_CONFIG_NOPULL 3 + +/* Values for IoRestriction field above */ + +#define ACPI_IO_RESTRICT_NONE 0 +#define ACPI_IO_RESTRICT_INPUT 1 +#define ACPI_IO_RESTRICT_OUTPUT 2 +#define ACPI_IO_RESTRICT_NONE_PRESERVE 3 + + +/* Common structure for I2C, SPI, and UART serial descriptors */ + +#define ACPI_RESOURCE_SERIAL_COMMON \ + UINT8 RevisionId; \ + UINT8 Type; \ + UINT8 ProducerConsumer; /* For values, see Producer/Consumer above */\ + UINT8 SlaveMode; \ + UINT8 ConnectionSharing; \ + UINT8 TypeRevisionId; \ + UINT16 TypeDataLength; \ + UINT16 VendorLength; \ + ACPI_RESOURCE_SOURCE ResourceSource; \ + UINT8 *VendorData; + +typedef struct acpi_resource_common_serialbus +{ + ACPI_RESOURCE_SERIAL_COMMON + +} ACPI_RESOURCE_COMMON_SERIALBUS; + +/* Values for the Type field above */ + +#define ACPI_RESOURCE_SERIAL_TYPE_I2C 1 +#define ACPI_RESOURCE_SERIAL_TYPE_SPI 2 +#define ACPI_RESOURCE_SERIAL_TYPE_UART 3 + +/* Values for SlaveMode field above */ + +#define ACPI_CONTROLLER_INITIATED 0 +#define ACPI_DEVICE_INITIATED 1 + + +typedef struct acpi_resource_i2c_serialbus +{ + ACPI_RESOURCE_SERIAL_COMMON + UINT8 AccessMode; + UINT16 SlaveAddress; + UINT32 ConnectionSpeed; + +} ACPI_RESOURCE_I2C_SERIALBUS; + +/* Values for AccessMode field above */ + +#define ACPI_I2C_7BIT_MODE 0 +#define ACPI_I2C_10BIT_MODE 1 + + +typedef struct acpi_resource_spi_serialbus +{ + ACPI_RESOURCE_SERIAL_COMMON + UINT8 WireMode; + UINT8 DevicePolarity; + UINT8 DataBitLength; + UINT8 ClockPhase; + UINT8 ClockPolarity; + UINT16 DeviceSelection; + UINT32 ConnectionSpeed; + +} ACPI_RESOURCE_SPI_SERIALBUS; + +/* Values for WireMode field above */ + +#define ACPI_SPI_4WIRE_MODE 0 +#define ACPI_SPI_3WIRE_MODE 1 + +/* Values for DevicePolarity field above */ + +#define ACPI_SPI_ACTIVE_LOW 0 +#define ACPI_SPI_ACTIVE_HIGH 1 + +/* Values for ClockPhase field above */ + +#define ACPI_SPI_FIRST_PHASE 0 +#define ACPI_SPI_SECOND_PHASE 1 + +/* Values for ClockPolarity field above */ + +#define ACPI_SPI_START_LOW 0 +#define ACPI_SPI_START_HIGH 1 + + +typedef struct acpi_resource_uart_serialbus +{ + ACPI_RESOURCE_SERIAL_COMMON + UINT8 Endian; + UINT8 DataBits; + UINT8 StopBits; + UINT8 FlowControl; + UINT8 Parity; + UINT8 LinesEnabled; + UINT16 RxFifoSize; + UINT16 TxFifoSize; + UINT32 DefaultBaudRate; + +} ACPI_RESOURCE_UART_SERIALBUS; + +/* Values for Endian field above */ + +#define ACPI_UART_LITTLE_ENDIAN 0 +#define ACPI_UART_BIG_ENDIAN 1 + +/* Values for DataBits field above */ + +#define ACPI_UART_5_DATA_BITS 0 +#define ACPI_UART_6_DATA_BITS 1 +#define ACPI_UART_7_DATA_BITS 2 +#define ACPI_UART_8_DATA_BITS 3 +#define ACPI_UART_9_DATA_BITS 4 + +/* Values for StopBits field above */ + +#define ACPI_UART_NO_STOP_BITS 0 +#define ACPI_UART_1_STOP_BIT 1 +#define ACPI_UART_1P5_STOP_BITS 2 +#define ACPI_UART_2_STOP_BITS 3 + +/* Values for FlowControl field above */ + +#define ACPI_UART_FLOW_CONTROL_NONE 0 +#define ACPI_UART_FLOW_CONTROL_HW 1 +#define ACPI_UART_FLOW_CONTROL_XON_XOFF 2 + +/* Values for Parity field above */ + +#define ACPI_UART_PARITY_NONE 0 +#define ACPI_UART_PARITY_EVEN 1 +#define ACPI_UART_PARITY_ODD 2 +#define ACPI_UART_PARITY_MARK 3 +#define ACPI_UART_PARITY_SPACE 4 + +/* Values for LinesEnabled bitfield above */ + +#define ACPI_UART_CARRIER_DETECT (1<<2) +#define ACPI_UART_RING_INDICATOR (1<<3) +#define ACPI_UART_DATA_SET_READY (1<<4) +#define ACPI_UART_DATA_TERMINAL_READY (1<<5) +#define ACPI_UART_CLEAR_TO_SEND (1<<6) +#define ACPI_UART_REQUEST_TO_SEND (1<<7) + +typedef struct acpi_resource_pin_function +{ + UINT8 RevisionId; + UINT8 PinConfig; + UINT8 Sharable; /* For values, see Interrupt Attributes above */ + UINT16 FunctionNumber; + UINT16 PinTableLength; + UINT16 VendorLength; + ACPI_RESOURCE_SOURCE ResourceSource; + UINT16 *PinTable; + UINT8 *VendorData; + +} ACPI_RESOURCE_PIN_FUNCTION; + +typedef struct acpi_resource_pin_config +{ + UINT8 RevisionId; + UINT8 ProducerConsumer; /* For values, see Producer/Consumer above */ + UINT8 Sharable; /* For values, see Interrupt Attributes above */ + UINT8 PinConfigType; + UINT32 PinConfigValue; + UINT16 PinTableLength; + UINT16 VendorLength; + ACPI_RESOURCE_SOURCE ResourceSource; + UINT16 *PinTable; + UINT8 *VendorData; + +} ACPI_RESOURCE_PIN_CONFIG; + +/* Values for PinConfigType field above */ + +#define ACPI_PIN_CONFIG_DEFAULT 0 +#define ACPI_PIN_CONFIG_BIAS_PULL_UP 1 +#define ACPI_PIN_CONFIG_BIAS_PULL_DOWN 2 +#define ACPI_PIN_CONFIG_BIAS_DEFAULT 3 +#define ACPI_PIN_CONFIG_BIAS_DISABLE 4 +#define ACPI_PIN_CONFIG_BIAS_HIGH_IMPEDANCE 5 +#define ACPI_PIN_CONFIG_BIAS_BUS_HOLD 6 +#define ACPI_PIN_CONFIG_DRIVE_OPEN_DRAIN 7 +#define ACPI_PIN_CONFIG_DRIVE_OPEN_SOURCE 8 +#define ACPI_PIN_CONFIG_DRIVE_PUSH_PULL 9 +#define ACPI_PIN_CONFIG_DRIVE_STRENGTH 10 +#define ACPI_PIN_CONFIG_SLEW_RATE 11 +#define ACPI_PIN_CONFIG_INPUT_DEBOUNCE 12 +#define ACPI_PIN_CONFIG_INPUT_SCHMITT_TRIGGER 13 + +typedef struct acpi_resource_pin_group +{ + UINT8 RevisionId; + UINT8 ProducerConsumer; /* For values, see Producer/Consumer above */ + UINT16 PinTableLength; + UINT16 VendorLength; + UINT16 *PinTable; + ACPI_RESOURCE_LABEL ResourceLabel; + UINT8 *VendorData; + +} ACPI_RESOURCE_PIN_GROUP; + +typedef struct acpi_resource_pin_group_function +{ + UINT8 RevisionId; + UINT8 ProducerConsumer; /* For values, see Producer/Consumer above */ + UINT8 Sharable; /* For values, see Interrupt Attributes above */ + UINT16 FunctionNumber; + UINT16 VendorLength; + ACPI_RESOURCE_SOURCE ResourceSource; + ACPI_RESOURCE_LABEL ResourceSourceLabel; + UINT8 *VendorData; + +} ACPI_RESOURCE_PIN_GROUP_FUNCTION; + +typedef struct acpi_resource_pin_group_config +{ + UINT8 RevisionId; + UINT8 ProducerConsumer; /* For values, see Producer/Consumer above */ + UINT8 Sharable; /* For values, see Interrupt Attributes above */ + UINT8 PinConfigType; /* For values, see PinConfigType above */ + UINT32 PinConfigValue; + UINT16 VendorLength; + ACPI_RESOURCE_SOURCE ResourceSource; + ACPI_RESOURCE_LABEL ResourceSourceLabel; + UINT8 *VendorData; + +} ACPI_RESOURCE_PIN_GROUP_CONFIG; + +/* ACPI_RESOURCE_TYPEs */ + +#define ACPI_RESOURCE_TYPE_IRQ 0 +#define ACPI_RESOURCE_TYPE_DMA 1 +#define ACPI_RESOURCE_TYPE_START_DEPENDENT 2 +#define ACPI_RESOURCE_TYPE_END_DEPENDENT 3 +#define ACPI_RESOURCE_TYPE_IO 4 +#define ACPI_RESOURCE_TYPE_FIXED_IO 5 +#define ACPI_RESOURCE_TYPE_VENDOR 6 +#define ACPI_RESOURCE_TYPE_END_TAG 7 +#define ACPI_RESOURCE_TYPE_MEMORY24 8 +#define ACPI_RESOURCE_TYPE_MEMORY32 9 +#define ACPI_RESOURCE_TYPE_FIXED_MEMORY32 10 +#define ACPI_RESOURCE_TYPE_ADDRESS16 11 +#define ACPI_RESOURCE_TYPE_ADDRESS32 12 +#define ACPI_RESOURCE_TYPE_ADDRESS64 13 +#define ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 14 /* ACPI 3.0 */ +#define ACPI_RESOURCE_TYPE_EXTENDED_IRQ 15 +#define ACPI_RESOURCE_TYPE_GENERIC_REGISTER 16 +#define ACPI_RESOURCE_TYPE_GPIO 17 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_FIXED_DMA 18 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_SERIAL_BUS 19 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_PIN_FUNCTION 20 /* ACPI 6.2 */ +#define ACPI_RESOURCE_TYPE_PIN_CONFIG 21 /* ACPI 6.2 */ +#define ACPI_RESOURCE_TYPE_PIN_GROUP 22 /* ACPI 6.2 */ +#define ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION 23 /* ACPI 6.2 */ +#define ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG 24 /* ACPI 6.2 */ +#define ACPI_RESOURCE_TYPE_MAX 24 + +/* Master union for resource descriptors */ + +typedef union acpi_resource_data +{ + ACPI_RESOURCE_IRQ Irq; + ACPI_RESOURCE_DMA Dma; + ACPI_RESOURCE_START_DEPENDENT StartDpf; + ACPI_RESOURCE_IO Io; + ACPI_RESOURCE_FIXED_IO FixedIo; + ACPI_RESOURCE_FIXED_DMA FixedDma; + ACPI_RESOURCE_VENDOR Vendor; + ACPI_RESOURCE_VENDOR_TYPED VendorTyped; + ACPI_RESOURCE_END_TAG EndTag; + ACPI_RESOURCE_MEMORY24 Memory24; + ACPI_RESOURCE_MEMORY32 Memory32; + ACPI_RESOURCE_FIXED_MEMORY32 FixedMemory32; + ACPI_RESOURCE_ADDRESS16 Address16; + ACPI_RESOURCE_ADDRESS32 Address32; + ACPI_RESOURCE_ADDRESS64 Address64; + ACPI_RESOURCE_EXTENDED_ADDRESS64 ExtAddress64; + ACPI_RESOURCE_EXTENDED_IRQ ExtendedIrq; + ACPI_RESOURCE_GENERIC_REGISTER GenericReg; + ACPI_RESOURCE_GPIO Gpio; + ACPI_RESOURCE_I2C_SERIALBUS I2cSerialBus; + ACPI_RESOURCE_SPI_SERIALBUS SpiSerialBus; + ACPI_RESOURCE_UART_SERIALBUS UartSerialBus; + ACPI_RESOURCE_COMMON_SERIALBUS CommonSerialBus; + ACPI_RESOURCE_PIN_FUNCTION PinFunction; + ACPI_RESOURCE_PIN_CONFIG PinConfig; + ACPI_RESOURCE_PIN_GROUP PinGroup; + ACPI_RESOURCE_PIN_GROUP_FUNCTION PinGroupFunction; + ACPI_RESOURCE_PIN_GROUP_CONFIG PinGroupConfig; + + /* Common fields */ + + ACPI_RESOURCE_ADDRESS Address; /* Common 16/32/64 address fields */ + +} ACPI_RESOURCE_DATA; + + +/* Common resource header */ + +typedef struct acpi_resource +{ + UINT32 Type; + UINT32 Length; + ACPI_RESOURCE_DATA Data; + +} ACPI_RESOURCE; + +/* restore default alignment */ + +#pragma pack() + + +#define ACPI_RS_SIZE_NO_DATA 8 /* Id + Length fields */ +#define ACPI_RS_SIZE_MIN (UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (12) +#define ACPI_RS_SIZE(Type) (UINT32) (ACPI_RS_SIZE_NO_DATA + sizeof (Type)) + +/* Macro for walking resource templates with multiple descriptors */ + +#define ACPI_NEXT_RESOURCE(Res) \ + ACPI_ADD_PTR (ACPI_RESOURCE, (Res), (Res)->Length) + + +typedef struct acpi_pci_routing_table +{ + UINT32 Length; + UINT32 Pin; + UINT64 Address; /* here for 64-bit alignment */ + UINT32 SourceIndex; + char Source[4]; /* pad to 64 bits so sizeof() works in all cases */ + +} ACPI_PCI_ROUTING_TABLE; + +#endif /* __ACRESTYP_H__ */ diff --git a/ports/acpica/include/acstruct.h b/ports/acpica/include/acstruct.h new file mode 100644 index 0000000..9c55d35 --- /dev/null +++ b/ports/acpica/include/acstruct.h @@ -0,0 +1,377 @@ +/****************************************************************************** + * + * Name: acstruct.h - Internal structs + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACSTRUCT_H__ +#define __ACSTRUCT_H__ + +/* acpisrc:StructDefs -- for acpisrc conversion */ + +/***************************************************************************** + * + * Tree walking typedefs and structs + * + ****************************************************************************/ + + +/* + * Walk state - current state of a parse tree walk. Used for both a leisurely + * stroll through the tree (for whatever reason), and for control method + * execution. + */ +#define ACPI_NEXT_OP_DOWNWARD 1 +#define ACPI_NEXT_OP_UPWARD 2 + +/* + * Groups of definitions for WalkType used for different implementations of + * walkers (never simultaneously) - flags for interpreter: + */ +#define ACPI_WALK_NON_METHOD 0 +#define ACPI_WALK_METHOD 0x01 +#define ACPI_WALK_METHOD_RESTART 0x02 + + +typedef struct acpi_walk_state +{ + struct acpi_walk_state *Next; /* Next WalkState in list */ + UINT8 DescriptorType; /* To differentiate various internal objs */ + UINT8 WalkType; + UINT16 Opcode; /* Current AML opcode */ + UINT8 NextOpInfo; /* Info about NextOp */ + UINT8 NumOperands; /* Stack pointer for Operands[] array */ + UINT8 OperandIndex; /* Index into operand stack, to be used by AcpiDsObjStackPush */ + ACPI_OWNER_ID OwnerId; /* Owner of objects created during the walk */ + BOOLEAN LastPredicate; /* Result of last predicate */ + UINT8 CurrentResult; + UINT8 ReturnUsed; + UINT8 ScopeDepth; + UINT8 PassNumber; /* Parse pass during table load */ + BOOLEAN NamespaceOverride; /* Override existing objects */ + UINT8 ResultSize; /* Total elements for the result stack */ + UINT8 ResultCount; /* Current number of occupied elements of result stack */ + UINT8 *Aml; + UINT32 ArgTypes; + UINT32 MethodBreakpoint; /* For single stepping */ + UINT32 UserBreakpoint; /* User AML breakpoint */ + UINT32 ParseFlags; + + ACPI_PARSE_STATE ParserState; /* Current state of parser */ + UINT32 PrevArgTypes; + UINT32 ArgCount; /* push for fixed or var args */ + + struct acpi_namespace_node Arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ + struct acpi_namespace_node LocalVariables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ + union acpi_operand_object *Operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */ + union acpi_operand_object **Params; + + UINT8 *AmlLastWhile; + union acpi_operand_object **CallerReturnDesc; + ACPI_GENERIC_STATE *ControlState; /* List of control states (nested IFs) */ + struct acpi_namespace_node *DeferredNode; /* Used when executing deferred opcodes */ + union acpi_operand_object *ImplicitReturnObj; + struct acpi_namespace_node *MethodCallNode; /* Called method Node*/ + ACPI_PARSE_OBJECT *MethodCallOp; /* MethodCall Op if running a method */ + union acpi_operand_object *MethodDesc; /* Method descriptor if running a method */ + struct acpi_namespace_node *MethodNode; /* Method node if running a method. */ + ACPI_PARSE_OBJECT *Op; /* Current parser op */ + const ACPI_OPCODE_INFO *OpInfo; /* Info on current opcode */ + ACPI_PARSE_OBJECT *Origin; /* Start of walk [Obsolete] */ + union acpi_operand_object *ResultObj; + ACPI_GENERIC_STATE *Results; /* Stack of accumulated results */ + union acpi_operand_object *ReturnDesc; /* Return object, if any */ + ACPI_GENERIC_STATE *ScopeInfo; /* Stack of nested scopes */ + ACPI_PARSE_OBJECT *PrevOp; /* Last op that was processed */ + ACPI_PARSE_OBJECT *NextOp; /* next op to be processed */ + ACPI_THREAD_STATE *Thread; + ACPI_PARSE_DOWNWARDS DescendingCallback; + ACPI_PARSE_UPWARDS AscendingCallback; + +} ACPI_WALK_STATE; + + +/* Info used by AcpiNsInitializeObjects and AcpiDsInitializeObjects */ + +typedef struct acpi_init_walk_info +{ + UINT32 TableIndex; + UINT32 ObjectCount; + UINT32 MethodCount; + UINT32 SerialMethodCount; + UINT32 NonSerialMethodCount; + UINT32 SerializedMethodCount; + UINT32 DeviceCount; + UINT32 OpRegionCount; + UINT32 FieldCount; + UINT32 BufferCount; + UINT32 PackageCount; + UINT32 OpRegionInit; + UINT32 FieldInit; + UINT32 BufferInit; + UINT32 PackageInit; + ACPI_OWNER_ID OwnerId; + +} ACPI_INIT_WALK_INFO; + + +typedef struct acpi_get_devices_info +{ + ACPI_WALK_CALLBACK UserFunction; + void *Context; + char *Hid; + +} ACPI_GET_DEVICES_INFO; + + +typedef union acpi_aml_operands +{ + ACPI_OPERAND_OBJECT *Operands[7]; + + struct + { + ACPI_OBJECT_INTEGER *Type; + ACPI_OBJECT_INTEGER *Code; + ACPI_OBJECT_INTEGER *Argument; + + } Fatal; + + struct + { + ACPI_OPERAND_OBJECT *Source; + ACPI_OBJECT_INTEGER *Index; + ACPI_OPERAND_OBJECT *Target; + + } Index; + + struct + { + ACPI_OPERAND_OBJECT *Source; + ACPI_OBJECT_INTEGER *Index; + ACPI_OBJECT_INTEGER *Length; + ACPI_OPERAND_OBJECT *Target; + + } Mid; + +} ACPI_AML_OPERANDS; + + +/* + * Structure used to pass object evaluation information and parameters. + * Purpose is to reduce CPU stack use. + */ +typedef struct acpi_evaluate_info +{ + /* The first 3 elements are passed by the caller to AcpiNsEvaluate */ + + ACPI_NAMESPACE_NODE *PrefixNode; /* Input: starting node */ + const char *RelativePathname; /* Input: path relative to PrefixNode */ + ACPI_OPERAND_OBJECT **Parameters; /* Input: argument list */ + + ACPI_NAMESPACE_NODE *Node; /* Resolved node (PrefixNode:RelativePathname) */ + ACPI_OPERAND_OBJECT *ObjDesc; /* Object attached to the resolved node */ + char *FullPathname; /* Full pathname of the resolved node */ + + const ACPI_PREDEFINED_INFO *Predefined; /* Used if Node is a predefined name */ + ACPI_OPERAND_OBJECT *ReturnObject; /* Object returned from the evaluation */ + union acpi_operand_object *ParentPackage; /* Used if return object is a Package */ + + UINT32 ReturnFlags; /* Used for return value analysis */ + UINT32 ReturnBtype; /* Bitmapped type of the returned object */ + UINT16 ParamCount; /* Count of the input argument list */ + UINT8 PassNumber; /* Parser pass number */ + UINT8 ReturnObjectType; /* Object type of the returned object */ + UINT8 NodeFlags; /* Same as Node->Flags */ + UINT8 Flags; /* General flags */ + +} ACPI_EVALUATE_INFO; + +/* Values for Flags above */ + +#define ACPI_IGNORE_RETURN_VALUE 1 + +/* Defines for ReturnFlags field above */ + +#define ACPI_OBJECT_REPAIRED 1 +#define ACPI_OBJECT_WRAPPED 2 + + +/* Info used by AcpiNsInitializeDevices */ + +typedef struct acpi_device_walk_info +{ + ACPI_TABLE_DESC *TableDesc; + ACPI_EVALUATE_INFO *EvaluateInfo; + UINT32 DeviceCount; + UINT32 Num_STA; + UINT32 Num_INI; + +} ACPI_DEVICE_WALK_INFO; + + +/* TBD: [Restructure] Merge with struct above */ + +typedef struct acpi_walk_info +{ + UINT32 DebugLevel; + UINT32 Count; + ACPI_OWNER_ID OwnerId; + UINT8 DisplayType; + +} ACPI_WALK_INFO; + +/* Display Types */ + +#define ACPI_DISPLAY_SUMMARY (UINT8) 0 +#define ACPI_DISPLAY_OBJECTS (UINT8) 1 +#define ACPI_DISPLAY_MASK (UINT8) 1 + +#define ACPI_DISPLAY_SHORT (UINT8) 2 + + +#endif diff --git a/ports/acpica/include/actables.h b/ports/acpica/include/actables.h new file mode 100644 index 0000000..59a9a39 --- /dev/null +++ b/ports/acpica/include/actables.h @@ -0,0 +1,390 @@ +/****************************************************************************** + * + * Name: actables.h - ACPI table management + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACTABLES_H__ +#define __ACTABLES_H__ + + +ACPI_STATUS +AcpiAllocateRootTable ( + UINT32 InitialTableCount); + +/* + * tbxfroot - Root pointer utilities + */ +UINT32 +AcpiTbGetRsdpLength ( + ACPI_TABLE_RSDP *Rsdp); + +ACPI_STATUS +AcpiTbValidateRsdp ( + ACPI_TABLE_RSDP *Rsdp); + +UINT8 * +AcpiTbScanMemoryForRsdp ( + UINT8 *StartAddress, + UINT32 Length); + + +/* + * tbdata - table data structure management + */ +ACPI_STATUS +AcpiTbGetNextTableDescriptor ( + UINT32 *TableIndex, + ACPI_TABLE_DESC **TableDesc); + +void +AcpiTbInitTableDescriptor ( + ACPI_TABLE_DESC *TableDesc, + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags, + ACPI_TABLE_HEADER *Table); + +ACPI_STATUS +AcpiTbAcquireTempTable ( + ACPI_TABLE_DESC *TableDesc, + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags); + +void +AcpiTbReleaseTempTable ( + ACPI_TABLE_DESC *TableDesc); + +ACPI_STATUS +AcpiTbValidateTempTable ( + ACPI_TABLE_DESC *TableDesc); + +ACPI_STATUS +AcpiTbVerifyTempTable ( + ACPI_TABLE_DESC *TableDesc, + char *Signature, + UINT32 *TableIndex); + +BOOLEAN +AcpiTbIsTableLoaded ( + UINT32 TableIndex); + +void +AcpiTbSetTableLoadedFlag ( + UINT32 TableIndex, + BOOLEAN IsLoaded); + + +/* + * tbfadt - FADT parse/convert/validate + */ +void +AcpiTbParseFadt ( + void); + +void +AcpiTbCreateLocalFadt ( + ACPI_TABLE_HEADER *Table, + UINT32 Length); + + +/* + * tbfind - find ACPI table + */ +ACPI_STATUS +AcpiTbFindTable ( + char *Signature, + char *OemId, + char *OemTableId, + UINT32 *TableIndex); + + +/* + * tbinstal - Table removal and deletion + */ +ACPI_STATUS +AcpiTbResizeRootTableList ( + void); + +ACPI_STATUS +AcpiTbValidateTable ( + ACPI_TABLE_DESC *TableDesc); + +void +AcpiTbInvalidateTable ( + ACPI_TABLE_DESC *TableDesc); + +void +AcpiTbOverrideTable ( + ACPI_TABLE_DESC *OldTableDesc); + +ACPI_STATUS +AcpiTbAcquireTable ( + ACPI_TABLE_DESC *TableDesc, + ACPI_TABLE_HEADER **TablePtr, + UINT32 *TableLength, + UINT8 *TableFlags); + +void +AcpiTbReleaseTable ( + ACPI_TABLE_HEADER *Table, + UINT32 TableLength, + UINT8 TableFlags); + +ACPI_STATUS +AcpiTbInstallStandardTable ( + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags, + BOOLEAN Reload, + BOOLEAN Override, + UINT32 *TableIndex); + +void +AcpiTbUninstallTable ( + ACPI_TABLE_DESC *TableDesc); + +ACPI_STATUS +AcpiTbLoadTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *ParentNode); + +ACPI_STATUS +AcpiTbInstallAndLoadTable ( + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags, + BOOLEAN Override, + UINT32 *TableIndex); + +ACPI_STATUS +AcpiTbUnloadTable ( + UINT32 TableIndex); + +void +AcpiTbNotifyTable ( + UINT32 Event, + void *Table); + +void +AcpiTbTerminate ( + void); + +ACPI_STATUS +AcpiTbDeleteNamespaceByOwner ( + UINT32 TableIndex); + +ACPI_STATUS +AcpiTbAllocateOwnerId ( + UINT32 TableIndex); + +ACPI_STATUS +AcpiTbReleaseOwnerId ( + UINT32 TableIndex); + +ACPI_STATUS +AcpiTbGetOwnerId ( + UINT32 TableIndex, + ACPI_OWNER_ID *OwnerId); + + +/* + * tbutils - table manager utilities + */ +ACPI_STATUS +AcpiTbInitializeFacs ( + void); + +void +AcpiTbPrintTableHeader( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER *Header); + +UINT8 +AcpiTbChecksum ( + UINT8 *Buffer, + UINT32 Length); + +ACPI_STATUS +AcpiTbVerifyChecksum ( + ACPI_TABLE_HEADER *Table, + UINT32 Length); + +void +AcpiTbCheckDsdtHeader ( + void); + +ACPI_TABLE_HEADER * +AcpiTbCopyDsdt ( + UINT32 TableIndex); + +void +AcpiTbInstallTableWithOverride ( + ACPI_TABLE_DESC *NewTableDesc, + BOOLEAN Override, + UINT32 *TableIndex); + +ACPI_STATUS +AcpiTbParseRootTable ( + ACPI_PHYSICAL_ADDRESS RsdpAddress); + +ACPI_STATUS +AcpiTbGetTable ( + ACPI_TABLE_DESC *TableDesc, + ACPI_TABLE_HEADER **OutTable); + +void +AcpiTbPutTable ( + ACPI_TABLE_DESC *TableDesc); + + +/* + * tbxfload + */ +ACPI_STATUS +AcpiTbLoadNamespace ( + void); + +#endif /* __ACTABLES_H__ */ diff --git a/ports/acpica/include/actbinfo.h b/ports/acpica/include/actbinfo.h new file mode 100644 index 0000000..5a84f35 --- /dev/null +++ b/ports/acpica/include/actbinfo.h @@ -0,0 +1,411 @@ +/****************************************************************************** + * + * Module Name: actbinfo - Table disassembly info for non-AML tables + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +/* + * Macros used to generate offsets to specific table fields + */ +#define ACPI_FACS_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_FACS,f) +#define ACPI_GAS_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GENERIC_ADDRESS,f) +#define ACPI_HDR_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_HEADER,f) +#define ACPI_RSDP_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_RSDP,f) +#define ACPI_BERT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_BERT,f) +#define ACPI_BGRT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_BGRT,f) +#define ACPI_BOOT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_BOOT,f) +#define ACPI_CPEP_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_CPEP,f) +#define ACPI_DBG2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_DBG2,f) +#define ACPI_DBGP_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_DBGP,f) +#define ACPI_DMAR_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_DMAR,f) +#define ACPI_DRTM_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_DRTM,f) +#define ACPI_ECDT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_ECDT,f) +#define ACPI_EINJ_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_EINJ,f) +#define ACPI_ERST_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_ERST,f) +#define ACPI_GTDT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_GTDT,f) +#define ACPI_HEST_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_HEST,f) +#define ACPI_HPET_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_HPET,f) +#define ACPI_HMAT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_HMAT,f) +#define ACPI_IORT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_IORT,f) +#define ACPI_IVRS_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_IVRS,f) +#define ACPI_MADT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MADT,f) +#define ACPI_MCFG_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MCFG,f) +#define ACPI_MCHI_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MCHI,f) +#define ACPI_MPST_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MPST,f) +#define ACPI_MSCT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MSCT,f) +#define ACPI_NFIT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_NFIT,f) +#define ACPI_PCCT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_PCCT,f) +#define ACPI_PDTT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_PDTT,f) +#define ACPI_PMTT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_PMTT,f) +#define ACPI_RASF_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_RASF,f) +#define ACPI_S3PT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_S3PT,f) +#define ACPI_SBST_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SBST,f) +#define ACPI_SDEI_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SDEI,f) +#define ACPI_SDEV_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SDEV,f) +#define ACPI_SLIT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SLIT,f) +#define ACPI_SPCR_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SPCR,f) +#define ACPI_SPMI_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SPMI,f) +#define ACPI_SRAT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SRAT,f) +#define ACPI_STAO_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_STAO,f) +#define ACPI_TCPA_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_TCPA_HDR,f) +#define ACPI_TPM2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_TPM2,f) +#define ACPI_UEFI_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_UEFI,f) +#define ACPI_WAET_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WAET,f) +#define ACPI_WDAT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WDAT,f) +#define ACPI_WDDT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WDDT,f) +#define ACPI_WDRT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WDRT,f) +#define ACPI_WPBT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WPBT,f) +#define ACPI_WSMT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WSMT,f) +#define ACPI_XENV_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_XENV,f) + +/* Subtables */ + +#define ACPI_ASF0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_INFO,f) +#define ACPI_ASF1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_ALERT,f) +#define ACPI_ASF1a_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_ALERT_DATA,f) +#define ACPI_ASF2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_REMOTE,f) +#define ACPI_ASF2a_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_CONTROL_DATA,f) +#define ACPI_ASF3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_RMCP,f) +#define ACPI_ASF4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_ADDRESS,f) +#define ACPI_CPEP0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_CPEP_POLLING,f) +#define ACPI_CSRT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_CSRT_GROUP,f) +#define ACPI_CSRT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_CSRT_SHARED_INFO,f) +#define ACPI_CSRT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_CSRT_DESCRIPTOR,f) +#define ACPI_DBG20_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DBG2_DEVICE,f) +#define ACPI_DMARS_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_DEVICE_SCOPE,f) +#define ACPI_DMAR0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_HARDWARE_UNIT,f) +#define ACPI_DMAR1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_RESERVED_MEMORY,f) +#define ACPI_DMAR2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_ATSR,f) +#define ACPI_DMAR3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_RHSA,f) +#define ACPI_DMAR4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_ANDD,f) +#define ACPI_DRTM0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DRTM_VTABLE_LIST,f) +#define ACPI_DRTM1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DRTM_RESOURCE_LIST,f) +#define ACPI_DRTM1a_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DRTM_RESOURCE,f) +#define ACPI_DRTM2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DRTM_DPS_ID,f) +#define ACPI_EINJ0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_WHEA_HEADER,f) +#define ACPI_ERST0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_WHEA_HEADER,f) +#define ACPI_FPDTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_FPDT_HEADER,f) +#define ACPI_FPDT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_FPDT_BOOT_POINTER,f) +#define ACPI_FPDT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_FPDT_S3PT_POINTER,f) +#define ACPI_GTDT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GTDT_TIMER_BLOCK,f) +#define ACPI_GTDT0a_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GTDT_TIMER_ENTRY,f) +#define ACPI_GTDT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GTDT_WATCHDOG,f) +#define ACPI_GTDTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GTDT_HEADER,f) +#define ACPI_HEST0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_MACHINE_CHECK,f) +#define ACPI_HEST1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_CORRECTED,f) +#define ACPI_HEST2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_NMI,f) +#define ACPI_HEST6_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_AER_ROOT,f) +#define ACPI_HEST7_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_AER,f) +#define ACPI_HEST8_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_AER_BRIDGE,f) +#define ACPI_HEST9_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_GENERIC,f) +#define ACPI_HEST10_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_GENERIC_V2,f) +#define ACPI_HEST11_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_DEFERRED_CHECK,f) +#define ACPI_HESTN_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_NOTIFY,f) +#define ACPI_HESTB_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_ERROR_BANK,f) +#define ACPI_HMAT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HMAT_ADDRESS_RANGE,f) +#define ACPI_HMAT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HMAT_LOCALITY,f) +#define ACPI_HMAT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HMAT_CACHE,f) +#define ACPI_HMATH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HMAT_STRUCTURE,f) +#define ACPI_IORT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_ITS_GROUP,f) +#define ACPI_IORT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_NAMED_COMPONENT,f) +#define ACPI_IORT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_ROOT_COMPLEX,f) +#define ACPI_IORT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_SMMU,f) +#define ACPI_IORT3A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_SMMU_GSI,f) +#define ACPI_IORT4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_SMMU_V3,f) +#define ACPI_IORTA_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_MEMORY_ACCESS,f) +#define ACPI_IORTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_NODE,f) +#define ACPI_IORTM_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_ID_MAPPING,f) +#define ACPI_IVRSH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_HEADER,f) +#define ACPI_IVRS0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_HARDWARE,f) +#define ACPI_IVRS1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_MEMORY,f) +#define ACPI_IVRSD_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_DE_HEADER,f) +#define ACPI_IVRS8A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_DEVICE8A,f) +#define ACPI_IVRS8B_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_DEVICE8B,f) +#define ACPI_IVRS8C_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_DEVICE8C,f) +#define ACPI_LPITH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_LPIT_HEADER,f) +#define ACPI_LPIT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_LPIT_NATIVE,f) +#define ACPI_MADT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_APIC,f) +#define ACPI_MADT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_IO_APIC,f) +#define ACPI_MADT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_INTERRUPT_OVERRIDE,f) +#define ACPI_MADT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_NMI_SOURCE,f) +#define ACPI_MADT4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_APIC_NMI,f) +#define ACPI_MADT5_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_APIC_OVERRIDE,f) +#define ACPI_MADT6_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_IO_SAPIC,f) +#define ACPI_MADT7_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_SAPIC,f) +#define ACPI_MADT8_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_INTERRUPT_SOURCE,f) +#define ACPI_MADT9_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_X2APIC,f) +#define ACPI_MADT10_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_X2APIC_NMI,f) +#define ACPI_MADT11_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_INTERRUPT,f) +#define ACPI_MADT12_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_DISTRIBUTOR,f) +#define ACPI_MADT13_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_MSI_FRAME,f) +#define ACPI_MADT14_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_REDISTRIBUTOR,f) +#define ACPI_MADT15_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_TRANSLATOR,f) +#define ACPI_MADTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SUBTABLE_HEADER,f) +#define ACPI_MCFG0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MCFG_ALLOCATION,f) +#define ACPI_MPST0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_POWER_NODE,f) +#define ACPI_MPST0A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_POWER_STATE,f) +#define ACPI_MPST0B_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_COMPONENT,f) +#define ACPI_MPST1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_DATA_HDR,f) +#define ACPI_MPST2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_POWER_DATA,f) +#define ACPI_MSCT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MSCT_PROXIMITY,f) +#define ACPI_MTMR0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MTMR_ENTRY,f) +#define ACPI_NFITH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_HEADER,f) +#define ACPI_NFIT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_SYSTEM_ADDRESS,f) +#define ACPI_NFIT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_MEMORY_MAP,f) +#define ACPI_NFIT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_INTERLEAVE,f) +#define ACPI_NFIT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_SMBIOS,f) +#define ACPI_NFIT4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_CONTROL_REGION,f) +#define ACPI_NFIT5_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_DATA_REGION,f) +#define ACPI_NFIT6_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_FLUSH_ADDRESS,f) +#define ACPI_NFIT7_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_CAPABILITIES,f) +#define ACPI_PCCT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PCCT_SUBSPACE,f) +#define ACPI_PCCT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PCCT_HW_REDUCED,f) +#define ACPI_PCCT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PCCT_HW_REDUCED_TYPE2,f) +#define ACPI_PCCT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PCCT_EXT_PCC_MASTER,f) +#define ACPI_PCCT4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PCCT_EXT_PCC_SLAVE,f) +#define ACPI_PDTT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PDTT_CHANNEL,f) +#define ACPI_PMTT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_SOCKET,f) +#define ACPI_PMTT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_CONTROLLER,f) +#define ACPI_PMTT1A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_DOMAIN,f) +#define ACPI_PMTT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_PHYSICAL_COMPONENT,f) +#define ACPI_PMTTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_HEADER,f) +#define ACPI_PPTTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SUBTABLE_HEADER,f) +#define ACPI_PPTT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PPTT_PROCESSOR,f) +#define ACPI_PPTT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PPTT_CACHE,f) +#define ACPI_PPTT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PPTT_ID,f) +#define ACPI_S3PTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_FPDT_HEADER,f) +#define ACPI_S3PT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_S3PT_RESUME,f) +#define ACPI_S3PT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_S3PT_SUSPEND,f) +#define ACPI_SDEVH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SDEV_HEADER,f) +#define ACPI_SDEV0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SDEV_NAMESPACE,f) +#define ACPI_SDEV1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SDEV_PCIE,f) +#define ACPI_SDEV1A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SDEV_PCIE_PATH,f) +#define ACPI_SLIC_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SLIC,f) +#define ACPI_SRATH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SUBTABLE_HEADER,f) +#define ACPI_SRAT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_CPU_AFFINITY,f) +#define ACPI_SRAT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_MEM_AFFINITY,f) +#define ACPI_SRAT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_X2APIC_CPU_AFFINITY,f) +#define ACPI_SRAT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_GICC_AFFINITY,f) +#define ACPI_SRAT4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_GIC_ITS_AFFINITY,f) +#define ACPI_TCPA_CLIENT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_TCPA_CLIENT,f) +#define ACPI_TCPA_SERVER_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_TCPA_SERVER,f) +#define ACPI_TPM2A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TPM2_TRAILER,f) +#define ACPI_TPM211_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TPM2_ARM_SMC,f) +#define ACPI_VRTC0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_VRTC_ENTRY,f) +#define ACPI_WDAT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_WDAT_ENTRY,f) + +/* + * Simplify access to flag fields by breaking them up into bytes + */ +#define ACPI_FLAG_OFFSET(d,f,o) (UINT16) (ACPI_OFFSET (d,f) + o) + +/* Flags */ + +#define ACPI_BGRT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_BGRT,f,o) +#define ACPI_DRTM_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_DRTM,f,o) +#define ACPI_DRTM1a_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_DRTM_RESOURCE,f,o) +#define ACPI_FADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_FADT,f,o) +#define ACPI_FACS_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_FACS,f,o) +#define ACPI_HPET_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_HPET,f,o) +#define ACPI_PPTT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PPTT_PROCESSOR,f,o) +#define ACPI_PPTT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PPTT_CACHE,f,o) +#define ACPI_SRAT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SRAT_CPU_AFFINITY,f,o) +#define ACPI_SRAT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SRAT_MEM_AFFINITY,f,o) +#define ACPI_SRAT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SRAT_X2APIC_CPU_AFFINITY,f,o) +#define ACPI_SRAT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SRAT_GICC_AFFINITY,f,o) +#define ACPI_GTDT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_GTDT,f,o) +#define ACPI_GTDT0a_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_GTDT_TIMER_ENTRY,f,o) +#define ACPI_GTDT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_GTDT_WATCHDOG,f,o) +#define ACPI_HMAT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HMAT_ADDRESS_RANGE,f,o) +#define ACPI_HMAT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HMAT_LOCALITY,f,o) +#define ACPI_HMAT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HMAT_CACHE,f,o) +#define ACPI_IORT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_IORT_SMMU,f,o) +#define ACPI_IORT3a_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_IORT_SMMU_GSI,f,o) +#define ACPI_IORT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_IORT_SMMU_V3,f,o) +#define ACPI_IORTA_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_IORT_MEMORY_ACCESS,f,o) +#define ACPI_IORTM_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_IORT_ID_MAPPING,f,o) +#define ACPI_LPITH_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_LPIT_HEADER,f,o) +#define ACPI_MADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_MADT,f,o) +#define ACPI_MADT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_APIC,f,o) +#define ACPI_MADT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_INTERRUPT_OVERRIDE,f,o) +#define ACPI_MADT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_NMI_SOURCE,f,o) +#define ACPI_MADT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_APIC_NMI,f,o) +#define ACPI_MADT7_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_SAPIC,f,o) +#define ACPI_MADT8_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_INTERRUPT_SOURCE,f,o) +#define ACPI_MADT9_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_X2APIC,f,o) +#define ACPI_MADT10_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_X2APIC_NMI,f,o) +#define ACPI_MADT11_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_GENERIC_INTERRUPT,f,o) +#define ACPI_MADT13_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_GENERIC_MSI_FRAME,f,o) +#define ACPI_MPST0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MPST_POWER_NODE,f,o) +#define ACPI_MPST2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MPST_POWER_DATA,f,o) +#define ACPI_NFIT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_NFIT_SYSTEM_ADDRESS,f,o) +#define ACPI_NFIT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_NFIT_MEMORY_MAP,f,o) +#define ACPI_NFIT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_NFIT_CONTROL_REGION,f,o) +#define ACPI_NFIT7_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_NFIT_CAPABILITIES,f,o) +#define ACPI_PCCT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_PCCT,f,o) +#define ACPI_PCCT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PCCT_HW_REDUCED,f,o) +#define ACPI_PCCT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PCCT_HW_REDUCED_TYPE2,f,o) +#define ACPI_PCCT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PCCT_EXT_PCC_MASTER,f,o) +#define ACPI_PCCT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PCCT_EXT_PCC_SLAVE,f,o) +#define ACPI_PDTT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PDTT_CHANNEL,f,o) +#define ACPI_PMTTH_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PMTT_HEADER,f,o) +#define ACPI_SDEVH_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SDEV_HEADER,f,o) +#define ACPI_WDDT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_WDDT,f,o) +#define ACPI_WSMT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_WSMT,f,o) +#define ACPI_EINJ0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_WHEA_HEADER,f,o) +#define ACPI_ERST0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_WHEA_HEADER,f,o) +#define ACPI_HEST0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HEST_IA_MACHINE_CHECK,f,o) +#define ACPI_HEST1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HEST_IA_CORRECTED,f,o) +#define ACPI_HEST6_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HEST_AER_ROOT,f,o) +#define ACPI_HEST11_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HEST_IA_DEFERRED_CHECK,f,o) + +/* + * Required terminator for all tables below + */ +#define ACPI_DMT_TERMINATOR {ACPI_DMT_EXIT, 0, NULL, 0} +#define ACPI_DMT_NEW_LINE {ACPI_DMT_EXTRA_TEXT, 0, "\n", 0} diff --git a/ports/acpica/include/actbl.h b/ports/acpica/include/actbl.h new file mode 100644 index 0000000..58a9b73 --- /dev/null +++ b/ports/acpica/include/actbl.h @@ -0,0 +1,578 @@ +/****************************************************************************** + * + * Name: actbl.h - Basic ACPI Table Definitions + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACTBL_H__ +#define __ACTBL_H__ + + +/******************************************************************************* + * + * Fundamental ACPI tables + * + * This file contains definitions for the ACPI tables that are directly consumed + * by ACPICA. All other tables are consumed by the OS-dependent ACPI-related + * device drivers and other OS support code. + * + * The RSDP and FACS do not use the common ACPI table header. All other ACPI + * tables use the header. + * + ******************************************************************************/ + + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_DSDT "DSDT" /* Differentiated System Description Table */ +#define ACPI_SIG_FADT "FACP" /* Fixed ACPI Description Table */ +#define ACPI_SIG_FACS "FACS" /* Firmware ACPI Control Structure */ +#define ACPI_SIG_OSDT "OSDT" /* Override System Description Table */ +#define ACPI_SIG_PSDT "PSDT" /* Persistent System Description Table */ +#define ACPI_SIG_RSDP "RSD PTR " /* Root System Description Pointer */ +#define ACPI_SIG_RSDT "RSDT" /* Root System Description Table */ +#define ACPI_SIG_XSDT "XSDT" /* Extended System Description Table */ +#define ACPI_SIG_SSDT "SSDT" /* Secondary System Description Table */ +#define ACPI_RSDP_NAME "RSDP" /* Short name for RSDP, not signature */ + + +/* + * All tables and structures must be byte-packed to match the ACPI + * specification, since the tables are provided by the system BIOS + */ +#pragma pack(1) + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/******************************************************************************* + * + * Master ACPI Table Header. This common header is used by all ACPI tables + * except the RSDP and FACS. + * + ******************************************************************************/ + +typedef struct acpi_table_header +{ + char Signature[ACPI_NAME_SIZE]; /* ASCII table signature */ + UINT32 Length; /* Length of table in bytes, including this header */ + UINT8 Revision; /* ACPI Specification minor version number */ + UINT8 Checksum; /* To make sum of entire table == 0 */ + char OemId[ACPI_OEM_ID_SIZE]; /* ASCII OEM identification */ + char OemTableId[ACPI_OEM_TABLE_ID_SIZE]; /* ASCII OEM table identification */ + UINT32 OemRevision; /* OEM revision number */ + char AslCompilerId[ACPI_NAME_SIZE]; /* ASCII ASL compiler vendor ID */ + UINT32 AslCompilerRevision; /* ASL compiler version */ + +} ACPI_TABLE_HEADER; + + +/******************************************************************************* + * + * GAS - Generic Address Structure (ACPI 2.0+) + * + * Note: Since this structure is used in the ACPI tables, it is byte aligned. + * If misaligned access is not supported by the hardware, accesses to the + * 64-bit Address field must be performed with care. + * + ******************************************************************************/ + +typedef struct acpi_generic_address +{ + UINT8 SpaceId; /* Address space where struct or register exists */ + UINT8 BitWidth; /* Size in bits of given register */ + UINT8 BitOffset; /* Bit offset within the register */ + UINT8 AccessWidth; /* Minimum Access size (ACPI 3.0) */ + UINT64 Address; /* 64-bit address of struct or register */ + +} ACPI_GENERIC_ADDRESS; + + +/******************************************************************************* + * + * RSDP - Root System Description Pointer (Signature is "RSD PTR ") + * Version 2 + * + ******************************************************************************/ + +typedef struct acpi_table_rsdp +{ + char Signature[8]; /* ACPI signature, contains "RSD PTR " */ + UINT8 Checksum; /* ACPI 1.0 checksum */ + char OemId[ACPI_OEM_ID_SIZE]; /* OEM identification */ + UINT8 Revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */ + UINT32 RsdtPhysicalAddress; /* 32-bit physical address of the RSDT */ + UINT32 Length; /* Table length in bytes, including header (ACPI 2.0+) */ + UINT64 XsdtPhysicalAddress; /* 64-bit physical address of the XSDT (ACPI 2.0+) */ + UINT8 ExtendedChecksum; /* Checksum of entire table (ACPI 2.0+) */ + UINT8 Reserved[3]; /* Reserved, must be zero */ + +} ACPI_TABLE_RSDP; + +/* Standalone struct for the ACPI 1.0 RSDP */ + +typedef struct acpi_rsdp_common +{ + char Signature[8]; + UINT8 Checksum; + char OemId[ACPI_OEM_ID_SIZE]; + UINT8 Revision; + UINT32 RsdtPhysicalAddress; + +} ACPI_RSDP_COMMON; + +/* Standalone struct for the extended part of the RSDP (ACPI 2.0+) */ + +typedef struct acpi_rsdp_extension +{ + UINT32 Length; + UINT64 XsdtPhysicalAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; + +} ACPI_RSDP_EXTENSION; + + +/******************************************************************************* + * + * RSDT/XSDT - Root System Description Tables + * Version 1 (both) + * + ******************************************************************************/ + +typedef struct acpi_table_rsdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 TableOffsetEntry[1]; /* Array of pointers to ACPI tables */ + +} ACPI_TABLE_RSDT; + +typedef struct acpi_table_xsdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 TableOffsetEntry[1]; /* Array of pointers to ACPI tables */ + +} ACPI_TABLE_XSDT; + +#define ACPI_RSDT_ENTRY_SIZE (sizeof (UINT32)) +#define ACPI_XSDT_ENTRY_SIZE (sizeof (UINT64)) + + +/******************************************************************************* + * + * FACS - Firmware ACPI Control Structure (FACS) + * + ******************************************************************************/ + +typedef struct acpi_table_facs +{ + char Signature[4]; /* ASCII table signature */ + UINT32 Length; /* Length of structure, in bytes */ + UINT32 HardwareSignature; /* Hardware configuration signature */ + UINT32 FirmwareWakingVector; /* 32-bit physical address of the Firmware Waking Vector */ + UINT32 GlobalLock; /* Global Lock for shared hardware resources */ + UINT32 Flags; + UINT64 XFirmwareWakingVector; /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */ + UINT8 Version; /* Version of this table (ACPI 2.0+) */ + UINT8 Reserved[3]; /* Reserved, must be zero */ + UINT32 OspmFlags; /* Flags to be set by OSPM (ACPI 4.0) */ + UINT8 Reserved1[24]; /* Reserved, must be zero */ + +} ACPI_TABLE_FACS; + +/* Masks for GlobalLock flag field above */ + +#define ACPI_GLOCK_PENDING (1) /* 00: Pending global lock ownership */ +#define ACPI_GLOCK_OWNED (1<<1) /* 01: Global lock is owned */ + +/* Masks for Flags field above */ + +#define ACPI_FACS_S4_BIOS_PRESENT (1) /* 00: S4BIOS support is present */ +#define ACPI_FACS_64BIT_WAKE (1<<1) /* 01: 64-bit wake vector supported (ACPI 4.0) */ + +/* Masks for OspmFlags field above */ + +#define ACPI_FACS_64BIT_ENVIRONMENT (1) /* 00: 64-bit wake environment is required (ACPI 4.0) */ + + +/******************************************************************************* + * + * FADT - Fixed ACPI Description Table (Signature "FACP") + * Version 6 + * + ******************************************************************************/ + +/* Fields common to all versions of the FADT */ + +typedef struct acpi_table_fadt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Facs; /* 32-bit physical address of FACS */ + UINT32 Dsdt; /* 32-bit physical address of DSDT */ + UINT8 Model; /* System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */ + UINT8 PreferredProfile; /* Conveys preferred power management profile to OSPM. */ + UINT16 SciInterrupt; /* System vector of SCI interrupt */ + UINT32 SmiCommand; /* 32-bit Port address of SMI command port */ + UINT8 AcpiEnable; /* Value to write to SMI_CMD to enable ACPI */ + UINT8 AcpiDisable; /* Value to write to SMI_CMD to disable ACPI */ + UINT8 S4BiosRequest; /* Value to write to SMI_CMD to enter S4BIOS state */ + UINT8 PstateControl; /* Processor performance state control*/ + UINT32 Pm1aEventBlock; /* 32-bit port address of Power Mgt 1a Event Reg Blk */ + UINT32 Pm1bEventBlock; /* 32-bit port address of Power Mgt 1b Event Reg Blk */ + UINT32 Pm1aControlBlock; /* 32-bit port address of Power Mgt 1a Control Reg Blk */ + UINT32 Pm1bControlBlock; /* 32-bit port address of Power Mgt 1b Control Reg Blk */ + UINT32 Pm2ControlBlock; /* 32-bit port address of Power Mgt 2 Control Reg Blk */ + UINT32 PmTimerBlock; /* 32-bit port address of Power Mgt Timer Ctrl Reg Blk */ + UINT32 Gpe0Block; /* 32-bit port address of General Purpose Event 0 Reg Blk */ + UINT32 Gpe1Block; /* 32-bit port address of General Purpose Event 1 Reg Blk */ + UINT8 Pm1EventLength; /* Byte Length of ports at Pm1xEventBlock */ + UINT8 Pm1ControlLength; /* Byte Length of ports at Pm1xControlBlock */ + UINT8 Pm2ControlLength; /* Byte Length of ports at Pm2ControlBlock */ + UINT8 PmTimerLength; /* Byte Length of ports at PmTimerBlock */ + UINT8 Gpe0BlockLength; /* Byte Length of ports at Gpe0Block */ + UINT8 Gpe1BlockLength; /* Byte Length of ports at Gpe1Block */ + UINT8 Gpe1Base; /* Offset in GPE number space where GPE1 events start */ + UINT8 CstControl; /* Support for the _CST object and C-States change notification */ + UINT16 C2Latency; /* Worst case HW latency to enter/exit C2 state */ + UINT16 C3Latency; /* Worst case HW latency to enter/exit C3 state */ + UINT16 FlushSize; /* Processor memory cache line width, in bytes */ + UINT16 FlushStride; /* Number of flush strides that need to be read */ + UINT8 DutyOffset; /* Processor duty cycle index in processor P_CNT reg */ + UINT8 DutyWidth; /* Processor duty cycle value bit width in P_CNT register */ + UINT8 DayAlarm; /* Index to day-of-month alarm in RTC CMOS RAM */ + UINT8 MonthAlarm; /* Index to month-of-year alarm in RTC CMOS RAM */ + UINT8 Century; /* Index to century in RTC CMOS RAM */ + UINT16 BootFlags; /* IA-PC Boot Architecture Flags (see below for individual flags) */ + UINT8 Reserved; /* Reserved, must be zero */ + UINT32 Flags; /* Miscellaneous flag bits (see below for individual flags) */ + ACPI_GENERIC_ADDRESS ResetRegister; /* 64-bit address of the Reset register */ + UINT8 ResetValue; /* Value to write to the ResetRegister port to reset the system */ + UINT16 ArmBootFlags; /* ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */ + UINT8 MinorRevision; /* FADT Minor Revision (ACPI 5.1) */ + UINT64 XFacs; /* 64-bit physical address of FACS */ + UINT64 XDsdt; /* 64-bit physical address of DSDT */ + ACPI_GENERIC_ADDRESS XPm1aEventBlock; /* 64-bit Extended Power Mgt 1a Event Reg Blk address */ + ACPI_GENERIC_ADDRESS XPm1bEventBlock; /* 64-bit Extended Power Mgt 1b Event Reg Blk address */ + ACPI_GENERIC_ADDRESS XPm1aControlBlock; /* 64-bit Extended Power Mgt 1a Control Reg Blk address */ + ACPI_GENERIC_ADDRESS XPm1bControlBlock; /* 64-bit Extended Power Mgt 1b Control Reg Blk address */ + ACPI_GENERIC_ADDRESS XPm2ControlBlock; /* 64-bit Extended Power Mgt 2 Control Reg Blk address */ + ACPI_GENERIC_ADDRESS XPmTimerBlock; /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */ + ACPI_GENERIC_ADDRESS XGpe0Block; /* 64-bit Extended General Purpose Event 0 Reg Blk address */ + ACPI_GENERIC_ADDRESS XGpe1Block; /* 64-bit Extended General Purpose Event 1 Reg Blk address */ + ACPI_GENERIC_ADDRESS SleepControl; /* 64-bit Sleep Control register (ACPI 5.0) */ + ACPI_GENERIC_ADDRESS SleepStatus; /* 64-bit Sleep Status register (ACPI 5.0) */ + UINT64 HypervisorId; /* Hypervisor Vendor ID (ACPI 6.0) */ + +} ACPI_TABLE_FADT; + + +/* Masks for FADT IA-PC Boot Architecture Flags (boot_flags) [Vx]=Introduced in this FADT revision */ + +#define ACPI_FADT_LEGACY_DEVICES (1) /* 00: [V2] System has LPC or ISA bus devices */ +#define ACPI_FADT_8042 (1<<1) /* 01: [V3] System has an 8042 controller on port 60/64 */ +#define ACPI_FADT_NO_VGA (1<<2) /* 02: [V4] It is not safe to probe for VGA hardware */ +#define ACPI_FADT_NO_MSI (1<<3) /* 03: [V4] Message Signaled Interrupts (MSI) must not be enabled */ +#define ACPI_FADT_NO_ASPM (1<<4) /* 04: [V4] PCIe ASPM control must not be enabled */ +#define ACPI_FADT_NO_CMOS_RTC (1<<5) /* 05: [V5] No CMOS real-time clock present */ + +/* Masks for FADT ARM Boot Architecture Flags (arm_boot_flags) ACPI 5.1 */ + +#define ACPI_FADT_PSCI_COMPLIANT (1) /* 00: [V5+] PSCI 0.2+ is implemented */ +#define ACPI_FADT_PSCI_USE_HVC (1<<1) /* 01: [V5+] HVC must be used instead of SMC as the PSCI conduit */ + +/* Masks for FADT flags */ + +#define ACPI_FADT_WBINVD (1) /* 00: [V1] The WBINVD instruction works properly */ +#define ACPI_FADT_WBINVD_FLUSH (1<<1) /* 01: [V1] WBINVD flushes but does not invalidate caches */ +#define ACPI_FADT_C1_SUPPORTED (1<<2) /* 02: [V1] All processors support C1 state */ +#define ACPI_FADT_C2_MP_SUPPORTED (1<<3) /* 03: [V1] C2 state works on MP system */ +#define ACPI_FADT_POWER_BUTTON (1<<4) /* 04: [V1] Power button is handled as a control method device */ +#define ACPI_FADT_SLEEP_BUTTON (1<<5) /* 05: [V1] Sleep button is handled as a control method device */ +#define ACPI_FADT_FIXED_RTC (1<<6) /* 06: [V1] RTC wakeup status is not in fixed register space */ +#define ACPI_FADT_S4_RTC_WAKE (1<<7) /* 07: [V1] RTC alarm can wake system from S4 */ +#define ACPI_FADT_32BIT_TIMER (1<<8) /* 08: [V1] ACPI timer width is 32-bit (0=24-bit) */ +#define ACPI_FADT_DOCKING_SUPPORTED (1<<9) /* 09: [V1] Docking supported */ +#define ACPI_FADT_RESET_REGISTER (1<<10) /* 10: [V2] System reset via the FADT RESET_REG supported */ +#define ACPI_FADT_SEALED_CASE (1<<11) /* 11: [V3] No internal expansion capabilities and case is sealed */ +#define ACPI_FADT_HEADLESS (1<<12) /* 12: [V3] No local video capabilities or local input devices */ +#define ACPI_FADT_SLEEP_TYPE (1<<13) /* 13: [V3] Must execute native instruction after writing SLP_TYPx register */ +#define ACPI_FADT_PCI_EXPRESS_WAKE (1<<14) /* 14: [V4] System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */ +#define ACPI_FADT_PLATFORM_CLOCK (1<<15) /* 15: [V4] OSPM should use platform-provided timer (ACPI 3.0) */ +#define ACPI_FADT_S4_RTC_VALID (1<<16) /* 16: [V4] Contents of RTC_STS valid after S4 wake (ACPI 3.0) */ +#define ACPI_FADT_REMOTE_POWER_ON (1<<17) /* 17: [V4] System is compatible with remote power on (ACPI 3.0) */ +#define ACPI_FADT_APIC_CLUSTER (1<<18) /* 18: [V4] All local APICs must use cluster model (ACPI 3.0) */ +#define ACPI_FADT_APIC_PHYSICAL (1<<19) /* 19: [V4] All local xAPICs must use physical dest mode (ACPI 3.0) */ +#define ACPI_FADT_HW_REDUCED (1<<20) /* 20: [V5] ACPI hardware is not implemented (ACPI 5.0) */ +#define ACPI_FADT_LOW_POWER_S0 (1<<21) /* 21: [V5] S0 power savings are equal or better than S3 (ACPI 5.0) */ + + +/* Values for PreferredProfile (Preferred Power Management Profiles) */ + +enum AcpiPreferredPmProfiles +{ + PM_UNSPECIFIED = 0, + PM_DESKTOP = 1, + PM_MOBILE = 2, + PM_WORKSTATION = 3, + PM_ENTERPRISE_SERVER = 4, + PM_SOHO_SERVER = 5, + PM_APPLIANCE_PC = 6, + PM_PERFORMANCE_SERVER = 7, + PM_TABLET = 8 +}; + +/* Values for SleepStatus and SleepControl registers (V5+ FADT) */ + +#define ACPI_X_WAKE_STATUS 0x80 +#define ACPI_X_SLEEP_TYPE_MASK 0x1C +#define ACPI_X_SLEEP_TYPE_POSITION 0x02 +#define ACPI_X_SLEEP_ENABLE 0x20 + + +/* Reset to default packing */ + +#pragma pack() + + +/* + * Internal table-related structures + */ +typedef union acpi_name_union +{ + UINT32 Integer; + char Ascii[4]; + +} ACPI_NAME_UNION; + + +/* Internal ACPI Table Descriptor. One per ACPI table. */ + +typedef struct acpi_table_desc +{ + ACPI_PHYSICAL_ADDRESS Address; + ACPI_TABLE_HEADER *Pointer; + UINT32 Length; /* Length fixed at 32 bits (fixed in table header) */ + ACPI_NAME_UNION Signature; + ACPI_OWNER_ID OwnerId; + UINT8 Flags; + UINT16 ValidationCount; + +} ACPI_TABLE_DESC; + +/* + * Maximum value of the ValidationCount field in ACPI_TABLE_DESC. + * When reached, ValidationCount cannot be changed any more and the table will + * be permanently regarded as validated. + * + * This is to prevent situations in which unbalanced table get/put operations + * may cause premature table unmapping in the OS to happen. + * + * The maximum validation count can be defined to any value, but should be + * greater than the maximum number of OS early stage mapping slots to avoid + * leaking early stage table mappings to the late stage. + */ +#define ACPI_MAX_TABLE_VALIDATIONS ACPI_UINT16_MAX + +/* Masks for Flags field above */ + +#define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL (0) /* Virtual address, external maintained */ +#define ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL (1) /* Physical address, internally mapped */ +#define ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL (2) /* Virtual address, internallly allocated */ +#define ACPI_TABLE_ORIGIN_MASK (3) +#define ACPI_TABLE_IS_VERIFIED (4) +#define ACPI_TABLE_IS_LOADED (8) + + +/* + * Get the remaining ACPI tables + */ +#include "actbl1.h" +#include "actbl2.h" +#include "actbl3.h" + +/* Macros used to generate offsets to specific table fields */ + +#define ACPI_FADT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_FADT, f) + +/* + * Sizes of the various flavors of FADT. We need to look closely + * at the FADT length because the version number essentially tells + * us nothing because of many BIOS bugs where the version does not + * match the expected length. In other words, the length of the + * FADT is the bottom line as to what the version really is. + * + * For reference, the values below are as follows: + * FADT V1 size: 0x074 + * FADT V2 size: 0x084 + * FADT V3 size: 0x0F4 + * FADT V4 size: 0x0F4 + * FADT V5 size: 0x10C + * FADT V6 size: 0x114 + */ +#define ACPI_FADT_V1_SIZE (UINT32) (ACPI_FADT_OFFSET (Flags) + 4) +#define ACPI_FADT_V2_SIZE (UINT32) (ACPI_FADT_OFFSET (MinorRevision) + 1) +#define ACPI_FADT_V3_SIZE (UINT32) (ACPI_FADT_OFFSET (SleepControl)) +#define ACPI_FADT_V5_SIZE (UINT32) (ACPI_FADT_OFFSET (HypervisorId)) +#define ACPI_FADT_V6_SIZE (UINT32) (sizeof (ACPI_TABLE_FADT)) + +#define ACPI_FADT_CONFORMANCE "ACPI 6.1 (FADT version 6)" + +#endif /* __ACTBL_H__ */ diff --git a/ports/acpica/include/actbl1.h b/ports/acpica/include/actbl1.h new file mode 100644 index 0000000..4f03ab0 --- /dev/null +++ b/ports/acpica/include/actbl1.h @@ -0,0 +1,2046 @@ +/****************************************************************************** + * + * Name: actbl1.h - Additional ACPI table definitions + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACTBL1_H__ +#define __ACTBL1_H__ + + +/******************************************************************************* + * + * Additional ACPI Tables + * + * These tables are not consumed directly by the ACPICA subsystem, but are + * included here to support device drivers and the AML disassembler. + * + ******************************************************************************/ + + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_ASF "ASF!" /* Alert Standard Format table */ +#define ACPI_SIG_BERT "BERT" /* Boot Error Record Table */ +#define ACPI_SIG_BGRT "BGRT" /* Boot Graphics Resource Table */ +#define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */ +#define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */ +#define ACPI_SIG_CSRT "CSRT" /* Core System Resource Table */ +#define ACPI_SIG_DBG2 "DBG2" /* Debug Port table type 2 */ +#define ACPI_SIG_DBGP "DBGP" /* Debug Port table */ +#define ACPI_SIG_DMAR "DMAR" /* DMA Remapping table */ +#define ACPI_SIG_DRTM "DRTM" /* Dynamic Root of Trust for Measurement table */ +#define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */ +#define ACPI_SIG_EINJ "EINJ" /* Error Injection table */ +#define ACPI_SIG_ERST "ERST" /* Error Record Serialization Table */ +#define ACPI_SIG_FPDT "FPDT" /* Firmware Performance Data Table */ +#define ACPI_SIG_GTDT "GTDT" /* Generic Timer Description Table */ +#define ACPI_SIG_HEST "HEST" /* Hardware Error Source Table */ +#define ACPI_SIG_HMAT "HMAT" /* Heterogeneous Memory Attributes Table */ +#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */ +#define ACPI_SIG_IBFT "IBFT" /* iSCSI Boot Firmware Table */ + +#define ACPI_SIG_S3PT "S3PT" /* S3 Performance (sub)Table */ +#define ACPI_SIG_PCCS "PCC" /* PCC Shared Memory Region */ + + +/* Reserved table signatures */ + +#define ACPI_SIG_MATR "MATR" /* Memory Address Translation Table */ +#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */ + +/* + * These tables have been seen in the field, but no definition has been found + */ +#ifdef ACPI_UNDEFINED_TABLES +#define ACPI_SIG_ATKG "ATKG" +#define ACPI_SIG_GSCI "GSCI" /* GMCH SCI table */ +#define ACPI_SIG_IEIT "IEIT" +#endif + +/* + * All tables must be byte-packed to match the ACPI specification, since + * the tables are provided by the system BIOS. + */ +#pragma pack(1) + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/******************************************************************************* + * + * Common subtable headers + * + ******************************************************************************/ + +/* Generic subtable header (used in MADT, SRAT, etc.) */ + +typedef struct acpi_subtable_header +{ + UINT8 Type; + UINT8 Length; + +} ACPI_SUBTABLE_HEADER; + + +/* Subtable header for WHEA tables (EINJ, ERST, WDAT) */ + +typedef struct acpi_whea_header +{ + UINT8 Action; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved; + ACPI_GENERIC_ADDRESS RegisterRegion; + UINT64 Value; /* Value used with Read/Write register */ + UINT64 Mask; /* Bitmask required for this register instruction */ + +} ACPI_WHEA_HEADER; + + +/******************************************************************************* + * + * ASF - Alert Standard Format table (Signature "ASF!") + * Revision 0x10 + * + * Conforms to the Alert Standard Format Specification V2.0, 23 April 2003 + * + ******************************************************************************/ + +typedef struct acpi_table_asf +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_ASF; + + +/* ASF subtable header */ + +typedef struct acpi_asf_header +{ + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + +} ACPI_ASF_HEADER; + + +/* Values for Type field above */ + +enum AcpiAsfType +{ + ACPI_ASF_TYPE_INFO = 0, + ACPI_ASF_TYPE_ALERT = 1, + ACPI_ASF_TYPE_CONTROL = 2, + ACPI_ASF_TYPE_BOOT = 3, + ACPI_ASF_TYPE_ADDRESS = 4, + ACPI_ASF_TYPE_RESERVED = 5 +}; + +/* + * ASF subtables + */ + +/* 0: ASF Information */ + +typedef struct acpi_asf_info +{ + ACPI_ASF_HEADER Header; + UINT8 MinResetValue; + UINT8 MinPollInterval; + UINT16 SystemId; + UINT32 MfgId; + UINT8 Flags; + UINT8 Reserved2[3]; + +} ACPI_ASF_INFO; + +/* Masks for Flags field above */ + +#define ACPI_ASF_SMBUS_PROTOCOLS (1) + + +/* 1: ASF Alerts */ + +typedef struct acpi_asf_alert +{ + ACPI_ASF_HEADER Header; + UINT8 AssertMask; + UINT8 DeassertMask; + UINT8 Alerts; + UINT8 DataLength; + +} ACPI_ASF_ALERT; + +typedef struct acpi_asf_alert_data +{ + UINT8 Address; + UINT8 Command; + UINT8 Mask; + UINT8 Value; + UINT8 SensorType; + UINT8 Type; + UINT8 Offset; + UINT8 SourceType; + UINT8 Severity; + UINT8 SensorNumber; + UINT8 Entity; + UINT8 Instance; + +} ACPI_ASF_ALERT_DATA; + + +/* 2: ASF Remote Control */ + +typedef struct acpi_asf_remote +{ + ACPI_ASF_HEADER Header; + UINT8 Controls; + UINT8 DataLength; + UINT16 Reserved2; + +} ACPI_ASF_REMOTE; + +typedef struct acpi_asf_control_data +{ + UINT8 Function; + UINT8 Address; + UINT8 Command; + UINT8 Value; + +} ACPI_ASF_CONTROL_DATA; + + +/* 3: ASF RMCP Boot Options */ + +typedef struct acpi_asf_rmcp +{ + ACPI_ASF_HEADER Header; + UINT8 Capabilities[7]; + UINT8 CompletionCode; + UINT32 EnterpriseId; + UINT8 Command; + UINT16 Parameter; + UINT16 BootOptions; + UINT16 OemParameters; + +} ACPI_ASF_RMCP; + + +/* 4: ASF Address */ + +typedef struct acpi_asf_address +{ + ACPI_ASF_HEADER Header; + UINT8 EpromAddress; + UINT8 Devices; + +} ACPI_ASF_ADDRESS; + + +/******************************************************************************* + * + * BERT - Boot Error Record Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_bert +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 RegionLength; /* Length of the boot error region */ + UINT64 Address; /* Physical address of the error region */ + +} ACPI_TABLE_BERT; + + +/* Boot Error Region (not a subtable, pointed to by Address field above) */ + +typedef struct acpi_bert_region +{ + UINT32 BlockStatus; /* Type of error information */ + UINT32 RawDataOffset; /* Offset to raw error data */ + UINT32 RawDataLength; /* Length of raw error data */ + UINT32 DataLength; /* Length of generic error data */ + UINT32 ErrorSeverity; /* Severity code */ + +} ACPI_BERT_REGION; + +/* Values for BlockStatus flags above */ + +#define ACPI_BERT_UNCORRECTABLE (1) +#define ACPI_BERT_CORRECTABLE (1<<1) +#define ACPI_BERT_MULTIPLE_UNCORRECTABLE (1<<2) +#define ACPI_BERT_MULTIPLE_CORRECTABLE (1<<3) +#define ACPI_BERT_ERROR_ENTRY_COUNT (0xFF<<4) /* 8 bits, error count */ + +/* Values for ErrorSeverity above */ + +enum AcpiBertErrorSeverity +{ + ACPI_BERT_ERROR_CORRECTABLE = 0, + ACPI_BERT_ERROR_FATAL = 1, + ACPI_BERT_ERROR_CORRECTED = 2, + ACPI_BERT_ERROR_NONE = 3, + ACPI_BERT_ERROR_RESERVED = 4 /* 4 and greater are reserved */ +}; + +/* + * Note: The generic error data that follows the ErrorSeverity field above + * uses the ACPI_HEST_GENERIC_DATA defined under the HEST table below + */ + + +/******************************************************************************* + * + * BGRT - Boot Graphics Resource Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_bgrt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT16 Version; + UINT8 Status; + UINT8 ImageType; + UINT64 ImageAddress; + UINT32 ImageOffsetX; + UINT32 ImageOffsetY; + +} ACPI_TABLE_BGRT; + +/* Flags for Status field above */ + +#define ACPI_BGRT_DISPLAYED (1) +#define ACPI_BGRT_ORIENTATION_OFFSET (3 << 1) + + +/******************************************************************************* + * + * BOOT - Simple Boot Flag Table + * Version 1 + * + * Conforms to the "Simple Boot Flag Specification", Version 2.1 + * + ******************************************************************************/ + +typedef struct acpi_table_boot +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 CmosIndex; /* Index in CMOS RAM for the boot register */ + UINT8 Reserved[3]; + +} ACPI_TABLE_BOOT; + + +/******************************************************************************* + * + * CPEP - Corrected Platform Error Polling table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_cpep +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 Reserved; + +} ACPI_TABLE_CPEP; + + +/* Subtable */ + +typedef struct acpi_cpep_polling +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Id; /* Processor ID */ + UINT8 Eid; /* Processor EID */ + UINT32 Interval; /* Polling interval (msec) */ + +} ACPI_CPEP_POLLING; + + +/******************************************************************************* + * + * CSRT - Core System Resource Table + * Version 0 + * + * Conforms to the "Core System Resource Table (CSRT)", November 14, 2011 + * + ******************************************************************************/ + +typedef struct acpi_table_csrt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_CSRT; + + +/* Resource Group subtable */ + +typedef struct acpi_csrt_group +{ + UINT32 Length; + UINT32 VendorId; + UINT32 SubvendorId; + UINT16 DeviceId; + UINT16 SubdeviceId; + UINT16 Revision; + UINT16 Reserved; + UINT32 SharedInfoLength; + + /* Shared data immediately follows (Length = SharedInfoLength) */ + +} ACPI_CSRT_GROUP; + +/* Shared Info subtable */ + +typedef struct acpi_csrt_shared_info +{ + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 MmioBaseLow; + UINT32 MmioBaseHigh; + UINT32 GsiInterrupt; + UINT8 InterruptPolarity; + UINT8 InterruptMode; + UINT8 NumChannels; + UINT8 DmaAddressWidth; + UINT16 BaseRequestLine; + UINT16 NumHandshakeSignals; + UINT32 MaxBlockSize; + + /* Resource descriptors immediately follow (Length = Group Length - SharedInfoLength) */ + +} ACPI_CSRT_SHARED_INFO; + +/* Resource Descriptor subtable */ + +typedef struct acpi_csrt_descriptor +{ + UINT32 Length; + UINT16 Type; + UINT16 Subtype; + UINT32 Uid; + + /* Resource-specific information immediately follows */ + +} ACPI_CSRT_DESCRIPTOR; + + +/* Resource Types */ + +#define ACPI_CSRT_TYPE_INTERRUPT 0x0001 +#define ACPI_CSRT_TYPE_TIMER 0x0002 +#define ACPI_CSRT_TYPE_DMA 0x0003 + +/* Resource Subtypes */ + +#define ACPI_CSRT_XRUPT_LINE 0x0000 +#define ACPI_CSRT_XRUPT_CONTROLLER 0x0001 +#define ACPI_CSRT_TIMER 0x0000 +#define ACPI_CSRT_DMA_CHANNEL 0x0000 +#define ACPI_CSRT_DMA_CONTROLLER 0x0001 + + +/******************************************************************************* + * + * DBG2 - Debug Port Table 2 + * Version 0 (Both main table and subtables) + * + * Conforms to "Microsoft Debug Port Table 2 (DBG2)", December 10, 2015 + * + ******************************************************************************/ + +typedef struct acpi_table_dbg2 +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 InfoOffset; + UINT32 InfoCount; + +} ACPI_TABLE_DBG2; + + +typedef struct acpi_dbg2_header +{ + UINT32 InfoOffset; + UINT32 InfoCount; + +} ACPI_DBG2_HEADER; + + +/* Debug Device Information Subtable */ + +typedef struct acpi_dbg2_device +{ + UINT8 Revision; + UINT16 Length; + UINT8 RegisterCount; /* Number of BaseAddress registers */ + UINT16 NamepathLength; + UINT16 NamepathOffset; + UINT16 OemDataLength; + UINT16 OemDataOffset; + UINT16 PortType; + UINT16 PortSubtype; + UINT16 Reserved; + UINT16 BaseAddressOffset; + UINT16 AddressSizeOffset; + /* + * Data that follows: + * BaseAddress (required) - Each in 12-byte Generic Address Structure format. + * AddressSize (required) - Array of UINT32 sizes corresponding to each BaseAddress register. + * Namepath (required) - Null terminated string. Single dot if not supported. + * OemData (optional) - Length is OemDataLength. + */ +} ACPI_DBG2_DEVICE; + +/* Types for PortType field above */ + +#define ACPI_DBG2_SERIAL_PORT 0x8000 +#define ACPI_DBG2_1394_PORT 0x8001 +#define ACPI_DBG2_USB_PORT 0x8002 +#define ACPI_DBG2_NET_PORT 0x8003 + +/* Subtypes for PortSubtype field above */ + +#define ACPI_DBG2_16550_COMPATIBLE 0x0000 +#define ACPI_DBG2_16550_SUBSET 0x0001 +#define ACPI_DBG2_ARM_PL011 0x0003 +#define ACPI_DBG2_ARM_SBSA_32BIT 0x000D +#define ACPI_DBG2_ARM_SBSA_GENERIC 0x000E +#define ACPI_DBG2_ARM_DCC 0x000F +#define ACPI_DBG2_BCM2835 0x0010 + +#define ACPI_DBG2_1394_STANDARD 0x0000 + +#define ACPI_DBG2_USB_XHCI 0x0000 +#define ACPI_DBG2_USB_EHCI 0x0001 + + +/******************************************************************************* + * + * DBGP - Debug Port table + * Version 1 + * + * Conforms to the "Debug Port Specification", Version 1.00, 2/9/2000 + * + ******************************************************************************/ + +typedef struct acpi_table_dbgp +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Type; /* 0=full 16550, 1=subset of 16550 */ + UINT8 Reserved[3]; + ACPI_GENERIC_ADDRESS DebugPort; + +} ACPI_TABLE_DBGP; + + +/******************************************************************************* + * + * DMAR - DMA Remapping table + * Version 1 + * + * Conforms to "Intel Virtualization Technology for Directed I/O", + * Version 2.3, October 2014 + * + ******************************************************************************/ + +typedef struct acpi_table_dmar +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Width; /* Host Address Width */ + UINT8 Flags; + UINT8 Reserved[10]; + +} ACPI_TABLE_DMAR; + +/* Masks for Flags field above */ + +#define ACPI_DMAR_INTR_REMAP (1) +#define ACPI_DMAR_X2APIC_OPT_OUT (1<<1) +#define ACPI_DMAR_X2APIC_MODE (1<<2) + + +/* DMAR subtable header */ + +typedef struct acpi_dmar_header +{ + UINT16 Type; + UINT16 Length; + +} ACPI_DMAR_HEADER; + +/* Values for subtable type in ACPI_DMAR_HEADER */ + +enum AcpiDmarType +{ + ACPI_DMAR_TYPE_HARDWARE_UNIT = 0, + ACPI_DMAR_TYPE_RESERVED_MEMORY = 1, + ACPI_DMAR_TYPE_ROOT_ATS = 2, + ACPI_DMAR_TYPE_HARDWARE_AFFINITY = 3, + ACPI_DMAR_TYPE_NAMESPACE = 4, + ACPI_DMAR_TYPE_RESERVED = 5 /* 5 and greater are reserved */ +}; + + +/* DMAR Device Scope structure */ + +typedef struct acpi_dmar_device_scope +{ + UINT8 EntryType; + UINT8 Length; + UINT16 Reserved; + UINT8 EnumerationId; + UINT8 Bus; + +} ACPI_DMAR_DEVICE_SCOPE; + +/* Values for EntryType in ACPI_DMAR_DEVICE_SCOPE - device types */ + +enum AcpiDmarScopeType +{ + ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0, + ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1, + ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2, + ACPI_DMAR_SCOPE_TYPE_IOAPIC = 3, + ACPI_DMAR_SCOPE_TYPE_HPET = 4, + ACPI_DMAR_SCOPE_TYPE_NAMESPACE = 5, + ACPI_DMAR_SCOPE_TYPE_RESERVED = 6 /* 6 and greater are reserved */ +}; + +typedef struct acpi_dmar_pci_path +{ + UINT8 Device; + UINT8 Function; + +} ACPI_DMAR_PCI_PATH; + + +/* + * DMAR Subtables, correspond to Type in ACPI_DMAR_HEADER + */ + +/* 0: Hardware Unit Definition */ + +typedef struct acpi_dmar_hardware_unit +{ + ACPI_DMAR_HEADER Header; + UINT8 Flags; + UINT8 Reserved; + UINT16 Segment; + UINT64 Address; /* Register Base Address */ + +} ACPI_DMAR_HARDWARE_UNIT; + +/* Masks for Flags field above */ + +#define ACPI_DMAR_INCLUDE_ALL (1) + + +/* 1: Reserved Memory Defininition */ + +typedef struct acpi_dmar_reserved_memory +{ + ACPI_DMAR_HEADER Header; + UINT16 Reserved; + UINT16 Segment; + UINT64 BaseAddress; /* 4K aligned base address */ + UINT64 EndAddress; /* 4K aligned limit address */ + +} ACPI_DMAR_RESERVED_MEMORY; + +/* Masks for Flags field above */ + +#define ACPI_DMAR_ALLOW_ALL (1) + + +/* 2: Root Port ATS Capability Reporting Structure */ + +typedef struct acpi_dmar_atsr +{ + ACPI_DMAR_HEADER Header; + UINT8 Flags; + UINT8 Reserved; + UINT16 Segment; + +} ACPI_DMAR_ATSR; + +/* Masks for Flags field above */ + +#define ACPI_DMAR_ALL_PORTS (1) + + +/* 3: Remapping Hardware Static Affinity Structure */ + +typedef struct acpi_dmar_rhsa +{ + ACPI_DMAR_HEADER Header; + UINT32 Reserved; + UINT64 BaseAddress; + UINT32 ProximityDomain; + +} ACPI_DMAR_RHSA; + + +/* 4: ACPI Namespace Device Declaration Structure */ + +typedef struct acpi_dmar_andd +{ + ACPI_DMAR_HEADER Header; + UINT8 Reserved[3]; + UINT8 DeviceNumber; + char DeviceName[1]; + +} ACPI_DMAR_ANDD; + + +/******************************************************************************* + * + * DRTM - Dynamic Root of Trust for Measurement table + * Conforms to "TCG D-RTM Architecture" June 17 2013, Version 1.0.0 + * Table version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_drtm +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 EntryBaseAddress; + UINT64 EntryLength; + UINT32 EntryAddress32; + UINT64 EntryAddress64; + UINT64 ExitAddress; + UINT64 LogAreaAddress; + UINT32 LogAreaLength; + UINT64 ArchDependentAddress; + UINT32 Flags; + +} ACPI_TABLE_DRTM; + +/* Flag Definitions for above */ + +#define ACPI_DRTM_ACCESS_ALLOWED (1) +#define ACPI_DRTM_ENABLE_GAP_CODE (1<<1) +#define ACPI_DRTM_INCOMPLETE_MEASUREMENTS (1<<2) +#define ACPI_DRTM_AUTHORITY_ORDER (1<<3) + + +/* 1) Validated Tables List (64-bit addresses) */ + +typedef struct acpi_drtm_vtable_list +{ + UINT32 ValidatedTableCount; + UINT64 ValidatedTables[1]; + +} ACPI_DRTM_VTABLE_LIST; + +/* 2) Resources List (of Resource Descriptors) */ + +/* Resource Descriptor */ + +typedef struct acpi_drtm_resource +{ + UINT8 Size[7]; + UINT8 Type; + UINT64 Address; + +} ACPI_DRTM_RESOURCE; + +typedef struct acpi_drtm_resource_list +{ + UINT32 ResourceCount; + ACPI_DRTM_RESOURCE Resources[1]; + +} ACPI_DRTM_RESOURCE_LIST; + +/* 3) Platform-specific Identifiers List */ + +typedef struct acpi_drtm_dps_id +{ + UINT32 DpsIdLength; + UINT8 DpsId[16]; + +} ACPI_DRTM_DPS_ID; + + +/******************************************************************************* + * + * ECDT - Embedded Controller Boot Resources Table + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_ecdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + ACPI_GENERIC_ADDRESS Control; /* Address of EC command/status register */ + ACPI_GENERIC_ADDRESS Data; /* Address of EC data register */ + UINT32 Uid; /* Unique ID - must be same as the EC _UID method */ + UINT8 Gpe; /* The GPE for the EC */ + UINT8 Id[1]; /* Full namepath of the EC in the ACPI namespace */ + +} ACPI_TABLE_ECDT; + + +/******************************************************************************* + * + * EINJ - Error Injection Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_einj +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 HeaderLength; + UINT8 Flags; + UINT8 Reserved[3]; + UINT32 Entries; + +} ACPI_TABLE_EINJ; + + +/* EINJ Injection Instruction Entries (actions) */ + +typedef struct acpi_einj_entry +{ + ACPI_WHEA_HEADER WheaHeader; /* Common header for WHEA tables */ + +} ACPI_EINJ_ENTRY; + +/* Masks for Flags field above */ + +#define ACPI_EINJ_PRESERVE (1) + +/* Values for Action field above */ + +enum AcpiEinjActions +{ + ACPI_EINJ_BEGIN_OPERATION = 0, + ACPI_EINJ_GET_TRIGGER_TABLE = 1, + ACPI_EINJ_SET_ERROR_TYPE = 2, + ACPI_EINJ_GET_ERROR_TYPE = 3, + ACPI_EINJ_END_OPERATION = 4, + ACPI_EINJ_EXECUTE_OPERATION = 5, + ACPI_EINJ_CHECK_BUSY_STATUS = 6, + ACPI_EINJ_GET_COMMAND_STATUS = 7, + ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS = 8, + ACPI_EINJ_GET_EXECUTE_TIMINGS = 9, + ACPI_EINJ_ACTION_RESERVED = 10, /* 10 and greater are reserved */ + ACPI_EINJ_TRIGGER_ERROR = 0xFF /* Except for this value */ +}; + +/* Values for Instruction field above */ + +enum AcpiEinjInstructions +{ + ACPI_EINJ_READ_REGISTER = 0, + ACPI_EINJ_READ_REGISTER_VALUE = 1, + ACPI_EINJ_WRITE_REGISTER = 2, + ACPI_EINJ_WRITE_REGISTER_VALUE = 3, + ACPI_EINJ_NOOP = 4, + ACPI_EINJ_FLUSH_CACHELINE = 5, + ACPI_EINJ_INSTRUCTION_RESERVED = 6 /* 6 and greater are reserved */ +}; + +typedef struct acpi_einj_error_type_with_addr +{ + UINT32 ErrorType; + UINT32 VendorStructOffset; + UINT32 Flags; + UINT32 ApicId; + UINT64 Address; + UINT64 Range; + UINT32 PcieId; + +} ACPI_EINJ_ERROR_TYPE_WITH_ADDR; + +typedef struct acpi_einj_vendor +{ + UINT32 Length; + UINT32 PcieId; + UINT16 VendorId; + UINT16 DeviceId; + UINT8 RevisionId; + UINT8 Reserved[3]; + +} ACPI_EINJ_VENDOR; + + +/* EINJ Trigger Error Action Table */ + +typedef struct acpi_einj_trigger +{ + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; + +} ACPI_EINJ_TRIGGER; + +/* Command status return values */ + +enum AcpiEinjCommandStatus +{ + ACPI_EINJ_SUCCESS = 0, + ACPI_EINJ_FAILURE = 1, + ACPI_EINJ_INVALID_ACCESS = 2, + ACPI_EINJ_STATUS_RESERVED = 3 /* 3 and greater are reserved */ +}; + + +/* Error types returned from ACPI_EINJ_GET_ERROR_TYPE (bitfield) */ + +#define ACPI_EINJ_PROCESSOR_CORRECTABLE (1) +#define ACPI_EINJ_PROCESSOR_UNCORRECTABLE (1<<1) +#define ACPI_EINJ_PROCESSOR_FATAL (1<<2) +#define ACPI_EINJ_MEMORY_CORRECTABLE (1<<3) +#define ACPI_EINJ_MEMORY_UNCORRECTABLE (1<<4) +#define ACPI_EINJ_MEMORY_FATAL (1<<5) +#define ACPI_EINJ_PCIX_CORRECTABLE (1<<6) +#define ACPI_EINJ_PCIX_UNCORRECTABLE (1<<7) +#define ACPI_EINJ_PCIX_FATAL (1<<8) +#define ACPI_EINJ_PLATFORM_CORRECTABLE (1<<9) +#define ACPI_EINJ_PLATFORM_UNCORRECTABLE (1<<10) +#define ACPI_EINJ_PLATFORM_FATAL (1<<11) +#define ACPI_EINJ_VENDOR_DEFINED (1<<31) + + +/******************************************************************************* + * + * ERST - Error Record Serialization Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_erst +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 HeaderLength; + UINT32 Reserved; + UINT32 Entries; + +} ACPI_TABLE_ERST; + + +/* ERST Serialization Entries (actions) */ + +typedef struct acpi_erst_entry +{ + ACPI_WHEA_HEADER WheaHeader; /* Common header for WHEA tables */ + +} ACPI_ERST_ENTRY; + +/* Masks for Flags field above */ + +#define ACPI_ERST_PRESERVE (1) + +/* Values for Action field above */ + +enum AcpiErstActions +{ + ACPI_ERST_BEGIN_WRITE = 0, + ACPI_ERST_BEGIN_READ = 1, + ACPI_ERST_BEGIN_CLEAR = 2, + ACPI_ERST_END = 3, + ACPI_ERST_SET_RECORD_OFFSET = 4, + ACPI_ERST_EXECUTE_OPERATION = 5, + ACPI_ERST_CHECK_BUSY_STATUS = 6, + ACPI_ERST_GET_COMMAND_STATUS = 7, + ACPI_ERST_GET_RECORD_ID = 8, + ACPI_ERST_SET_RECORD_ID = 9, + ACPI_ERST_GET_RECORD_COUNT = 10, + ACPI_ERST_BEGIN_DUMMY_WRIITE = 11, + ACPI_ERST_NOT_USED = 12, + ACPI_ERST_GET_ERROR_RANGE = 13, + ACPI_ERST_GET_ERROR_LENGTH = 14, + ACPI_ERST_GET_ERROR_ATTRIBUTES = 15, + ACPI_ERST_EXECUTE_TIMINGS = 16, + ACPI_ERST_ACTION_RESERVED = 17 /* 17 and greater are reserved */ +}; + +/* Values for Instruction field above */ + +enum AcpiErstInstructions +{ + ACPI_ERST_READ_REGISTER = 0, + ACPI_ERST_READ_REGISTER_VALUE = 1, + ACPI_ERST_WRITE_REGISTER = 2, + ACPI_ERST_WRITE_REGISTER_VALUE = 3, + ACPI_ERST_NOOP = 4, + ACPI_ERST_LOAD_VAR1 = 5, + ACPI_ERST_LOAD_VAR2 = 6, + ACPI_ERST_STORE_VAR1 = 7, + ACPI_ERST_ADD = 8, + ACPI_ERST_SUBTRACT = 9, + ACPI_ERST_ADD_VALUE = 10, + ACPI_ERST_SUBTRACT_VALUE = 11, + ACPI_ERST_STALL = 12, + ACPI_ERST_STALL_WHILE_TRUE = 13, + ACPI_ERST_SKIP_NEXT_IF_TRUE = 14, + ACPI_ERST_GOTO = 15, + ACPI_ERST_SET_SRC_ADDRESS_BASE = 16, + ACPI_ERST_SET_DST_ADDRESS_BASE = 17, + ACPI_ERST_MOVE_DATA = 18, + ACPI_ERST_INSTRUCTION_RESERVED = 19 /* 19 and greater are reserved */ +}; + +/* Command status return values */ + +enum AcpiErstCommandStatus +{ + ACPI_ERST_SUCESS = 0, + ACPI_ERST_NO_SPACE = 1, + ACPI_ERST_NOT_AVAILABLE = 2, + ACPI_ERST_FAILURE = 3, + ACPI_ERST_RECORD_EMPTY = 4, + ACPI_ERST_NOT_FOUND = 5, + ACPI_ERST_STATUS_RESERVED = 6 /* 6 and greater are reserved */ +}; + + +/* Error Record Serialization Information */ + +typedef struct acpi_erst_info +{ + UINT16 Signature; /* Should be "ER" */ + UINT8 Data[48]; + +} ACPI_ERST_INFO; + + +/******************************************************************************* + * + * FPDT - Firmware Performance Data Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_fpdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_FPDT; + + +/* FPDT subtable header (Performance Record Structure) */ + +typedef struct acpi_fpdt_header +{ + UINT16 Type; + UINT8 Length; + UINT8 Revision; + +} ACPI_FPDT_HEADER; + +/* Values for Type field above */ + +enum AcpiFpdtType +{ + ACPI_FPDT_TYPE_BOOT = 0, + ACPI_FPDT_TYPE_S3PERF = 1 +}; + + +/* + * FPDT subtables + */ + +/* 0: Firmware Basic Boot Performance Record */ + +typedef struct acpi_fpdt_boot_pointer +{ + ACPI_FPDT_HEADER Header; + UINT8 Reserved[4]; + UINT64 Address; + +} ACPI_FPDT_BOOT_POINTER; + + +/* 1: S3 Performance Table Pointer Record */ + +typedef struct acpi_fpdt_s3pt_pointer +{ + ACPI_FPDT_HEADER Header; + UINT8 Reserved[4]; + UINT64 Address; + +} ACPI_FPDT_S3PT_POINTER; + + +/* + * S3PT - S3 Performance Table. This table is pointed to by the + * S3 Pointer Record above. + */ +typedef struct acpi_table_s3pt +{ + UINT8 Signature[4]; /* "S3PT" */ + UINT32 Length; + +} ACPI_TABLE_S3PT; + + +/* + * S3PT Subtables (Not part of the actual FPDT) + */ + +/* Values for Type field in S3PT header */ + +enum AcpiS3ptType +{ + ACPI_S3PT_TYPE_RESUME = 0, + ACPI_S3PT_TYPE_SUSPEND = 1, + ACPI_FPDT_BOOT_PERFORMANCE = 2 +}; + +typedef struct acpi_s3pt_resume +{ + ACPI_FPDT_HEADER Header; + UINT32 ResumeCount; + UINT64 FullResume; + UINT64 AverageResume; + +} ACPI_S3PT_RESUME; + +typedef struct acpi_s3pt_suspend +{ + ACPI_FPDT_HEADER Header; + UINT64 SuspendStart; + UINT64 SuspendEnd; + +} ACPI_S3PT_SUSPEND; + + +/* + * FPDT Boot Performance Record (Not part of the actual FPDT) + */ +typedef struct acpi_fpdt_boot +{ + ACPI_FPDT_HEADER Header; + UINT8 Reserved[4]; + UINT64 ResetEnd; + UINT64 LoadStart; + UINT64 StartupStart; + UINT64 ExitServicesEntry; + UINT64 ExitServicesExit; + +} ACPI_FPDT_BOOT; + + +/******************************************************************************* + * + * GTDT - Generic Timer Description Table (ACPI 5.1) + * Version 2 + * + ******************************************************************************/ + +typedef struct acpi_table_gtdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 CounterBlockAddresss; + UINT32 Reserved; + UINT32 SecureEl1Interrupt; + UINT32 SecureEl1Flags; + UINT32 NonSecureEl1Interrupt; + UINT32 NonSecureEl1Flags; + UINT32 VirtualTimerInterrupt; + UINT32 VirtualTimerFlags; + UINT32 NonSecureEl2Interrupt; + UINT32 NonSecureEl2Flags; + UINT64 CounterReadBlockAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; + +} ACPI_TABLE_GTDT; + +/* Flag Definitions: Timer Block Physical Timers and Virtual timers */ + +#define ACPI_GTDT_INTERRUPT_MODE (1) +#define ACPI_GTDT_INTERRUPT_POLARITY (1<<1) +#define ACPI_GTDT_ALWAYS_ON (1<<2) + + +/* Common GTDT subtable header */ + +typedef struct acpi_gtdt_header +{ + UINT8 Type; + UINT16 Length; + +} ACPI_GTDT_HEADER; + +/* Values for GTDT subtable type above */ + +enum AcpiGtdtType +{ + ACPI_GTDT_TYPE_TIMER_BLOCK = 0, + ACPI_GTDT_TYPE_WATCHDOG = 1, + ACPI_GTDT_TYPE_RESERVED = 2 /* 2 and greater are reserved */ +}; + + +/* GTDT Subtables, correspond to Type in acpi_gtdt_header */ + +/* 0: Generic Timer Block */ + +typedef struct acpi_gtdt_timer_block +{ + ACPI_GTDT_HEADER Header; + UINT8 Reserved; + UINT64 BlockAddress; + UINT32 TimerCount; + UINT32 TimerOffset; + +} ACPI_GTDT_TIMER_BLOCK; + +/* Timer Sub-Structure, one per timer */ + +typedef struct acpi_gtdt_timer_entry +{ + UINT8 FrameNumber; + UINT8 Reserved[3]; + UINT64 BaseAddress; + UINT64 El0BaseAddress; + UINT32 TimerInterrupt; + UINT32 TimerFlags; + UINT32 VirtualTimerInterrupt; + UINT32 VirtualTimerFlags; + UINT32 CommonFlags; + +} ACPI_GTDT_TIMER_ENTRY; + +/* Flag Definitions: TimerFlags and VirtualTimerFlags above */ + +#define ACPI_GTDT_GT_IRQ_MODE (1) +#define ACPI_GTDT_GT_IRQ_POLARITY (1<<1) + +/* Flag Definitions: CommonFlags above */ + +#define ACPI_GTDT_GT_IS_SECURE_TIMER (1) +#define ACPI_GTDT_GT_ALWAYS_ON (1<<1) + + +/* 1: SBSA Generic Watchdog Structure */ + +typedef struct acpi_gtdt_watchdog +{ + ACPI_GTDT_HEADER Header; + UINT8 Reserved; + UINT64 RefreshFrameAddress; + UINT64 ControlFrameAddress; + UINT32 TimerInterrupt; + UINT32 TimerFlags; + +} ACPI_GTDT_WATCHDOG; + +/* Flag Definitions: TimerFlags above */ + +#define ACPI_GTDT_WATCHDOG_IRQ_MODE (1) +#define ACPI_GTDT_WATCHDOG_IRQ_POLARITY (1<<1) +#define ACPI_GTDT_WATCHDOG_SECURE (1<<2) + + +/******************************************************************************* + * + * HEST - Hardware Error Source Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_hest +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 ErrorSourceCount; + +} ACPI_TABLE_HEST; + + +/* HEST subtable header */ + +typedef struct acpi_hest_header +{ + UINT16 Type; + UINT16 SourceId; + +} ACPI_HEST_HEADER; + + +/* Values for Type field above for subtables */ + +enum AcpiHestTypes +{ + ACPI_HEST_TYPE_IA32_CHECK = 0, + ACPI_HEST_TYPE_IA32_CORRECTED_CHECK = 1, + ACPI_HEST_TYPE_IA32_NMI = 2, + ACPI_HEST_TYPE_NOT_USED3 = 3, + ACPI_HEST_TYPE_NOT_USED4 = 4, + ACPI_HEST_TYPE_NOT_USED5 = 5, + ACPI_HEST_TYPE_AER_ROOT_PORT = 6, + ACPI_HEST_TYPE_AER_ENDPOINT = 7, + ACPI_HEST_TYPE_AER_BRIDGE = 8, + ACPI_HEST_TYPE_GENERIC_ERROR = 9, + ACPI_HEST_TYPE_GENERIC_ERROR_V2 = 10, + ACPI_HEST_TYPE_IA32_DEFERRED_CHECK = 11, + ACPI_HEST_TYPE_RESERVED = 12 /* 12 and greater are reserved */ +}; + + +/* + * HEST substructures contained in subtables + */ + +/* + * IA32 Error Bank(s) - Follows the ACPI_HEST_IA_MACHINE_CHECK and + * ACPI_HEST_IA_CORRECTED structures. + */ +typedef struct acpi_hest_ia_error_bank +{ + UINT8 BankNumber; + UINT8 ClearStatusOnInit; + UINT8 StatusFormat; + UINT8 Reserved; + UINT32 ControlRegister; + UINT64 ControlData; + UINT32 StatusRegister; + UINT32 AddressRegister; + UINT32 MiscRegister; + +} ACPI_HEST_IA_ERROR_BANK; + + +/* Common HEST sub-structure for PCI/AER structures below (6,7,8) */ + +typedef struct acpi_hest_aer_common +{ + UINT16 Reserved1; + UINT8 Flags; + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; /* Bus and Segment numbers */ + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT16 Reserved2; + UINT32 UncorrectableMask; + UINT32 UncorrectableSeverity; + UINT32 CorrectableMask; + UINT32 AdvancedCapabilities; + +} ACPI_HEST_AER_COMMON; + +/* Masks for HEST Flags fields */ + +#define ACPI_HEST_FIRMWARE_FIRST (1) +#define ACPI_HEST_GLOBAL (1<<1) +#define ACPI_HEST_GHES_ASSIST (1<<2) + +/* + * Macros to access the bus/segment numbers in Bus field above: + * Bus number is encoded in bits 7:0 + * Segment number is encoded in bits 23:8 + */ +#define ACPI_HEST_BUS(Bus) ((Bus) & 0xFF) +#define ACPI_HEST_SEGMENT(Bus) (((Bus) >> 8) & 0xFFFF) + + +/* Hardware Error Notification */ + +typedef struct acpi_hest_notify +{ + UINT8 Type; + UINT8 Length; + UINT16 ConfigWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 PollingThresholdValue; + UINT32 PollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; + +} ACPI_HEST_NOTIFY; + +/* Values for Notify Type field above */ + +enum AcpiHestNotifyTypes +{ + ACPI_HEST_NOTIFY_POLLED = 0, + ACPI_HEST_NOTIFY_EXTERNAL = 1, + ACPI_HEST_NOTIFY_LOCAL = 2, + ACPI_HEST_NOTIFY_SCI = 3, + ACPI_HEST_NOTIFY_NMI = 4, + ACPI_HEST_NOTIFY_CMCI = 5, /* ACPI 5.0 */ + ACPI_HEST_NOTIFY_MCE = 6, /* ACPI 5.0 */ + ACPI_HEST_NOTIFY_GPIO = 7, /* ACPI 6.0 */ + ACPI_HEST_NOTIFY_SEA = 8, /* ACPI 6.1 */ + ACPI_HEST_NOTIFY_SEI = 9, /* ACPI 6.1 */ + ACPI_HEST_NOTIFY_GSIV = 10, /* ACPI 6.1 */ + ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED = 11, /* ACPI 6.2 */ + ACPI_HEST_NOTIFY_RESERVED = 12 /* 12 and greater are reserved */ +}; + +/* Values for ConfigWriteEnable bitfield above */ + +#define ACPI_HEST_TYPE (1) +#define ACPI_HEST_POLL_INTERVAL (1<<1) +#define ACPI_HEST_POLL_THRESHOLD_VALUE (1<<2) +#define ACPI_HEST_POLL_THRESHOLD_WINDOW (1<<3) +#define ACPI_HEST_ERR_THRESHOLD_VALUE (1<<4) +#define ACPI_HEST_ERR_THRESHOLD_WINDOW (1<<5) + + +/* + * HEST subtables + */ + +/* 0: IA32 Machine Check Exception */ + +typedef struct acpi_hest_ia_machine_check +{ + ACPI_HEST_HEADER Header; + UINT16 Reserved1; + UINT8 Flags; /* See flags ACPI_HEST_GLOBAL, etc. above */ + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityData; + UINT64 GlobalControlData; + UINT8 NumHardwareBanks; + UINT8 Reserved3[7]; + +} ACPI_HEST_IA_MACHINE_CHECK; + + +/* 1: IA32 Corrected Machine Check */ + +typedef struct acpi_hest_ia_corrected +{ + ACPI_HEST_HEADER Header; + UINT16 Reserved1; + UINT8 Flags; /* See flags ACPI_HEST_GLOBAL, etc. above */ + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + ACPI_HEST_NOTIFY Notify; + UINT8 NumHardwareBanks; + UINT8 Reserved2[3]; + +} ACPI_HEST_IA_CORRECTED; + + +/* 2: IA32 Non-Maskable Interrupt */ + +typedef struct acpi_hest_ia_nmi +{ + ACPI_HEST_HEADER Header; + UINT32 Reserved; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + +} ACPI_HEST_IA_NMI; + + +/* 3,4,5: Not used */ + +/* 6: PCI Express Root Port AER */ + +typedef struct acpi_hest_aer_root +{ + ACPI_HEST_HEADER Header; + ACPI_HEST_AER_COMMON Aer; + UINT32 RootErrorCommand; + +} ACPI_HEST_AER_ROOT; + + +/* 7: PCI Express AER (AER Endpoint) */ + +typedef struct acpi_hest_aer +{ + ACPI_HEST_HEADER Header; + ACPI_HEST_AER_COMMON Aer; + +} ACPI_HEST_AER; + + +/* 8: PCI Express/PCI-X Bridge AER */ + +typedef struct acpi_hest_aer_bridge +{ + ACPI_HEST_HEADER Header; + ACPI_HEST_AER_COMMON Aer; + UINT32 UncorrectableMask2; + UINT32 UncorrectableSeverity2; + UINT32 AdvancedCapabilities2; + +} ACPI_HEST_AER_BRIDGE; + + +/* 9: Generic Hardware Error Source */ + +typedef struct acpi_hest_generic +{ + ACPI_HEST_HEADER Header; + UINT16 RelatedSourceId; + UINT8 Reserved; + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + ACPI_GENERIC_ADDRESS ErrorStatusAddress; + ACPI_HEST_NOTIFY Notify; + UINT32 ErrorBlockLength; + +} ACPI_HEST_GENERIC; + + +/* 10: Generic Hardware Error Source, version 2 */ + +typedef struct acpi_hest_generic_v2 +{ + ACPI_HEST_HEADER Header; + UINT16 RelatedSourceId; + UINT8 Reserved; + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + ACPI_GENERIC_ADDRESS ErrorStatusAddress; + ACPI_HEST_NOTIFY Notify; + UINT32 ErrorBlockLength; + ACPI_GENERIC_ADDRESS ReadAckRegister; + UINT64 ReadAckPreserve; + UINT64 ReadAckWrite; + +} ACPI_HEST_GENERIC_V2; + + +/* Generic Error Status block */ + +typedef struct acpi_hest_generic_status +{ + UINT32 BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; + +} ACPI_HEST_GENERIC_STATUS; + +/* Values for BlockStatus flags above */ + +#define ACPI_HEST_UNCORRECTABLE (1) +#define ACPI_HEST_CORRECTABLE (1<<1) +#define ACPI_HEST_MULTIPLE_UNCORRECTABLE (1<<2) +#define ACPI_HEST_MULTIPLE_CORRECTABLE (1<<3) +#define ACPI_HEST_ERROR_ENTRY_COUNT (0xFF<<4) /* 8 bits, error count */ + + +/* Generic Error Data entry */ + +typedef struct acpi_hest_generic_data +{ + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; + +} ACPI_HEST_GENERIC_DATA; + +/* Extension for revision 0x0300 */ + +typedef struct acpi_hest_generic_data_v300 +{ + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; + UINT64 TimeStamp; + +} ACPI_HEST_GENERIC_DATA_V300; + +/* Values for ErrorSeverity above */ + +#define ACPI_HEST_GEN_ERROR_RECOVERABLE 0 +#define ACPI_HEST_GEN_ERROR_FATAL 1 +#define ACPI_HEST_GEN_ERROR_CORRECTED 2 +#define ACPI_HEST_GEN_ERROR_NONE 3 + +/* Flags for ValidationBits above */ + +#define ACPI_HEST_GEN_VALID_FRU_ID (1) +#define ACPI_HEST_GEN_VALID_FRU_STRING (1<<1) +#define ACPI_HEST_GEN_VALID_TIMESTAMP (1<<2) + + +/* 11: IA32 Deferred Machine Check Exception (ACPI 6.2) */ + +typedef struct acpi_hest_ia_deferred_check +{ + ACPI_HEST_HEADER Header; + UINT16 Reserved1; + UINT8 Flags; /* See flags ACPI_HEST_GLOBAL, etc. above */ + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + ACPI_HEST_NOTIFY Notify; + UINT8 NumHardwareBanks; + UINT8 Reserved2[3]; + +} ACPI_HEST_IA_DEFERRED_CHECK; + + +/******************************************************************************* + * + * HMAT - Heterogeneous Memory Attributes Table (ACPI 6.2) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_hmat +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Reserved; + +} ACPI_TABLE_HMAT; + + +/* Values for HMAT structure types */ + +enum AcpiHmatType +{ + ACPI_HMAT_TYPE_ADDRESS_RANGE = 0, /* Memory subystem address range */ + ACPI_HMAT_TYPE_LOCALITY = 1, /* System locality latency and bandwidth information */ + ACPI_HMAT_TYPE_CACHE = 2, /* Memory side cache information */ + ACPI_HMAT_TYPE_RESERVED = 3 /* 3 and greater are reserved */ +}; + +typedef struct acpi_hmat_structure +{ + UINT16 Type; + UINT16 Reserved; + UINT32 Length; + +} ACPI_HMAT_STRUCTURE; + + +/* + * HMAT Structures, correspond to Type in ACPI_HMAT_STRUCTURE + */ + +/* 0: Memory subystem address range */ + +typedef struct acpi_hmat_address_range +{ + ACPI_HMAT_STRUCTURE Header; + UINT16 Flags; + UINT16 Reserved1; + UINT32 ProcessorPD; /* Processor proximity domain */ + UINT32 MemoryPD; /* Memory proximity domain */ + UINT32 Reserved2; + UINT64 PhysicalAddressBase; /* Physical address range base */ + UINT64 PhysicalAddressLength; /* Physical address range length */ + +} ACPI_HMAT_ADDRESS_RANGE; + +/* Masks for Flags field above */ + +#define ACPI_HMAT_PROCESSOR_PD_VALID (1) /* 1: ProcessorPD field is valid */ +#define ACPI_HMAT_MEMORY_PD_VALID (1<<1) /* 1: MemoryPD field is valid */ +#define ACPI_HMAT_RESERVATION_HINT (1<<2) /* 1: Reservation hint */ + + +/* 1: System locality latency and bandwidth information */ + +typedef struct acpi_hmat_locality +{ + ACPI_HMAT_STRUCTURE Header; + UINT8 Flags; + UINT8 DataType; + UINT16 Reserved1; + UINT32 NumberOfInitiatorPDs; + UINT32 NumberOfTargetPDs; + UINT32 Reserved2; + UINT64 EntryBaseUnit; + +} ACPI_HMAT_LOCALITY; + +/* Masks for Flags field above */ + +#define ACPI_HMAT_MEMORY_HIERARCHY (0x0F) + +/* Values for Memory Hierarchy flag */ + +#define ACPI_HMAT_MEMORY 0 +#define ACPI_HMAT_LAST_LEVEL_CACHE 1 +#define ACPI_HMAT_1ST_LEVEL_CACHE 2 +#define ACPI_HMAT_2ND_LEVEL_CACHE 3 +#define ACPI_HMAT_3RD_LEVEL_CACHE 4 + +/* Values for DataType field above */ + +#define ACPI_HMAT_ACCESS_LATENCY 0 +#define ACPI_HMAT_READ_LATENCY 1 +#define ACPI_HMAT_WRITE_LATENCY 2 +#define ACPI_HMAT_ACCESS_BANDWIDTH 3 +#define ACPI_HMAT_READ_BANDWIDTH 4 +#define ACPI_HMAT_WRITE_BANDWIDTH 5 + + +/* 2: Memory side cache information */ + +typedef struct acpi_hmat_cache +{ + ACPI_HMAT_STRUCTURE Header; + UINT32 MemoryPD; + UINT32 Reserved1; + UINT64 CacheSize; + UINT32 CacheAttributes; + UINT16 Reserved2; + UINT16 NumberOfSMBIOSHandles; + +} ACPI_HMAT_CACHE; + +/* Masks for CacheAttributes field above */ + +#define ACPI_HMAT_TOTAL_CACHE_LEVEL (0x0000000F) +#define ACPI_HMAT_CACHE_LEVEL (0x000000F0) +#define ACPI_HMAT_CACHE_ASSOCIATIVITY (0x00000F00) +#define ACPI_HMAT_WRITE_POLICY (0x0000F000) +#define ACPI_HMAT_CACHE_LINE_SIZE (0xFFFF0000) + +/* Values for cache associativity flag */ + +#define ACPI_HMAT_CA_NONE (0) +#define ACPI_HMAT_CA_DIRECT_MAPPED (1) +#define ACPI_HMAT_CA_COMPLEX_CACHE_INDEXING (2) + +/* Values for write policy flag */ + +#define ACPI_HMAT_CP_NONE (0) +#define ACPI_HMAT_CP_WB (1) +#define ACPI_HMAT_CP_WT (2) + + +/******************************************************************************* + * + * HPET - High Precision Event Timer table + * Version 1 + * + * Conforms to "IA-PC HPET (High Precision Event Timers) Specification", + * Version 1.0a, October 2004 + * + ******************************************************************************/ + +typedef struct acpi_table_hpet +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Id; /* Hardware ID of event timer block */ + ACPI_GENERIC_ADDRESS Address; /* Address of event timer block */ + UINT8 Sequence; /* HPET sequence number */ + UINT16 MinimumTick; /* Main counter min tick, periodic mode */ + UINT8 Flags; + +} ACPI_TABLE_HPET; + +/* Masks for Flags field above */ + +#define ACPI_HPET_PAGE_PROTECT_MASK (3) + +/* Values for Page Protect flags */ + +enum AcpiHpetPageProtect +{ + ACPI_HPET_NO_PAGE_PROTECT = 0, + ACPI_HPET_PAGE_PROTECT4 = 1, + ACPI_HPET_PAGE_PROTECT64 = 2 +}; + + +/******************************************************************************* + * + * IBFT - Boot Firmware Table + * Version 1 + * + * Conforms to "iSCSI Boot Firmware Table (iBFT) as Defined in ACPI 3.0b + * Specification", Version 1.01, March 1, 2007 + * + * Note: It appears that this table is not intended to appear in the RSDT/XSDT. + * Therefore, it is not currently supported by the disassembler. + * + ******************************************************************************/ + +typedef struct acpi_table_ibft +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Reserved[12]; + +} ACPI_TABLE_IBFT; + + +/* IBFT common subtable header */ + +typedef struct acpi_ibft_header +{ + UINT8 Type; + UINT8 Version; + UINT16 Length; + UINT8 Index; + UINT8 Flags; + +} ACPI_IBFT_HEADER; + +/* Values for Type field above */ + +enum AcpiIbftType +{ + ACPI_IBFT_TYPE_NOT_USED = 0, + ACPI_IBFT_TYPE_CONTROL = 1, + ACPI_IBFT_TYPE_INITIATOR = 2, + ACPI_IBFT_TYPE_NIC = 3, + ACPI_IBFT_TYPE_TARGET = 4, + ACPI_IBFT_TYPE_EXTENSIONS = 5, + ACPI_IBFT_TYPE_RESERVED = 6 /* 6 and greater are reserved */ +}; + + +/* IBFT subtables */ + +typedef struct acpi_ibft_control +{ + ACPI_IBFT_HEADER Header; + UINT16 Extensions; + UINT16 InitiatorOffset; + UINT16 Nic0Offset; + UINT16 Target0Offset; + UINT16 Nic1Offset; + UINT16 Target1Offset; + +} ACPI_IBFT_CONTROL; + +typedef struct acpi_ibft_initiator +{ + ACPI_IBFT_HEADER Header; + UINT8 SnsServer[16]; + UINT8 SlpServer[16]; + UINT8 PrimaryServer[16]; + UINT8 SecondaryServer[16]; + UINT16 NameLength; + UINT16 NameOffset; + +} ACPI_IBFT_INITIATOR; + +typedef struct acpi_ibft_nic +{ + ACPI_IBFT_HEADER Header; + UINT8 IpAddress[16]; + UINT8 SubnetMaskPrefix; + UINT8 Origin; + UINT8 Gateway[16]; + UINT8 PrimaryDns[16]; + UINT8 SecondaryDns[16]; + UINT8 Dhcp[16]; + UINT16 Vlan; + UINT8 MacAddress[6]; + UINT16 PciAddress; + UINT16 NameLength; + UINT16 NameOffset; + +} ACPI_IBFT_NIC; + +typedef struct acpi_ibft_target +{ + ACPI_IBFT_HEADER Header; + UINT8 TargetIpAddress[16]; + UINT16 TargetIpSocket; + UINT8 TargetBootLun[8]; + UINT8 ChapType; + UINT8 NicAssociation; + UINT16 TargetNameLength; + UINT16 TargetNameOffset; + UINT16 ChapNameLength; + UINT16 ChapNameOffset; + UINT16 ChapSecretLength; + UINT16 ChapSecretOffset; + UINT16 ReverseChapNameLength; + UINT16 ReverseChapNameOffset; + UINT16 ReverseChapSecretLength; + UINT16 ReverseChapSecretOffset; + +} ACPI_IBFT_TARGET; + + +/* Reset to default packing */ + +#pragma pack() + +#endif /* __ACTBL1_H__ */ diff --git a/ports/acpica/include/actbl2.h b/ports/acpica/include/actbl2.h new file mode 100644 index 0000000..4b3d460 --- /dev/null +++ b/ports/acpica/include/actbl2.h @@ -0,0 +1,2150 @@ +/****************************************************************************** + * + * Name: actbl2.h - ACPI Table Definitions (tables not in ACPI spec) + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACTBL2_H__ +#define __ACTBL2_H__ + + +/******************************************************************************* + * + * Additional ACPI Tables (2) + * + * These tables are not consumed directly by the ACPICA subsystem, but are + * included here to support device drivers and the AML disassembler. + * + ******************************************************************************/ + + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_IORT "IORT" /* IO Remapping Table */ +#define ACPI_SIG_IVRS "IVRS" /* I/O Virtualization Reporting Structure */ +#define ACPI_SIG_LPIT "LPIT" /* Low Power Idle Table */ +#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */ +#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */ +#define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */ +#define ACPI_SIG_MPST "MPST" /* Memory Power State Table */ +#define ACPI_SIG_MSCT "MSCT" /* Maximum System Characteristics Table */ +#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */ +#define ACPI_SIG_MTMR "MTMR" /* MID Timer table */ +#define ACPI_SIG_NFIT "NFIT" /* NVDIMM Firmware Interface Table */ +#define ACPI_SIG_PCCT "PCCT" /* Platform Communications Channel Table */ +#define ACPI_SIG_PDTT "PDTT" /* Platform Debug Trigger Table */ +#define ACPI_SIG_PMTT "PMTT" /* Platform Memory Topology Table */ +#define ACPI_SIG_PPTT "PPTT" /* Processor Properties Topology Table */ +#define ACPI_SIG_RASF "RASF" /* RAS Feature table */ +#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */ +#define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */ +#define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */ + + +/* + * All tables must be byte-packed to match the ACPI specification, since + * the tables are provided by the system BIOS. + */ +#pragma pack(1) + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/******************************************************************************* + * + * IORT - IO Remapping Table + * + * Conforms to "IO Remapping Table System Software on ARM Platforms", + * Document number: ARM DEN 0049C, May 2017 + * + ******************************************************************************/ + +typedef struct acpi_table_iort +{ + ACPI_TABLE_HEADER Header; + UINT32 NodeCount; + UINT32 NodeOffset; + UINT32 Reserved; + +} ACPI_TABLE_IORT; + + +/* + * IORT subtables + */ +typedef struct acpi_iort_node +{ + UINT8 Type; + UINT16 Length; + UINT8 Revision; + UINT32 Reserved; + UINT32 MappingCount; + UINT32 MappingOffset; + char NodeData[1]; + +} ACPI_IORT_NODE; + +/* Values for subtable Type above */ + +enum AcpiIortNodeType +{ + ACPI_IORT_NODE_ITS_GROUP = 0x00, + ACPI_IORT_NODE_NAMED_COMPONENT = 0x01, + ACPI_IORT_NODE_PCI_ROOT_COMPLEX = 0x02, + ACPI_IORT_NODE_SMMU = 0x03, + ACPI_IORT_NODE_SMMU_V3 = 0x04 +}; + + +typedef struct acpi_iort_id_mapping +{ + UINT32 InputBase; /* Lowest value in input range */ + UINT32 IdCount; /* Number of IDs */ + UINT32 OutputBase; /* Lowest value in output range */ + UINT32 OutputReference; /* A reference to the output node */ + UINT32 Flags; + +} ACPI_IORT_ID_MAPPING; + +/* Masks for Flags field above for IORT subtable */ + +#define ACPI_IORT_ID_SINGLE_MAPPING (1) + + +typedef struct acpi_iort_memory_access +{ + UINT32 CacheCoherency; + UINT8 Hints; + UINT16 Reserved; + UINT8 MemoryFlags; + +} ACPI_IORT_MEMORY_ACCESS; + +/* Values for CacheCoherency field above */ + +#define ACPI_IORT_NODE_COHERENT 0x00000001 /* The device node is fully coherent */ +#define ACPI_IORT_NODE_NOT_COHERENT 0x00000000 /* The device node is not coherent */ + +/* Masks for Hints field above */ + +#define ACPI_IORT_HT_TRANSIENT (1) +#define ACPI_IORT_HT_WRITE (1<<1) +#define ACPI_IORT_HT_READ (1<<2) +#define ACPI_IORT_HT_OVERRIDE (1<<3) + +/* Masks for MemoryFlags field above */ + +#define ACPI_IORT_MF_COHERENCY (1) +#define ACPI_IORT_MF_ATTRIBUTES (1<<1) + + +/* + * IORT node specific subtables + */ +typedef struct acpi_iort_its_group +{ + UINT32 ItsCount; + UINT32 Identifiers[1]; /* GIC ITS identifier arrary */ + +} ACPI_IORT_ITS_GROUP; + + +typedef struct acpi_iort_named_component +{ + UINT32 NodeFlags; + UINT64 MemoryProperties; /* Memory access properties */ + UINT8 MemoryAddressLimit; /* Memory address size limit */ + char DeviceName[1]; /* Path of namespace object */ + +} ACPI_IORT_NAMED_COMPONENT; + + +typedef struct acpi_iort_root_complex +{ + UINT64 MemoryProperties; /* Memory access properties */ + UINT32 AtsAttribute; + UINT32 PciSegmentNumber; + +} ACPI_IORT_ROOT_COMPLEX; + +/* Values for AtsAttribute field above */ + +#define ACPI_IORT_ATS_SUPPORTED 0x00000001 /* The root complex supports ATS */ +#define ACPI_IORT_ATS_UNSUPPORTED 0x00000000 /* The root complex doesn't support ATS */ + + +typedef struct acpi_iort_smmu +{ + UINT64 BaseAddress; /* SMMU base address */ + UINT64 Span; /* Length of memory range */ + UINT32 Model; + UINT32 Flags; + UINT32 GlobalInterruptOffset; + UINT32 ContextInterruptCount; + UINT32 ContextInterruptOffset; + UINT32 PmuInterruptCount; + UINT32 PmuInterruptOffset; + UINT64 Interrupts[1]; /* Interrupt array */ + +} ACPI_IORT_SMMU; + +/* Values for Model field above */ + +#define ACPI_IORT_SMMU_V1 0x00000000 /* Generic SMMUv1 */ +#define ACPI_IORT_SMMU_V2 0x00000001 /* Generic SMMUv2 */ +#define ACPI_IORT_SMMU_CORELINK_MMU400 0x00000002 /* ARM Corelink MMU-400 */ +#define ACPI_IORT_SMMU_CORELINK_MMU500 0x00000003 /* ARM Corelink MMU-500 */ +#define ACPI_IORT_SMMU_CORELINK_MMU401 0x00000004 /* ARM Corelink MMU-401 */ +#define ACPI_IORT_SMMU_CAVIUM_THUNDERX 0x00000005 /* Cavium ThunderX SMMUv2 */ + +/* Masks for Flags field above */ + +#define ACPI_IORT_SMMU_DVM_SUPPORTED (1) +#define ACPI_IORT_SMMU_COHERENT_WALK (1<<1) + +/* Global interrupt format */ + +typedef struct acpi_iort_smmu_gsi +{ + UINT32 NSgIrpt; + UINT32 NSgIrptFlags; + UINT32 NSgCfgIrpt; + UINT32 NSgCfgIrptFlags; + +} ACPI_IORT_SMMU_GSI; + + +typedef struct acpi_iort_smmu_v3 +{ + UINT64 BaseAddress; /* SMMUv3 base address */ + UINT32 Flags; + UINT32 Reserved; + UINT64 VatosAddress; + UINT32 Model; + UINT32 EventGsiv; + UINT32 PriGsiv; + UINT32 GerrGsiv; + UINT32 SyncGsiv; + UINT8 Pxm; + UINT8 Reserved1; + UINT16 Reserved2; + UINT32 IdMappingIndex; + +} ACPI_IORT_SMMU_V3; + +/* Values for Model field above */ + +#define ACPI_IORT_SMMU_V3_GENERIC 0x00000000 /* Generic SMMUv3 */ +#define ACPI_IORT_SMMU_V3_HISILICON_HI161X 0x00000001 /* HiSilicon Hi161x SMMUv3 */ +#define ACPI_IORT_SMMU_V3_CAVIUM_CN99XX 0x00000002 /* Cavium CN99xx SMMUv3 */ + +/* Masks for Flags field above */ + +#define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE (1) +#define ACPI_IORT_SMMU_V3_HTTU_OVERRIDE (1<<1) +#define ACPI_IORT_SMMU_V3_PXM_VALID (1<<3) + + +/******************************************************************************* + * + * IVRS - I/O Virtualization Reporting Structure + * Version 1 + * + * Conforms to "AMD I/O Virtualization Technology (IOMMU) Specification", + * Revision 1.26, February 2009. + * + ******************************************************************************/ + +typedef struct acpi_table_ivrs +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Info; /* Common virtualization info */ + UINT64 Reserved; + +} ACPI_TABLE_IVRS; + +/* Values for Info field above */ + +#define ACPI_IVRS_PHYSICAL_SIZE 0x00007F00 /* 7 bits, physical address size */ +#define ACPI_IVRS_VIRTUAL_SIZE 0x003F8000 /* 7 bits, virtual address size */ +#define ACPI_IVRS_ATS_RESERVED 0x00400000 /* ATS address translation range reserved */ + + +/* IVRS subtable header */ + +typedef struct acpi_ivrs_header +{ + UINT8 Type; /* Subtable type */ + UINT8 Flags; + UINT16 Length; /* Subtable length */ + UINT16 DeviceId; /* ID of IOMMU */ + +} ACPI_IVRS_HEADER; + +/* Values for subtable Type above */ + +enum AcpiIvrsType +{ + ACPI_IVRS_TYPE_HARDWARE = 0x10, + ACPI_IVRS_TYPE_MEMORY1 = 0x20, + ACPI_IVRS_TYPE_MEMORY2 = 0x21, + ACPI_IVRS_TYPE_MEMORY3 = 0x22 +}; + +/* Masks for Flags field above for IVHD subtable */ + +#define ACPI_IVHD_TT_ENABLE (1) +#define ACPI_IVHD_PASS_PW (1<<1) +#define ACPI_IVHD_RES_PASS_PW (1<<2) +#define ACPI_IVHD_ISOC (1<<3) +#define ACPI_IVHD_IOTLB (1<<4) + +/* Masks for Flags field above for IVMD subtable */ + +#define ACPI_IVMD_UNITY (1) +#define ACPI_IVMD_READ (1<<1) +#define ACPI_IVMD_WRITE (1<<2) +#define ACPI_IVMD_EXCLUSION_RANGE (1<<3) + + +/* + * IVRS subtables, correspond to Type in ACPI_IVRS_HEADER + */ + +/* 0x10: I/O Virtualization Hardware Definition Block (IVHD) */ + +typedef struct acpi_ivrs_hardware +{ + ACPI_IVRS_HEADER Header; + UINT16 CapabilityOffset; /* Offset for IOMMU control fields */ + UINT64 BaseAddress; /* IOMMU control registers */ + UINT16 PciSegmentGroup; + UINT16 Info; /* MSI number and unit ID */ + UINT32 Reserved; + +} ACPI_IVRS_HARDWARE; + +/* Masks for Info field above */ + +#define ACPI_IVHD_MSI_NUMBER_MASK 0x001F /* 5 bits, MSI message number */ +#define ACPI_IVHD_UNIT_ID_MASK 0x1F00 /* 5 bits, UnitID */ + + +/* + * Device Entries for IVHD subtable, appear after ACPI_IVRS_HARDWARE structure. + * Upper two bits of the Type field are the (encoded) length of the structure. + * Currently, only 4 and 8 byte entries are defined. 16 and 32 byte entries + * are reserved for future use but not defined. + */ +typedef struct acpi_ivrs_de_header +{ + UINT8 Type; + UINT16 Id; + UINT8 DataSetting; + +} ACPI_IVRS_DE_HEADER; + +/* Length of device entry is in the top two bits of Type field above */ + +#define ACPI_IVHD_ENTRY_LENGTH 0xC0 + +/* Values for device entry Type field above */ + +enum AcpiIvrsDeviceEntryType +{ + /* 4-byte device entries, all use ACPI_IVRS_DEVICE4 */ + + ACPI_IVRS_TYPE_PAD4 = 0, + ACPI_IVRS_TYPE_ALL = 1, + ACPI_IVRS_TYPE_SELECT = 2, + ACPI_IVRS_TYPE_START = 3, + ACPI_IVRS_TYPE_END = 4, + + /* 8-byte device entries */ + + ACPI_IVRS_TYPE_PAD8 = 64, + ACPI_IVRS_TYPE_NOT_USED = 65, + ACPI_IVRS_TYPE_ALIAS_SELECT = 66, /* Uses ACPI_IVRS_DEVICE8A */ + ACPI_IVRS_TYPE_ALIAS_START = 67, /* Uses ACPI_IVRS_DEVICE8A */ + ACPI_IVRS_TYPE_EXT_SELECT = 70, /* Uses ACPI_IVRS_DEVICE8B */ + ACPI_IVRS_TYPE_EXT_START = 71, /* Uses ACPI_IVRS_DEVICE8B */ + ACPI_IVRS_TYPE_SPECIAL = 72 /* Uses ACPI_IVRS_DEVICE8C */ +}; + +/* Values for Data field above */ + +#define ACPI_IVHD_INIT_PASS (1) +#define ACPI_IVHD_EINT_PASS (1<<1) +#define ACPI_IVHD_NMI_PASS (1<<2) +#define ACPI_IVHD_SYSTEM_MGMT (3<<4) +#define ACPI_IVHD_LINT0_PASS (1<<6) +#define ACPI_IVHD_LINT1_PASS (1<<7) + + +/* Types 0-4: 4-byte device entry */ + +typedef struct acpi_ivrs_device4 +{ + ACPI_IVRS_DE_HEADER Header; + +} ACPI_IVRS_DEVICE4; + +/* Types 66-67: 8-byte device entry */ + +typedef struct acpi_ivrs_device8a +{ + ACPI_IVRS_DE_HEADER Header; + UINT8 Reserved1; + UINT16 UsedId; + UINT8 Reserved2; + +} ACPI_IVRS_DEVICE8A; + +/* Types 70-71: 8-byte device entry */ + +typedef struct acpi_ivrs_device8b +{ + ACPI_IVRS_DE_HEADER Header; + UINT32 ExtendedData; + +} ACPI_IVRS_DEVICE8B; + +/* Values for ExtendedData above */ + +#define ACPI_IVHD_ATS_DISABLED (1<<31) + +/* Type 72: 8-byte device entry */ + +typedef struct acpi_ivrs_device8c +{ + ACPI_IVRS_DE_HEADER Header; + UINT8 Handle; + UINT16 UsedId; + UINT8 Variety; + +} ACPI_IVRS_DEVICE8C; + +/* Values for Variety field above */ + +#define ACPI_IVHD_IOAPIC 1 +#define ACPI_IVHD_HPET 2 + + +/* 0x20, 0x21, 0x22: I/O Virtualization Memory Definition Block (IVMD) */ + +typedef struct acpi_ivrs_memory +{ + ACPI_IVRS_HEADER Header; + UINT16 AuxData; + UINT64 Reserved; + UINT64 StartAddress; + UINT64 MemoryLength; + +} ACPI_IVRS_MEMORY; + + +/******************************************************************************* + * + * LPIT - Low Power Idle Table + * + * Conforms to "ACPI Low Power Idle Table (LPIT)" July 2014. + * + ******************************************************************************/ + +typedef struct acpi_table_lpit +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_LPIT; + + +/* LPIT subtable header */ + +typedef struct acpi_lpit_header +{ + UINT32 Type; /* Subtable type */ + UINT32 Length; /* Subtable length */ + UINT16 UniqueId; + UINT16 Reserved; + UINT32 Flags; + +} ACPI_LPIT_HEADER; + +/* Values for subtable Type above */ + +enum AcpiLpitType +{ + ACPI_LPIT_TYPE_NATIVE_CSTATE = 0x00, + ACPI_LPIT_TYPE_RESERVED = 0x01 /* 1 and above are reserved */ +}; + +/* Masks for Flags field above */ + +#define ACPI_LPIT_STATE_DISABLED (1) +#define ACPI_LPIT_NO_COUNTER (1<<1) + +/* + * LPIT subtables, correspond to Type in ACPI_LPIT_HEADER + */ + +/* 0x00: Native C-state instruction based LPI structure */ + +typedef struct acpi_lpit_native +{ + ACPI_LPIT_HEADER Header; + ACPI_GENERIC_ADDRESS EntryTrigger; + UINT32 Residency; + UINT32 Latency; + ACPI_GENERIC_ADDRESS ResidencyCounter; + UINT64 CounterFrequency; + +} ACPI_LPIT_NATIVE; + + +/******************************************************************************* + * + * MADT - Multiple APIC Description Table + * Version 3 + * + ******************************************************************************/ + +typedef struct acpi_table_madt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Address; /* Physical address of local APIC */ + UINT32 Flags; + +} ACPI_TABLE_MADT; + +/* Masks for Flags field above */ + +#define ACPI_MADT_PCAT_COMPAT (1) /* 00: System also has dual 8259s */ + +/* Values for PCATCompat flag */ + +#define ACPI_MADT_DUAL_PIC 1 +#define ACPI_MADT_MULTIPLE_APIC 0 + + +/* Values for MADT subtable type in ACPI_SUBTABLE_HEADER */ + +enum AcpiMadtType +{ + ACPI_MADT_TYPE_LOCAL_APIC = 0, + ACPI_MADT_TYPE_IO_APIC = 1, + ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2, + ACPI_MADT_TYPE_NMI_SOURCE = 3, + ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4, + ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5, + ACPI_MADT_TYPE_IO_SAPIC = 6, + ACPI_MADT_TYPE_LOCAL_SAPIC = 7, + ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, + ACPI_MADT_TYPE_LOCAL_X2APIC = 9, + ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10, + ACPI_MADT_TYPE_GENERIC_INTERRUPT = 11, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12, + ACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14, + ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15, + ACPI_MADT_TYPE_RESERVED = 16 /* 16 and greater are reserved */ +}; + + +/* + * MADT Subtables, correspond to Type in ACPI_SUBTABLE_HEADER + */ + +/* 0: Processor Local APIC */ + +typedef struct acpi_madt_local_apic +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 ProcessorId; /* ACPI processor id */ + UINT8 Id; /* Processor's local APIC id */ + UINT32 LapicFlags; + +} ACPI_MADT_LOCAL_APIC; + + +/* 1: IO APIC */ + +typedef struct acpi_madt_io_apic +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Id; /* I/O APIC ID */ + UINT8 Reserved; /* Reserved - must be zero */ + UINT32 Address; /* APIC physical address */ + UINT32 GlobalIrqBase; /* Global system interrupt where INTI lines start */ + +} ACPI_MADT_IO_APIC; + + +/* 2: Interrupt Override */ + +typedef struct acpi_madt_interrupt_override +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Bus; /* 0 - ISA */ + UINT8 SourceIrq; /* Interrupt source (IRQ) */ + UINT32 GlobalIrq; /* Global system interrupt */ + UINT16 IntiFlags; + +} ACPI_MADT_INTERRUPT_OVERRIDE; + + +/* 3: NMI Source */ + +typedef struct acpi_madt_nmi_source +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 IntiFlags; + UINT32 GlobalIrq; /* Global system interrupt */ + +} ACPI_MADT_NMI_SOURCE; + + +/* 4: Local APIC NMI */ + +typedef struct acpi_madt_local_apic_nmi +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 ProcessorId; /* ACPI processor id */ + UINT16 IntiFlags; + UINT8 Lint; /* LINTn to which NMI is connected */ + +} ACPI_MADT_LOCAL_APIC_NMI; + + +/* 5: Address Override */ + +typedef struct acpi_madt_local_apic_override +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved, must be zero */ + UINT64 Address; /* APIC physical address */ + +} ACPI_MADT_LOCAL_APIC_OVERRIDE; + + +/* 6: I/O Sapic */ + +typedef struct acpi_madt_io_sapic +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Id; /* I/O SAPIC ID */ + UINT8 Reserved; /* Reserved, must be zero */ + UINT32 GlobalIrqBase; /* Global interrupt for SAPIC start */ + UINT64 Address; /* SAPIC physical address */ + +} ACPI_MADT_IO_SAPIC; + + +/* 7: Local Sapic */ + +typedef struct acpi_madt_local_sapic +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 ProcessorId; /* ACPI processor id */ + UINT8 Id; /* SAPIC ID */ + UINT8 Eid; /* SAPIC EID */ + UINT8 Reserved[3]; /* Reserved, must be zero */ + UINT32 LapicFlags; + UINT32 Uid; /* Numeric UID - ACPI 3.0 */ + char UidString[1]; /* String UID - ACPI 3.0 */ + +} ACPI_MADT_LOCAL_SAPIC; + + +/* 8: Platform Interrupt Source */ + +typedef struct acpi_madt_interrupt_source +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 IntiFlags; + UINT8 Type; /* 1=PMI, 2=INIT, 3=corrected */ + UINT8 Id; /* Processor ID */ + UINT8 Eid; /* Processor EID */ + UINT8 IoSapicVector; /* Vector value for PMI interrupts */ + UINT32 GlobalIrq; /* Global system interrupt */ + UINT32 Flags; /* Interrupt Source Flags */ + +} ACPI_MADT_INTERRUPT_SOURCE; + +/* Masks for Flags field above */ + +#define ACPI_MADT_CPEI_OVERRIDE (1) + + +/* 9: Processor Local X2APIC (ACPI 4.0) */ + +typedef struct acpi_madt_local_x2apic +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved - must be zero */ + UINT32 LocalApicId; /* Processor x2APIC ID */ + UINT32 LapicFlags; + UINT32 Uid; /* ACPI processor UID */ + +} ACPI_MADT_LOCAL_X2APIC; + + +/* 10: Local X2APIC NMI (ACPI 4.0) */ + +typedef struct acpi_madt_local_x2apic_nmi +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 IntiFlags; + UINT32 Uid; /* ACPI processor UID */ + UINT8 Lint; /* LINTn to which NMI is connected */ + UINT8 Reserved[3]; /* Reserved - must be zero */ + +} ACPI_MADT_LOCAL_X2APIC_NMI; + + +/* 11: Generic Interrupt (ACPI 5.0 + ACPI 6.0 changes) */ + +typedef struct acpi_madt_generic_interrupt +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved - must be zero */ + UINT32 CpuInterfaceNumber; + UINT32 Uid; + UINT32 Flags; + UINT32 ParkingVersion; + UINT32 PerformanceInterrupt; + UINT64 ParkedAddress; + UINT64 BaseAddress; + UINT64 GicvBaseAddress; + UINT64 GichBaseAddress; + UINT32 VgicInterrupt; + UINT64 GicrBaseAddress; + UINT64 ArmMpidr; + UINT8 EfficiencyClass; + UINT8 Reserved2[3]; + +} ACPI_MADT_GENERIC_INTERRUPT; + +/* Masks for Flags field above */ + +/* ACPI_MADT_ENABLED (1) Processor is usable if set */ +#define ACPI_MADT_PERFORMANCE_IRQ_MODE (1<<1) /* 01: Performance Interrupt Mode */ +#define ACPI_MADT_VGIC_IRQ_MODE (1<<2) /* 02: VGIC Maintenance Interrupt mode */ + + +/* 12: Generic Distributor (ACPI 5.0 + ACPI 6.0 changes) */ + +typedef struct acpi_madt_generic_distributor +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved - must be zero */ + UINT32 GicId; + UINT64 BaseAddress; + UINT32 GlobalIrqBase; + UINT8 Version; + UINT8 Reserved2[3]; /* Reserved - must be zero */ + +} ACPI_MADT_GENERIC_DISTRIBUTOR; + +/* Values for Version field above */ + +enum AcpiMadtGicVersion +{ + ACPI_MADT_GIC_VERSION_NONE = 0, + ACPI_MADT_GIC_VERSION_V1 = 1, + ACPI_MADT_GIC_VERSION_V2 = 2, + ACPI_MADT_GIC_VERSION_V3 = 3, + ACPI_MADT_GIC_VERSION_V4 = 4, + ACPI_MADT_GIC_VERSION_RESERVED = 5 /* 5 and greater are reserved */ +}; + + +/* 13: Generic MSI Frame (ACPI 5.1) */ + +typedef struct acpi_madt_generic_msi_frame +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved - must be zero */ + UINT32 MsiFrameId; + UINT64 BaseAddress; + UINT32 Flags; + UINT16 SpiCount; + UINT16 SpiBase; + +} ACPI_MADT_GENERIC_MSI_FRAME; + +/* Masks for Flags field above */ + +#define ACPI_MADT_OVERRIDE_SPI_VALUES (1) + + +/* 14: Generic Redistributor (ACPI 5.1) */ + +typedef struct acpi_madt_generic_redistributor +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* reserved - must be zero */ + UINT64 BaseAddress; + UINT32 Length; + +} ACPI_MADT_GENERIC_REDISTRIBUTOR; + + +/* 15: Generic Translator (ACPI 6.0) */ + +typedef struct acpi_madt_generic_translator +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* reserved - must be zero */ + UINT32 TranslationId; + UINT64 BaseAddress; + UINT32 Reserved2; + +} ACPI_MADT_GENERIC_TRANSLATOR; + + +/* + * Common flags fields for MADT subtables + */ + +/* MADT Local APIC flags */ + +#define ACPI_MADT_ENABLED (1) /* 00: Processor is usable if set */ + +/* MADT MPS INTI flags (IntiFlags) */ + +#define ACPI_MADT_POLARITY_MASK (3) /* 00-01: Polarity of APIC I/O input signals */ +#define ACPI_MADT_TRIGGER_MASK (3<<2) /* 02-03: Trigger mode of APIC input signals */ + +/* Values for MPS INTI flags */ + +#define ACPI_MADT_POLARITY_CONFORMS 0 +#define ACPI_MADT_POLARITY_ACTIVE_HIGH 1 +#define ACPI_MADT_POLARITY_RESERVED 2 +#define ACPI_MADT_POLARITY_ACTIVE_LOW 3 + +#define ACPI_MADT_TRIGGER_CONFORMS (0) +#define ACPI_MADT_TRIGGER_EDGE (1<<2) +#define ACPI_MADT_TRIGGER_RESERVED (2<<2) +#define ACPI_MADT_TRIGGER_LEVEL (3<<2) + + +/******************************************************************************* + * + * MCFG - PCI Memory Mapped Configuration table and subtable + * Version 1 + * + * Conforms to "PCI Firmware Specification", Revision 3.0, June 20, 2005 + * + ******************************************************************************/ + +typedef struct acpi_table_mcfg +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Reserved[8]; + +} ACPI_TABLE_MCFG; + + +/* Subtable */ + +typedef struct acpi_mcfg_allocation +{ + UINT64 Address; /* Base address, processor-relative */ + UINT16 PciSegment; /* PCI segment group number */ + UINT8 StartBusNumber; /* Starting PCI Bus number */ + UINT8 EndBusNumber; /* Final PCI Bus number */ + UINT32 Reserved; + +} ACPI_MCFG_ALLOCATION; + + +/******************************************************************************* + * + * MCHI - Management Controller Host Interface Table + * Version 1 + * + * Conforms to "Management Component Transport Protocol (MCTP) Host + * Interface Specification", Revision 1.0.0a, October 13, 2009 + * + ******************************************************************************/ + +typedef struct acpi_table_mchi +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 InterfaceType; + UINT8 Protocol; + UINT64 ProtocolData; + UINT8 InterruptType; + UINT8 Gpe; + UINT8 PciDeviceFlag; + UINT32 GlobalInterrupt; + ACPI_GENERIC_ADDRESS ControlRegister; + UINT8 PciSegment; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunction; + +} ACPI_TABLE_MCHI; + + +/******************************************************************************* + * + * MPST - Memory Power State Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +#define ACPI_MPST_CHANNEL_INFO \ + UINT8 ChannelId; \ + UINT8 Reserved1[3]; \ + UINT16 PowerNodeCount; \ + UINT16 Reserved2; + +/* Main table */ + +typedef struct acpi_table_mpst +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */ + +} ACPI_TABLE_MPST; + + +/* Memory Platform Communication Channel Info */ + +typedef struct acpi_mpst_channel +{ + ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */ + +} ACPI_MPST_CHANNEL; + + +/* Memory Power Node Structure */ + +typedef struct acpi_mpst_power_node +{ + UINT8 Flags; + UINT8 Reserved1; + UINT16 NodeId; + UINT32 Length; + UINT64 RangeAddress; + UINT64 RangeLength; + UINT32 NumPowerStates; + UINT32 NumPhysicalComponents; + +} ACPI_MPST_POWER_NODE; + +/* Values for Flags field above */ + +#define ACPI_MPST_ENABLED 1 +#define ACPI_MPST_POWER_MANAGED 2 +#define ACPI_MPST_HOT_PLUG_CAPABLE 4 + + +/* Memory Power State Structure (follows POWER_NODE above) */ + +typedef struct acpi_mpst_power_state +{ + UINT8 PowerState; + UINT8 InfoIndex; + +} ACPI_MPST_POWER_STATE; + + +/* Physical Component ID Structure (follows POWER_STATE above) */ + +typedef struct acpi_mpst_component +{ + UINT16 ComponentId; + +} ACPI_MPST_COMPONENT; + + +/* Memory Power State Characteristics Structure (follows all POWER_NODEs) */ + +typedef struct acpi_mpst_data_hdr +{ + UINT16 CharacteristicsCount; + UINT16 Reserved; + +} ACPI_MPST_DATA_HDR; + +typedef struct acpi_mpst_power_data +{ + UINT8 StructureId; + UINT8 Flags; + UINT16 Reserved1; + UINT32 AveragePower; + UINT32 PowerSaving; + UINT64 ExitLatency; + UINT64 Reserved2; + +} ACPI_MPST_POWER_DATA; + +/* Values for Flags field above */ + +#define ACPI_MPST_PRESERVE 1 +#define ACPI_MPST_AUTOENTRY 2 +#define ACPI_MPST_AUTOEXIT 4 + + +/* Shared Memory Region (not part of an ACPI table) */ + +typedef struct acpi_mpst_shared +{ + UINT32 Signature; + UINT16 PccCommand; + UINT16 PccStatus; + UINT32 CommandRegister; + UINT32 StatusRegister; + UINT32 PowerStateId; + UINT32 PowerNodeId; + UINT64 EnergyConsumed; + UINT64 AveragePower; + +} ACPI_MPST_SHARED; + + +/******************************************************************************* + * + * MSCT - Maximum System Characteristics Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_msct +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 ProximityOffset; /* Location of proximity info struct(s) */ + UINT32 MaxProximityDomains;/* Max number of proximity domains */ + UINT32 MaxClockDomains; /* Max number of clock domains */ + UINT64 MaxAddress; /* Max physical address in system */ + +} ACPI_TABLE_MSCT; + + +/* Subtable - Maximum Proximity Domain Information. Version 1 */ + +typedef struct acpi_msct_proximity +{ + UINT8 Revision; + UINT8 Length; + UINT32 RangeStart; /* Start of domain range */ + UINT32 RangeEnd; /* End of domain range */ + UINT32 ProcessorCapacity; + UINT64 MemoryCapacity; /* In bytes */ + +} ACPI_MSCT_PROXIMITY; + + +/******************************************************************************* + * + * MSDM - Microsoft Data Management table + * + * Conforms to "Microsoft Software Licensing Tables (SLIC and MSDM)", + * November 29, 2011. Copyright 2011 Microsoft + * + ******************************************************************************/ + +/* Basic MSDM table is only the common ACPI header */ + +typedef struct acpi_table_msdm +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_MSDM; + + +/******************************************************************************* + * + * MTMR - MID Timer Table + * Version 1 + * + * Conforms to "Simple Firmware Interface Specification", + * Draft 0.8.2, Oct 19, 2010 + * NOTE: The ACPI MTMR is equivalent to the SFI MTMR table. + * + ******************************************************************************/ + +typedef struct acpi_table_mtmr +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_MTMR; + +/* MTMR entry */ + +typedef struct acpi_mtmr_entry +{ + ACPI_GENERIC_ADDRESS PhysicalAddress; + UINT32 Frequency; + UINT32 Irq; + +} ACPI_MTMR_ENTRY; + + +/******************************************************************************* + * + * NFIT - NVDIMM Interface Table (ACPI 6.0+) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_nfit +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Reserved; /* Reserved, must be zero */ + +} ACPI_TABLE_NFIT; + +/* Subtable header for NFIT */ + +typedef struct acpi_nfit_header +{ + UINT16 Type; + UINT16 Length; + +} ACPI_NFIT_HEADER; + + +/* Values for subtable type in ACPI_NFIT_HEADER */ + +enum AcpiNfitType +{ + ACPI_NFIT_TYPE_SYSTEM_ADDRESS = 0, + ACPI_NFIT_TYPE_MEMORY_MAP = 1, + ACPI_NFIT_TYPE_INTERLEAVE = 2, + ACPI_NFIT_TYPE_SMBIOS = 3, + ACPI_NFIT_TYPE_CONTROL_REGION = 4, + ACPI_NFIT_TYPE_DATA_REGION = 5, + ACPI_NFIT_TYPE_FLUSH_ADDRESS = 6, + ACPI_NFIT_TYPE_CAPABILITIES = 7, + ACPI_NFIT_TYPE_RESERVED = 8 /* 8 and greater are reserved */ +}; + +/* + * NFIT Subtables + */ + +/* 0: System Physical Address Range Structure */ + +typedef struct acpi_nfit_system_address +{ + ACPI_NFIT_HEADER Header; + UINT16 RangeIndex; + UINT16 Flags; + UINT32 Reserved; /* Reserved, must be zero */ + UINT32 ProximityDomain; + UINT8 RangeGuid[16]; + UINT64 Address; + UINT64 Length; + UINT64 MemoryMapping; + +} ACPI_NFIT_SYSTEM_ADDRESS; + +/* Flags */ + +#define ACPI_NFIT_ADD_ONLINE_ONLY (1) /* 00: Add/Online Operation Only */ +#define ACPI_NFIT_PROXIMITY_VALID (1<<1) /* 01: Proximity Domain Valid */ + +/* Range Type GUIDs appear in the include/acuuid.h file */ + + +/* 1: Memory Device to System Address Range Map Structure */ + +typedef struct acpi_nfit_memory_map +{ + ACPI_NFIT_HEADER Header; + UINT32 DeviceHandle; + UINT16 PhysicalId; + UINT16 RegionId; + UINT16 RangeIndex; + UINT16 RegionIndex; + UINT64 RegionSize; + UINT64 RegionOffset; + UINT64 Address; + UINT16 InterleaveIndex; + UINT16 InterleaveWays; + UINT16 Flags; + UINT16 Reserved; /* Reserved, must be zero */ + +} ACPI_NFIT_MEMORY_MAP; + +/* Flags */ + +#define ACPI_NFIT_MEM_SAVE_FAILED (1) /* 00: Last SAVE to Memory Device failed */ +#define ACPI_NFIT_MEM_RESTORE_FAILED (1<<1) /* 01: Last RESTORE from Memory Device failed */ +#define ACPI_NFIT_MEM_FLUSH_FAILED (1<<2) /* 02: Platform flush failed */ +#define ACPI_NFIT_MEM_NOT_ARMED (1<<3) /* 03: Memory Device is not armed */ +#define ACPI_NFIT_MEM_HEALTH_OBSERVED (1<<4) /* 04: Memory Device observed SMART/health events */ +#define ACPI_NFIT_MEM_HEALTH_ENABLED (1<<5) /* 05: SMART/health events enabled */ +#define ACPI_NFIT_MEM_MAP_FAILED (1<<6) /* 06: Mapping to SPA failed */ + + +/* 2: Interleave Structure */ + +typedef struct acpi_nfit_interleave +{ + ACPI_NFIT_HEADER Header; + UINT16 InterleaveIndex; + UINT16 Reserved; /* Reserved, must be zero */ + UINT32 LineCount; + UINT32 LineSize; + UINT32 LineOffset[1]; /* Variable length */ + +} ACPI_NFIT_INTERLEAVE; + + +/* 3: SMBIOS Management Information Structure */ + +typedef struct acpi_nfit_smbios +{ + ACPI_NFIT_HEADER Header; + UINT32 Reserved; /* Reserved, must be zero */ + UINT8 Data[1]; /* Variable length */ + +} ACPI_NFIT_SMBIOS; + + +/* 4: NVDIMM Control Region Structure */ + +typedef struct acpi_nfit_control_region +{ + ACPI_NFIT_HEADER Header; + UINT16 RegionIndex; + UINT16 VendorId; + UINT16 DeviceId; + UINT16 RevisionId; + UINT16 SubsystemVendorId; + UINT16 SubsystemDeviceId; + UINT16 SubsystemRevisionId; + UINT8 ValidFields; + UINT8 ManufacturingLocation; + UINT16 ManufacturingDate; + UINT8 Reserved[2]; /* Reserved, must be zero */ + UINT32 SerialNumber; + UINT16 Code; + UINT16 Windows; + UINT64 WindowSize; + UINT64 CommandOffset; + UINT64 CommandSize; + UINT64 StatusOffset; + UINT64 StatusSize; + UINT16 Flags; + UINT8 Reserved1[6]; /* Reserved, must be zero */ + +} ACPI_NFIT_CONTROL_REGION; + +/* Flags */ + +#define ACPI_NFIT_CONTROL_BUFFERED (1) /* Block Data Windows implementation is buffered */ + +/* ValidFields bits */ + +#define ACPI_NFIT_CONTROL_MFG_INFO_VALID (1) /* Manufacturing fields are valid */ + + +/* 5: NVDIMM Block Data Window Region Structure */ + +typedef struct acpi_nfit_data_region +{ + ACPI_NFIT_HEADER Header; + UINT16 RegionIndex; + UINT16 Windows; + UINT64 Offset; + UINT64 Size; + UINT64 Capacity; + UINT64 StartAddress; + +} ACPI_NFIT_DATA_REGION; + + +/* 6: Flush Hint Address Structure */ + +typedef struct acpi_nfit_flush_address +{ + ACPI_NFIT_HEADER Header; + UINT32 DeviceHandle; + UINT16 HintCount; + UINT8 Reserved[6]; /* Reserved, must be zero */ + UINT64 HintAddress[1]; /* Variable length */ + +} ACPI_NFIT_FLUSH_ADDRESS; + + +/* 7: Platform Capabilities Structure */ + +typedef struct acpi_nfit_capabilities +{ + ACPI_NFIT_HEADER Header; + UINT8 HighestCapability; + UINT8 Reserved[3]; /* Reserved, must be zero */ + UINT32 Capabilities; + UINT32 Reserved2; + +} ACPI_NFIT_CAPABILITIES; + +/* Capabilities Flags */ + +#define ACPI_NFIT_CAPABILITY_CACHE_FLUSH (1) /* 00: Cache Flush to NVDIMM capable */ +#define ACPI_NFIT_CAPABILITY_MEM_FLUSH (1<<1) /* 01: Memory Flush to NVDIMM capable */ +#define ACPI_NFIT_CAPABILITY_MEM_MIRRORING (1<<2) /* 02: Memory Mirroring capable */ + + +/* + * NFIT/DVDIMM device handle support - used as the _ADR for each NVDIMM + */ +typedef struct nfit_device_handle +{ + UINT32 Handle; + +} NFIT_DEVICE_HANDLE; + +/* Device handle construction and extraction macros */ + +#define ACPI_NFIT_DIMM_NUMBER_MASK 0x0000000F +#define ACPI_NFIT_CHANNEL_NUMBER_MASK 0x000000F0 +#define ACPI_NFIT_MEMORY_ID_MASK 0x00000F00 +#define ACPI_NFIT_SOCKET_ID_MASK 0x0000F000 +#define ACPI_NFIT_NODE_ID_MASK 0x0FFF0000 + +#define ACPI_NFIT_DIMM_NUMBER_OFFSET 0 +#define ACPI_NFIT_CHANNEL_NUMBER_OFFSET 4 +#define ACPI_NFIT_MEMORY_ID_OFFSET 8 +#define ACPI_NFIT_SOCKET_ID_OFFSET 12 +#define ACPI_NFIT_NODE_ID_OFFSET 16 + +/* Macro to construct a NFIT/NVDIMM device handle */ + +#define ACPI_NFIT_BUILD_DEVICE_HANDLE(dimm, channel, memory, socket, node) \ + ((dimm) | \ + ((channel) << ACPI_NFIT_CHANNEL_NUMBER_OFFSET) | \ + ((memory) << ACPI_NFIT_MEMORY_ID_OFFSET) | \ + ((socket) << ACPI_NFIT_SOCKET_ID_OFFSET) | \ + ((node) << ACPI_NFIT_NODE_ID_OFFSET)) + +/* Macros to extract individual fields from a NFIT/NVDIMM device handle */ + +#define ACPI_NFIT_GET_DIMM_NUMBER(handle) \ + ((handle) & ACPI_NFIT_DIMM_NUMBER_MASK) + +#define ACPI_NFIT_GET_CHANNEL_NUMBER(handle) \ + (((handle) & ACPI_NFIT_CHANNEL_NUMBER_MASK) >> ACPI_NFIT_CHANNEL_NUMBER_OFFSET) + +#define ACPI_NFIT_GET_MEMORY_ID(handle) \ + (((handle) & ACPI_NFIT_MEMORY_ID_MASK) >> ACPI_NFIT_MEMORY_ID_OFFSET) + +#define ACPI_NFIT_GET_SOCKET_ID(handle) \ + (((handle) & ACPI_NFIT_SOCKET_ID_MASK) >> ACPI_NFIT_SOCKET_ID_OFFSET) + +#define ACPI_NFIT_GET_NODE_ID(handle) \ + (((handle) & ACPI_NFIT_NODE_ID_MASK) >> ACPI_NFIT_NODE_ID_OFFSET) + + +/******************************************************************************* + * + * PCCT - Platform Communications Channel Table (ACPI 5.0) + * Version 2 (ACPI 6.2) + * + ******************************************************************************/ + +typedef struct acpi_table_pcct +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Flags; + UINT64 Reserved; + +} ACPI_TABLE_PCCT; + +/* Values for Flags field above */ + +#define ACPI_PCCT_DOORBELL 1 + +/* Values for subtable type in ACPI_SUBTABLE_HEADER */ + +enum AcpiPcctType +{ + ACPI_PCCT_TYPE_GENERIC_SUBSPACE = 0, + ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE = 1, + ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2 = 2, /* ACPI 6.1 */ + ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE = 3, /* ACPI 6.2 */ + ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE = 4, /* ACPI 6.2 */ + ACPI_PCCT_TYPE_RESERVED = 5 /* 5 and greater are reserved */ +}; + +/* + * PCCT Subtables, correspond to Type in ACPI_SUBTABLE_HEADER + */ + +/* 0: Generic Communications Subspace */ + +typedef struct acpi_pcct_subspace +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 Length; + ACPI_GENERIC_ADDRESS DoorbellRegister; + UINT64 PreserveMask; + UINT64 WriteMask; + UINT32 Latency; + UINT32 MaxAccessRate; + UINT16 MinTurnaroundTime; + +} ACPI_PCCT_SUBSPACE; + + +/* 1: HW-reduced Communications Subspace (ACPI 5.1) */ + +typedef struct acpi_pcct_hw_reduced +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 PlatformInterrupt; + UINT8 Flags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 Length; + ACPI_GENERIC_ADDRESS DoorbellRegister; + UINT64 PreserveMask; + UINT64 WriteMask; + UINT32 Latency; + UINT32 MaxAccessRate; + UINT16 MinTurnaroundTime; + +} ACPI_PCCT_HW_REDUCED; + + +/* 2: HW-reduced Communications Subspace Type 2 (ACPI 6.1) */ + +typedef struct acpi_pcct_hw_reduced_type2 +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 PlatformInterrupt; + UINT8 Flags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 Length; + ACPI_GENERIC_ADDRESS DoorbellRegister; + UINT64 PreserveMask; + UINT64 WriteMask; + UINT32 Latency; + UINT32 MaxAccessRate; + UINT16 MinTurnaroundTime; + ACPI_GENERIC_ADDRESS PlatformAckRegister; + UINT64 AckPreserveMask; + UINT64 AckWriteMask; + +} ACPI_PCCT_HW_REDUCED_TYPE2; + + +/* 3: Extended PCC Master Subspace Type 3 (ACPI 6.2) */ + +typedef struct acpi_pcct_ext_pcc_master +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 PlatformInterrupt; + UINT8 Flags; + UINT8 Reserved1; + UINT64 BaseAddress; + UINT32 Length; + ACPI_GENERIC_ADDRESS DoorbellRegister; + UINT64 PreserveMask; + UINT64 WriteMask; + UINT32 Latency; + UINT32 MaxAccessRate; + UINT32 MinTurnaroundTime; + ACPI_GENERIC_ADDRESS PlatformAckRegister; + UINT64 AckPreserveMask; + UINT64 AckSetMask; + UINT64 Reserved2; + ACPI_GENERIC_ADDRESS CmdCompleteRegister; + UINT64 CmdCompleteMask; + ACPI_GENERIC_ADDRESS CmdUpdateRegister; + UINT64 CmdUpdatePreserveMask; + UINT64 CmdUpdateSetMask; + ACPI_GENERIC_ADDRESS ErrorStatusRegister; + UINT64 ErrorStatusMask; + +} ACPI_PCCT_EXT_PCC_MASTER; + + +/* 4: Extended PCC Slave Subspace Type 4 (ACPI 6.2) */ + +typedef struct acpi_pcct_ext_pcc_slave +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 PlatformInterrupt; + UINT8 Flags; + UINT8 Reserved1; + UINT64 BaseAddress; + UINT32 Length; + ACPI_GENERIC_ADDRESS DoorbellRegister; + UINT64 PreserveMask; + UINT64 WriteMask; + UINT32 Latency; + UINT32 MaxAccessRate; + UINT32 MinTurnaroundTime; + ACPI_GENERIC_ADDRESS PlatformAckRegister; + UINT64 AckPreserveMask; + UINT64 AckSetMask; + UINT64 Reserved2; + ACPI_GENERIC_ADDRESS CmdCompleteRegister; + UINT64 CmdCompleteMask; + ACPI_GENERIC_ADDRESS CmdUpdateRegister; + UINT64 CmdUpdatePreserveMask; + UINT64 CmdUpdateSetMask; + ACPI_GENERIC_ADDRESS ErrorStatusRegister; + UINT64 ErrorStatusMask; + +} ACPI_PCCT_EXT_PCC_SLAVE; + + +/* Values for doorbell flags above */ + +#define ACPI_PCCT_INTERRUPT_POLARITY (1) +#define ACPI_PCCT_INTERRUPT_MODE (1<<1) + + +/* + * PCC memory structures (not part of the ACPI table) + */ + +/* Shared Memory Region */ + +typedef struct acpi_pcct_shared_memory +{ + UINT32 Signature; + UINT16 Command; + UINT16 Status; + +} ACPI_PCCT_SHARED_MEMORY; + + +/* Extended PCC Subspace Shared Memory Region (ACPI 6.2) */ + +typedef struct acpi_pcct_ext_pcc_shared_memory +{ + UINT32 Signature; + UINT32 Flags; + UINT32 Length; + UINT32 Command; + +} ACPI_PCCT_EXT_PCC_SHARED_MEMORY; + + +/******************************************************************************* + * + * PDTT - Platform Debug Trigger Table (ACPI 6.2) + * Version 0 + * + ******************************************************************************/ + +typedef struct acpi_table_pdtt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 TriggerCount; + UINT8 Reserved[3]; + UINT32 ArrayOffset; + +} ACPI_TABLE_PDTT; + + +/* + * PDTT Communication Channel Identifier Structure. + * The number of these structures is defined by TriggerCount above, + * starting at ArrayOffset. + */ +typedef struct acpi_pdtt_channel +{ + UINT8 SubchannelId; + UINT8 Flags; + +} ACPI_PDTT_CHANNEL; + +/* Flags for above */ + +#define ACPI_PDTT_RUNTIME_TRIGGER (1) +#define ACPI_PDTT_WAIT_COMPLETION (1<<1) + + +/******************************************************************************* + * + * PMTT - Platform Memory Topology Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_pmtt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Reserved; + +} ACPI_TABLE_PMTT; + + +/* Common header for PMTT subtables that follow main table */ + +typedef struct acpi_pmtt_header +{ + UINT8 Type; + UINT8 Reserved1; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved2; + +} ACPI_PMTT_HEADER; + +/* Values for Type field above */ + +#define ACPI_PMTT_TYPE_SOCKET 0 +#define ACPI_PMTT_TYPE_CONTROLLER 1 +#define ACPI_PMTT_TYPE_DIMM 2 +#define ACPI_PMTT_TYPE_RESERVED 3 /* 0x03-0xFF are reserved */ + +/* Values for Flags field above */ + +#define ACPI_PMTT_TOP_LEVEL 0x0001 +#define ACPI_PMTT_PHYSICAL 0x0002 +#define ACPI_PMTT_MEMORY_TYPE 0x000C + + +/* + * PMTT subtables, correspond to Type in acpi_pmtt_header + */ + + +/* 0: Socket Structure */ + +typedef struct acpi_pmtt_socket +{ + ACPI_PMTT_HEADER Header; + UINT16 SocketId; + UINT16 Reserved; + +} ACPI_PMTT_SOCKET; + + +/* 1: Memory Controller subtable */ + +typedef struct acpi_pmtt_controller +{ + ACPI_PMTT_HEADER Header; + UINT32 ReadLatency; + UINT32 WriteLatency; + UINT32 ReadBandwidth; + UINT32 WriteBandwidth; + UINT16 AccessWidth; + UINT16 Alignment; + UINT16 Reserved; + UINT16 DomainCount; + +} ACPI_PMTT_CONTROLLER; + +/* 1a: Proximity Domain substructure */ + +typedef struct acpi_pmtt_domain +{ + UINT32 ProximityDomain; + +} ACPI_PMTT_DOMAIN; + + +/* 2: Physical Component Identifier (DIMM) */ + +typedef struct acpi_pmtt_physical_component +{ + ACPI_PMTT_HEADER Header; + UINT16 ComponentId; + UINT16 Reserved; + UINT32 MemorySize; + UINT32 BiosHandle; + +} ACPI_PMTT_PHYSICAL_COMPONENT; + + +/******************************************************************************* + * + * PPTT - Processor Properties Topology Table (ACPI 6.2) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_pptt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_PPTT; + +/* Values for Type field above */ + +enum AcpiPpttType +{ + ACPI_PPTT_TYPE_PROCESSOR = 0, + ACPI_PPTT_TYPE_CACHE = 1, + ACPI_PPTT_TYPE_ID = 2, + ACPI_PPTT_TYPE_RESERVED = 3 +}; + + +/* 0: Processor Hierarchy Node Structure */ + +typedef struct acpi_pptt_processor +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; + UINT32 Flags; + UINT32 Parent; + UINT32 AcpiProcessorId; + UINT32 NumberOfPrivResources; + +} ACPI_PPTT_PROCESSOR; + +/* Flags */ + +#define ACPI_PPTT_PHYSICAL_PACKAGE (1) /* Physical package */ +#define ACPI_PPTT_ACPI_PROCESSOR_ID_VALID (2) /* ACPI Processor ID valid */ + + +/* 1: Cache Type Structure */ + +typedef struct acpi_pptt_cache +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; + UINT32 Flags; + UINT32 NextLevelOfCache; + UINT32 Size; + UINT32 NumberOfSets; + UINT8 Associativity; + UINT8 Attributes; + UINT16 LineSize; + +} ACPI_PPTT_CACHE; + +/* Flags */ + +#define ACPI_PPTT_SIZE_PROPERTY_VALID (1) /* Physical property valid */ +#define ACPI_PPTT_NUMBER_OF_SETS_VALID (1<<1) /* Number of sets valid */ +#define ACPI_PPTT_ASSOCIATIVITY_VALID (1<<2) /* Associativity valid */ +#define ACPI_PPTT_ALLOCATION_TYPE_VALID (1<<3) /* Allocation type valid */ +#define ACPI_PPTT_CACHE_TYPE_VALID (1<<4) /* Cache type valid */ +#define ACPI_PPTT_WRITE_POLICY_VALID (1<<5) /* Write policy valid */ +#define ACPI_PPTT_LINE_SIZE_VALID (1<<6) /* Line size valid */ + +/* Masks for Attributes */ + +#define ACPI_PPTT_MASK_ALLOCATION_TYPE (0x03) /* Allocation type */ +#define ACPI_PPTT_MASK_CACHE_TYPE (0x0C) /* Cache type */ +#define ACPI_PPTT_MASK_WRITE_POLICY (0x10) /* Write policy */ + +/* Attributes describing cache */ +#define ACPI_PPTT_CACHE_READ_ALLOCATE (0x0) /* Cache line is allocated on read */ +#define ACPI_PPTT_CACHE_WRITE_ALLOCATE (0x01) /* Cache line is allocated on write */ +#define ACPI_PPTT_CACHE_RW_ALLOCATE (0x02) /* Cache line is allocated on read and write */ +#define ACPI_PPTT_CACHE_RW_ALLOCATE_ALT (0x03) /* Alternate representation of above */ + +#define ACPI_PPTT_CACHE_TYPE_DATA (0x0) /* Data cache */ +#define ACPI_PPTT_CACHE_TYPE_INSTR (1<<2) /* Instruction cache */ +#define ACPI_PPTT_CACHE_TYPE_UNIFIED (2<<2) /* Unified I & D cache */ +#define ACPI_PPTT_CACHE_TYPE_UNIFIED_ALT (3<<2) /* Alternate representation of above */ + +#define ACPI_PPTT_CACHE_POLICY_WB (0x0) /* Cache is write back */ +#define ACPI_PPTT_CACHE_POLICY_WT (1<<4) /* Cache is write through */ + +/* 2: ID Structure */ + +typedef struct acpi_pptt_id +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; + UINT32 VendorId; + UINT64 Level1Id; + UINT64 Level2Id; + UINT16 MajorRev; + UINT16 MinorRev; + UINT16 SpinRev; + +} ACPI_PPTT_ID; + + +/******************************************************************************* + * + * RASF - RAS Feature Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_rasf +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 ChannelId[12]; + +} ACPI_TABLE_RASF; + +/* RASF Platform Communication Channel Shared Memory Region */ + +typedef struct acpi_rasf_shared_memory +{ + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 Capabilities[16]; + UINT8 SetCapabilities[16]; + UINT16 NumParameterBlocks; + UINT32 SetCapabilitiesStatus; + +} ACPI_RASF_SHARED_MEMORY; + +/* RASF Parameter Block Structure Header */ + +typedef struct acpi_rasf_parameter_block +{ + UINT16 Type; + UINT16 Version; + UINT16 Length; + +} ACPI_RASF_PARAMETER_BLOCK; + +/* RASF Parameter Block Structure for PATROL_SCRUB */ + +typedef struct acpi_rasf_patrol_scrub_parameter +{ + ACPI_RASF_PARAMETER_BLOCK Header; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; + +} ACPI_RASF_PATROL_SCRUB_PARAMETER; + +/* Masks for Flags and Speed fields above */ + +#define ACPI_RASF_SCRUBBER_RUNNING 1 +#define ACPI_RASF_SPEED (7<<1) +#define ACPI_RASF_SPEED_SLOW (0<<1) +#define ACPI_RASF_SPEED_MEDIUM (4<<1) +#define ACPI_RASF_SPEED_FAST (7<<1) + +/* Channel Commands */ + +enum AcpiRasfCommands +{ + ACPI_RASF_EXECUTE_RASF_COMMAND = 1 +}; + +/* Platform RAS Capabilities */ + +enum AcpiRasfCapabiliities +{ + ACPI_HW_PATROL_SCRUB_SUPPORTED = 0, + ACPI_SW_PATROL_SCRUB_EXPOSED = 1 +}; + +/* Patrol Scrub Commands */ + +enum AcpiRasfPatrolScrubCommands +{ + ACPI_RASF_GET_PATROL_PARAMETERS = 1, + ACPI_RASF_START_PATROL_SCRUBBER = 2, + ACPI_RASF_STOP_PATROL_SCRUBBER = 3 +}; + +/* Channel Command flags */ + +#define ACPI_RASF_GENERATE_SCI (1<<15) + +/* Status values */ + +enum AcpiRasfStatus +{ + ACPI_RASF_SUCCESS = 0, + ACPI_RASF_NOT_VALID = 1, + ACPI_RASF_NOT_SUPPORTED = 2, + ACPI_RASF_BUSY = 3, + ACPI_RASF_FAILED = 4, + ACPI_RASF_ABORTED = 5, + ACPI_RASF_INVALID_DATA = 6 +}; + +/* Status flags */ + +#define ACPI_RASF_COMMAND_COMPLETE (1) +#define ACPI_RASF_SCI_DOORBELL (1<<1) +#define ACPI_RASF_ERROR (1<<2) +#define ACPI_RASF_STATUS (0x1F<<3) + + +/******************************************************************************* + * + * SBST - Smart Battery Specification Table + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_sbst +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 WarningLevel; + UINT32 LowLevel; + UINT32 CriticalLevel; + +} ACPI_TABLE_SBST; + + +/******************************************************************************* + * + * SDEI - Software Delegated Exception Interface Descriptor Table + * + * Conforms to "Software Delegated Exception Interface (SDEI)" ARM DEN0054A, + * May 8th, 2017. Copyright 2017 ARM Ltd. + * + ******************************************************************************/ + +typedef struct acpi_table_sdei +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_SDEI; + + +/******************************************************************************* + * + * SDEV - Secure Devices Table (ACPI 6.2) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_sdev +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_SDEV; + + +typedef struct acpi_sdev_header +{ + UINT8 Type; + UINT8 Flags; + UINT16 Length; + +} ACPI_SDEV_HEADER; + + +/* Values for subtable type above */ + +enum AcpiSdevType +{ + ACPI_SDEV_TYPE_NAMESPACE_DEVICE = 0, + ACPI_SDEV_TYPE_PCIE_ENDPOINT_DEVICE = 1, + ACPI_SDEV_TYPE_RESERVED = 2 /* 2 and greater are reserved */ +}; + +/* Values for flags above */ + +#define ACPI_SDEV_HANDOFF_TO_UNSECURE_OS (1) + +/* + * SDEV subtables + */ + +/* 0: Namespace Device Based Secure Device Structure */ + +typedef struct acpi_sdev_namespace +{ + ACPI_SDEV_HEADER Header; + UINT16 DeviceIdOffset; + UINT16 DeviceIdLength; + UINT16 VendorDataOffset; + UINT16 VendorDataLength; + +} ACPI_SDEV_NAMESPACE; + +/* 1: PCIe Endpoint Device Based Device Structure */ + +typedef struct acpi_sdev_pcie +{ + ACPI_SDEV_HEADER Header; + UINT16 Segment; + UINT16 StartBus; + UINT16 PathOffset; + UINT16 PathLength; + UINT16 VendorDataOffset; + UINT16 VendorDataLength; + +} ACPI_SDEV_PCIE; + +/* 1a: PCIe Endpoint path entry */ + +typedef struct acpi_sdev_pcie_path +{ + UINT8 Device; + UINT8 Function; + +} ACPI_SDEV_PCIE_PATH; + + +/* Reset to default packing */ + +#pragma pack() + +#endif /* __ACTBL2_H__ */ diff --git a/ports/acpica/include/actbl3.h b/ports/acpica/include/actbl3.h new file mode 100644 index 0000000..d4c1583 --- /dev/null +++ b/ports/acpica/include/actbl3.h @@ -0,0 +1,906 @@ +/****************************************************************************** + * + * Name: actbl3.h - ACPI Table Definitions + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACTBL3_H__ +#define __ACTBL3_H__ + + +/******************************************************************************* + * + * Additional ACPI Tables + * + * These tables are not consumed directly by the ACPICA subsystem, but are + * included here to support device drivers and the AML disassembler. + * + ******************************************************************************/ + + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_SLIC "SLIC" /* Software Licensing Description Table */ +#define ACPI_SIG_SLIT "SLIT" /* System Locality Distance Information Table */ +#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */ +#define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */ +#define ACPI_SIG_SRAT "SRAT" /* System Resource Affinity Table */ +#define ACPI_SIG_STAO "STAO" /* Status Override table */ +#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */ +#define ACPI_SIG_TPM2 "TPM2" /* Trusted Platform Module 2.0 H/W interface table */ +#define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */ +#define ACPI_SIG_VRTC "VRTC" /* Virtual Real Time Clock Table */ +#define ACPI_SIG_WAET "WAET" /* Windows ACPI Emulated devices Table */ +#define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */ +#define ACPI_SIG_WDDT "WDDT" /* Watchdog Timer Description Table */ +#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */ +#define ACPI_SIG_WPBT "WPBT" /* Windows Platform Binary Table */ +#define ACPI_SIG_WSMT "WSMT" /* Windows SMM Security Migrations Table */ +#define ACPI_SIG_XENV "XENV" /* Xen Environment table */ +#define ACPI_SIG_XXXX "XXXX" /* Intermediate AML header for ASL/ASL+ converter */ + +/* + * All tables must be byte-packed to match the ACPI specification, since + * the tables are provided by the system BIOS. + */ +#pragma pack(1) + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/******************************************************************************* + * + * SLIC - Software Licensing Description Table + * + * Conforms to "Microsoft Software Licensing Tables (SLIC and MSDM)", + * November 29, 2011. Copyright 2011 Microsoft + * + ******************************************************************************/ + +/* Basic SLIC table is only the common ACPI header */ + +typedef struct acpi_table_slic +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_SLIC; + + +/******************************************************************************* + * + * SLIT - System Locality Distance Information Table + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_slit +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 LocalityCount; + UINT8 Entry[1]; /* Real size = localities^2 */ + +} ACPI_TABLE_SLIT; + + +/******************************************************************************* + * + * SPCR - Serial Port Console Redirection table + * Version 2 + * + * Conforms to "Serial Port Console Redirection Table", + * Version 1.03, August 10, 2015 + * + ******************************************************************************/ + +typedef struct acpi_table_spcr +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 InterfaceType; /* 0=full 16550, 1=subset of 16550 */ + UINT8 Reserved[3]; + ACPI_GENERIC_ADDRESS SerialPort; + UINT8 InterruptType; + UINT8 PcInterrupt; + UINT32 Interrupt; + UINT8 BaudRate; + UINT8 Parity; + UINT8 StopBits; + UINT8 FlowControl; + UINT8 TerminalType; + UINT8 Reserved1; + UINT16 PciDeviceId; + UINT16 PciVendorId; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunction; + UINT32 PciFlags; + UINT8 PciSegment; + UINT32 Reserved2; + +} ACPI_TABLE_SPCR; + +/* Masks for PciFlags field above */ + +#define ACPI_SPCR_DO_NOT_DISABLE (1) + +/* Values for Interface Type: See the definition of the DBG2 table */ + + +/******************************************************************************* + * + * SPMI - Server Platform Management Interface table + * Version 5 + * + * Conforms to "Intelligent Platform Management Interface Specification + * Second Generation v2.0", Document Revision 1.0, February 12, 2004 with + * June 12, 2009 markup. + * + ******************************************************************************/ + +typedef struct acpi_table_spmi +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 InterfaceType; + UINT8 Reserved; /* Must be 1 */ + UINT16 SpecRevision; /* Version of IPMI */ + UINT8 InterruptType; + UINT8 GpeNumber; /* GPE assigned */ + UINT8 Reserved1; + UINT8 PciDeviceFlag; + UINT32 Interrupt; + ACPI_GENERIC_ADDRESS IpmiRegister; + UINT8 PciSegment; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunction; + UINT8 Reserved2; + +} ACPI_TABLE_SPMI; + +/* Values for InterfaceType above */ + +enum AcpiSpmiInterfaceTypes +{ + ACPI_SPMI_NOT_USED = 0, + ACPI_SPMI_KEYBOARD = 1, + ACPI_SPMI_SMI = 2, + ACPI_SPMI_BLOCK_TRANSFER = 3, + ACPI_SPMI_SMBUS = 4, + ACPI_SPMI_RESERVED = 5 /* 5 and above are reserved */ +}; + + +/******************************************************************************* + * + * SRAT - System Resource Affinity Table + * Version 3 + * + ******************************************************************************/ + +typedef struct acpi_table_srat +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 TableRevision; /* Must be value '1' */ + UINT64 Reserved; /* Reserved, must be zero */ + +} ACPI_TABLE_SRAT; + +/* Values for subtable type in ACPI_SUBTABLE_HEADER */ + +enum AcpiSratType +{ + ACPI_SRAT_TYPE_CPU_AFFINITY = 0, + ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1, + ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2, + ACPI_SRAT_TYPE_GICC_AFFINITY = 3, + ACPI_SRAT_TYPE_GIC_ITS_AFFINITY = 4, /* ACPI 6.2 */ + ACPI_SRAT_TYPE_RESERVED = 5 /* 5 and greater are reserved */ +}; + +/* + * SRAT Subtables, correspond to Type in ACPI_SUBTABLE_HEADER + */ + +/* 0: Processor Local APIC/SAPIC Affinity */ + +typedef struct acpi_srat_cpu_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 ProximityDomainLo; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomainHi[3]; + UINT32 ClockDomain; + +} ACPI_SRAT_CPU_AFFINITY; + +/* Flags */ + +#define ACPI_SRAT_CPU_USE_AFFINITY (1) /* 00: Use affinity structure */ + + +/* 1: Memory Affinity */ + +typedef struct acpi_srat_mem_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 ProximityDomain; + UINT16 Reserved; /* Reserved, must be zero */ + UINT64 BaseAddress; + UINT64 Length; + UINT32 Reserved1; + UINT32 Flags; + UINT64 Reserved2; /* Reserved, must be zero */ + +} ACPI_SRAT_MEM_AFFINITY; + +/* Flags */ + +#define ACPI_SRAT_MEM_ENABLED (1) /* 00: Use affinity structure */ +#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */ +#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */ + + +/* 2: Processor Local X2_APIC Affinity (ACPI 4.0) */ + +typedef struct acpi_srat_x2apic_cpu_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved, must be zero */ + UINT32 ProximityDomain; + UINT32 ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT32 Reserved2; + +} ACPI_SRAT_X2APIC_CPU_AFFINITY; + +/* Flags for ACPI_SRAT_CPU_AFFINITY and ACPI_SRAT_X2APIC_CPU_AFFINITY */ + +#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */ + + +/* 3: GICC Affinity (ACPI 5.1) */ + +typedef struct acpi_srat_gicc_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; + +} ACPI_SRAT_GICC_AFFINITY; + +/* Flags for ACPI_SRAT_GICC_AFFINITY */ + +#define ACPI_SRAT_GICC_ENABLED (1) /* 00: Use affinity structure */ + + +/* 4: GCC ITS Affinity (ACPI 6.2) */ + +typedef struct acpi_srat_gic_its_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 ProximityDomain; + UINT16 Reserved; + UINT32 ItsId; + +} ACPI_SRAT_GIC_ITS_AFFINITY; + + +/******************************************************************************* + * + * STAO - Status Override Table (_STA override) - ACPI 6.0 + * Version 1 + * + * Conforms to "ACPI Specification for Status Override Table" + * 6 January 2015 + * + ******************************************************************************/ + +typedef struct acpi_table_stao +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 IgnoreUart; + +} ACPI_TABLE_STAO; + + +/******************************************************************************* + * + * TCPA - Trusted Computing Platform Alliance table + * Version 2 + * + * TCG Hardware Interface Table for TPM 1.2 Clients and Servers + * + * Conforms to "TCG ACPI Specification, Family 1.2 and 2.0", + * Version 1.2, Revision 8 + * February 27, 2017 + * + * NOTE: There are two versions of the table with the same signature -- + * the client version and the server version. The common PlatformClass + * field is used to differentiate the two types of tables. + * + ******************************************************************************/ + +typedef struct acpi_table_tcpa_hdr +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT16 PlatformClass; + +} ACPI_TABLE_TCPA_HDR; + +/* + * Values for PlatformClass above. + * This is how the client and server subtables are differentiated + */ +#define ACPI_TCPA_CLIENT_TABLE 0 +#define ACPI_TCPA_SERVER_TABLE 1 + + +typedef struct acpi_table_tcpa_client +{ + UINT32 MinimumLogLength; /* Minimum length for the event log area */ + UINT64 LogAddress; /* Address of the event log area */ + +} ACPI_TABLE_TCPA_CLIENT; + +typedef struct acpi_table_tcpa_server +{ + UINT16 Reserved; + UINT64 MinimumLogLength; /* Minimum length for the event log area */ + UINT64 LogAddress; /* Address of the event log area */ + UINT16 SpecRevision; + UINT8 DeviceFlags; + UINT8 InterruptFlags; + UINT8 GpeNumber; + UINT8 Reserved2[3]; + UINT32 GlobalInterrupt; + ACPI_GENERIC_ADDRESS Address; + UINT32 Reserved3; + ACPI_GENERIC_ADDRESS ConfigAddress; + UINT8 Group; + UINT8 Bus; /* PCI Bus/Segment/Function numbers */ + UINT8 Device; + UINT8 Function; + +} ACPI_TABLE_TCPA_SERVER; + +/* Values for DeviceFlags above */ + +#define ACPI_TCPA_PCI_DEVICE (1) +#define ACPI_TCPA_BUS_PNP (1<<1) +#define ACPI_TCPA_ADDRESS_VALID (1<<2) + +/* Values for InterruptFlags above */ + +#define ACPI_TCPA_INTERRUPT_MODE (1) +#define ACPI_TCPA_INTERRUPT_POLARITY (1<<1) +#define ACPI_TCPA_SCI_VIA_GPE (1<<2) +#define ACPI_TCPA_GLOBAL_INTERRUPT (1<<3) + + +/******************************************************************************* + * + * TPM2 - Trusted Platform Module (TPM) 2.0 Hardware Interface Table + * Version 4 + * + * TCG Hardware Interface Table for TPM 2.0 Clients and Servers + * + * Conforms to "TCG ACPI Specification, Family 1.2 and 2.0", + * Version 1.2, Revision 8 + * February 27, 2017 + * + ******************************************************************************/ + +typedef struct acpi_table_tpm2 +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT16 PlatformClass; + UINT16 Reserved; + UINT64 ControlAddress; + UINT32 StartMethod; + + /* Platform-specific data follows */ + +} ACPI_TABLE_TPM2; + +/* Values for StartMethod above */ + +#define ACPI_TPM2_NOT_ALLOWED 0 +#define ACPI_TPM2_RESERVED1 1 +#define ACPI_TPM2_START_METHOD 2 +#define ACPI_TPM2_RESERVED3 3 +#define ACPI_TPM2_RESERVED4 4 +#define ACPI_TPM2_RESERVED5 5 +#define ACPI_TPM2_MEMORY_MAPPED 6 +#define ACPI_TPM2_COMMAND_BUFFER 7 +#define ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD 8 +#define ACPI_TPM2_RESERVED9 9 +#define ACPI_TPM2_RESERVED10 10 +#define ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC 11 /* V1.2 Rev 8 */ +#define ACPI_TPM2_RESERVED 12 + + +/* Optional trailer appears after any StartMethod subtables */ + +typedef struct acpi_tpm2_trailer +{ + UINT8 MethodParameters[12]; + UINT32 MinimumLogLength; /* Minimum length for the event log area */ + UINT64 LogAddress; /* Address of the event log area */ + +} ACPI_TPM2_TRAILER; + + +/* + * Subtables (StartMethod-specific) + */ + +/* 11: Start Method for ARM SMC (V1.2 Rev 8) */ + +typedef struct acpi_tpm2_arm_smc +{ + UINT32 GlobalInterrupt; + UINT8 InterruptFlags; + UINT8 OperationFlags; + UINT16 Reserved; + UINT32 FunctionId; + +} ACPI_TPM2_ARM_SMC; + +/* Values for InterruptFlags above */ + +#define ACPI_TPM2_INTERRUPT_SUPPORT (1) + +/* Values for OperationFlags above */ + +#define ACPI_TPM2_IDLE_SUPPORT (1) + + +/******************************************************************************* + * + * UEFI - UEFI Boot optimization Table + * Version 1 + * + * Conforms to "Unified Extensible Firmware Interface Specification", + * Version 2.3, May 8, 2009 + * + ******************************************************************************/ + +typedef struct acpi_table_uefi +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Identifier[16]; /* UUID identifier */ + UINT16 DataOffset; /* Offset of remaining data in table */ + +} ACPI_TABLE_UEFI; + + +/******************************************************************************* + * + * VRTC - Virtual Real Time Clock Table + * Version 1 + * + * Conforms to "Simple Firmware Interface Specification", + * Draft 0.8.2, Oct 19, 2010 + * NOTE: The ACPI VRTC is equivalent to The SFI MRTC table. + * + ******************************************************************************/ + +typedef struct acpi_table_vrtc +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_VRTC; + +/* VRTC entry */ + +typedef struct acpi_vrtc_entry +{ + ACPI_GENERIC_ADDRESS PhysicalAddress; + UINT32 Irq; + +} ACPI_VRTC_ENTRY; + + +/******************************************************************************* + * + * WAET - Windows ACPI Emulated devices Table + * Version 1 + * + * Conforms to "Windows ACPI Emulated Devices Table", version 1.0, April 6, 2009 + * + ******************************************************************************/ + +typedef struct acpi_table_waet +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Flags; + +} ACPI_TABLE_WAET; + +/* Masks for Flags field above */ + +#define ACPI_WAET_RTC_NO_ACK (1) /* RTC requires no int acknowledge */ +#define ACPI_WAET_TIMER_ONE_READ (1<<1) /* PM timer requires only one read */ + + +/******************************************************************************* + * + * WDAT - Watchdog Action Table + * Version 1 + * + * Conforms to "Hardware Watchdog Timers Design Specification", + * Copyright 2006 Microsoft Corporation. + * + ******************************************************************************/ + +typedef struct acpi_table_wdat +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 HeaderLength; /* Watchdog Header Length */ + UINT16 PciSegment; /* PCI Segment number */ + UINT8 PciBus; /* PCI Bus number */ + UINT8 PciDevice; /* PCI Device number */ + UINT8 PciFunction; /* PCI Function number */ + UINT8 Reserved[3]; + UINT32 TimerPeriod; /* Period of one timer count (msec) */ + UINT32 MaxCount; /* Maximum counter value supported */ + UINT32 MinCount; /* Minimum counter value */ + UINT8 Flags; + UINT8 Reserved2[3]; + UINT32 Entries; /* Number of watchdog entries that follow */ + +} ACPI_TABLE_WDAT; + +/* Masks for Flags field above */ + +#define ACPI_WDAT_ENABLED (1) +#define ACPI_WDAT_STOPPED 0x80 + + +/* WDAT Instruction Entries (actions) */ + +typedef struct acpi_wdat_entry +{ + UINT8 Action; + UINT8 Instruction; + UINT16 Reserved; + ACPI_GENERIC_ADDRESS RegisterRegion; + UINT32 Value; /* Value used with Read/Write register */ + UINT32 Mask; /* Bitmask required for this register instruction */ + +} ACPI_WDAT_ENTRY; + +/* Values for Action field above */ + +enum AcpiWdatActions +{ + ACPI_WDAT_RESET = 1, + ACPI_WDAT_GET_CURRENT_COUNTDOWN = 4, + ACPI_WDAT_GET_COUNTDOWN = 5, + ACPI_WDAT_SET_COUNTDOWN = 6, + ACPI_WDAT_GET_RUNNING_STATE = 8, + ACPI_WDAT_SET_RUNNING_STATE = 9, + ACPI_WDAT_GET_STOPPED_STATE = 10, + ACPI_WDAT_SET_STOPPED_STATE = 11, + ACPI_WDAT_GET_REBOOT = 16, + ACPI_WDAT_SET_REBOOT = 17, + ACPI_WDAT_GET_SHUTDOWN = 18, + ACPI_WDAT_SET_SHUTDOWN = 19, + ACPI_WDAT_GET_STATUS = 32, + ACPI_WDAT_SET_STATUS = 33, + ACPI_WDAT_ACTION_RESERVED = 34 /* 34 and greater are reserved */ +}; + +/* Values for Instruction field above */ + +enum AcpiWdatInstructions +{ + ACPI_WDAT_READ_VALUE = 0, + ACPI_WDAT_READ_COUNTDOWN = 1, + ACPI_WDAT_WRITE_VALUE = 2, + ACPI_WDAT_WRITE_COUNTDOWN = 3, + ACPI_WDAT_INSTRUCTION_RESERVED = 4, /* 4 and greater are reserved */ + ACPI_WDAT_PRESERVE_REGISTER = 0x80 /* Except for this value */ +}; + + +/******************************************************************************* + * + * WDDT - Watchdog Descriptor Table + * Version 1 + * + * Conforms to "Using the Intel ICH Family Watchdog Timer (WDT)", + * Version 001, September 2002 + * + ******************************************************************************/ + +typedef struct acpi_table_wddt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT16 SpecVersion; + UINT16 TableVersion; + UINT16 PciVendorId; + ACPI_GENERIC_ADDRESS Address; + UINT16 MaxCount; /* Maximum counter value supported */ + UINT16 MinCount; /* Minimum counter value supported */ + UINT16 Period; + UINT16 Status; + UINT16 Capability; + +} ACPI_TABLE_WDDT; + +/* Flags for Status field above */ + +#define ACPI_WDDT_AVAILABLE (1) +#define ACPI_WDDT_ACTIVE (1<<1) +#define ACPI_WDDT_TCO_OS_OWNED (1<<2) +#define ACPI_WDDT_USER_RESET (1<<11) +#define ACPI_WDDT_WDT_RESET (1<<12) +#define ACPI_WDDT_POWER_FAIL (1<<13) +#define ACPI_WDDT_UNKNOWN_RESET (1<<14) + +/* Flags for Capability field above */ + +#define ACPI_WDDT_AUTO_RESET (1) +#define ACPI_WDDT_ALERT_SUPPORT (1<<1) + + +/******************************************************************************* + * + * WDRT - Watchdog Resource Table + * Version 1 + * + * Conforms to "Watchdog Timer Hardware Requirements for Windows Server 2003", + * Version 1.01, August 28, 2006 + * + ******************************************************************************/ + +typedef struct acpi_table_wdrt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + ACPI_GENERIC_ADDRESS ControlRegister; + ACPI_GENERIC_ADDRESS CountRegister; + UINT16 PciDeviceId; + UINT16 PciVendorId; + UINT8 PciBus; /* PCI Bus number */ + UINT8 PciDevice; /* PCI Device number */ + UINT8 PciFunction; /* PCI Function number */ + UINT8 PciSegment; /* PCI Segment number */ + UINT16 MaxCount; /* Maximum counter value supported */ + UINT8 Units; + +} ACPI_TABLE_WDRT; + + +/******************************************************************************* + * + * WPBT - Windows Platform Environment Table (ACPI 6.0) + * Version 1 + * + * Conforms to "Windows Platform Binary Table (WPBT)" 29 November 2011 + * + ******************************************************************************/ + +typedef struct acpi_table_wpbt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 HandoffSize; + UINT64 HandoffAddress; + UINT8 Layout; + UINT8 Type; + UINT16 ArgumentsLength; + +} ACPI_TABLE_WPBT; + + +/******************************************************************************* + * + * WSMT - Windows SMM Security Migrations Table + * Version 1 + * + * Conforms to "Windows SMM Security Migrations Table", + * Version 1.0, April 18, 2016 + * + ******************************************************************************/ + +typedef struct acpi_table_wsmt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 ProtectionFlags; + +} ACPI_TABLE_WSMT; + +/* Flags for ProtectionFlags field above */ + +#define ACPI_WSMT_FIXED_COMM_BUFFERS (1) +#define ACPI_WSMT_COMM_BUFFER_NESTED_PTR_PROTECTION (2) +#define ACPI_WSMT_SYSTEM_RESOURCE_PROTECTION (4) + + +/******************************************************************************* + * + * XENV - Xen Environment Table (ACPI 6.0) + * Version 1 + * + * Conforms to "ACPI Specification for Xen Environment Table" 4 January 2015 + * + ******************************************************************************/ + +typedef struct acpi_table_xenv +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 GrantTableAddress; + UINT64 GrantTableSize; + UINT32 EventInterrupt; + UINT8 EventFlags; + +} ACPI_TABLE_XENV; + + +/* Reset to default packing */ + +#pragma pack() + +#endif /* __ACTBL3_H__ */ diff --git a/ports/acpica/include/actypes.h b/ports/acpica/include/actypes.h new file mode 100644 index 0000000..4d2438c --- /dev/null +++ b/ports/acpica/include/actypes.h @@ -0,0 +1,1522 @@ +/****************************************************************************** + * + * Name: actypes.h - Common data types for the entire ACPI subsystem + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACTYPES_H__ +#define __ACTYPES_H__ + +/* acpisrc:StructDefs -- for acpisrc conversion */ + +/* + * ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent + * header and must be either 32 or 64. 16-bit ACPICA is no longer + * supported, as of 12/2006. + */ +#ifndef ACPI_MACHINE_WIDTH +#error ACPI_MACHINE_WIDTH not defined +#endif + +/* + * Data type ranges + * Note: These macros are designed to be compiler independent as well as + * working around problems that some 32-bit compilers have with 64-bit + * constants. + */ +#define ACPI_UINT8_MAX (UINT8) (~((UINT8) 0)) /* 0xFF */ +#define ACPI_UINT16_MAX (UINT16)(~((UINT16) 0)) /* 0xFFFF */ +#define ACPI_UINT32_MAX (UINT32)(~((UINT32) 0)) /* 0xFFFFFFFF */ +#define ACPI_UINT64_MAX (UINT64)(~((UINT64) 0)) /* 0xFFFFFFFFFFFFFFFF */ +#define ACPI_ASCII_MAX 0x7F + + +/* + * Architecture-specific ACPICA Subsystem Data Types + * + * The goal of these types is to provide source code portability across + * 16-bit, 32-bit, and 64-bit targets. + * + * 1) The following types are of fixed size for all targets (16/32/64): + * + * BOOLEAN Logical boolean + * + * UINT8 8-bit (1 byte) unsigned value + * UINT16 16-bit (2 byte) unsigned value + * UINT32 32-bit (4 byte) unsigned value + * UINT64 64-bit (8 byte) unsigned value + * + * INT16 16-bit (2 byte) signed value + * INT32 32-bit (4 byte) signed value + * INT64 64-bit (8 byte) signed value + * + * COMPILER_DEPENDENT_UINT64/INT64 - These types are defined in the + * compiler-dependent header(s) and were introduced because there is no + * common 64-bit integer type across the various compilation models, as + * shown in the table below. + * + * Datatype LP64 ILP64 LLP64 ILP32 LP32 16bit + * char 8 8 8 8 8 8 + * short 16 16 16 16 16 16 + * _int32 32 + * int 32 64 32 32 16 16 + * long 64 64 32 32 32 32 + * long long 64 64 + * pointer 64 64 64 32 32 32 + * + * Note: ILP64 and LP32 are currently not supported. + * + * + * 2) These types represent the native word size of the target mode of the + * processor, and may be 16-bit, 32-bit, or 64-bit as required. They are + * usually used for memory allocation, efficient loop counters, and array + * indexes. The types are similar to the size_t type in the C library and + * are required because there is no C type that consistently represents the + * native data width. ACPI_SIZE is needed because there is no guarantee + * that a kernel-level C library is present. + * + * ACPI_SIZE 16/32/64-bit unsigned value + * ACPI_NATIVE_INT 16/32/64-bit signed value + */ + +/******************************************************************************* + * + * Common types for all compilers, all targets + * + ******************************************************************************/ + +#ifndef ACPI_USE_SYSTEM_INTTYPES + +typedef unsigned char BOOLEAN; +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef short INT16; +typedef COMPILER_DEPENDENT_UINT64 UINT64; +typedef COMPILER_DEPENDENT_INT64 INT64; + +#endif /* ACPI_USE_SYSTEM_INTTYPES */ + +/* + * Value returned by AcpiOsGetThreadId. There is no standard "thread_id" + * across operating systems or even the various UNIX systems. Since ACPICA + * only needs the thread ID as a unique thread identifier, we use a UINT64 + * as the only common data type - it will accommodate any type of pointer or + * any type of integer. It is up to the host-dependent OSL to cast the + * native thread ID type to a UINT64 (in AcpiOsGetThreadId). + */ +#define ACPI_THREAD_ID UINT64 + + +/******************************************************************************* + * + * Types specific to 64-bit targets + * + ******************************************************************************/ + +#if ACPI_MACHINE_WIDTH == 64 + +#ifndef ACPI_USE_SYSTEM_INTTYPES + +typedef unsigned int UINT32; +typedef int INT32; + +#endif /* ACPI_USE_SYSTEM_INTTYPES */ + + +typedef INT64 ACPI_NATIVE_INT; +typedef UINT64 ACPI_SIZE; +typedef UINT64 ACPI_IO_ADDRESS; +typedef UINT64 ACPI_PHYSICAL_ADDRESS; + +#define ACPI_MAX_PTR ACPI_UINT64_MAX +#define ACPI_SIZE_MAX ACPI_UINT64_MAX +#define ACPI_USE_NATIVE_DIVIDE /* Has native 64-bit integer support */ +#define ACPI_USE_NATIVE_MATH64 /* Has native 64-bit integer support */ + +/* + * In the case of the Itanium Processor Family (IPF), the hardware does not + * support misaligned memory transfers. Set the MISALIGNMENT_NOT_SUPPORTED + * flag to indicate that special precautions must be taken to avoid alignment + * faults. (IA64 or ia64 is currently used by existing compilers to indicate + * IPF.) + * + * Note: EM64T and other X86-64 processors support misaligned transfers, + * so there is no need to define this flag. + */ +#if defined (__IA64__) || defined (__ia64__) +#define ACPI_MISALIGNMENT_NOT_SUPPORTED +#endif + + +/******************************************************************************* + * + * Types specific to 32-bit targets + * + ******************************************************************************/ + +#elif ACPI_MACHINE_WIDTH == 32 + +#ifndef ACPI_USE_SYSTEM_INTTYPES + +typedef unsigned int UINT32; +typedef int INT32; + +#endif /* ACPI_USE_SYSTEM_INTTYPES */ + + +typedef INT32 ACPI_NATIVE_INT; +typedef UINT32 ACPI_SIZE; + +#ifdef ACPI_32BIT_PHYSICAL_ADDRESS + +/* + * OSPMs can define this to shrink the size of the structures for 32-bit + * none PAE environment. ASL compiler may always define this to generate + * 32-bit OSPM compliant tables. + */ +typedef UINT32 ACPI_IO_ADDRESS; +typedef UINT32 ACPI_PHYSICAL_ADDRESS; + +#else /* ACPI_32BIT_PHYSICAL_ADDRESS */ + +/* + * It is reported that, after some calculations, the physical addresses can + * wrap over the 32-bit boundary on 32-bit PAE environment. + * https://bugzilla.kernel.org/show_bug.cgi?id=87971 + */ +typedef UINT64 ACPI_IO_ADDRESS; +typedef UINT64 ACPI_PHYSICAL_ADDRESS; + +#endif /* ACPI_32BIT_PHYSICAL_ADDRESS */ + +#define ACPI_MAX_PTR ACPI_UINT32_MAX +#define ACPI_SIZE_MAX ACPI_UINT32_MAX + +#else + +/* ACPI_MACHINE_WIDTH must be either 64 or 32 */ + +#error unknown ACPI_MACHINE_WIDTH +#endif + + +/******************************************************************************* + * + * OS-dependent types + * + * If the defaults below are not appropriate for the host system, they can + * be defined in the OS-specific header, and this will take precedence. + * + ******************************************************************************/ + +/* Flags for AcpiOsAcquireLock/AcpiOsReleaseLock */ + +#ifndef ACPI_CPU_FLAGS +#define ACPI_CPU_FLAGS ACPI_SIZE +#endif + +/* Object returned from AcpiOsCreateCache */ + +#ifndef ACPI_CACHE_T +#ifdef ACPI_USE_LOCAL_CACHE +#define ACPI_CACHE_T ACPI_MEMORY_LIST +#else +#define ACPI_CACHE_T void * +#endif +#endif + +/* + * Synchronization objects - Mutexes, Semaphores, and SpinLocks + */ +#if (ACPI_MUTEX_TYPE == ACPI_BINARY_SEMAPHORE) +/* + * These macros are used if the host OS does not support a mutex object. + * Map the OSL Mutex interfaces to binary semaphores. + */ +#define ACPI_MUTEX ACPI_SEMAPHORE +#define AcpiOsCreateMutex(OutHandle) AcpiOsCreateSemaphore (1, 1, OutHandle) +#define AcpiOsDeleteMutex(Handle) (void) AcpiOsDeleteSemaphore (Handle) +#define AcpiOsAcquireMutex(Handle,Time) AcpiOsWaitSemaphore (Handle, 1, Time) +#define AcpiOsReleaseMutex(Handle) (void) AcpiOsSignalSemaphore (Handle, 1) +#endif + +/* Configurable types for synchronization objects */ + +#ifndef ACPI_SPINLOCK +#define ACPI_SPINLOCK void * +#endif + +#ifndef ACPI_SEMAPHORE +#define ACPI_SEMAPHORE void * +#endif + +#ifndef ACPI_MUTEX +#define ACPI_MUTEX void * +#endif + + +/******************************************************************************* + * + * Compiler-dependent types + * + * If the defaults below are not appropriate for the host compiler, they can + * be defined in the compiler-specific header, and this will take precedence. + * + ******************************************************************************/ + +/* Use C99 uintptr_t for pointer casting if available, "void *" otherwise */ + +#ifndef ACPI_UINTPTR_T +#define ACPI_UINTPTR_T void * +#endif + +/* + * ACPI_PRINTF_LIKE is used to tag functions as "printf-like" because + * some compilers can catch printf format string problems + */ +#ifndef ACPI_PRINTF_LIKE +#define ACPI_PRINTF_LIKE(c) +#endif + +/* + * Some compilers complain about unused variables. Sometimes we don't want + * to use all the variables (for example, _AcpiModuleName). This allows us + * to tell the compiler in a per-variable manner that a variable + * is unused + */ +#ifndef ACPI_UNUSED_VAR +#define ACPI_UNUSED_VAR +#endif + +/* + * All ACPICA external functions that are available to the rest of the + * kernel are tagged with these macros which can be defined as appropriate + * for the host. + * + * Notes: + * ACPI_EXPORT_SYMBOL_INIT is used for initialization and termination + * interfaces that may need special processing. + * ACPI_EXPORT_SYMBOL is used for all other public external functions. + */ +#ifndef ACPI_EXPORT_SYMBOL_INIT +#define ACPI_EXPORT_SYMBOL_INIT(Symbol) +#endif + +#ifndef ACPI_EXPORT_SYMBOL +#define ACPI_EXPORT_SYMBOL(Symbol) +#endif + +/* + * Compiler/Clibrary-dependent debug initialization. Used for ACPICA + * utilities only. + */ +#ifndef ACPI_DEBUG_INITIALIZE +#define ACPI_DEBUG_INITIALIZE() +#endif + + +/******************************************************************************* + * + * Configuration + * + ******************************************************************************/ + +#ifdef ACPI_NO_MEM_ALLOCATIONS + +#define ACPI_ALLOCATE(a) NULL +#define ACPI_ALLOCATE_ZEROED(a) NULL +#define ACPI_FREE(a) +#define ACPI_MEM_TRACKING(a) + +#else /* ACPI_NO_MEM_ALLOCATIONS */ + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +/* + * Memory allocation tracking (used by AcpiExec to detect memory leaks) + */ +#define ACPI_MEM_PARAMETERS _COMPONENT, _AcpiModuleName, __LINE__ +#define ACPI_ALLOCATE(a) AcpiUtAllocateAndTrack ((ACPI_SIZE) (a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE_ZEROED(a) AcpiUtAllocateZeroedAndTrack ((ACPI_SIZE) (a), ACPI_MEM_PARAMETERS) +#define ACPI_FREE(a) AcpiUtFreeAndTrack (a, ACPI_MEM_PARAMETERS) +#define ACPI_MEM_TRACKING(a) a + +#else +/* + * Normal memory allocation directly via the OS services layer + */ +#define ACPI_ALLOCATE(a) AcpiOsAllocate ((ACPI_SIZE) (a)) +#define ACPI_ALLOCATE_ZEROED(a) AcpiOsAllocateZeroed ((ACPI_SIZE) (a)) +#define ACPI_FREE(a) AcpiOsFree (a) +#define ACPI_MEM_TRACKING(a) + +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ + +#endif /* ACPI_NO_MEM_ALLOCATIONS */ + + +/****************************************************************************** + * + * ACPI Specification constants (Do not change unless the specification + * changes) + * + *****************************************************************************/ + +/* Number of distinct FADT-based GPE register blocks (GPE0 and GPE1) */ + +#define ACPI_MAX_GPE_BLOCKS 2 + +/* Default ACPI register widths */ + +#define ACPI_GPE_REGISTER_WIDTH 8 +#define ACPI_PM1_REGISTER_WIDTH 16 +#define ACPI_PM2_REGISTER_WIDTH 8 +#define ACPI_PM_TIMER_WIDTH 32 +#define ACPI_RESET_REGISTER_WIDTH 8 + +/* Names within the namespace are 4 bytes long */ + +#define ACPI_NAME_SIZE 4 +#define ACPI_PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */ +#define ACPI_PATH_SEPARATOR '.' + +/* Sizes for ACPI table headers */ + +#define ACPI_OEM_ID_SIZE 6 +#define ACPI_OEM_TABLE_ID_SIZE 8 + +/* ACPI/PNP hardware IDs */ + +#define PCI_ROOT_HID_STRING "PNP0A03" +#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08" + +/* PM Timer ticks per second (HZ) */ + +#define ACPI_PM_TIMER_FREQUENCY 3579545 + + +/******************************************************************************* + * + * Independent types + * + ******************************************************************************/ + +/* Logical defines and NULL */ + +#ifdef FALSE +#undef FALSE +#endif +#define FALSE (1 == 0) + +#ifdef TRUE +#undef TRUE +#endif +#define TRUE (1 == 1) + +#ifndef NULL +#define NULL (void *) 0 +#endif + + +/* + * Miscellaneous types + */ +typedef UINT32 ACPI_STATUS; /* All ACPI Exceptions */ +typedef UINT32 ACPI_NAME; /* 4-byte ACPI name */ +typedef char * ACPI_STRING; /* Null terminated ASCII string */ +typedef void * ACPI_HANDLE; /* Actually a ptr to a NS Node */ + + +/* Time constants for timer calculations */ + +#define ACPI_MSEC_PER_SEC 1000L + +#define ACPI_USEC_PER_MSEC 1000L +#define ACPI_USEC_PER_SEC 1000000L + +#define ACPI_100NSEC_PER_USEC 10L +#define ACPI_100NSEC_PER_MSEC 10000L +#define ACPI_100NSEC_PER_SEC 10000000L + +#define ACPI_NSEC_PER_USEC 1000L +#define ACPI_NSEC_PER_MSEC 1000000L +#define ACPI_NSEC_PER_SEC 1000000000L + +#define ACPI_TIME_AFTER(a, b) ((INT64)((b) - (a)) < 0) + + +/* Owner IDs are used to track namespace nodes for selective deletion */ + +typedef UINT8 ACPI_OWNER_ID; +#define ACPI_OWNER_ID_MAX 0xFF + + +#define ACPI_INTEGER_BIT_SIZE 64 +#define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ +#define ACPI_MAX64_DECIMAL_DIGITS 20 +#define ACPI_MAX32_DECIMAL_DIGITS 10 +#define ACPI_MAX16_DECIMAL_DIGITS 5 +#define ACPI_MAX8_DECIMAL_DIGITS 3 + +/* + * Constants with special meanings + */ +#define ACPI_ROOT_OBJECT ((ACPI_HANDLE) ACPI_TO_POINTER (ACPI_MAX_PTR)) +#define ACPI_WAIT_FOREVER 0xFFFF /* UINT16, as per ACPI spec */ +#define ACPI_DO_NOT_WAIT 0 + +/* + * Obsolete: Acpi integer width. In ACPI version 1 (1996), integers are + * 32 bits. In ACPI version 2 (2000) and later, integers are max 64 bits. + * Note that this pertains to the ACPI integer type only, not to other + * integers used in the implementation of the ACPICA subsystem. + * + * 01/2010: This type is obsolete and has been removed from the entire ACPICA + * code base. It remains here for compatibility with device drivers that use + * the type. However, it will be removed in the future. + */ +typedef UINT64 ACPI_INTEGER; +#define ACPI_INTEGER_MAX ACPI_UINT64_MAX + + +/******************************************************************************* + * + * Commonly used macros + * + ******************************************************************************/ + +/* Data manipulation */ + +#define ACPI_LOBYTE(Integer) ((UINT8) (UINT16)(Integer)) +#define ACPI_HIBYTE(Integer) ((UINT8) (((UINT16)(Integer)) >> 8)) +#define ACPI_LOWORD(Integer) ((UINT16) (UINT32)(Integer)) +#define ACPI_HIWORD(Integer) ((UINT16)(((UINT32)(Integer)) >> 16)) +#define ACPI_LODWORD(Integer64) ((UINT32) (UINT64)(Integer64)) +#define ACPI_HIDWORD(Integer64) ((UINT32)(((UINT64)(Integer64)) >> 32)) + +#define ACPI_SET_BIT(target,bit) ((target) |= (bit)) +#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) +#define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) +#define ACPI_MAX(a,b) (((a)>(b))?(a):(b)) + +/* Size calculation */ + +#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) + +/* Pointer manipulation */ + +#define ACPI_CAST_PTR(t, p) ((t *) (ACPI_UINTPTR_T) (p)) +#define ACPI_CAST_INDIRECT_PTR(t, p) ((t **) (ACPI_UINTPTR_T) (p)) +#define ACPI_ADD_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (UINT8, (a)) + (ACPI_SIZE)(b))) +#define ACPI_SUB_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (UINT8, (a)) - (ACPI_SIZE)(b))) +#define ACPI_PTR_DIFF(a, b) ((ACPI_SIZE) (ACPI_CAST_PTR (UINT8, (a)) - ACPI_CAST_PTR (UINT8, (b)))) + +/* Pointer/Integer type conversions */ + +#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void, (void *) 0, (ACPI_SIZE) (i)) +#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p, (void *) 0) +#define ACPI_OFFSET(d, f) ACPI_PTR_DIFF (&(((d *) 0)->f), (void *) 0) +#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i) +#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) + +/* Optimizations for 4-character (32-bit) ACPI_NAME manipulation */ + +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (UINT32, (a)) == *ACPI_CAST_PTR (UINT32, (b))) +#define ACPI_MOVE_NAME(dest,src) (*ACPI_CAST_PTR (UINT32, (dest)) = *ACPI_CAST_PTR (UINT32, (src))) +#else +#define ACPI_COMPARE_NAME(a,b) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) +#define ACPI_MOVE_NAME(dest,src) (strncpy (ACPI_CAST_PTR (char, (dest)), ACPI_CAST_PTR (char, (src)), ACPI_NAME_SIZE)) +#endif + +/* Support for the special RSDP signature (8 characters) */ + +#define ACPI_VALIDATE_RSDP_SIG(a) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) +#define ACPI_MAKE_RSDP_SIG(dest) (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) + +/* + * Algorithm to obtain access bit width. + * Can be used with AccessWidth of ACPI_GENERIC_ADDRESS and AccessSize of + * ACPI_RESOURCE_GENERIC_REGISTER. + */ +#define ACPI_ACCESS_BIT_WIDTH(size) (1 << ((size) + 2)) + + +/******************************************************************************* + * + * Miscellaneous constants + * + ******************************************************************************/ + +/* + * Initialization sequence options + */ +#define ACPI_FULL_INITIALIZATION 0x0000 +#define ACPI_NO_FACS_INIT 0x0001 +#define ACPI_NO_ACPI_ENABLE 0x0002 +#define ACPI_NO_HARDWARE_INIT 0x0004 +#define ACPI_NO_EVENT_INIT 0x0008 +#define ACPI_NO_HANDLER_INIT 0x0010 +#define ACPI_NO_OBJECT_INIT 0x0020 +#define ACPI_NO_DEVICE_INIT 0x0040 +#define ACPI_NO_ADDRESS_SPACE_INIT 0x0080 + +/* + * Initialization state + */ +#define ACPI_SUBSYSTEM_INITIALIZE 0x01 +#define ACPI_INITIALIZED_OK 0x02 + +/* + * Power state values + */ +#define ACPI_STATE_UNKNOWN (UINT8) 0xFF + +#define ACPI_STATE_S0 (UINT8) 0 +#define ACPI_STATE_S1 (UINT8) 1 +#define ACPI_STATE_S2 (UINT8) 2 +#define ACPI_STATE_S3 (UINT8) 3 +#define ACPI_STATE_S4 (UINT8) 4 +#define ACPI_STATE_S5 (UINT8) 5 +#define ACPI_S_STATES_MAX ACPI_STATE_S5 +#define ACPI_S_STATE_COUNT 6 + +#define ACPI_STATE_D0 (UINT8) 0 +#define ACPI_STATE_D1 (UINT8) 1 +#define ACPI_STATE_D2 (UINT8) 2 +#define ACPI_STATE_D3 (UINT8) 3 +#define ACPI_D_STATES_MAX ACPI_STATE_D3 +#define ACPI_D_STATE_COUNT 4 + +#define ACPI_STATE_C0 (UINT8) 0 +#define ACPI_STATE_C1 (UINT8) 1 +#define ACPI_STATE_C2 (UINT8) 2 +#define ACPI_STATE_C3 (UINT8) 3 +#define ACPI_C_STATES_MAX ACPI_STATE_C3 +#define ACPI_C_STATE_COUNT 4 + +/* + * Sleep type invalid value + */ +#define ACPI_SLEEP_TYPE_MAX 0x7 +#define ACPI_SLEEP_TYPE_INVALID 0xFF + +/* + * Standard notify values + */ +#define ACPI_NOTIFY_BUS_CHECK (UINT8) 0x00 +#define ACPI_NOTIFY_DEVICE_CHECK (UINT8) 0x01 +#define ACPI_NOTIFY_DEVICE_WAKE (UINT8) 0x02 +#define ACPI_NOTIFY_EJECT_REQUEST (UINT8) 0x03 +#define ACPI_NOTIFY_DEVICE_CHECK_LIGHT (UINT8) 0x04 +#define ACPI_NOTIFY_FREQUENCY_MISMATCH (UINT8) 0x05 +#define ACPI_NOTIFY_BUS_MODE_MISMATCH (UINT8) 0x06 +#define ACPI_NOTIFY_POWER_FAULT (UINT8) 0x07 +#define ACPI_NOTIFY_CAPABILITIES_CHECK (UINT8) 0x08 +#define ACPI_NOTIFY_DEVICE_PLD_CHECK (UINT8) 0x09 +#define ACPI_NOTIFY_RESERVED (UINT8) 0x0A +#define ACPI_NOTIFY_LOCALITY_UPDATE (UINT8) 0x0B +#define ACPI_NOTIFY_SHUTDOWN_REQUEST (UINT8) 0x0C +#define ACPI_NOTIFY_AFFINITY_UPDATE (UINT8) 0x0D +#define ACPI_NOTIFY_MEMORY_UPDATE (UINT8) 0x0E + +#define ACPI_GENERIC_NOTIFY_MAX 0x0E +#define ACPI_SPECIFIC_NOTIFY_MAX 0x84 + +/* + * Types associated with ACPI names and objects. The first group of + * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition + * of the ACPI ObjectType() operator (See the ACPI Spec). Therefore, + * only add to the first group if the spec changes. + * + * NOTE: Types must be kept in sync with the global AcpiNsProperties + * and AcpiNsTypeNames arrays. + */ +typedef UINT32 ACPI_OBJECT_TYPE; + +#define ACPI_TYPE_ANY 0x00 +#define ACPI_TYPE_INTEGER 0x01 /* Byte/Word/Dword/Zero/One/Ones */ +#define ACPI_TYPE_STRING 0x02 +#define ACPI_TYPE_BUFFER 0x03 +#define ACPI_TYPE_PACKAGE 0x04 /* ByteConst, multiple DataTerm/Constant/SuperName */ +#define ACPI_TYPE_FIELD_UNIT 0x05 +#define ACPI_TYPE_DEVICE 0x06 /* Name, multiple Node */ +#define ACPI_TYPE_EVENT 0x07 +#define ACPI_TYPE_METHOD 0x08 /* Name, ByteConst, multiple Code */ +#define ACPI_TYPE_MUTEX 0x09 +#define ACPI_TYPE_REGION 0x0A +#define ACPI_TYPE_POWER 0x0B /* Name,ByteConst,WordConst,multi Node */ +#define ACPI_TYPE_PROCESSOR 0x0C /* Name,ByteConst,DWordConst,ByteConst,multi NmO */ +#define ACPI_TYPE_THERMAL 0x0D /* Name, multiple Node */ +#define ACPI_TYPE_BUFFER_FIELD 0x0E +#define ACPI_TYPE_DDB_HANDLE 0x0F +#define ACPI_TYPE_DEBUG_OBJECT 0x10 + +#define ACPI_TYPE_EXTERNAL_MAX 0x10 +#define ACPI_NUM_TYPES (ACPI_TYPE_EXTERNAL_MAX + 1) + +/* + * These are object types that do not map directly to the ACPI + * ObjectType() operator. They are used for various internal purposes + * only. If new predefined ACPI_TYPEs are added (via the ACPI + * specification), these internal types must move upwards. (There + * is code that depends on these values being contiguous with the + * external types above.) + */ +#define ACPI_TYPE_LOCAL_REGION_FIELD 0x11 +#define ACPI_TYPE_LOCAL_BANK_FIELD 0x12 +#define ACPI_TYPE_LOCAL_INDEX_FIELD 0x13 +#define ACPI_TYPE_LOCAL_REFERENCE 0x14 /* Arg#, Local#, Name, Debug, RefOf, Index */ +#define ACPI_TYPE_LOCAL_ALIAS 0x15 +#define ACPI_TYPE_LOCAL_METHOD_ALIAS 0x16 +#define ACPI_TYPE_LOCAL_NOTIFY 0x17 +#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x18 +#define ACPI_TYPE_LOCAL_RESOURCE 0x19 +#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x1A +#define ACPI_TYPE_LOCAL_SCOPE 0x1B /* 1 Name, multiple ObjectList Nodes */ + +#define ACPI_TYPE_NS_NODE_MAX 0x1B /* Last typecode used within a NS Node */ +#define ACPI_TOTAL_TYPES (ACPI_TYPE_NS_NODE_MAX + 1) + +/* + * These are special object types that never appear in + * a Namespace node, only in an object of ACPI_OPERAND_OBJECT + */ +#define ACPI_TYPE_LOCAL_EXTRA 0x1C +#define ACPI_TYPE_LOCAL_DATA 0x1D + +#define ACPI_TYPE_LOCAL_MAX 0x1D + +/* All types above here are invalid */ + +#define ACPI_TYPE_INVALID 0x1E +#define ACPI_TYPE_NOT_FOUND 0xFF + +#define ACPI_NUM_NS_TYPES (ACPI_TYPE_INVALID + 1) + + +/* + * All I/O + */ +#define ACPI_READ 0 +#define ACPI_WRITE 1 +#define ACPI_IO_MASK 1 + +/* + * Event Types: Fixed & General Purpose + */ +typedef UINT32 ACPI_EVENT_TYPE; + +/* + * Fixed events + */ +#define ACPI_EVENT_PMTIMER 0 +#define ACPI_EVENT_GLOBAL 1 +#define ACPI_EVENT_POWER_BUTTON 2 +#define ACPI_EVENT_SLEEP_BUTTON 3 +#define ACPI_EVENT_RTC 4 +#define ACPI_EVENT_MAX 4 +#define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1 + +/* + * Event Status - Per event + * ------------- + * The encoding of ACPI_EVENT_STATUS is illustrated below. + * Note that a set bit (1) indicates the property is TRUE + * (e.g. if bit 0 is set then the event is enabled). + * +-------------+-+-+-+-+-+-+ + * | Bits 31:6 |5|4|3|2|1|0| + * +-------------+-+-+-+-+-+-+ + * | | | | | | | + * | | | | | | +- Enabled? + * | | | | | +--- Enabled for wake? + * | | | | +----- Status bit set? + * | | | +------- Enable bit set? + * | | +--------- Has a handler? + * | +----------- Masked? + * +----------------- + */ +typedef UINT32 ACPI_EVENT_STATUS; + +#define ACPI_EVENT_FLAG_DISABLED (ACPI_EVENT_STATUS) 0x00 +#define ACPI_EVENT_FLAG_ENABLED (ACPI_EVENT_STATUS) 0x01 +#define ACPI_EVENT_FLAG_WAKE_ENABLED (ACPI_EVENT_STATUS) 0x02 +#define ACPI_EVENT_FLAG_STATUS_SET (ACPI_EVENT_STATUS) 0x04 +#define ACPI_EVENT_FLAG_ENABLE_SET (ACPI_EVENT_STATUS) 0x08 +#define ACPI_EVENT_FLAG_HAS_HANDLER (ACPI_EVENT_STATUS) 0x10 +#define ACPI_EVENT_FLAG_MASKED (ACPI_EVENT_STATUS) 0x20 +#define ACPI_EVENT_FLAG_SET ACPI_EVENT_FLAG_STATUS_SET + +/* Actions for AcpiSetGpe, AcpiGpeWakeup, AcpiHwLowSetGpe */ + +#define ACPI_GPE_ENABLE 0 +#define ACPI_GPE_DISABLE 1 +#define ACPI_GPE_CONDITIONAL_ENABLE 2 + +/* + * GPE info flags - Per GPE + * +---+-+-+-+---+ + * |7:6|5|4|3|2:0| + * +---+-+-+-+---+ + * | | | | | + * | | | | +-- Type of dispatch:to method, handler, notify, or none + * | | | +----- Interrupt type: edge or level triggered + * | | +------- Is a Wake GPE + * | +--------- Has been enabled automatically at init time + * +------------ + */ +#define ACPI_GPE_DISPATCH_NONE (UINT8) 0x00 +#define ACPI_GPE_DISPATCH_METHOD (UINT8) 0x01 +#define ACPI_GPE_DISPATCH_HANDLER (UINT8) 0x02 +#define ACPI_GPE_DISPATCH_NOTIFY (UINT8) 0x03 +#define ACPI_GPE_DISPATCH_RAW_HANDLER (UINT8) 0x04 +#define ACPI_GPE_DISPATCH_MASK (UINT8) 0x07 +#define ACPI_GPE_DISPATCH_TYPE(flags) ((UINT8) ((flags) & ACPI_GPE_DISPATCH_MASK)) + +#define ACPI_GPE_LEVEL_TRIGGERED (UINT8) 0x08 +#define ACPI_GPE_EDGE_TRIGGERED (UINT8) 0x00 +#define ACPI_GPE_XRUPT_TYPE_MASK (UINT8) 0x08 + +#define ACPI_GPE_CAN_WAKE (UINT8) 0x10 +#define ACPI_GPE_AUTO_ENABLED (UINT8) 0x20 +#define ACPI_GPE_INITIALIZED (UINT8) 0x40 + +/* + * Flags for GPE and Lock interfaces + */ +#define ACPI_NOT_ISR 0x1 +#define ACPI_ISR 0x0 + + +/* Notify types */ + +#define ACPI_SYSTEM_NOTIFY 0x1 +#define ACPI_DEVICE_NOTIFY 0x2 +#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY) +#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3 +#define ACPI_NUM_NOTIFY_TYPES 2 + +#define ACPI_MAX_SYS_NOTIFY 0x7F +#define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF + +#define ACPI_SYSTEM_HANDLER_LIST 0 /* Used as index, must be SYSTEM_NOTIFY -1 */ +#define ACPI_DEVICE_HANDLER_LIST 1 /* Used as index, must be DEVICE_NOTIFY -1 */ + + +/* Address Space (Operation Region) Types */ + +typedef UINT8 ACPI_ADR_SPACE_TYPE; + +#define ACPI_ADR_SPACE_SYSTEM_MEMORY (ACPI_ADR_SPACE_TYPE) 0 +#define ACPI_ADR_SPACE_SYSTEM_IO (ACPI_ADR_SPACE_TYPE) 1 +#define ACPI_ADR_SPACE_PCI_CONFIG (ACPI_ADR_SPACE_TYPE) 2 +#define ACPI_ADR_SPACE_EC (ACPI_ADR_SPACE_TYPE) 3 +#define ACPI_ADR_SPACE_SMBUS (ACPI_ADR_SPACE_TYPE) 4 +#define ACPI_ADR_SPACE_CMOS (ACPI_ADR_SPACE_TYPE) 5 +#define ACPI_ADR_SPACE_PCI_BAR_TARGET (ACPI_ADR_SPACE_TYPE) 6 +#define ACPI_ADR_SPACE_IPMI (ACPI_ADR_SPACE_TYPE) 7 +#define ACPI_ADR_SPACE_GPIO (ACPI_ADR_SPACE_TYPE) 8 +#define ACPI_ADR_SPACE_GSBUS (ACPI_ADR_SPACE_TYPE) 9 +#define ACPI_ADR_SPACE_PLATFORM_COMM (ACPI_ADR_SPACE_TYPE) 10 + +#define ACPI_NUM_PREDEFINED_REGIONS 11 + +/* + * Special Address Spaces + * + * Note: A Data Table region is a special type of operation region + * that has its own AML opcode. However, internally, the AML + * interpreter simply creates an operation region with an an address + * space type of ACPI_ADR_SPACE_DATA_TABLE. + */ +#define ACPI_ADR_SPACE_DATA_TABLE (ACPI_ADR_SPACE_TYPE) 0x7E /* Internal to ACPICA only */ +#define ACPI_ADR_SPACE_FIXED_HARDWARE (ACPI_ADR_SPACE_TYPE) 0x7F + +/* Values for _REG connection code */ + +#define ACPI_REG_DISCONNECT 0 +#define ACPI_REG_CONNECT 1 + +/* + * BitRegister IDs + * + * These values are intended to be used by the hardware interfaces + * and are mapped to individual bitfields defined within the ACPI + * registers. See the AcpiGbl_BitRegisterInfo global table in utglobal.c + * for this mapping. + */ + +/* PM1 Status register */ + +#define ACPI_BITREG_TIMER_STATUS 0x00 +#define ACPI_BITREG_BUS_MASTER_STATUS 0x01 +#define ACPI_BITREG_GLOBAL_LOCK_STATUS 0x02 +#define ACPI_BITREG_POWER_BUTTON_STATUS 0x03 +#define ACPI_BITREG_SLEEP_BUTTON_STATUS 0x04 +#define ACPI_BITREG_RT_CLOCK_STATUS 0x05 +#define ACPI_BITREG_WAKE_STATUS 0x06 +#define ACPI_BITREG_PCIEXP_WAKE_STATUS 0x07 + +/* PM1 Enable register */ + +#define ACPI_BITREG_TIMER_ENABLE 0x08 +#define ACPI_BITREG_GLOBAL_LOCK_ENABLE 0x09 +#define ACPI_BITREG_POWER_BUTTON_ENABLE 0x0A +#define ACPI_BITREG_SLEEP_BUTTON_ENABLE 0x0B +#define ACPI_BITREG_RT_CLOCK_ENABLE 0x0C +#define ACPI_BITREG_PCIEXP_WAKE_DISABLE 0x0D + +/* PM1 Control register */ + +#define ACPI_BITREG_SCI_ENABLE 0x0E +#define ACPI_BITREG_BUS_MASTER_RLD 0x0F +#define ACPI_BITREG_GLOBAL_LOCK_RELEASE 0x10 +#define ACPI_BITREG_SLEEP_TYPE 0x11 +#define ACPI_BITREG_SLEEP_ENABLE 0x12 + +/* PM2 Control register */ + +#define ACPI_BITREG_ARB_DISABLE 0x13 + +#define ACPI_BITREG_MAX 0x13 +#define ACPI_NUM_BITREG ACPI_BITREG_MAX + 1 + + +/* Status register values. A 1 clears a status bit. 0 = no effect */ + +#define ACPI_CLEAR_STATUS 1 + +/* Enable and Control register values */ + +#define ACPI_ENABLE_EVENT 1 +#define ACPI_DISABLE_EVENT 0 + + +/* Sleep function dispatch */ + +typedef ACPI_STATUS (*ACPI_SLEEP_FUNCTION) ( + UINT8 SleepState); + +typedef struct acpi_sleep_functions +{ + ACPI_SLEEP_FUNCTION LegacyFunction; + ACPI_SLEEP_FUNCTION ExtendedFunction; + +} ACPI_SLEEP_FUNCTIONS; + + +/* + * External ACPI object definition + */ + +/* + * Note: Type == ACPI_TYPE_ANY (0) is used to indicate a NULL package + * element or an unresolved named reference. + */ +typedef union acpi_object +{ + ACPI_OBJECT_TYPE Type; /* See definition of AcpiNsType for values */ + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_INTEGER */ + UINT64 Value; /* The actual number */ + } Integer; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_STRING */ + UINT32 Length; /* # of bytes in string, excluding trailing null */ + char *Pointer; /* points to the string value */ + } String; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_BUFFER */ + UINT32 Length; /* # of bytes in buffer */ + UINT8 *Pointer; /* points to the buffer */ + } Buffer; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_PACKAGE */ + UINT32 Count; /* # of elements in package */ + union acpi_object *Elements; /* Pointer to an array of ACPI_OBJECTs */ + } Package; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_LOCAL_REFERENCE */ + ACPI_OBJECT_TYPE ActualType; /* Type associated with the Handle */ + ACPI_HANDLE Handle; /* object reference */ + } Reference; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_PROCESSOR */ + UINT32 ProcId; + ACPI_IO_ADDRESS PblkAddress; + UINT32 PblkLength; + } Processor; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_POWER */ + UINT32 SystemLevel; + UINT32 ResourceOrder; + } PowerResource; + +} ACPI_OBJECT; + + +/* + * List of objects, used as a parameter list for control method evaluation + */ +typedef struct acpi_object_list +{ + UINT32 Count; + ACPI_OBJECT *Pointer; + +} ACPI_OBJECT_LIST; + + +/* + * Miscellaneous common Data Structures used by the interfaces + */ +#define ACPI_NO_BUFFER 0 + +#ifdef ACPI_NO_MEM_ALLOCATIONS + +#define ACPI_ALLOCATE_BUFFER (ACPI_SIZE) (0) +#define ACPI_ALLOCATE_LOCAL_BUFFER (ACPI_SIZE) (0) + +#else /* ACPI_NO_MEM_ALLOCATIONS */ + +#define ACPI_ALLOCATE_BUFFER (ACPI_SIZE) (-1) /* Let ACPICA allocate buffer */ +#define ACPI_ALLOCATE_LOCAL_BUFFER (ACPI_SIZE) (-2) /* For internal use only (enables tracking) */ + +#endif /* ACPI_NO_MEM_ALLOCATIONS */ + +typedef struct acpi_buffer +{ + ACPI_SIZE Length; /* Length in bytes of the buffer */ + void *Pointer; /* pointer to buffer */ + +} ACPI_BUFFER; + + +/* + * NameType for AcpiGetName + */ +#define ACPI_FULL_PATHNAME 0 +#define ACPI_SINGLE_NAME 1 +#define ACPI_FULL_PATHNAME_NO_TRAILING 2 +#define ACPI_NAME_TYPE_MAX 2 + + +/* + * Predefined Namespace items + */ +typedef struct acpi_predefined_names +{ + const char *Name; + UINT8 Type; + char *Val; + +} ACPI_PREDEFINED_NAMES; + + +/* + * Structure and flags for AcpiGetSystemInfo + */ +#define ACPI_SYS_MODE_UNKNOWN 0x0000 +#define ACPI_SYS_MODE_ACPI 0x0001 +#define ACPI_SYS_MODE_LEGACY 0x0002 +#define ACPI_SYS_MODES_MASK 0x0003 + + +/* + * System info returned by AcpiGetSystemInfo() + */ +typedef struct acpi_system_info +{ + UINT32 AcpiCaVersion; + UINT32 Flags; + UINT32 TimerResolution; + UINT32 Reserved1; + UINT32 Reserved2; + UINT32 DebugLevel; + UINT32 DebugLayer; + +} ACPI_SYSTEM_INFO; + + +/* + * System statistics returned by AcpiGetStatistics() + */ +typedef struct acpi_statistics +{ + UINT32 SciCount; + UINT32 GpeCount; + UINT32 FixedEventCount[ACPI_NUM_FIXED_EVENTS]; + UINT32 MethodCount; + +} ACPI_STATISTICS; + + +/* + * Types specific to the OS service interfaces + */ +typedef UINT32 +(ACPI_SYSTEM_XFACE *ACPI_OSD_HANDLER) ( + void *Context); + +typedef void +(ACPI_SYSTEM_XFACE *ACPI_OSD_EXEC_CALLBACK) ( + void *Context); + +/* + * Various handlers and callback procedures + */ +typedef +UINT32 (*ACPI_SCI_HANDLER) ( + void *Context); + +typedef +void (*ACPI_GBL_EVENT_HANDLER) ( + UINT32 EventType, + ACPI_HANDLE Device, + UINT32 EventNumber, + void *Context); + +#define ACPI_EVENT_TYPE_GPE 0 +#define ACPI_EVENT_TYPE_FIXED 1 + +typedef +UINT32 (*ACPI_EVENT_HANDLER) ( + void *Context); + +typedef +UINT32 (*ACPI_GPE_HANDLER) ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + void *Context); + +typedef +void (*ACPI_NOTIFY_HANDLER) ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context); + +typedef +void (*ACPI_OBJECT_HANDLER) ( + ACPI_HANDLE Object, + void *Data); + +typedef +ACPI_STATUS (*ACPI_INIT_HANDLER) ( + ACPI_HANDLE Object, + UINT32 Function); + +#define ACPI_INIT_DEVICE_INI 1 + +typedef +ACPI_STATUS (*ACPI_EXCEPTION_HANDLER) ( + ACPI_STATUS AmlStatus, + ACPI_NAME Name, + UINT16 Opcode, + UINT32 AmlOffset, + void *Context); + +/* Table Event handler (Load, LoadTable, etc.) and types */ + +typedef +ACPI_STATUS (*ACPI_TABLE_HANDLER) ( + UINT32 Event, + void *Table, + void *Context); + + +/* Table Event Types */ + +#define ACPI_TABLE_EVENT_LOAD 0x0 +#define ACPI_TABLE_EVENT_UNLOAD 0x1 +#define ACPI_TABLE_EVENT_INSTALL 0x2 +#define ACPI_TABLE_EVENT_UNINSTALL 0x3 +#define ACPI_NUM_TABLE_EVENTS 4 + + +/* Address Spaces (For Operation Regions) */ + +typedef +ACPI_STATUS (*ACPI_ADR_SPACE_HANDLER) ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +#define ACPI_DEFAULT_HANDLER NULL + +/* Special Context data for GenericSerialBus/GeneralPurposeIo (ACPI 5.0) */ + +typedef struct acpi_connection_info +{ + UINT8 *Connection; + UINT16 Length; + UINT8 AccessLength; + +} ACPI_CONNECTION_INFO; + + +typedef +ACPI_STATUS (*ACPI_ADR_SPACE_SETUP) ( + ACPI_HANDLE RegionHandle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +#define ACPI_REGION_ACTIVATE 0 +#define ACPI_REGION_DEACTIVATE 1 + +typedef +ACPI_STATUS (*ACPI_WALK_CALLBACK) ( + ACPI_HANDLE Object, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +typedef +UINT32 (*ACPI_INTERFACE_HANDLER) ( + ACPI_STRING InterfaceName, + UINT32 Supported); + + +/* Interrupt handler return values */ + +#define ACPI_INTERRUPT_NOT_HANDLED 0x00 +#define ACPI_INTERRUPT_HANDLED 0x01 + +/* GPE handler return values */ + +#define ACPI_REENABLE_GPE 0x80 + + +/* Length of 32-bit EISAID values when converted back to a string */ + +#define ACPI_EISAID_STRING_SIZE 8 /* Includes null terminator */ + +/* Length of UUID (string) values */ + +#define ACPI_UUID_LENGTH 16 + +/* Length of 3-byte PCI class code values when converted back to a string */ + +#define ACPI_PCICLS_STRING_SIZE 7 /* Includes null terminator */ + + +/* Structures used for device/processor HID, UID, CID */ + +typedef struct acpi_pnp_device_id +{ + UINT32 Length; /* Length of string + null */ + char *String; + +} ACPI_PNP_DEVICE_ID; + +typedef struct acpi_pnp_device_id_list +{ + UINT32 Count; /* Number of IDs in Ids array */ + UINT32 ListSize; /* Size of list, including ID strings */ + ACPI_PNP_DEVICE_ID Ids[1]; /* ID array */ + +} ACPI_PNP_DEVICE_ID_LIST; + +/* + * Structure returned from AcpiGetObjectInfo. + * Optimized for both 32-bit and 64-bit builds. + */ +typedef struct acpi_device_info +{ + UINT32 InfoSize; /* Size of info, including ID strings */ + UINT32 Name; /* ACPI object Name */ + ACPI_OBJECT_TYPE Type; /* ACPI object Type */ + UINT8 ParamCount; /* If a method, required parameter count */ + UINT16 Valid; /* Indicates which optional fields are valid */ + UINT8 Flags; /* Miscellaneous info */ + UINT8 HighestDstates[4]; /* _SxD values: 0xFF indicates not valid */ + UINT8 LowestDstates[5]; /* _SxW values: 0xFF indicates not valid */ + UINT64 Address; /* _ADR value */ + ACPI_PNP_DEVICE_ID HardwareId; /* _HID value */ + ACPI_PNP_DEVICE_ID UniqueId; /* _UID value */ + ACPI_PNP_DEVICE_ID ClassCode; /* _CLS value */ + ACPI_PNP_DEVICE_ID_LIST CompatibleIdList; /* _CID list */ + +} ACPI_DEVICE_INFO; + +/* Values for Flags field above (AcpiGetObjectInfo) */ + +#define ACPI_PCI_ROOT_BRIDGE 0x01 + +/* Flags for Valid field above (AcpiGetObjectInfo) */ + +#define ACPI_VALID_ADR 0x0002 +#define ACPI_VALID_HID 0x0004 +#define ACPI_VALID_UID 0x0008 +#define ACPI_VALID_CID 0x0020 +#define ACPI_VALID_CLS 0x0040 +#define ACPI_VALID_SXDS 0x0100 +#define ACPI_VALID_SXWS 0x0200 + +/* Flags for _STA method */ + +#define ACPI_STA_DEVICE_PRESENT 0x01 +#define ACPI_STA_DEVICE_ENABLED 0x02 +#define ACPI_STA_DEVICE_UI 0x04 +#define ACPI_STA_DEVICE_FUNCTIONING 0x08 +#define ACPI_STA_DEVICE_OK 0x08 /* Synonym */ +#define ACPI_STA_BATTERY_PRESENT 0x10 + + +/* Context structs for address space handlers */ + +typedef struct acpi_pci_id +{ + UINT16 Segment; + UINT16 Bus; + UINT16 Device; + UINT16 Function; + +} ACPI_PCI_ID; + +typedef struct acpi_mem_space_context +{ + UINT32 Length; + ACPI_PHYSICAL_ADDRESS Address; + ACPI_PHYSICAL_ADDRESS MappedPhysicalAddress; + UINT8 *MappedLogicalAddress; + ACPI_SIZE MappedLength; + +} ACPI_MEM_SPACE_CONTEXT; + + +/* + * ACPI_MEMORY_LIST is used only if the ACPICA local cache is enabled + */ +typedef struct acpi_memory_list +{ + const char *ListName; + void *ListHead; + UINT16 ObjectSize; + UINT16 MaxDepth; + UINT16 CurrentDepth; + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + + /* Statistics for debug memory tracking only */ + + UINT32 TotalAllocated; + UINT32 TotalFreed; + UINT32 MaxOccupied; + UINT32 TotalSize; + UINT32 CurrentTotalSize; + UINT32 Requests; + UINT32 Hits; +#endif + +} ACPI_MEMORY_LIST; + + +/* Definitions of trace event types */ + +typedef enum +{ + ACPI_TRACE_AML_METHOD, + ACPI_TRACE_AML_OPCODE, + ACPI_TRACE_AML_REGION + +} ACPI_TRACE_EVENT_TYPE; + + +/* Definitions of _OSI support */ + +#define ACPI_VENDOR_STRINGS 0x01 +#define ACPI_FEATURE_STRINGS 0x02 +#define ACPI_ENABLE_INTERFACES 0x00 +#define ACPI_DISABLE_INTERFACES 0x04 + +#define ACPI_DISABLE_ALL_VENDOR_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS) +#define ACPI_DISABLE_ALL_FEATURE_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_FEATURE_STRINGS) +#define ACPI_DISABLE_ALL_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) +#define ACPI_ENABLE_ALL_VENDOR_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS) +#define ACPI_ENABLE_ALL_FEATURE_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_FEATURE_STRINGS) +#define ACPI_ENABLE_ALL_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) + +#define ACPI_OSI_WIN_2000 0x01 +#define ACPI_OSI_WIN_XP 0x02 +#define ACPI_OSI_WIN_XP_SP1 0x03 +#define ACPI_OSI_WINSRV_2003 0x04 +#define ACPI_OSI_WIN_XP_SP2 0x05 +#define ACPI_OSI_WINSRV_2003_SP1 0x06 +#define ACPI_OSI_WIN_VISTA 0x07 +#define ACPI_OSI_WINSRV_2008 0x08 +#define ACPI_OSI_WIN_VISTA_SP1 0x09 +#define ACPI_OSI_WIN_VISTA_SP2 0x0A +#define ACPI_OSI_WIN_7 0x0B +#define ACPI_OSI_WIN_8 0x0C +#define ACPI_OSI_WIN_10 0x0D +#define ACPI_OSI_WIN_10_RS1 0x0E +#define ACPI_OSI_WIN_10_RS2 0x0F +#define ACPI_OSI_WIN_10_RS3 0x10 + + +/* Definitions of getopt */ + +#define ACPI_OPT_END -1 + + +#endif /* __ACTYPES_H__ */ diff --git a/ports/acpica/include/acutils.h b/ports/acpica/include/acutils.h new file mode 100644 index 0000000..8dfce90 --- /dev/null +++ b/ports/acpica/include/acutils.h @@ -0,0 +1,1264 @@ +/****************************************************************************** + * + * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef _ACUTILS_H +#define _ACUTILS_H + + +extern const UINT8 AcpiGbl_ResourceAmlSizes[]; +extern const UINT8 AcpiGbl_ResourceAmlSerialBusSizes[]; + +/* Strings used by the disassembler and debugger resource dump routines */ + +#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) + +extern const char *AcpiGbl_BmDecode[]; +extern const char *AcpiGbl_ConfigDecode[]; +extern const char *AcpiGbl_ConsumeDecode[]; +extern const char *AcpiGbl_DecDecode[]; +extern const char *AcpiGbl_HeDecode[]; +extern const char *AcpiGbl_IoDecode[]; +extern const char *AcpiGbl_LlDecode[]; +extern const char *AcpiGbl_MaxDecode[]; +extern const char *AcpiGbl_MemDecode[]; +extern const char *AcpiGbl_MinDecode[]; +extern const char *AcpiGbl_MtpDecode[]; +extern const char *AcpiGbl_RngDecode[]; +extern const char *AcpiGbl_RwDecode[]; +extern const char *AcpiGbl_ShrDecode[]; +extern const char *AcpiGbl_SizDecode[]; +extern const char *AcpiGbl_TrsDecode[]; +extern const char *AcpiGbl_TtpDecode[]; +extern const char *AcpiGbl_TypDecode[]; +extern const char *AcpiGbl_PpcDecode[]; +extern const char *AcpiGbl_IorDecode[]; +extern const char *AcpiGbl_DtsDecode[]; +extern const char *AcpiGbl_CtDecode[]; +extern const char *AcpiGbl_SbtDecode[]; +extern const char *AcpiGbl_AmDecode[]; +extern const char *AcpiGbl_SmDecode[]; +extern const char *AcpiGbl_WmDecode[]; +extern const char *AcpiGbl_CphDecode[]; +extern const char *AcpiGbl_CpoDecode[]; +extern const char *AcpiGbl_DpDecode[]; +extern const char *AcpiGbl_EdDecode[]; +extern const char *AcpiGbl_BpbDecode[]; +extern const char *AcpiGbl_SbDecode[]; +extern const char *AcpiGbl_FcDecode[]; +extern const char *AcpiGbl_PtDecode[]; +extern const char *AcpiGbl_PtypDecode[]; +#endif + +/* + * For the iASL compiler case, the output is redirected to stderr so that + * any of the various ACPI errors and warnings do not appear in the output + * files, for either the compiler or disassembler portions of the tool. + */ +#ifdef ACPI_ASL_COMPILER + +#include + +#define ACPI_MSG_REDIRECT_BEGIN \ + FILE *OutputFile = AcpiGbl_OutputFile; \ + AcpiOsRedirectOutput (stderr); + +#define ACPI_MSG_REDIRECT_END \ + AcpiOsRedirectOutput (OutputFile); + +#else +/* + * non-iASL case - no redirection, nothing to do + */ +#define ACPI_MSG_REDIRECT_BEGIN +#define ACPI_MSG_REDIRECT_END +#endif + +/* + * Common error message prefixes + */ +#ifndef ACPI_MSG_ERROR +#define ACPI_MSG_ERROR "ACPI Error: " +#endif +#ifndef ACPI_MSG_WARNING +#define ACPI_MSG_WARNING "ACPI Warning: " +#endif +#ifndef ACPI_MSG_INFO +#define ACPI_MSG_INFO "ACPI: " +#endif + +#ifndef ACPI_MSG_BIOS_ERROR +#define ACPI_MSG_BIOS_ERROR "Firmware Error (ACPI): " +#endif +#ifndef ACPI_MSG_BIOS_WARNING +#define ACPI_MSG_BIOS_WARNING "Firmware Warning (ACPI): " +#endif + +/* + * Common message suffix + */ +#define ACPI_MSG_SUFFIX \ + AcpiOsPrintf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, ModuleName, LineNumber) + +/* Flags to indicate implicit or explicit string-to-integer conversion */ + +#define ACPI_IMPLICIT_CONVERSION TRUE +#define ACPI_NO_IMPLICIT_CONVERSION FALSE + +/* Types for Resource descriptor entries */ + +#define ACPI_INVALID_RESOURCE 0 +#define ACPI_FIXED_LENGTH 1 +#define ACPI_VARIABLE_LENGTH 2 +#define ACPI_SMALL_VARIABLE_LENGTH 3 + +typedef +ACPI_STATUS (*ACPI_WALK_AML_CALLBACK) ( + UINT8 *Aml, + UINT32 Length, + UINT32 Offset, + UINT8 ResourceIndex, + void **Context); + +typedef +ACPI_STATUS (*ACPI_PKG_CALLBACK) ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context); + +typedef struct acpi_pkg_info +{ + UINT8 *FreeSpace; + ACPI_SIZE Length; + UINT32 ObjectSpace; + UINT32 NumPackages; + +} ACPI_PKG_INFO; + +/* Object reference counts */ + +#define REF_INCREMENT (UINT16) 0 +#define REF_DECREMENT (UINT16) 1 + +/* AcpiUtDumpBuffer */ + +#define DB_BYTE_DISPLAY 1 +#define DB_WORD_DISPLAY 2 +#define DB_DWORD_DISPLAY 4 +#define DB_QWORD_DISPLAY 8 + + +/* + * utascii - ASCII utilities + */ +BOOLEAN +AcpiUtValidNameseg ( + char *Signature); + +BOOLEAN +AcpiUtValidNameChar ( + char Character, + UINT32 Position); + +void +AcpiUtCheckAndRepairAscii ( + UINT8 *Name, + char *RepairedName, + UINT32 Count); + + +/* + * utnonansi - Non-ANSI C library functions + */ +void +AcpiUtStrupr ( + char *SrcString); + +void +AcpiUtStrlwr ( + char *SrcString); + +int +AcpiUtStricmp ( + char *String1, + char *String2); + + +/* + * utstrsuppt - string-to-integer conversion support functions + */ +ACPI_STATUS +AcpiUtConvertOctalString ( + char *String, + UINT64 *ReturnValue); + +ACPI_STATUS +AcpiUtConvertDecimalString ( + char *String, + UINT64 *ReturnValuePtr); + +ACPI_STATUS +AcpiUtConvertHexString ( + char *String, + UINT64 *ReturnValuePtr); + +char +AcpiUtRemoveWhitespace ( + char **String); + +char +AcpiUtRemoveLeadingZeros ( + char **String); + +BOOLEAN +AcpiUtDetectHexPrefix ( + char **String); + +BOOLEAN +AcpiUtDetectOctalPrefix ( + char **String); + + +/* + * utstrtoul64 - string-to-integer conversion functions + */ +ACPI_STATUS +AcpiUtStrtoul64 ( + char *String, + UINT64 *RetInteger); + +UINT64 +AcpiUtExplicitStrtoul64 ( + char *String); + +UINT64 +AcpiUtImplicitStrtoul64 ( + char *String); + + +/* + * utglobal - Global data structures and procedures + */ +ACPI_STATUS +AcpiUtInitGlobals ( + void); + +const char * +AcpiUtGetMutexName ( + UINT32 MutexId); + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +const char * +AcpiUtGetNotifyName ( + UINT32 NotifyValue, + ACPI_OBJECT_TYPE Type); +#endif + +const char * +AcpiUtGetTypeName ( + ACPI_OBJECT_TYPE Type); + +const char * +AcpiUtGetNodeName ( + void *Object); + +const char * +AcpiUtGetDescriptorName ( + void *Object); + +const char * +AcpiUtGetReferenceName ( + ACPI_OPERAND_OBJECT *Object); + +const char * +AcpiUtGetObjectTypeName ( + ACPI_OPERAND_OBJECT *ObjDesc); + +const char * +AcpiUtGetRegionName ( + UINT8 SpaceId); + +const char * +AcpiUtGetEventName ( + UINT32 EventId); + +const char * +AcpiUtGetArgumentTypeName ( + UINT32 ArgType); + +char +AcpiUtHexToAsciiChar ( + UINT64 Integer, + UINT32 Position); + +ACPI_STATUS +AcpiUtAsciiToHexByte ( + char *TwoAsciiChars, + UINT8 *ReturnByte); + +UINT8 +AcpiUtAsciiCharToHex ( + int HexChar); + +BOOLEAN +AcpiUtValidObjectType ( + ACPI_OBJECT_TYPE Type); + + +/* + * utinit - miscellaneous initialization and shutdown + */ +ACPI_STATUS +AcpiUtHardwareInitialize ( + void); + +void +AcpiUtSubsystemShutdown ( + void); + + +/* + * utcopy - Object construction and conversion interfaces + */ +ACPI_STATUS +AcpiUtBuildSimpleObject( + ACPI_OPERAND_OBJECT *Obj, + ACPI_OBJECT *UserObj, + UINT8 *DataSpace, + UINT32 *BufferSpaceUsed); + +ACPI_STATUS +AcpiUtBuildPackageObject ( + ACPI_OPERAND_OBJECT *Obj, + UINT8 *Buffer, + UINT32 *SpaceUsed); + +ACPI_STATUS +AcpiUtCopyIobjectToEobject ( + ACPI_OPERAND_OBJECT *Obj, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiUtCopyEobjectToIobject ( + ACPI_OBJECT *Obj, + ACPI_OPERAND_OBJECT **InternalObj); + +ACPI_STATUS +AcpiUtCopyISimpleToIsimple ( + ACPI_OPERAND_OBJECT *SourceObj, + ACPI_OPERAND_OBJECT *DestObj); + +ACPI_STATUS +AcpiUtCopyIobjectToIobject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT **DestDesc, + ACPI_WALK_STATE *WalkState); + + +/* + * utcreate - Object creation + */ +ACPI_STATUS +AcpiUtUpdateObjectReference ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action); + + +/* + * utdebug - Debug interfaces + */ +void +AcpiUtInitStackPtrTrace ( + void); + +void +AcpiUtTrackStackPtr ( + void); + +void +AcpiUtTrace ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId); + +void +AcpiUtTracePtr ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const void *Pointer); + +void +AcpiUtTraceU32 ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT32 Integer); + +void +AcpiUtTraceStr ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const char *String); + +void +AcpiUtExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId); + +void +AcpiUtStatusExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + ACPI_STATUS Status); + +void +AcpiUtValueExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT64 Value); + +void +AcpiUtPtrExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT8 *Ptr); + +void +AcpiUtStrExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const char *String); + +void +AcpiUtDebugDumpBuffer ( + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 ComponentId); + +void +AcpiUtDumpBuffer ( + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 Offset); + +#ifdef ACPI_APPLICATION +void +AcpiUtDumpBufferToFile ( + ACPI_FILE File, + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 BaseOffset); +#endif + +void +AcpiUtReportError ( + char *ModuleName, + UINT32 LineNumber); + +void +AcpiUtReportInfo ( + char *ModuleName, + UINT32 LineNumber); + +void +AcpiUtReportWarning ( + char *ModuleName, + UINT32 LineNumber); + + +/* + * utdelete - Object deletion and reference counts + */ +void +AcpiUtAddReference ( + ACPI_OPERAND_OBJECT *Object); + +void +AcpiUtRemoveReference ( + ACPI_OPERAND_OBJECT *Object); + +void +AcpiUtDeleteInternalPackageObject ( + ACPI_OPERAND_OBJECT *Object); + +void +AcpiUtDeleteInternalSimpleObject ( + ACPI_OPERAND_OBJECT *Object); + +void +AcpiUtDeleteInternalObjectList ( + ACPI_OPERAND_OBJECT **ObjList); + + +/* + * uteval - object evaluation + */ +ACPI_STATUS +AcpiUtEvaluateObject ( + ACPI_NAMESPACE_NODE *PrefixNode, + const char *Path, + UINT32 ExpectedReturnBtypes, + ACPI_OPERAND_OBJECT **ReturnDesc); + +ACPI_STATUS +AcpiUtEvaluateNumericObject ( + const char *ObjectName, + ACPI_NAMESPACE_NODE *DeviceNode, + UINT64 *Value); + +ACPI_STATUS +AcpiUtExecute_STA ( + ACPI_NAMESPACE_NODE *DeviceNode, + UINT32 *StatusFlags); + +ACPI_STATUS +AcpiUtExecutePowerMethods ( + ACPI_NAMESPACE_NODE *DeviceNode, + const char **MethodNames, + UINT8 MethodCount, + UINT8 *OutValues); + + +/* + * utids - device ID support + */ +ACPI_STATUS +AcpiUtExecute_HID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId); + +ACPI_STATUS +AcpiUtExecute_UID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId); + +ACPI_STATUS +AcpiUtExecute_CID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID_LIST **ReturnCidList); + +ACPI_STATUS +AcpiUtExecute_CLS ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId); + + +/* + * utlock - reader/writer locks + */ +ACPI_STATUS +AcpiUtCreateRwLock ( + ACPI_RW_LOCK *Lock); + +void +AcpiUtDeleteRwLock ( + ACPI_RW_LOCK *Lock); + +ACPI_STATUS +AcpiUtAcquireReadLock ( + ACPI_RW_LOCK *Lock); + +ACPI_STATUS +AcpiUtReleaseReadLock ( + ACPI_RW_LOCK *Lock); + +ACPI_STATUS +AcpiUtAcquireWriteLock ( + ACPI_RW_LOCK *Lock); + +void +AcpiUtReleaseWriteLock ( + ACPI_RW_LOCK *Lock); + + +/* + * utobject - internal object create/delete/cache routines + */ +ACPI_OPERAND_OBJECT * +AcpiUtCreateInternalObjectDbg ( + const char *ModuleName, + UINT32 LineNumber, + UINT32 ComponentId, + ACPI_OBJECT_TYPE Type); + +void * +AcpiUtAllocateObjectDescDbg ( + const char *ModuleName, + UINT32 LineNumber, + UINT32 ComponentId); + +#define AcpiUtCreateInternalObject(t) AcpiUtCreateInternalObjectDbg (_AcpiModuleName,__LINE__,_COMPONENT,t) +#define AcpiUtAllocateObjectDesc() AcpiUtAllocateObjectDescDbg (_AcpiModuleName,__LINE__,_COMPONENT) + +void +AcpiUtDeleteObjectDesc ( + ACPI_OPERAND_OBJECT *Object); + +BOOLEAN +AcpiUtValidInternalObject ( + void *Object); + +ACPI_OPERAND_OBJECT * +AcpiUtCreatePackageObject ( + UINT32 Count); + +ACPI_OPERAND_OBJECT * +AcpiUtCreateIntegerObject ( + UINT64 Value); + +ACPI_OPERAND_OBJECT * +AcpiUtCreateBufferObject ( + ACPI_SIZE BufferSize); + +ACPI_OPERAND_OBJECT * +AcpiUtCreateStringObject ( + ACPI_SIZE StringSize); + +ACPI_STATUS +AcpiUtGetObjectSize( + ACPI_OPERAND_OBJECT *Obj, + ACPI_SIZE *ObjLength); + + +/* + * utosi - Support for the _OSI predefined control method + */ +ACPI_STATUS +AcpiUtInitializeInterfaces ( + void); + +ACPI_STATUS +AcpiUtInterfaceTerminate ( + void); + +ACPI_STATUS +AcpiUtInstallInterface ( + ACPI_STRING InterfaceName); + +ACPI_STATUS +AcpiUtRemoveInterface ( + ACPI_STRING InterfaceName); + +ACPI_STATUS +AcpiUtUpdateInterfaces ( + UINT8 Action); + +ACPI_INTERFACE_INFO * +AcpiUtGetInterface ( + ACPI_STRING InterfaceName); + +ACPI_STATUS +AcpiUtOsiImplementation ( + ACPI_WALK_STATE *WalkState); + + +/* + * utpredef - support for predefined names + */ +const ACPI_PREDEFINED_INFO * +AcpiUtGetNextPredefinedMethod ( + const ACPI_PREDEFINED_INFO *ThisName); + +const ACPI_PREDEFINED_INFO * +AcpiUtMatchPredefinedMethod ( + char *Name); + +void +AcpiUtGetExpectedReturnTypes ( + char *Buffer, + UINT32 ExpectedBtypes); + +#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP) +const ACPI_PREDEFINED_INFO * +AcpiUtMatchResourceName ( + char *Name); + +void +AcpiUtDisplayPredefinedMethod ( + char *Buffer, + const ACPI_PREDEFINED_INFO *ThisName, + BOOLEAN MultiLine); + +UINT32 +AcpiUtGetResourceBitWidth ( + char *Buffer, + UINT16 Types); +#endif + + +/* + * utstate - Generic state creation/cache routines + */ +void +AcpiUtPushGenericState ( + ACPI_GENERIC_STATE **ListHead, + ACPI_GENERIC_STATE *State); + +ACPI_GENERIC_STATE * +AcpiUtPopGenericState ( + ACPI_GENERIC_STATE **ListHead); + + +ACPI_GENERIC_STATE * +AcpiUtCreateGenericState ( + void); + +ACPI_THREAD_STATE * +AcpiUtCreateThreadState ( + void); + +ACPI_GENERIC_STATE * +AcpiUtCreateUpdateState ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action); + +ACPI_GENERIC_STATE * +AcpiUtCreatePkgState ( + void *InternalObject, + void *ExternalObject, + UINT32 Index); + +ACPI_STATUS +AcpiUtCreateUpdateStateAndPush ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action, + ACPI_GENERIC_STATE **StateList); + +ACPI_GENERIC_STATE * +AcpiUtCreateControlState ( + void); + +void +AcpiUtDeleteGenericState ( + ACPI_GENERIC_STATE *State); + + +/* + * utmath + */ +ACPI_STATUS +AcpiUtDivide ( + UINT64 InDividend, + UINT64 InDivisor, + UINT64 *OutQuotient, + UINT64 *OutRemainder); + +ACPI_STATUS +AcpiUtShortDivide ( + UINT64 InDividend, + UINT32 Divisor, + UINT64 *OutQuotient, + UINT32 *OutRemainder); + +ACPI_STATUS +AcpiUtShortMultiply ( + UINT64 InMultiplicand, + UINT32 Multiplier, + UINT64 *Outproduct); + +ACPI_STATUS +AcpiUtShortShiftLeft ( + UINT64 Operand, + UINT32 Count, + UINT64 *OutResult); + +ACPI_STATUS +AcpiUtShortShiftRight ( + UINT64 Operand, + UINT32 Count, + UINT64 *OutResult); + + +/* + * utmisc + */ +const ACPI_EXCEPTION_INFO * +AcpiUtValidateException ( + ACPI_STATUS Status); + +BOOLEAN +AcpiUtIsPciRootBridge ( + char *Id); + +#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_NAMES_APP) +BOOLEAN +AcpiUtIsAmlTable ( + ACPI_TABLE_HEADER *Table); +#endif + +ACPI_STATUS +AcpiUtWalkPackageTree ( + ACPI_OPERAND_OBJECT *SourceObject, + void *TargetObject, + ACPI_PKG_CALLBACK WalkCallback, + void *Context); + +/* Values for Base above (16=Hex, 10=Decimal) */ + +#define ACPI_ANY_BASE 0 + + +UINT32 +AcpiUtDwordByteSwap ( + UINT32 Value); + +void +AcpiUtSetIntegerWidth ( + UINT8 Revision); + +#ifdef ACPI_DEBUG_OUTPUT +void +AcpiUtDisplayInitPathname ( + UINT8 Type, + ACPI_NAMESPACE_NODE *ObjHandle, + const char *Path); +#endif + + +/* + * utownerid - Support for Table/Method Owner IDs + */ +ACPI_STATUS +AcpiUtAllocateOwnerId ( + ACPI_OWNER_ID *OwnerId); + +void +AcpiUtReleaseOwnerId ( + ACPI_OWNER_ID *OwnerId); + + +/* + * utresrc + */ +ACPI_STATUS +AcpiUtWalkAmlResources ( + ACPI_WALK_STATE *WalkState, + UINT8 *Aml, + ACPI_SIZE AmlLength, + ACPI_WALK_AML_CALLBACK UserFunction, + void **Context); + +ACPI_STATUS +AcpiUtValidateResource ( + ACPI_WALK_STATE *WalkState, + void *Aml, + UINT8 *ReturnIndex); + +UINT32 +AcpiUtGetDescriptorLength ( + void *Aml); + +UINT16 +AcpiUtGetResourceLength ( + void *Aml); + +UINT8 +AcpiUtGetResourceHeaderLength ( + void *Aml); + +UINT8 +AcpiUtGetResourceType ( + void *Aml); + +ACPI_STATUS +AcpiUtGetResourceEndTag ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT8 **EndTag); + + +/* + * utstring - String and character utilities + */ +void +AcpiUtPrintString ( + char *String, + UINT16 MaxLength); + +#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP +void +UtConvertBackslashes ( + char *Pathname); +#endif + +void +AcpiUtRepairName ( + char *Name); + +#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) || defined (ACPI_DEBUG_OUTPUT) +BOOLEAN +AcpiUtSafeStrcpy ( + char *Dest, + ACPI_SIZE DestSize, + char *Source); + +void +AcpiUtSafeStrncpy ( + char *Dest, + char *Source, + ACPI_SIZE DestSize); + +BOOLEAN +AcpiUtSafeStrcat ( + char *Dest, + ACPI_SIZE DestSize, + char *Source); + +BOOLEAN +AcpiUtSafeStrncat ( + char *Dest, + ACPI_SIZE DestSize, + char *Source, + ACPI_SIZE MaxTransferLength); +#endif + + +/* + * utmutex - mutex support + */ +ACPI_STATUS +AcpiUtMutexInitialize ( + void); + +void +AcpiUtMutexTerminate ( + void); + +ACPI_STATUS +AcpiUtAcquireMutex ( + ACPI_MUTEX_HANDLE MutexId); + +ACPI_STATUS +AcpiUtReleaseMutex ( + ACPI_MUTEX_HANDLE MutexId); + + +/* + * utalloc - memory allocation and object caching + */ +ACPI_STATUS +AcpiUtCreateCaches ( + void); + +ACPI_STATUS +AcpiUtDeleteCaches ( + void); + +ACPI_STATUS +AcpiUtValidateBuffer ( + ACPI_BUFFER *Buffer); + +ACPI_STATUS +AcpiUtInitializeBuffer ( + ACPI_BUFFER *Buffer, + ACPI_SIZE RequiredLength); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +void * +AcpiUtAllocateAndTrack ( + ACPI_SIZE Size, + UINT32 Component, + const char *Module, + UINT32 Line); + +void * +AcpiUtAllocateZeroedAndTrack ( + ACPI_SIZE Size, + UINT32 Component, + const char *Module, + UINT32 Line); + +void +AcpiUtFreeAndTrack ( + void *Address, + UINT32 Component, + const char *Module, + UINT32 Line); + +void +AcpiUtDumpAllocationInfo ( + void); + +void +AcpiUtDumpAllocations ( + UINT32 Component, + const char *Module); + +ACPI_STATUS +AcpiUtCreateList ( + const char *ListName, + UINT16 ObjectSize, + ACPI_MEMORY_LIST **ReturnCache); + +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ + + +/* + * utaddress - address range check + */ +ACPI_STATUS +AcpiUtAddAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 Length, + ACPI_NAMESPACE_NODE *RegionNode); + +void +AcpiUtRemoveAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_NAMESPACE_NODE *RegionNode); + +UINT32 +AcpiUtCheckAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 Length, + BOOLEAN Warn); + +void +AcpiUtDeleteAddressLists ( + void); + + +/* + * utxferror - various error/warning output functions + */ +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedWarning ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...); + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedInfo ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...); + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedBiosError ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...); + +void +AcpiUtPrefixedNamespaceError ( + const char *ModuleName, + UINT32 LineNumber, + ACPI_GENERIC_STATE *PrefixScope, + const char *InternalName, + ACPI_STATUS LookupStatus); + +void +AcpiUtMethodError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Message, + ACPI_NAMESPACE_NODE *Node, + const char *Path, + ACPI_STATUS LookupStatus); + + +/* + * Utility functions for ACPI names and IDs + */ +const AH_PREDEFINED_NAME * +AcpiAhMatchPredefinedName ( + char *Nameseg); + +const AH_DEVICE_ID * +AcpiAhMatchHardwareId ( + char *Hid); + +const char * +AcpiAhMatchUuid ( + UINT8 *Data); + + +/* + * utuuid -- UUID support functions + */ +#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_HELP_APP) +void +AcpiUtConvertStringToUuid ( + char *InString, + UINT8 *UuidBuffer); +#endif + +#endif /* _ACUTILS_H */ diff --git a/ports/acpica/include/acuuid.h b/ports/acpica/include/acuuid.h new file mode 100644 index 0000000..9b8ba69 --- /dev/null +++ b/ports/acpica/include/acuuid.h @@ -0,0 +1,203 @@ +/****************************************************************************** + * + * Name: acuuid.h - ACPI-related UUID/GUID definitions + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACUUID_H__ +#define __ACUUID_H__ + +/* + * Note1: UUIDs and GUIDs are defined to be identical in ACPI. + * + * Note2: This file is standalone and should remain that way. + */ + +/* Controllers */ + +#define UUID_GPIO_CONTROLLER "4f248f40-d5e2-499f-834c-27758ea1cd3f" +#define UUID_USB_CONTROLLER "ce2ee385-00e6-48cb-9f05-2edb927c4899" +#define UUID_SATA_CONTROLLER "e4db149b-fcfe-425b-a6d8-92357d78fc7f" + +/* Devices */ + +#define UUID_PCI_HOST_BRIDGE "33db4d5b-1ff7-401c-9657-7441c03dd766" +#define UUID_I2C_DEVICE "3cdff6f7-4267-4555-ad05-b30a3d8938de" +#define UUID_POWER_BUTTON "dfbcf3c5-e7a5-44e6-9c1f-29c76f6e059c" + +/* Interfaces */ + +#define UUID_DEVICE_LABELING "e5c937d0-3553-4d7a-9117-ea4d19c3434d" +#define UUID_PHYSICAL_PRESENCE "3dddfaa6-361b-4eb4-a424-8d10089d1653" + +/* NVDIMM - NFIT table */ + +#define UUID_VOLATILE_MEMORY "7305944f-fdda-44e3-b16c-3f22d252e5d0" +#define UUID_PERSISTENT_MEMORY "66f0d379-b4f3-4074-ac43-0d3318b78cdb" +#define UUID_CONTROL_REGION "92f701f6-13b4-405d-910b-299367e8234c" +#define UUID_DATA_REGION "91af0530-5d86-470e-a6b0-0a2db9408249" +#define UUID_VOLATILE_VIRTUAL_DISK "77ab535a-45fc-624b-5560-f7b281d1f96e" +#define UUID_VOLATILE_VIRTUAL_CD "3d5abd30-4175-87ce-6d64-d2ade523c4bb" +#define UUID_PERSISTENT_VIRTUAL_DISK "5cea02c9-4d07-69d3-269f-4496fbe096f9" +#define UUID_PERSISTENT_VIRTUAL_CD "08018188-42cd-bb48-100f-5387d53ded3d" + +/* Processor Properties (ACPI 6.2) */ + +#define UUID_CACHE_PROPERTIES "6DC63E77-257E-4E78-A973-A21F2796898D" +#define UUID_PHYSICAL_PROPERTY "DDE4D59A-AA42-4349-B407-EA40F57D9FB7" + +/* Miscellaneous */ + +#define UUID_PLATFORM_CAPABILITIES "0811b06e-4a27-44f9-8d60-3cbbc22e7b48" +#define UUID_DYNAMIC_ENUMERATION "d8c1a3a6-be9b-4c9b-91bf-c3cb81fc5daf" +#define UUID_BATTERY_THERMAL_LIMIT "4c2067e3-887d-475c-9720-4af1d3ed602e" +#define UUID_THERMAL_EXTENSIONS "14d399cd-7a27-4b18-8fb4-7cb7b9f4e500" +#define UUID_DEVICE_PROPERTIES "daffd814-6eba-4d8c-8a91-bc9bbf4aa301" + + +#endif /* __AUUID_H__ */ diff --git a/ports/acpica/include/amlcode.h b/ports/acpica/include/amlcode.h new file mode 100644 index 0000000..6507ae6 --- /dev/null +++ b/ports/acpica/include/amlcode.h @@ -0,0 +1,618 @@ +/****************************************************************************** + * + * Name: amlcode.h - Definitions for AML, as included in "definition blocks" + * Declarations and definitions contained herein are derived + * directly from the ACPI specification. + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __AMLCODE_H__ +#define __AMLCODE_H__ + +/* primary opcodes */ + +#define AML_ZERO_OP (UINT16) 0x00 +#define AML_ONE_OP (UINT16) 0x01 +#define AML_ALIAS_OP (UINT16) 0x06 +#define AML_NAME_OP (UINT16) 0x08 +#define AML_BYTE_OP (UINT16) 0x0a +#define AML_WORD_OP (UINT16) 0x0b +#define AML_DWORD_OP (UINT16) 0x0c +#define AML_STRING_OP (UINT16) 0x0d +#define AML_QWORD_OP (UINT16) 0x0e /* ACPI 2.0 */ +#define AML_SCOPE_OP (UINT16) 0x10 +#define AML_BUFFER_OP (UINT16) 0x11 +#define AML_PACKAGE_OP (UINT16) 0x12 +#define AML_VARIABLE_PACKAGE_OP (UINT16) 0x13 /* ACPI 2.0 */ +#define AML_METHOD_OP (UINT16) 0x14 +#define AML_EXTERNAL_OP (UINT16) 0x15 /* ACPI 6.0 */ +#define AML_DUAL_NAME_PREFIX (UINT16) 0x2e +#define AML_MULTI_NAME_PREFIX (UINT16) 0x2f +#define AML_EXTENDED_PREFIX (UINT16) 0x5b +#define AML_ROOT_PREFIX (UINT16) 0x5c +#define AML_PARENT_PREFIX (UINT16) 0x5e +#define AML_FIRST_LOCAL_OP (UINT16) 0x60 /* Used for Local op # calculations */ +#define AML_LOCAL0 (UINT16) 0x60 +#define AML_LOCAL1 (UINT16) 0x61 +#define AML_LOCAL2 (UINT16) 0x62 +#define AML_LOCAL3 (UINT16) 0x63 +#define AML_LOCAL4 (UINT16) 0x64 +#define AML_LOCAL5 (UINT16) 0x65 +#define AML_LOCAL6 (UINT16) 0x66 +#define AML_LOCAL7 (UINT16) 0x67 +#define AML_FIRST_ARG_OP (UINT16) 0x68 /* Used for Arg op # calculations */ +#define AML_ARG0 (UINT16) 0x68 +#define AML_ARG1 (UINT16) 0x69 +#define AML_ARG2 (UINT16) 0x6a +#define AML_ARG3 (UINT16) 0x6b +#define AML_ARG4 (UINT16) 0x6c +#define AML_ARG5 (UINT16) 0x6d +#define AML_ARG6 (UINT16) 0x6e +#define AML_STORE_OP (UINT16) 0x70 +#define AML_REF_OF_OP (UINT16) 0x71 +#define AML_ADD_OP (UINT16) 0x72 +#define AML_CONCATENATE_OP (UINT16) 0x73 +#define AML_SUBTRACT_OP (UINT16) 0x74 +#define AML_INCREMENT_OP (UINT16) 0x75 +#define AML_DECREMENT_OP (UINT16) 0x76 +#define AML_MULTIPLY_OP (UINT16) 0x77 +#define AML_DIVIDE_OP (UINT16) 0x78 +#define AML_SHIFT_LEFT_OP (UINT16) 0x79 +#define AML_SHIFT_RIGHT_OP (UINT16) 0x7a +#define AML_BIT_AND_OP (UINT16) 0x7b +#define AML_BIT_NAND_OP (UINT16) 0x7c +#define AML_BIT_OR_OP (UINT16) 0x7d +#define AML_BIT_NOR_OP (UINT16) 0x7e +#define AML_BIT_XOR_OP (UINT16) 0x7f +#define AML_BIT_NOT_OP (UINT16) 0x80 +#define AML_FIND_SET_LEFT_BIT_OP (UINT16) 0x81 +#define AML_FIND_SET_RIGHT_BIT_OP (UINT16) 0x82 +#define AML_DEREF_OF_OP (UINT16) 0x83 +#define AML_CONCATENATE_TEMPLATE_OP (UINT16) 0x84 /* ACPI 2.0 */ +#define AML_MOD_OP (UINT16) 0x85 /* ACPI 2.0 */ +#define AML_NOTIFY_OP (UINT16) 0x86 +#define AML_SIZE_OF_OP (UINT16) 0x87 +#define AML_INDEX_OP (UINT16) 0x88 +#define AML_MATCH_OP (UINT16) 0x89 +#define AML_CREATE_DWORD_FIELD_OP (UINT16) 0x8a +#define AML_CREATE_WORD_FIELD_OP (UINT16) 0x8b +#define AML_CREATE_BYTE_FIELD_OP (UINT16) 0x8c +#define AML_CREATE_BIT_FIELD_OP (UINT16) 0x8d +#define AML_OBJECT_TYPE_OP (UINT16) 0x8e +#define AML_CREATE_QWORD_FIELD_OP (UINT16) 0x8f /* ACPI 2.0 */ +#define AML_LOGICAL_AND_OP (UINT16) 0x90 +#define AML_LOGICAL_OR_OP (UINT16) 0x91 +#define AML_LOGICAL_NOT_OP (UINT16) 0x92 +#define AML_LOGICAL_EQUAL_OP (UINT16) 0x93 +#define AML_LOGICAL_GREATER_OP (UINT16) 0x94 +#define AML_LOGICAL_LESS_OP (UINT16) 0x95 +#define AML_TO_BUFFER_OP (UINT16) 0x96 /* ACPI 2.0 */ +#define AML_TO_DECIMAL_STRING_OP (UINT16) 0x97 /* ACPI 2.0 */ +#define AML_TO_HEX_STRING_OP (UINT16) 0x98 /* ACPI 2.0 */ +#define AML_TO_INTEGER_OP (UINT16) 0x99 /* ACPI 2.0 */ +#define AML_TO_STRING_OP (UINT16) 0x9c /* ACPI 2.0 */ +#define AML_COPY_OBJECT_OP (UINT16) 0x9d /* ACPI 2.0 */ +#define AML_MID_OP (UINT16) 0x9e /* ACPI 2.0 */ +#define AML_CONTINUE_OP (UINT16) 0x9f /* ACPI 2.0 */ +#define AML_IF_OP (UINT16) 0xa0 +#define AML_ELSE_OP (UINT16) 0xa1 +#define AML_WHILE_OP (UINT16) 0xa2 +#define AML_NOOP_OP (UINT16) 0xa3 +#define AML_RETURN_OP (UINT16) 0xa4 +#define AML_BREAK_OP (UINT16) 0xa5 +#define AML_COMMENT_OP (UINT16) 0xa9 +#define AML_BREAKPOINT_OP (UINT16) 0xcc +#define AML_ONES_OP (UINT16) 0xff + + +/* + * Combination opcodes (actually two one-byte opcodes) + * Used by the disassembler and iASL compiler + */ +#define AML_LOGICAL_GREATER_EQUAL_OP (UINT16) 0x9295 /* LNot (LLess) */ +#define AML_LOGICAL_LESS_EQUAL_OP (UINT16) 0x9294 /* LNot (LGreater) */ +#define AML_LOGICAL_NOT_EQUAL_OP (UINT16) 0x9293 /* LNot (LEqual) */ + + +/* Prefixed (2-byte) opcodes (with AML_EXTENDED_PREFIX) */ + +#define AML_EXTENDED_OPCODE (UINT16) 0x5b00 /* Prefix for 2-byte opcodes */ + +#define AML_MUTEX_OP (UINT16) 0x5b01 +#define AML_EVENT_OP (UINT16) 0x5b02 +#define AML_SHIFT_RIGHT_BIT_OP (UINT16) 0x5b10 /* Obsolete, not in ACPI spec */ +#define AML_SHIFT_LEFT_BIT_OP (UINT16) 0x5b11 /* Obsolete, not in ACPI spec */ +#define AML_CONDITIONAL_REF_OF_OP (UINT16) 0x5b12 +#define AML_CREATE_FIELD_OP (UINT16) 0x5b13 +#define AML_LOAD_TABLE_OP (UINT16) 0x5b1f /* ACPI 2.0 */ +#define AML_LOAD_OP (UINT16) 0x5b20 +#define AML_STALL_OP (UINT16) 0x5b21 +#define AML_SLEEP_OP (UINT16) 0x5b22 +#define AML_ACQUIRE_OP (UINT16) 0x5b23 +#define AML_SIGNAL_OP (UINT16) 0x5b24 +#define AML_WAIT_OP (UINT16) 0x5b25 +#define AML_RESET_OP (UINT16) 0x5b26 +#define AML_RELEASE_OP (UINT16) 0x5b27 +#define AML_FROM_BCD_OP (UINT16) 0x5b28 +#define AML_TO_BCD_OP (UINT16) 0x5b29 +#define AML_UNLOAD_OP (UINT16) 0x5b2a +#define AML_REVISION_OP (UINT16) 0x5b30 +#define AML_DEBUG_OP (UINT16) 0x5b31 +#define AML_FATAL_OP (UINT16) 0x5b32 +#define AML_TIMER_OP (UINT16) 0x5b33 /* ACPI 3.0 */ +#define AML_REGION_OP (UINT16) 0x5b80 +#define AML_FIELD_OP (UINT16) 0x5b81 +#define AML_DEVICE_OP (UINT16) 0x5b82 +#define AML_PROCESSOR_OP (UINT16) 0x5b83 +#define AML_POWER_RESOURCE_OP (UINT16) 0x5b84 +#define AML_THERMAL_ZONE_OP (UINT16) 0x5b85 +#define AML_INDEX_FIELD_OP (UINT16) 0x5b86 +#define AML_BANK_FIELD_OP (UINT16) 0x5b87 +#define AML_DATA_REGION_OP (UINT16) 0x5b88 /* ACPI 2.0 */ + + +/* + * Opcodes for "Field" operators + */ +#define AML_FIELD_OFFSET_OP (UINT8) 0x00 +#define AML_FIELD_ACCESS_OP (UINT8) 0x01 +#define AML_FIELD_CONNECTION_OP (UINT8) 0x02 /* ACPI 5.0 */ +#define AML_FIELD_EXT_ACCESS_OP (UINT8) 0x03 /* ACPI 5.0 */ + + +/* + * Internal opcodes + * Use only "Unknown" AML opcodes, don't attempt to use + * any valid ACPI ASCII values (A-Z, 0-9, '-') + */ +#define AML_INT_NAMEPATH_OP (UINT16) 0x002d +#define AML_INT_NAMEDFIELD_OP (UINT16) 0x0030 +#define AML_INT_RESERVEDFIELD_OP (UINT16) 0x0031 +#define AML_INT_ACCESSFIELD_OP (UINT16) 0x0032 +#define AML_INT_BYTELIST_OP (UINT16) 0x0033 +#define AML_INT_METHODCALL_OP (UINT16) 0x0035 +#define AML_INT_RETURN_VALUE_OP (UINT16) 0x0036 +#define AML_INT_EVAL_SUBTREE_OP (UINT16) 0x0037 +#define AML_INT_CONNECTION_OP (UINT16) 0x0038 +#define AML_INT_EXTACCESSFIELD_OP (UINT16) 0x0039 + +#define ARG_NONE 0x0 + +/* + * Argument types for the AML Parser + * Each field in the ArgTypes UINT32 is 5 bits, allowing for a maximum of 6 arguments. + * There can be up to 31 unique argument types + * Zero is reserved as end-of-list indicator + */ +#define ARGP_BYTEDATA 0x01 +#define ARGP_BYTELIST 0x02 +#define ARGP_CHARLIST 0x03 +#define ARGP_DATAOBJ 0x04 +#define ARGP_DATAOBJLIST 0x05 +#define ARGP_DWORDDATA 0x06 +#define ARGP_FIELDLIST 0x07 +#define ARGP_NAME 0x08 +#define ARGP_NAMESTRING 0x09 +#define ARGP_OBJLIST 0x0A +#define ARGP_PKGLENGTH 0x0B +#define ARGP_SUPERNAME 0x0C +#define ARGP_TARGET 0x0D +#define ARGP_TERMARG 0x0E +#define ARGP_TERMLIST 0x0F +#define ARGP_WORDDATA 0x10 +#define ARGP_QWORDDATA 0x11 +#define ARGP_SIMPLENAME 0x12 /* NameString | LocalTerm | ArgTerm */ +#define ARGP_NAME_OR_REF 0x13 /* For ObjectType only */ +#define ARGP_MAX 0x13 +#define ARGP_COMMENT 0x14 + +/* + * Resolved argument types for the AML Interpreter + * Each field in the ArgTypes UINT32 is 5 bits, allowing for a maximum of 6 arguments. + * There can be up to 31 unique argument types (0 is end-of-arg-list indicator) + * + * Note1: These values are completely independent from the ACPI_TYPEs + * i.e., ARGI_INTEGER != ACPI_TYPE_INTEGER + * + * Note2: If and when 5 bits becomes insufficient, it would probably be best + * to convert to a 6-byte array of argument types, allowing 8 bits per argument. + */ + +/* Single, simple types */ + +#define ARGI_ANYTYPE 0x01 /* Don't care */ +#define ARGI_PACKAGE 0x02 +#define ARGI_EVENT 0x03 +#define ARGI_MUTEX 0x04 +#define ARGI_DDBHANDLE 0x05 + +/* Interchangeable types (via implicit conversion) */ + +#define ARGI_INTEGER 0x06 +#define ARGI_STRING 0x07 +#define ARGI_BUFFER 0x08 +#define ARGI_BUFFER_OR_STRING 0x09 /* Used by MID op only */ +#define ARGI_COMPUTEDATA 0x0A /* Buffer, String, or Integer */ + +/* Reference objects */ + +#define ARGI_INTEGER_REF 0x0B +#define ARGI_OBJECT_REF 0x0C +#define ARGI_DEVICE_REF 0x0D +#define ARGI_REFERENCE 0x0E +#define ARGI_TARGETREF 0x0F /* Target, subject to implicit conversion */ +#define ARGI_FIXED_TARGET 0x10 /* Target, no implicit conversion */ +#define ARGI_SIMPLE_TARGET 0x11 /* Name, Local, Arg -- no implicit conversion */ +#define ARGI_STORE_TARGET 0x12 /* Target for store is TARGETREF + package objects */ + +/* Multiple/complex types */ + +#define ARGI_DATAOBJECT 0x13 /* Buffer, String, package or reference to a Node - Used only by SizeOf operator*/ +#define ARGI_COMPLEXOBJ 0x14 /* Buffer, String, or package (Used by INDEX op only) */ +#define ARGI_REF_OR_STRING 0x15 /* Reference or String (Used by DEREFOF op only) */ +#define ARGI_REGION_OR_BUFFER 0x16 /* Used by LOAD op only */ +#define ARGI_DATAREFOBJ 0x17 + +/* Note: types above can expand to 0x1F maximum */ + +#define ARGI_INVALID_OPCODE 0xFFFFFFFF + + +/* + * Some of the flags and types below are of the form: + * + * AML_FLAGS_EXEC_#A_#T,#R, or + * AML_TYPE_EXEC_#A_#T,#R where: + * + * #A is the number of required arguments + * #T is the number of target operands + * #R indicates whether there is a return value + * + * These types are used for the top-level dispatch of the AML + * opcode. They group similar operators that can share common + * front-end code before dispatch to the final code that implements + * the operator. + */ + +/* + * Opcode information flags + */ +#define AML_LOGICAL 0x0001 +#define AML_LOGICAL_NUMERIC 0x0002 +#define AML_MATH 0x0004 +#define AML_CREATE 0x0008 +#define AML_FIELD 0x0010 +#define AML_DEFER 0x0020 +#define AML_NAMED 0x0040 +#define AML_NSNODE 0x0080 +#define AML_NSOPCODE 0x0100 +#define AML_NSOBJECT 0x0200 +#define AML_HAS_RETVAL 0x0400 +#define AML_HAS_TARGET 0x0800 +#define AML_HAS_ARGS 0x1000 +#define AML_CONSTANT 0x2000 +#define AML_NO_OPERAND_RESOLVE 0x4000 + +/* Convenient flag groupings of the flags above */ + +#define AML_FLAGS_EXEC_0A_0T_1R AML_HAS_RETVAL +#define AML_FLAGS_EXEC_1A_0T_0R AML_HAS_ARGS /* Monadic1 */ +#define AML_FLAGS_EXEC_1A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Monadic2 */ +#define AML_FLAGS_EXEC_1A_1T_0R AML_HAS_ARGS | AML_HAS_TARGET +#define AML_FLAGS_EXEC_1A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* Monadic2R */ +#define AML_FLAGS_EXEC_2A_0T_0R AML_HAS_ARGS /* Dyadic1 */ +#define AML_FLAGS_EXEC_2A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Dyadic2 */ +#define AML_FLAGS_EXEC_2A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* Dyadic2R */ +#define AML_FLAGS_EXEC_2A_2T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL +#define AML_FLAGS_EXEC_3A_0T_0R AML_HAS_ARGS +#define AML_FLAGS_EXEC_3A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL +#define AML_FLAGS_EXEC_6A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL + + +/* + * The opcode Type is used in a dispatch table, do not change + * or add anything new without updating the table. + */ +#define AML_TYPE_EXEC_0A_0T_1R 0x00 /* 0 Args, 0 Target, 1 RetVal */ +#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* 1 Args, 0 Target, 0 RetVal */ +#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* 1 Args, 0 Target, 1 RetVal */ +#define AML_TYPE_EXEC_1A_1T_0R 0x03 /* 1 Args, 1 Target, 0 RetVal */ +#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* 1 Args, 1 Target, 1 RetVal */ +#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* 2 Args, 0 Target, 0 RetVal */ +#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* 2 Args, 0 Target, 1 RetVal */ +#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* 2 Args, 1 Target, 1 RetVal */ +#define AML_TYPE_EXEC_2A_2T_1R 0x08 /* 2 Args, 2 Target, 1 RetVal */ +#define AML_TYPE_EXEC_3A_0T_0R 0x09 /* 3 Args, 0 Target, 0 RetVal */ +#define AML_TYPE_EXEC_3A_1T_1R 0x0A /* 3 Args, 1 Target, 1 RetVal */ +#define AML_TYPE_EXEC_6A_0T_1R 0x0B /* 6 Args, 0 Target, 1 RetVal */ +/* End of types used in dispatch table */ + +#define AML_TYPE_LITERAL 0x0C +#define AML_TYPE_CONSTANT 0x0D +#define AML_TYPE_METHOD_ARGUMENT 0x0E +#define AML_TYPE_LOCAL_VARIABLE 0x0F +#define AML_TYPE_DATA_TERM 0x10 + +/* Generic for an op that returns a value */ + +#define AML_TYPE_METHOD_CALL 0x11 + +/* Miscellaneous types */ + +#define AML_TYPE_CREATE_FIELD 0x12 +#define AML_TYPE_CREATE_OBJECT 0x13 +#define AML_TYPE_CONTROL 0x14 +#define AML_TYPE_NAMED_NO_OBJ 0x15 +#define AML_TYPE_NAMED_FIELD 0x16 +#define AML_TYPE_NAMED_SIMPLE 0x17 +#define AML_TYPE_NAMED_COMPLEX 0x18 +#define AML_TYPE_RETURN 0x19 +#define AML_TYPE_UNDEFINED 0x1A +#define AML_TYPE_BOGUS 0x1B + +/* AML Package Length encodings */ + +#define ACPI_AML_PACKAGE_TYPE1 0x40 +#define ACPI_AML_PACKAGE_TYPE2 0x4000 +#define ACPI_AML_PACKAGE_TYPE3 0x400000 +#define ACPI_AML_PACKAGE_TYPE4 0x40000000 + +/* + * Opcode classes + */ +#define AML_CLASS_EXECUTE 0x00 +#define AML_CLASS_CREATE 0x01 +#define AML_CLASS_ARGUMENT 0x02 +#define AML_CLASS_NAMED_OBJECT 0x03 +#define AML_CLASS_CONTROL 0x04 +#define AML_CLASS_ASCII 0x05 +#define AML_CLASS_PREFIX 0x06 +#define AML_CLASS_INTERNAL 0x07 +#define AML_CLASS_RETURN_VALUE 0x08 +#define AML_CLASS_METHOD_CALL 0x09 +#define AML_CLASS_UNKNOWN 0x0A + + +/* Comparison operation codes for MatchOp operator */ + +typedef enum +{ + MATCH_MTR = 0, + MATCH_MEQ = 1, + MATCH_MLE = 2, + MATCH_MLT = 3, + MATCH_MGE = 4, + MATCH_MGT = 5 + +} AML_MATCH_OPERATOR; + +#define MAX_MATCH_OPERATOR 5 + + +/* + * FieldFlags + * + * This byte is extracted from the AML and includes three separate + * pieces of information about the field: + * 1) The field access type + * 2) The field update rule + * 3) The lock rule for the field + * + * Bits 00 - 03 : AccessType (AnyAcc, ByteAcc, etc.) + * 04 : LockRule (1 == Lock) + * 05 - 06 : UpdateRule + */ +#define AML_FIELD_ACCESS_TYPE_MASK 0x0F +#define AML_FIELD_LOCK_RULE_MASK 0x10 +#define AML_FIELD_UPDATE_RULE_MASK 0x60 + + +/* 1) Field Access Types */ + +typedef enum +{ + AML_FIELD_ACCESS_ANY = 0x00, + AML_FIELD_ACCESS_BYTE = 0x01, + AML_FIELD_ACCESS_WORD = 0x02, + AML_FIELD_ACCESS_DWORD = 0x03, + AML_FIELD_ACCESS_QWORD = 0x04, /* ACPI 2.0 */ + AML_FIELD_ACCESS_BUFFER = 0x05 /* ACPI 2.0 */ + +} AML_ACCESS_TYPE; + + +/* 2) Field Lock Rules */ + +typedef enum +{ + AML_FIELD_LOCK_NEVER = 0x00, + AML_FIELD_LOCK_ALWAYS = 0x10 + +} AML_LOCK_RULE; + + +/* 3) Field Update Rules */ + +typedef enum +{ + AML_FIELD_UPDATE_PRESERVE = 0x00, + AML_FIELD_UPDATE_WRITE_AS_ONES = 0x20, + AML_FIELD_UPDATE_WRITE_AS_ZEROS = 0x40 + +} AML_UPDATE_RULE; + + +/* + * Field Access Attributes. + * This byte is extracted from the AML via the + * AccessAs keyword + */ +typedef enum +{ + AML_FIELD_ATTRIB_QUICK = 0x02, + AML_FIELD_ATTRIB_SEND_RCV = 0x04, + AML_FIELD_ATTRIB_BYTE = 0x06, + AML_FIELD_ATTRIB_WORD = 0x08, + AML_FIELD_ATTRIB_BLOCK = 0x0A, + AML_FIELD_ATTRIB_MULTIBYTE = 0x0B, + AML_FIELD_ATTRIB_WORD_CALL = 0x0C, + AML_FIELD_ATTRIB_BLOCK_CALL = 0x0D, + AML_FIELD_ATTRIB_RAW_BYTES = 0x0E, + AML_FIELD_ATTRIB_RAW_PROCESS = 0x0F + +} AML_ACCESS_ATTRIBUTE; + + +/* Bit fields in the AML MethodFlags byte */ + +#define AML_METHOD_ARG_COUNT 0x07 +#define AML_METHOD_SERIALIZED 0x08 +#define AML_METHOD_SYNC_LEVEL 0xF0 + + +#endif /* __AMLCODE_H__ */ diff --git a/ports/acpica/include/amlresrc.h b/ports/acpica/include/amlresrc.h new file mode 100644 index 0000000..e9ee794 --- /dev/null +++ b/ports/acpica/include/amlresrc.h @@ -0,0 +1,857 @@ +/****************************************************************************** + * + * Module Name: amlresrc.h - AML resource descriptors + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +/* acpisrc:StructDefs -- for acpisrc conversion */ + +#ifndef __AMLRESRC_H +#define __AMLRESRC_H + + +/* + * Resource descriptor tags, as defined in the ACPI specification. + * Used to symbolically reference fields within a descriptor. + */ +#define ACPI_RESTAG_ADDRESS "_ADR" +#define ACPI_RESTAG_ALIGNMENT "_ALN" +#define ACPI_RESTAG_ADDRESSSPACE "_ASI" +#define ACPI_RESTAG_ACCESSSIZE "_ASZ" +#define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT" +#define ACPI_RESTAG_BASEADDRESS "_BAS" +#define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */ +#define ACPI_RESTAG_DEBOUNCETIME "_DBT" +#define ACPI_RESTAG_DECODE "_DEC" +#define ACPI_RESTAG_DEVICEPOLARITY "_DPL" +#define ACPI_RESTAG_DMA "_DMA" +#define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ +#define ACPI_RESTAG_DRIVESTRENGTH "_DRS" +#define ACPI_RESTAG_ENDIANNESS "_END" +#define ACPI_RESTAG_FLOWCONTROL "_FLC" +#define ACPI_RESTAG_FUNCTION "_FUN" +#define ACPI_RESTAG_GRANULARITY "_GRA" +#define ACPI_RESTAG_INTERRUPT "_INT" +#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* ActiveLo(1), ActiveHi(0) */ +#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), NoShare(0) */ +#define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ +#define ACPI_RESTAG_IORESTRICTION "_IOR" +#define ACPI_RESTAG_LENGTH "_LEN" +#define ACPI_RESTAG_LINE "_LIN" +#define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ +#define ACPI_RESTAG_MEMTYPE "_MEM" /* NonCache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ +#define ACPI_RESTAG_MAXADDR "_MAX" +#define ACPI_RESTAG_MINADDR "_MIN" +#define ACPI_RESTAG_MAXTYPE "_MAF" +#define ACPI_RESTAG_MINTYPE "_MIF" +#define ACPI_RESTAG_MODE "_MOD" +#define ACPI_RESTAG_PARITY "_PAR" +#define ACPI_RESTAG_PHASE "_PHA" +#define ACPI_RESTAG_PIN "_PIN" +#define ACPI_RESTAG_PINCONFIG "_PPI" +#define ACPI_RESTAG_PINCONFIG_TYPE "_TYP" +#define ACPI_RESTAG_PINCONFIG_VALUE "_VAL" +#define ACPI_RESTAG_POLARITY "_POL" +#define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" +#define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" +#define ACPI_RESTAG_RANGETYPE "_RNG" +#define ACPI_RESTAG_READWRITETYPE "_RW_" /* ReadOnly(0), Writeable (1) */ +#define ACPI_RESTAG_LENGTH_RX "_RXL" +#define ACPI_RESTAG_LENGTH_TX "_TXL" +#define ACPI_RESTAG_SLAVEMODE "_SLV" +#define ACPI_RESTAG_SPEED "_SPE" +#define ACPI_RESTAG_STOPBITS "_STB" +#define ACPI_RESTAG_TRANSLATION "_TRA" +#define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ +#define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */ +#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8And16(1), 16(2) */ +#define ACPI_RESTAG_VENDORDATA "_VEN" + + +/* Default sizes for "small" resource descriptors */ + +#define ASL_RDESC_IRQ_SIZE 0x02 +#define ASL_RDESC_DMA_SIZE 0x02 +#define ASL_RDESC_ST_DEPEND_SIZE 0x00 +#define ASL_RDESC_END_DEPEND_SIZE 0x00 +#define ASL_RDESC_IO_SIZE 0x07 +#define ASL_RDESC_FIXED_IO_SIZE 0x03 +#define ASL_RDESC_FIXED_DMA_SIZE 0x05 +#define ASL_RDESC_END_TAG_SIZE 0x01 + + +typedef struct asl_resource_node +{ + UINT32 BufferLength; + void *Buffer; + struct asl_resource_node *Next; + +} ASL_RESOURCE_NODE; + +typedef struct asl_resource_info +{ + ACPI_PARSE_OBJECT *DescriptorTypeOp; /* Resource descriptor parse node */ + ACPI_PARSE_OBJECT *MappingOp; /* Used for mapfile support */ + UINT32 CurrentByteOffset; /* Offset in resource template */ + +} ASL_RESOURCE_INFO; + + +/* Macros used to generate AML resource length fields */ + +#define ACPI_AML_SIZE_LARGE(r) (sizeof (r) - sizeof (AML_RESOURCE_LARGE_HEADER)) +#define ACPI_AML_SIZE_SMALL(r) (sizeof (r) - sizeof (AML_RESOURCE_SMALL_HEADER)) + +/* + * Resource descriptors defined in the ACPI specification. + * + * Packing/alignment must be BYTE because these descriptors + * are used to overlay the raw AML byte stream. + */ +#pragma pack(1) + +/* + * SMALL descriptors + */ +#define AML_RESOURCE_SMALL_HEADER_COMMON \ + UINT8 DescriptorType; + +typedef struct aml_resource_small_header +{ + AML_RESOURCE_SMALL_HEADER_COMMON + +} AML_RESOURCE_SMALL_HEADER; + + +typedef struct aml_resource_irq +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT16 IrqMask; + UINT8 Flags; + +} AML_RESOURCE_IRQ; + + +typedef struct aml_resource_irq_noflags +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT16 IrqMask; + +} AML_RESOURCE_IRQ_NOFLAGS; + + +typedef struct aml_resource_dma +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT8 DmaChannelMask; + UINT8 Flags; + +} AML_RESOURCE_DMA; + + +typedef struct aml_resource_start_dependent +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT8 Flags; + +} AML_RESOURCE_START_DEPENDENT; + + +typedef struct aml_resource_start_dependent_noprio +{ + AML_RESOURCE_SMALL_HEADER_COMMON + +} AML_RESOURCE_START_DEPENDENT_NOPRIO; + + +typedef struct aml_resource_end_dependent +{ + AML_RESOURCE_SMALL_HEADER_COMMON + +} AML_RESOURCE_END_DEPENDENT; + + +typedef struct aml_resource_io +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT8 Flags; + UINT16 Minimum; + UINT16 Maximum; + UINT8 Alignment; + UINT8 AddressLength; + +} AML_RESOURCE_IO; + + +typedef struct aml_resource_fixed_io +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT16 Address; + UINT8 AddressLength; + +} AML_RESOURCE_FIXED_IO; + + +typedef struct aml_resource_vendor_small +{ + AML_RESOURCE_SMALL_HEADER_COMMON + +} AML_RESOURCE_VENDOR_SMALL; + + +typedef struct aml_resource_end_tag +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT8 Checksum; + +} AML_RESOURCE_END_TAG; + + +typedef struct aml_resource_fixed_dma +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT16 RequestLines; + UINT16 Channels; + UINT8 Width; + +} AML_RESOURCE_FIXED_DMA; + + +/* + * LARGE descriptors + */ +#define AML_RESOURCE_LARGE_HEADER_COMMON \ + UINT8 DescriptorType;\ + UINT16 ResourceLength; + +typedef struct aml_resource_large_header +{ + AML_RESOURCE_LARGE_HEADER_COMMON + +} AML_RESOURCE_LARGE_HEADER; + + +/* General Flags for address space resource descriptors */ + +#define ACPI_RESOURCE_FLAG_DEC 2 +#define ACPI_RESOURCE_FLAG_MIF 4 +#define ACPI_RESOURCE_FLAG_MAF 8 + +typedef struct aml_resource_memory24 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 Flags; + UINT16 Minimum; + UINT16 Maximum; + UINT16 Alignment; + UINT16 AddressLength; + +} AML_RESOURCE_MEMORY24; + + +typedef struct aml_resource_vendor_large +{ + AML_RESOURCE_LARGE_HEADER_COMMON + +} AML_RESOURCE_VENDOR_LARGE; + + +typedef struct aml_resource_memory32 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 Flags; + UINT32 Minimum; + UINT32 Maximum; + UINT32 Alignment; + UINT32 AddressLength; + +} AML_RESOURCE_MEMORY32; + + +typedef struct aml_resource_fixed_memory32 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 Flags; + UINT32 Address; + UINT32 AddressLength; + +} AML_RESOURCE_FIXED_MEMORY32; + + +#define AML_RESOURCE_ADDRESS_COMMON \ + UINT8 ResourceType; \ + UINT8 Flags; \ + UINT8 SpecificFlags; + + +typedef struct aml_resource_address +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + +} AML_RESOURCE_ADDRESS; + + +typedef struct aml_resource_extended_address64 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + UINT8 RevisionID; + UINT8 Reserved; + UINT64 Granularity; + UINT64 Minimum; + UINT64 Maximum; + UINT64 TranslationOffset; + UINT64 AddressLength; + UINT64 TypeSpecific; + +} AML_RESOURCE_EXTENDED_ADDRESS64; + +#define AML_RESOURCE_EXTENDED_ADDRESS_REVISION 1 /* ACPI 3.0 */ + + +typedef struct aml_resource_address64 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + UINT64 Granularity; + UINT64 Minimum; + UINT64 Maximum; + UINT64 TranslationOffset; + UINT64 AddressLength; + +} AML_RESOURCE_ADDRESS64; + + +typedef struct aml_resource_address32 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + UINT32 Granularity; + UINT32 Minimum; + UINT32 Maximum; + UINT32 TranslationOffset; + UINT32 AddressLength; + +} AML_RESOURCE_ADDRESS32; + + +typedef struct aml_resource_address16 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + UINT16 Granularity; + UINT16 Minimum; + UINT16 Maximum; + UINT16 TranslationOffset; + UINT16 AddressLength; + +} AML_RESOURCE_ADDRESS16; + + +typedef struct aml_resource_extended_irq +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 Flags; + UINT8 InterruptCount; + UINT32 Interrupts[1]; + /* ResSourceIndex, ResSource optional fields follow */ + +} AML_RESOURCE_EXTENDED_IRQ; + + +typedef struct aml_resource_generic_register +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 AddressSpaceId; + UINT8 BitWidth; + UINT8 BitOffset; + UINT8 AccessSize; /* ACPI 3.0, was previously Reserved */ + UINT64 Address; + +} AML_RESOURCE_GENERIC_REGISTER; + + +/* Common descriptor for GpioInt and GpioIo (ACPI 5.0) */ + +typedef struct aml_resource_gpio +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 RevisionId; + UINT8 ConnectionType; + UINT16 Flags; + UINT16 IntFlags; + UINT8 PinConfig; + UINT16 DriveStrength; + UINT16 DebounceTimeout; + UINT16 PinTableOffset; + UINT8 ResSourceIndex; + UINT16 ResSourceOffset; + UINT16 VendorOffset; + UINT16 VendorLength; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ + +} AML_RESOURCE_GPIO; + +#define AML_RESOURCE_GPIO_REVISION 1 /* ACPI 5.0 */ + +/* Values for ConnectionType above */ + +#define AML_RESOURCE_GPIO_TYPE_INT 0 +#define AML_RESOURCE_GPIO_TYPE_IO 1 +#define AML_RESOURCE_MAX_GPIOTYPE 1 + + +/* Common preamble for all serial descriptors (ACPI 5.0) */ + +#define AML_RESOURCE_SERIAL_COMMON \ + UINT8 RevisionId; \ + UINT8 ResSourceIndex; \ + UINT8 Type; \ + UINT8 Flags; \ + UINT16 TypeSpecificFlags; \ + UINT8 TypeRevisionId; \ + UINT16 TypeDataLength; \ + +/* Values for the type field above */ + +#define AML_RESOURCE_I2C_SERIALBUSTYPE 1 +#define AML_RESOURCE_SPI_SERIALBUSTYPE 2 +#define AML_RESOURCE_UART_SERIALBUSTYPE 3 +#define AML_RESOURCE_MAX_SERIALBUSTYPE 3 +#define AML_RESOURCE_VENDOR_SERIALBUSTYPE 192 /* Vendor defined is 0xC0-0xFF (NOT SUPPORTED) */ + +typedef struct aml_resource_common_serialbus +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON + +} AML_RESOURCE_COMMON_SERIALBUS; + +typedef struct aml_resource_i2c_serialbus +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON + UINT32 ConnectionSpeed; + UINT16 SlaveAddress; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ + +} AML_RESOURCE_I2C_SERIALBUS; + +#define AML_RESOURCE_I2C_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_I2C_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_I2C_MIN_DATA_LEN 6 + +typedef struct aml_resource_spi_serialbus +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON + UINT32 ConnectionSpeed; + UINT8 DataBitLength; + UINT8 ClockPhase; + UINT8 ClockPolarity; + UINT16 DeviceSelection; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ + +} AML_RESOURCE_SPI_SERIALBUS; + +#define AML_RESOURCE_SPI_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_SPI_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_SPI_MIN_DATA_LEN 9 + + +typedef struct aml_resource_uart_serialbus +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON + UINT32 DefaultBaudRate; + UINT16 RxFifoSize; + UINT16 TxFifoSize; + UINT8 Parity; + UINT8 LinesEnabled; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ + +} AML_RESOURCE_UART_SERIALBUS; + +#define AML_RESOURCE_UART_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_UART_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_UART_MIN_DATA_LEN 10 + +typedef struct aml_resource_pin_function +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 RevisionId; + UINT16 Flags; + UINT8 PinConfig; + UINT16 FunctionNumber; + UINT16 PinTableOffset; + UINT8 ResSourceIndex; + UINT16 ResSourceOffset; + UINT16 VendorOffset; + UINT16 VendorLength; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ + +} AML_RESOURCE_PIN_FUNCTION; + +#define AML_RESOURCE_PIN_FUNCTION_REVISION 1 /* ACPI 6.2 */ + +typedef struct aml_resource_pin_config +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 RevisionId; + UINT16 Flags; + UINT8 PinConfigType; + UINT32 PinConfigValue; + UINT16 PinTableOffset; + UINT8 ResSourceIndex; + UINT16 ResSourceOffset; + UINT16 VendorOffset; + UINT16 VendorLength; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ + +} AML_RESOURCE_PIN_CONFIG; + +#define AML_RESOURCE_PIN_CONFIG_REVISION 1 /* ACPI 6.2 */ + +typedef struct aml_resource_pin_group +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 RevisionId; + UINT16 Flags; + UINT16 PinTableOffset; + UINT16 LabelOffset; + UINT16 VendorOffset; + UINT16 VendorLength; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Label String + * 3) Vendor Data bytes + */ + +} AML_RESOURCE_PIN_GROUP; + +#define AML_RESOURCE_PIN_GROUP_REVISION 1 /* ACPI 6.2 */ + +typedef struct aml_resource_pin_group_function +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 RevisionId; + UINT16 Flags; + UINT16 FunctionNumber; + UINT8 ResSourceIndex; + UINT16 ResSourceOffset; + UINT16 ResSourceLabelOffset; + UINT16 VendorOffset; + UINT16 VendorLength; + /* + * Optional fields follow immediately: + * 1) Resource Source String + * 2) Resource Source Label String + * 3) Vendor Data bytes + */ + +} AML_RESOURCE_PIN_GROUP_FUNCTION; + +#define AML_RESOURCE_PIN_GROUP_FUNCTION_REVISION 1 /* ACPI 6.2 */ + +typedef struct aml_resource_pin_group_config +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 RevisionId; + UINT16 Flags; + UINT8 PinConfigType; + UINT32 PinConfigValue; + UINT8 ResSourceIndex; + UINT16 ResSourceOffset; + UINT16 ResSourceLabelOffset; + UINT16 VendorOffset; + UINT16 VendorLength; + /* + * Optional fields follow immediately: + * 1) Resource Source String + * 2) Resource Source Label String + * 3) Vendor Data bytes + */ + +} AML_RESOURCE_PIN_GROUP_CONFIG; + +#define AML_RESOURCE_PIN_GROUP_CONFIG_REVISION 1 /* ACPI 6.2 */ + +/* restore default alignment */ + +#pragma pack() + +/* Union of all resource descriptors, so we can allocate the worst case */ + +typedef union aml_resource +{ + /* Descriptor headers */ + + UINT8 DescriptorType; + AML_RESOURCE_SMALL_HEADER SmallHeader; + AML_RESOURCE_LARGE_HEADER LargeHeader; + + /* Small resource descriptors */ + + AML_RESOURCE_IRQ Irq; + AML_RESOURCE_DMA Dma; + AML_RESOURCE_START_DEPENDENT StartDpf; + AML_RESOURCE_END_DEPENDENT EndDpf; + AML_RESOURCE_IO Io; + AML_RESOURCE_FIXED_IO FixedIo; + AML_RESOURCE_FIXED_DMA FixedDma; + AML_RESOURCE_VENDOR_SMALL VendorSmall; + AML_RESOURCE_END_TAG EndTag; + + /* Large resource descriptors */ + + AML_RESOURCE_MEMORY24 Memory24; + AML_RESOURCE_GENERIC_REGISTER GenericReg; + AML_RESOURCE_VENDOR_LARGE VendorLarge; + AML_RESOURCE_MEMORY32 Memory32; + AML_RESOURCE_FIXED_MEMORY32 FixedMemory32; + AML_RESOURCE_ADDRESS16 Address16; + AML_RESOURCE_ADDRESS32 Address32; + AML_RESOURCE_ADDRESS64 Address64; + AML_RESOURCE_EXTENDED_ADDRESS64 ExtAddress64; + AML_RESOURCE_EXTENDED_IRQ ExtendedIrq; + AML_RESOURCE_GPIO Gpio; + AML_RESOURCE_I2C_SERIALBUS I2cSerialBus; + AML_RESOURCE_SPI_SERIALBUS SpiSerialBus; + AML_RESOURCE_UART_SERIALBUS UartSerialBus; + AML_RESOURCE_COMMON_SERIALBUS CommonSerialBus; + AML_RESOURCE_PIN_FUNCTION PinFunction; + AML_RESOURCE_PIN_CONFIG PinConfig; + AML_RESOURCE_PIN_GROUP PinGroup; + AML_RESOURCE_PIN_GROUP_FUNCTION PinGroupFunction; + AML_RESOURCE_PIN_GROUP_CONFIG PinGroupConfig; + + /* Utility overlays */ + + AML_RESOURCE_ADDRESS Address; + UINT32 DwordItem; + UINT16 WordItem; + UINT8 ByteItem; + +} AML_RESOURCE; + + +/* Interfaces used by both the disassembler and compiler */ + +void +MpSaveGpioInfo ( + ACPI_PARSE_OBJECT *Op, + AML_RESOURCE *Resource, + UINT32 PinCount, + UINT16 *PinList, + char *DeviceName); + +void +MpSaveSerialInfo ( + ACPI_PARSE_OBJECT *Op, + AML_RESOURCE *Resource, + char *DeviceName); + +char * +MpGetHidFromParseTree ( + ACPI_NAMESPACE_NODE *HidNode); + +char * +MpGetHidViaNamestring ( + char *DeviceName); + +char * +MpGetConnectionInfo ( + ACPI_PARSE_OBJECT *Op, + UINT32 PinIndex, + ACPI_NAMESPACE_NODE **TargetNode, + char **TargetName); + +char * +MpGetParentDeviceHid ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE **TargetNode, + char **ParentDeviceName); + +char * +MpGetDdnValue ( + char *DeviceName); + +char * +MpGetHidValue ( + ACPI_NAMESPACE_NODE *DeviceNode); + +#endif diff --git a/ports/acpica/include/platform/acenv.h b/ports/acpica/include/platform/acenv.h new file mode 100644 index 0000000..09f74fb --- /dev/null +++ b/ports/acpica/include/platform/acenv.h @@ -0,0 +1,504 @@ +/****************************************************************************** + * + * Name: acenv.h - Host and compiler configuration + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACENV_H__ +#define __ACENV_H__ + +/* + * Environment configuration. The purpose of this file is to interface ACPICA + * to the local environment. This includes compiler-specific, OS-specific, + * and machine-specific configuration. + */ + +/* Types for ACPI_MUTEX_TYPE */ + +#define ACPI_BINARY_SEMAPHORE 0 +#define ACPI_OSL_MUTEX 1 + +/* Types for DEBUGGER_THREADING */ + +#define DEBUGGER_SINGLE_THREADED 0 +#define DEBUGGER_MULTI_THREADED 1 + + +/****************************************************************************** + * + * Configuration for ACPI tools and utilities + * + *****************************************************************************/ + +/* Common application configuration. All single threaded except for AcpiExec. */ + +#if (defined ACPI_ASL_COMPILER) || \ + (defined ACPI_BIN_APP) || \ + (defined ACPI_DUMP_APP) || \ + (defined ACPI_HELP_APP) || \ + (defined ACPI_NAMES_APP) || \ + (defined ACPI_SRC_APP) || \ + (defined ACPI_XTRACT_APP) || \ + (defined ACPI_EXAMPLE_APP) || \ + (defined ACPI_EFI_HELLO) +#define ACPI_APPLICATION +#define ACPI_SINGLE_THREADED +#define USE_NATIVE_ALLOCATE_ZEROED +#endif + +/* iASL configuration */ + +#ifdef ACPI_ASL_COMPILER +#define ACPI_DEBUG_OUTPUT +#define ACPI_CONSTANT_EVAL_ONLY +#define ACPI_LARGE_NAMESPACE_NODE +#define ACPI_DATA_TABLE_DISASSEMBLY +#define ACPI_32BIT_PHYSICAL_ADDRESS +#define ACPI_DISASSEMBLER 1 +#endif + +/* AcpiExec configuration. Multithreaded with full AML debugger */ + +#ifdef ACPI_EXEC_APP +#define ACPI_APPLICATION +#define ACPI_FULL_DEBUG +#define ACPI_MUTEX_DEBUG +#define ACPI_DBG_TRACK_ALLOCATIONS +#endif + +/* AcpiHelp configuration. Error messages disabled. */ + +#ifdef ACPI_HELP_APP +#define ACPI_NO_ERROR_MESSAGES +#endif + +/* AcpiNames configuration. Debug output enabled. */ + +#ifdef ACPI_NAMES_APP +#define ACPI_DEBUG_OUTPUT +#endif + +/* AcpiExec/AcpiNames/Example configuration. Native RSDP used. */ + +#if (defined ACPI_EXEC_APP) || \ + (defined ACPI_EXAMPLE_APP) || \ + (defined ACPI_NAMES_APP) +#define ACPI_USE_NATIVE_RSDP_POINTER +#endif + +/* AcpiDump configuration. Native mapping used if provided by the host */ + +#ifdef ACPI_DUMP_APP +#define ACPI_USE_NATIVE_MEMORY_MAPPING +#endif + +/* AcpiNames/Example configuration. Hardware disabled */ + +#if (defined ACPI_EXAMPLE_APP) || \ + (defined ACPI_NAMES_APP) +#define ACPI_REDUCED_HARDWARE 1 +#endif + +/* Linkable ACPICA library. Two versions, one with full debug. */ + +#ifdef ACPI_LIBRARY +#define ACPI_USE_LOCAL_CACHE +#define ACPI_DEBUGGER 1 +#define ACPI_DISASSEMBLER 1 + +#ifdef _DEBUG +#define ACPI_DEBUG_OUTPUT +#endif +#endif + +/* Common for all ACPICA applications */ + +#ifdef ACPI_APPLICATION +#define ACPI_USE_LOCAL_CACHE +#endif + +/* Common debug/disassembler support */ + +#ifdef ACPI_FULL_DEBUG +#define ACPI_DEBUG_OUTPUT +#define ACPI_DEBUGGER 1 +#define ACPI_DISASSEMBLER 1 +#endif + +/*! [Begin] no source code translation */ + +/****************************************************************************** + * + * Host configuration files. The compiler configuration files are included + * first. + * + *****************************************************************************/ + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#include "acgcc.h" + +#elif defined(_MSC_VER) +#include "acmsvc.h" + +#elif defined(__INTEL_COMPILER) +#include "acintel.h" + +#endif + +#include "acessence.h" + +#if defined(_LINUX) || defined(__linux__) +#include "aclinux.h" + +#elif defined(_APPLE) || defined(__APPLE__) +#include "acmacosx.h" + +#elif defined(__DragonFly__) +#include "acdragonfly.h" + +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include "acfreebsd.h" + +#elif defined(__NetBSD__) +#include "acnetbsd.h" + +#elif defined(__sun) +#include "acsolaris.h" + +#elif defined(MODESTO) +#include "acmodesto.h" + +#elif defined(NETWARE) +#include "acnetware.h" + +#elif defined(_CYGWIN) +#include "accygwin.h" + +#elif defined(WIN32) +#include "acwin.h" + +#elif defined(WIN64) +#include "acwin64.h" + +#elif defined(_WRS_LIB_BUILD) +#include "acvxworks.h" + +#elif defined(__OS2__) +#include "acos2.h" + +#elif defined(__HAIKU__) +#include "achaiku.h" + +#elif defined(__QNX__) +#include "acqnx.h" + +/* + * EFI applications can be built with -nostdlib, in this case, it must be + * included after including all other host environmental definitions, in + * order to override the definitions. + */ +#elif defined(_AED_EFI) || defined(_GNU_EFI) || defined(_EDK2_EFI) +#include "acefi.h" + +#else + +/* Unknown environment */ + +/*#error Unknown target environment*/ +#endif + +/*! [End] no source code translation !*/ + + +/****************************************************************************** + * + * Setup defaults for the required symbols that were not defined in one of + * the host/compiler files above. + * + *****************************************************************************/ + +/* 64-bit data types */ + +#ifndef COMPILER_DEPENDENT_INT64 +#define COMPILER_DEPENDENT_INT64 long long +#endif + +#ifndef COMPILER_DEPENDENT_UINT64 +#define COMPILER_DEPENDENT_UINT64 unsigned long long +#endif + +/* Type of mutex supported by host. Default is binary semaphores. */ + +#ifndef ACPI_MUTEX_TYPE +#define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE +#endif + +/* Global Lock acquire/release */ + +#ifndef ACPI_ACQUIRE_GLOBAL_LOCK +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acquired) Acquired = 1 +#endif + +#ifndef ACPI_RELEASE_GLOBAL_LOCK +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Pending) Pending = 0 +#endif + +/* Flush CPU cache - used when going to sleep. Wbinvd or similar. */ + +#ifndef ACPI_FLUSH_CPU_CACHE +#define ACPI_FLUSH_CPU_CACHE() +#endif + +/* "inline" keywords - configurable since inline is not standardized */ + +#ifndef ACPI_INLINE +#define ACPI_INLINE +#endif + +/* Use ordered initialization if compiler doesn't support designated. */ +#ifndef ACPI_STRUCT_INIT +#define ACPI_STRUCT_INIT(field, value) value +#endif + +/* + * Configurable calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#ifndef ACPI_SYSTEM_XFACE +#define ACPI_SYSTEM_XFACE +#endif + +#ifndef ACPI_EXTERNAL_XFACE +#define ACPI_EXTERNAL_XFACE +#endif + +#ifndef ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#endif + +#ifndef ACPI_INTERNAL_VAR_XFACE +#define ACPI_INTERNAL_VAR_XFACE +#endif + + +/* + * Debugger threading model + * Use single threaded if the entire subsystem is contained in an application + * Use multiple threaded when the subsystem is running in the kernel. + * + * By default the model is single threaded if ACPI_APPLICATION is set, + * multi-threaded if ACPI_APPLICATION is not set. + */ +#ifndef DEBUGGER_THREADING +#if !defined (ACPI_APPLICATION) || defined (ACPI_EXEC_APP) +#define DEBUGGER_THREADING DEBUGGER_MULTI_THREADED + +#else +#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED +#endif +#endif /* !DEBUGGER_THREADING */ + + +/****************************************************************************** + * + * C library configuration + * + *****************************************************************************/ + +/* + * ACPI_USE_SYSTEM_CLIBRARY - Define this if linking to an actual C library. + * Otherwise, local versions of string/memory functions will be used. + * ACPI_USE_STANDARD_HEADERS - Define this if linking to a C library and + * the standard header files may be used. Defining this implies that + * ACPI_USE_SYSTEM_CLIBRARY has been defined. + * + * The ACPICA subsystem only uses low level C library functions that do not + * call operating system services and may therefore be inlined in the code. + * + * It may be necessary to tailor these include files to the target + * generation environment. + */ + +/* Use the standard C library headers. We want to keep these to a minimum. */ + +#ifdef ACPI_USE_STANDARD_HEADERS + +/* Use the standard headers from the standard locations */ + +#include +#include +#include +#if defined (ACPI_APPLICATION) || defined(ACPI_LIBRARY) +#include +#include +#include +#include +#include +#endif + +#endif /* ACPI_USE_STANDARD_HEADERS */ + +#ifdef ACPI_APPLICATION +#define ACPI_FILE FILE * +#define ACPI_FILE_OUT stdout +#define ACPI_FILE_ERR stderr +#else +#define ACPI_FILE void * +#define ACPI_FILE_OUT NULL +#define ACPI_FILE_ERR NULL +#endif /* ACPI_APPLICATION */ + +#ifndef ACPI_INIT_FUNCTION +#define ACPI_INIT_FUNCTION +#endif + +#endif /* __ACENV_H__ */ diff --git a/ports/acpica/include/platform/acenvex.h b/ports/acpica/include/platform/acenvex.h new file mode 100644 index 0000000..65573d7 --- /dev/null +++ b/ports/acpica/include/platform/acenvex.h @@ -0,0 +1,190 @@ +/****************************************************************************** + * + * Name: acenvex.h - Extra host and compiler configuration + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACENVEX_H__ +#define __ACENVEX_H__ + +/*! [Begin] no source code translation */ + +/****************************************************************************** + * + * Extra host configuration files. All ACPICA headers are included before + * including these files. + * + *****************************************************************************/ + +#if defined(_LINUX) || defined(__linux__) +#include "aclinuxex.h" + +#elif defined(__DragonFly__) +#include "acdragonflyex.h" + +/* + * EFI applications can be built with -nostdlib, in this case, it must be + * included after including all other host environmental definitions, in + * order to override the definitions. + */ +#elif defined(_AED_EFI) || defined(_GNU_EFI) || defined(_EDK2_EFI) +#include "acefiex.h" + +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#include "acgccex.h" + +#elif defined(_MSC_VER) +#include "acmsvcex.h" + +#endif + +/*! [End] no source code translation !*/ + +#endif /* __ACENVEX_H__ */ diff --git a/ports/acpica/include/platform/acessence.h b/ports/acpica/include/platform/acessence.h new file mode 100644 index 0000000..56a15c0 --- /dev/null +++ b/ports/acpica/include/platform/acessence.h @@ -0,0 +1,11 @@ +#ifndef _included_acessence +#define _included_acessence + +void ProcessorFlushCodeCache(); + +#define ACPI_MACHINE_WIDTH (64) +#define ACPI_CACHE_T ACPI_MEMORY_LIST +#define ACPI_USE_LOCAL_CACHE 1 +#define ACPI_FLUSH_CPU_CACHE() ProcessorFlushCodeCache() + +#endif diff --git a/ports/acpica/include/platform/acgcc.h b/ports/acpica/include/platform/acgcc.h new file mode 100644 index 0000000..7de4a66 --- /dev/null +++ b/ports/acpica/include/platform/acgcc.h @@ -0,0 +1,199 @@ +/****************************************************************************** + * + * Name: acgcc.h - GCC specific defines, etc. + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACGCC_H__ +#define __ACGCC_H__ + +/* + * Use compiler specific is a good practice for even when + * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined. + */ +#ifndef va_arg +#ifdef ACPI_USE_BUILTIN_STDARG +typedef __builtin_va_list va_list; +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) +#else +#include +#endif +#endif + +#define ACPI_INLINE __inline__ + +/* Function name is used for debug output. Non-ANSI, compiler-dependent */ + +#define ACPI_GET_FUNCTION_NAME __func__ + +/* + * This macro is used to tag functions as "printf-like" because + * some compilers (like GCC) can catch printf format string problems. + */ +#define ACPI_PRINTF_LIKE(c) __attribute__ ((__format__ (__printf__, c, c+1))) + +/* + * Some compilers complain about unused variables. Sometimes we don't want to + * use all the variables (for example, _AcpiModuleName). This allows us + * to tell the compiler warning in a per-variable manner that a variable + * is unused. + */ +#define ACPI_UNUSED_VAR __attribute__ ((unused)) + +/* GCC supports __VA_ARGS__ in macros */ + +#define COMPILER_VA_MACRO 1 + +/* GCC supports native multiply/shift on 32-bit platforms */ + +#define ACPI_USE_NATIVE_MATH64 + +#endif /* __ACGCC_H__ */ diff --git a/ports/acpica/include/platform/acgccex.h b/ports/acpica/include/platform/acgccex.h new file mode 100644 index 0000000..f262c72 --- /dev/null +++ b/ports/acpica/include/platform/acgccex.h @@ -0,0 +1,166 @@ +/****************************************************************************** + * + * Name: acgccex.h - Extra GCC specific defines, etc. + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#ifndef __ACGCCEX_H__ +#define __ACGCCEX_H__ + +/* + * Some versions of gcc implement strchr() with a buggy macro. So, + * undef it here. Prevents error messages of this form (usually from the + * file getopt.c): + * + * error: logical '&&' with non-zero constant will always evaluate as true + */ +#ifdef strchr +#undef strchr +#endif + +#endif /* __ACGCCEX_H__ */ diff --git a/ports/acpica/libacpica.a b/ports/acpica/libacpica.a new file mode 100644 index 0000000..1fb5b21 Binary files /dev/null and b/ports/acpica/libacpica.a differ diff --git a/ports/acpica/licensing.txt b/ports/acpica/licensing.txt new file mode 100644 index 0000000..69e782f --- /dev/null +++ b/ports/acpica/licensing.txt @@ -0,0 +1,144 @@ +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2017, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ diff --git a/ports/bochs/Makefile.in b/ports/bochs/Makefile.in new file mode 100644 index 0000000..247d020 --- /dev/null +++ b/ports/bochs/Makefile.in @@ -0,0 +1,842 @@ +# Copyright (C) 2001-2017 The Bochs Project +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +#################################################### +# NOTE: To be compatibile with nmake (microsoft vc++) please follow +# the following rules: +# use $(VAR) not ${VAR} + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +srcdir = @srcdir@ +VPATH = @srcdir@ +bindir = @bindir@ +libdir = @libdir@ +plugdir = @libdir@/bochs/plugins +datarootdir = @datarootdir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man5dir = $(mandir)/man5 +docdir = $(datarootdir)/doc/bochs +sharedir = $(datarootdir)/bochs +top_builddir = . +top_srcdir = $(srcdir) + +DESTDIR = + +VERSION=@VERSION@ +VER_STRING=@VER_STRING@ +REL_STRING=@REL_STRING@ +MAN_PAGE_1_LIST=bochs bximage bochs-dlx +MAN_PAGE_5_LIST=bochsrc +INSTALL_LIST_SHARE=bios/BIOS-bochs-* bios/VGABIOS* bios/SeaBIOS* bios/bios.bin-* @INSTALL_LIST_FOR_PLATFORM@ +INSTALL_LIST_DOC=CHANGES COPYING LICENSE README TODO misc/slirp.conf +INSTALL_LIST_BIN=bochs@EXE@ bximage@EXE@ +INSTALL_LIST_BIN_OPTIONAL=bochsdbg@EXE@ @OPTIONAL_TARGET@ +INSTALL_LIST_WIN32=$(INSTALL_LIST_SHARE) $(INSTALL_LIST_DOC) $(INSTALL_LIST_BIN) $(INSTALL_LIST_BIN_OPTIONAL) +INSTALL_LIST_MACOSX=$(INSTALL_LIST_SHARE) $(INSTALL_LIST_DOC) bochs.scpt +# for win32 and macosx, these files get renamed to *.txt in install process +TEXT_FILE_LIST=README CHANGES COPYING LICENSE TODO VGABIOS-elpin-LICENSE VGABIOS-lgpl-README SeaBIOS-README +CP=cp +CAT=cat +RM=rm +MV=mv +LN_S=ln -sf +DLXLINUX_TAR=dlxlinux4.tar.gz +DLXLINUX_TAR_URL=http://bochs.sourceforge.net/guestos/$(DLXLINUX_TAR) +DLXLINUX_ROMFILE=BIOS-bochs-latest +GUNZIP=gunzip +WGET=@WGET@ +SED=sed +MKDIR=mkdir +RMDIR=rmdir +TAR=tar +CHMOD=chmod +# the GZIP variable is reserved by gzip program +GZIP_BIN=gzip -9 +GUNZIP=gunzip +ZIP=zip +UNIX2DOS=unix2dos +LIBTOOL=@LIBTOOL@ +DLLTOOL=dlltool +RC_CMD=@RC_CMD@ + +@SUFFIX_LINE@ + +srcdir = @srcdir@ +VPATH = @srcdir@ + +SHELL = @SHELL@ + +@SET_MAKE@ + +CC = @CC@ +CXX = @CXX@ +CFLAGS = @CFLAGS@ @GUI_CFLAGS@ $(MCH_CFLAGS) $(FLA_FLAGS) @DEFINE_PLUGIN_PATH@ -DBX_SHARE_PATH='"$(sharedir)"' +CXXFLAGS = @CXXFLAGS@ @GUI_CXXFLAGS@ $(MCH_CFLAGS) $(FLA_FLAGS) @DEFINE_PLUGIN_PATH@ -DBX_SHARE_PATH='"$(sharedir)"' + +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +# To compile with readline: +# linux needs just -lreadline +# solaris needs -lreadline -lcurses +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +GUI_LINK_OPTS_X = $(X_LIBS) $(X_PRE_LIBS) +GUI_LINK_OPTS_SDL = @GUI_LINK_OPTS_SDL@ +GUI_LINK_OPTS_SDL2 = @GUI_LINK_OPTS_SDL2@ +GUI_LINK_OPTS_SVGA = -lvga -lvgagl +GUI_LINK_OPTS_RFB = @RFB_LIBS@ +GUI_LINK_OPTS_VNCSRV = @GUI_LINK_OPTS_VNCSRV@ +GUI_LINK_OPTS_AMIGAOS = +GUI_LINK_OPTS_WIN32 = -luser32 -lgdi32 -lcomdlg32 -lcomctl32 -lshell32 +GUI_LINK_OPTS_WIN32_VCPP = user32.lib gdi32.lib winmm.lib \ + comdlg32.lib comctl32.lib advapi32.lib shell32.lib +GUI_LINK_OPTS_MACOS = +GUI_LINK_OPTS_CARBON = -framework Carbon +GUI_LINK_OPTS_NOGUI = +GUI_LINK_OPTS_ESSENCE = +GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@ +GUI_LINK_OPTS_WX = @GUI_LINK_OPTS_WX@ +GUI_LINK_OPTS = @GUI_LINK_OPTS@ +DEVICE_LINK_OPTS = @DEVICE_LINK_OPTS@ +RANLIB = @RANLIB@ + +CFLAGS_CONSOLE = @CFLAGS@ $(MCH_CFLAGS) $(FLA_FLAGS) +CXXFLAGS_CONSOLE = @CXXFLAGS_CONSOLE@ $(MCH_CFLAGS) $(FLA_FLAGS) +BXIMAGE_LINK_OPTS = @BXIMAGE_LINK_OPTS@ + +BX_INCDIRS = -I. -I$(srcdir)/. -I@INSTRUMENT_DIR@ -I$(srcdir)/@INSTRUMENT_DIR@ + +#SUBDIRS = iodev bx_debug + +#all install uninstall: config.h# +# for subdir in $(SUBDIRS); do # +# echo making $@ in $$subdir; # +# ($(MAKE) -C $$subdir $(MDEFINES) $@) || exit 1; # +# done# + + + +# gnu flags for clean up +#CFLAGS = -ansi -O -g -Wunused -Wuninitialized + + +NONINLINE_OBJS = \ + logio.o \ + main.o \ + config.o \ + load32bitOShack.o \ + pc_system.o \ + osdep.o \ + plugin.o \ + crc.o \ + @EXTRA_BX_OBJS@ + +EXTERN_ENVIRONMENT_OBJS = \ + main.o \ + config.o \ + load32bitOShack.o \ + pc_system.o + +DEBUGGER_LIB = bx_debug/libdebug.a +DISASM_LIB = disasm/libdisasm.a +INSTRUMENT_LIB = @INSTRUMENT_DIR@/libinstrument.a +FPU_LIB = cpu/fpu/libfpu.a +AVX_LIB = cpu/avx/libavx.a +READLINE_LIB = @READLINE_LIB@ +EXTRA_LINK_OPTS = @EXTRA_LINK_OPTS@ + +GDBSTUB_OBJS = gdbstub.o + +BX_OBJS = @NONINLINE_VAR@ + +BX_INCLUDES = bochs.h config.h osdep.h + + +.@CPP_SUFFIX@.o: + $(CXX) @DASH@c $(BX_INCDIRS) $(CXXFLAGS) @CXXFP@$< @OFP@$@ +.c.o: + $(CC) @DASH@c $(BX_INCDIRS) $(CFLAGS) $(FPU_FLAGS) $< @OFP@$@ + + +all: @PRIMARY_TARGET@ @PLUGIN_TARGET@ bximage@EXE@ @OPTIONAL_TARGET@ @BUILD_DOCBOOK_VAR@ + +@EXTERNAL_DEPENDENCY@ + +bochs@EXE@: @IODEV_LIB_VAR@ @DISPLAY_LIB_VAR@ @HDIMAGE_LIB_VAR@ @USB_LIB_VAR@ @NETWORK_LIB_VAR@ @SOUND_LIB_VAR@ \ + @DEBUGGER_VAR@ cpu/libcpu.a @AVX_LIB_VAR@ cpu/cpudb/libcpudb.a memory/libmemory.a \ + gui/libgui.a @DISASM_VAR@ @INSTRUMENT_VAR@ $(BX_OBJS) \ + $(SIMX86_OBJS) @FPU_VAR@ @GDBSTUB_VAR@ @PLUGIN_VAR@ + @LINK@ @EXPORT_DYNAMIC@ $(BX_OBJS) $(SIMX86_OBJS) \ + @IODEV_LIB_VAR@ @DISPLAY_LIB_VAR@ @HDIMAGE_LIB_VAR@ @USB_LIB_VAR@ @NETWORK_LIB_VAR@ @SOUND_LIB_VAR@ \ + @DEBUGGER_VAR@ cpu/libcpu.a @AVX_LIB_VAR@ cpu/cpudb/libcpudb.a \ + memory/libmemory.a gui/libgui.a \ + @DISASM_VAR@ @INSTRUMENT_VAR@ @PLUGIN_LIB@ \ + @GDBSTUB_VAR@ @FPU_VAR@ \ + @NONPLUGIN_GUI_LINK_OPTS@ \ + $(DEVICE_LINK_OPTS) \ + $(MCH_LINK_FLAGS) \ + $(SIMX86_LINK_FLAGS) \ + $(READLINE_LIB) \ + $(EXTRA_LINK_OPTS) \ + $(LIBS) + +# Special make target for cygwin/mingw using dlltool instead of +# libtool. This creates a .DEF file, and exports file, an import library, +# and then links bochs.exe with the exports file. +.win32_dll_plugin_target: @IODEV_LIB_VAR@ @DISPLAY_LIB_VAR@ @HDIMAGE_LIB_VAR@ @USB_LIB_VAR@ @NETWORK_LIB_VAR@ \ + @SOUND_LIB_VAR@ @DEBUGGER_VAR@ cpu/libcpu.a @AVX_LIB_VAR@ cpu/cpudb/libcpudb.a \ + memory/libmemory.a gui/libgui.a @DISASM_VAR@ @INSTRUMENT_VAR@ \ + $(BX_OBJS) $(SIMX86_OBJS) @FPU_VAR@ @GDBSTUB_VAR@ @PLUGIN_VAR@ + $(DLLTOOL) --export-all-symbols --output-def bochs.def \ + $(BX_OBJS) $(SIMX86_OBJS) \ + @IODEV_LIB_VAR@ @DISPLAY_LIB_VAR@ @HDIMAGE_LIB_VAR@ @USB_LIB_VAR@ @NETWORK_LIB_VAR@ @SOUND_LIB_VAR@ \ + cpu/libcpu.a @AVX_LIB_VAR@ cpu/cpudb/libcpudb.a memory/libmemory.a gui/libgui.a \ + @DEBUGGER_VAR@ @DISASM_VAR@ @INSTRUMENT_VAR@ @PLUGIN_VAR@ \ + @GDBSTUB_VAR@ @FPU_VAR@ + $(DLLTOOL) --dllname bochs.exe --def bochs.def --output-lib dllexports.a + $(DLLTOOL) --dllname bochs.exe --output-exp bochs.exp --def bochs.def + $(CXX) -o bochs.exe $(CXXFLAGS) $(LDFLAGS) \ + $(BX_OBJS) bochs.exp $(SIMX86_OBJS) \ + @IODEV_LIB_VAR@ @DISPLAY_LIB_VAR@ @HDIMAGE_LIB_VAR@ @USB_LIB_VAR@ @NETWORK_LIB_VAR@ @SOUND_LIB_VAR@ \ + cpu/libcpu.a @AVX_LIB_VAR@ cpu/cpudb/libcpudb.a memory/libmemory.a gui/libgui.a \ + @DEBUGGER_VAR@ @DISASM_VAR@ @INSTRUMENT_VAR@ @PLUGIN_LIB@ \ + @GDBSTUB_VAR@ @FPU_VAR@ \ + $(GUI_LINK_OPTS) \ + $(DEVICE_LINK_OPTS) \ + $(MCH_LINK_FLAGS) \ + $(SIMX86_LINK_FLAGS) \ + $(READLINE_LIB) \ + $(EXTRA_LINK_OPTS) \ + $(LIBS) + touch .win32_dll_plugin_target + +bochs_plugins: + cd gui @COMMAND_SEPARATOR@ + $(MAKE) plugins + @CD_UP_ONE@ + cd iodev @COMMAND_SEPARATOR@ + $(MAKE) plugins + @CD_UP_ONE@ + cd iodev/display @COMMAND_SEPARATOR@ + $(MAKE) plugins + @CD_UP_TWO@ + cd iodev/hdimage @COMMAND_SEPARATOR@ + $(MAKE) plugins + @CD_UP_TWO@ + cd iodev/usb @COMMAND_SEPARATOR@ + $(MAKE) plugins + @CD_UP_TWO@ + cd iodev/network @COMMAND_SEPARATOR@ + $(MAKE) plugins + @CD_UP_TWO@ + cd iodev/sound @COMMAND_SEPARATOR@ + $(MAKE) plugins + @CD_UP_TWO@ + +bximage@EXE@: misc/bximage.o misc/hdimage.o misc/vmware3.o misc/vmware4.o misc/vpc-img.o misc/vbox.o + @LINK_CONSOLE@ $(BXIMAGE_LINK_OPTS) misc/bximage.o misc/hdimage.o misc/vmware3.o misc/vmware4.o misc/vpc-img.o misc/vbox.o + +niclist@EXE@: misc/niclist.o + @LINK_CONSOLE@ misc/niclist.o + +bxhub@EXE@: misc/bxhub.o misc/netutil.o + @LINK_CONSOLE@ misc/bxhub.o misc/netutil.o @BXHUB_LINK_OPTS@ + +# compile with console CXXFLAGS, not gui CXXFLAGS +misc/bximage.o: $(srcdir)/misc/bximage.cc $(srcdir)/misc/bswap.h \ + $(srcdir)/misc/bxcompat.h $(srcdir)/iodev/hdimage/hdimage.h + $(CXX) @DASH@c $(BX_INCDIRS) $(CXXFLAGS_CONSOLE) $(srcdir)/misc/bximage.cc @OFP@$@ + +misc/hdimage.o: $(srcdir)/iodev/hdimage/hdimage.cc \ + $(srcdir)/iodev/hdimage/hdimage.h $(srcdir)/misc/bxcompat.h + $(CXX) @DASH@c $(BX_INCDIRS) @BXIMAGE_FLAG@ $(CXXFLAGS_CONSOLE) $(srcdir)/iodev/hdimage/hdimage.cc @OFP@$@ + +misc/vmware3.o: $(srcdir)/iodev/hdimage/vmware3.cc $(srcdir)/iodev/hdimage/vmware3.h \ + $(srcdir)/iodev/hdimage/hdimage.h $(srcdir)/misc/bxcompat.h + $(CXX) @DASH@c $(BX_INCDIRS) @BXIMAGE_FLAG@ $(CXXFLAGS_CONSOLE) $(srcdir)/iodev/hdimage/vmware3.cc @OFP@$@ + +misc/vmware4.o: $(srcdir)/iodev/hdimage/vmware4.cc $(srcdir)/iodev/hdimage/vmware4.h \ + $(srcdir)/iodev/hdimage/hdimage.h $(srcdir)/misc/bxcompat.h + $(CXX) @DASH@c $(BX_INCDIRS) @BXIMAGE_FLAG@ $(CXXFLAGS_CONSOLE) $(srcdir)/iodev/hdimage/vmware4.cc @OFP@$@ + +misc/vpc-img.o: $(srcdir)/iodev/hdimage/vpc-img.cc $(srcdir)/iodev/hdimage/vpc-img.h \ + $(srcdir)/iodev/hdimage/hdimage.h $(srcdir)/misc/bxcompat.h + $(CXX) @DASH@c $(BX_INCDIRS) @BXIMAGE_FLAG@ $(CXXFLAGS_CONSOLE) $(srcdir)/iodev/hdimage/vpc-img.cc @OFP@$@ + +misc/vbox.o: $(srcdir)/iodev/hdimage/vbox.cc $(srcdir)/iodev/hdimage/vbox.h \ + $(srcdir)/iodev/hdimage/hdimage.h $(srcdir)/misc/bxcompat.h + $(CXX) @DASH@c $(BX_INCDIRS) @BXIMAGE_FLAG@ $(CXXFLAGS_CONSOLE) $(srcdir)/iodev/hdimage/vbox.cc @OFP@$@ + +misc/bxhub.o: $(srcdir)/misc/bxhub.cc $(srcdir)/iodev/network/netmod.h \ + $(srcdir)/misc/bxcompat.h + $(CC) @DASH@c $(BX_INCDIRS) $(CXXFLAGS_CONSOLE) $(srcdir)/misc/bxhub.cc @OFP@$@ + +misc/netutil.o: $(srcdir)/iodev/network/netutil.cc $(srcdir)/iodev/network/netutil.h \ + $(srcdir)/iodev/network/netmod.h $(srcdir)/misc/bxcompat.h + $(CXX) @DASH@c $(BX_INCDIRS) @BXHUB_FLAG@ $(CXXFLAGS_CONSOLE) $(srcdir)/iodev/network/netutil.cc @OFP@$@ + +# compile with console CFLAGS, not gui CXXFLAGS +misc/niclist.o: $(srcdir)/misc/niclist.c + $(CC) @DASH@c $(BX_INCDIRS) $(CFLAGS_CONSOLE) $(srcdir)/misc/niclist.c @OFP@$@ + +$(BX_OBJS): $(BX_INCLUDES) + +# cannot use -C option to be compatible with Microsoft nmake +iodev/libiodev.a:: + cd iodev @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libiodev.a + @CD_UP_ONE@ + +iodev/display/libdisplay.a:: + cd iodev/display @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libdisplay.a + @CD_UP_TWO@ + +iodev/hdimage/libhdimage.a:: + cd iodev/hdimage @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libhdimage.a + @CD_UP_TWO@ + +iodev/usb/libusb.a:: + cd iodev/usb @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libusb.a + @CD_UP_TWO@ + +iodev/network/libnetwork.a:: + cd iodev/network @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libnetwork.a + @CD_UP_TWO@ + +iodev/sound/libsound.a:: + cd iodev/sound @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libsound.a + @CD_UP_TWO@ + +bx_debug/libdebug.a:: + cd bx_debug @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libdebug.a + @CD_UP_ONE@ + +cpu/libcpu.a:: + cd cpu @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libcpu.a + @CD_UP_ONE@ + +cpu/avx/libavx.a:: + cd cpu/avx @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libavx.a + @CD_UP_TWO@ + +cpu/cpudb/libcpudb.a:: + cd cpu/cpudb @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libcpudb.a + @CD_UP_TWO@ + +cpu/fpu/libfpu.a:: + cd cpu/fpu @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libfpu.a + @CD_UP_TWO@ + +memory/libmemory.a:: + cd memory @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libmemory.a + @CD_UP_ONE@ + +gui/libgui.a:: + cd gui @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libgui.a + @CD_UP_ONE@ + +disasm/libdisasm.a:: + cd disasm @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libdisasm.a + @CD_UP_ONE@ + +@INSTRUMENT_DIR@/libinstrument.a:: + cd @INSTRUMENT_DIR@ @COMMAND_SEPARATOR@ + $(MAKE) $(MDEFINES) libinstrument.a + @CD_UP_TWO@ + +libbochs.a: + -rm -f libbochs.a + ar rv libbochs.a $(EXTERN_ENVIRONMENT_OBJS) + $(RANLIB) libbochs.a + +# for wxWidgets port, on win32 platform +wxbochs_resources.o: wxbochs.rc + windres $(srcdir)/wxbochs.rc -o $@ --include-dir=`@WX_CONFIG@ --prefix`/include + +# for win32 gui +win32res.o: win32res.rc bxversion.rc + $(RC_CMD)$@ $(srcdir)/win32res.rc + +##################################################################### +# Install target for all platforms. +##################################################################### + +install: all @INSTALL_TARGET@ + +##################################################################### +# Install target for win32 +# +# This is intended to be run in cygwin, since it has better scripting +# tools. +##################################################################### + +install_win32: download_dlx dl_docbook + -mkdir -p $(INSTDIR) + -cp -p obj-release/*.exe . + for i in $(INSTALL_LIST_WIN32); do if test -f $$i; then cp -p $$i $(INSTDIR); else cp -p $(srcdir)/$$i $(INSTDIR); fi; done + cp $(srcdir)/misc/sb16/sb16ctrl.example $(INSTDIR)/sb16ctrl.txt + cp -p $(srcdir)/misc/sb16/sb16ctrl.exe $(INSTDIR) + cp $(srcdir)/.bochsrc $(INSTDIR)/bochsrc-sample.txt + cp $(srcdir)/TESTFORM.txt $(INSTDIR) + -mkdir $(INSTDIR)/keymaps + cp -p $(srcdir)/gui/keymaps/*.map $(INSTDIR)/keymaps + cat $(DLXLINUX_TAR) | (cd $(INSTDIR) && tar xzvf -) + echo '..\bochs -q' > $(INSTDIR)/dlxlinux/run.bat + dlxrc=$(INSTDIR)/dlxlinux/bochsrc; mv $$dlxrc.txt $$dlxrc.orig && sed < $$dlxrc.orig 's/$$BXSHARE/../' > $$dlxrc.bxrc && rm -f $$dlxrc.orig + mv $(INSTDIR)/README $(INSTDIR)/README.orig + cat $(srcdir)/build/win32/README.win32-binary $(INSTDIR)/README.orig > $(INSTDIR)/README + rm -f $(INSTDIR)/README.orig + for i in $(TEXT_FILE_LIST); do mv $(INSTDIR)/$$i $(INSTDIR)/$$i.txt; done + cd $(INSTDIR); $(UNIX2DOS) *.txt */*.txt + -mkdir -p $(INSTDIR)/docs + $(GUNZIP) -c $(srcdir)/doc/docbook/bochsdoc.tar.gz | $(TAR) -xvf - -C $(INSTDIR)/docs + cd $(INSTDIR); NAME=`pwd|$(SED) 's/.*\///'`; (cd ..; $(ZIP) $$NAME.zip -r $$NAME); ls -l ../$$NAME.zip + +##################################################################### +# install target for unix +##################################################################### + +install_unix: install_bin @INSTALL_PLUGINS_VAR@ install_man install_share install_doc @INSTALL_DOCBOOK_VAR@ + +install_bin:: + for i in $(DESTDIR)$(bindir); do mkdir -p $$i && test -d $$i && test -w $$i; done + for i in $(INSTALL_LIST_BIN); do if test -f $$i; then install $$i $(DESTDIR)$(bindir); else install $(srcdir)/$$i $(DESTDIR)$(bindir); fi; done + -for i in $(INSTALL_LIST_BIN_OPTIONAL); do if test -f $$i; then install $$i $(DESTDIR)$(bindir); else install $(srcdir)/$$i $(DESTDIR)$(bindir); fi; done + +install_libtool_plugins:: + for i in $(DESTDIR)$(plugdir); do mkdir -p $$i && test -d $$i && test -w $$i; done + for i in gui iodev; do \ + find $$i -type f -name '*.la' -exec $(LIBTOOL) --mode=install install '{}' $(DESTDIR)$(plugdir) ';'; done + $(LIBTOOL) --finish $(DESTDIR)$(plugdir) + +install_dll_plugins:: + for i in $(DESTDIR)$(plugdir); do mkdir -p $$i && test -d $$i && test -w $$i; done + for i in gui iodev; do \ + find $$i -type f -name '*.dll' -exec cp '{}' $(DESTDIR)$(plugdir) ';'; done + +install_share:: + for i in $(DESTDIR)$(sharedir); do mkdir -p $$i && test -d $$i && test -w $$i; done + for i in $(INSTALL_LIST_SHARE); do if test -f $$i; then install -m 644 $$i $(DESTDIR)$(sharedir); else install -m 644 $(srcdir)/$$i $(DESTDIR)$(sharedir); fi; done + -mkdir $(DESTDIR)$(sharedir)/keymaps + for i in $(srcdir)/gui/keymaps/*.map; do install -m 644 $$i $(DESTDIR)$(sharedir)/keymaps/; done + +install_doc:: + for i in $(DESTDIR)$(docdir); do mkdir -p $$i && test -d $$i && test -w $$i; done + for i in $(INSTALL_LIST_DOC); do if test -f $$i; then install -m 644 $$i $(DESTDIR)$(docdir); else install -m 644 $(srcdir)/$$i $(DESTDIR)$(docdir); fi; done + $(RM) -f $(DESTDIR)$(docdir)/README + $(CAT) $(srcdir)/build/linux/README.linux-binary $(srcdir)/README > $(DESTDIR)$(docdir)/README + install -m 644 $(srcdir)/.bochsrc $(DESTDIR)$(docdir)/bochsrc-sample.txt + + +# docbook section: the -C option can be used here +build_docbook:: + $(MAKE) -C doc/docbook + +dl_docbook:: + $(MAKE) -C doc/docbook dl_docs + +install_docbook: build_docbook + $(MAKE) -C doc/docbook install + +clean_docbook:: + $(MAKE) -C doc/docbook clean + +install_man:: + -mkdir -p $(DESTDIR)$(man1dir) + -mkdir -p $(DESTDIR)$(man5dir) + for i in $(MAN_PAGE_1_LIST); do cat $(srcdir)/doc/man/$$i.1 | $(SED) 's/@version@/$(VERSION)/g' | $(GZIP_BIN) -c > $(DESTDIR)$(man1dir)/$$i.1.gz; chmod 644 $(DESTDIR)$(man1dir)/$$i.1.gz; done + for i in $(MAN_PAGE_5_LIST); do cat $(srcdir)/doc/man/$$i.5 | $(GZIP_BIN) -c > $(DESTDIR)$(man5dir)/$$i.5.gz; chmod 644 $(DESTDIR)$(man5dir)/$$i.5.gz; done + +download_dlx: $(DLXLINUX_TAR) + +$(DLXLINUX_TAR): + $(RM) -f $(DLXLINUX_TAR) + $(WGET) $(DLXLINUX_TAR_URL) + test -f $(DLXLINUX_TAR) + +unpack_dlx: $(DLXLINUX_TAR) + rm -rf dlxlinux + $(GUNZIP) -c $(DLXLINUX_TAR) | $(TAR) -xvf - + test -d dlxlinux + (cd dlxlinux; $(MV) bochsrc.txt bochsrc.txt.orig; $(SED) -e "s/1\.1\.2/$(VERSION)/g" -e 's,/usr/local/bochs/latest,$(prefix)/share/bochs,g' < bochsrc.txt.orig > bochsrc.txt; rm -f bochsrc.txt.orig) + +install_dlx: + $(RM) -rf $(DESTDIR)$(sharedir)/dlxlinux + cp -r dlxlinux $(DESTDIR)$(sharedir)/dlxlinux + $(CHMOD) 755 $(DESTDIR)$(sharedir)/dlxlinux + $(GZIP_BIN) $(DESTDIR)$(sharedir)/dlxlinux/hd10meg.img + $(CHMOD) 644 $(DESTDIR)$(sharedir)/dlxlinux/* + for i in bochs-dlx; do cp $(srcdir)/build/linux/$$i $(DESTDIR)$(bindir)/$$i; $(CHMOD) 755 $(DESTDIR)$(bindir)/$$i; done + +uninstall:: + $(RM) -rf $(DESTDIR)$(sharedir) + $(RM) -rf $(DESTDIR)$(docdir) + $(RM) -rf $(DESTDIR)$(libdir)/bochs + for i in $(INSTALL_LIST_BIN); do rm -f $(DESTDIR)$(bindir)/$$i; done + -for i in $(INSTALL_LIST_BIN_OPTIONAL); do rm -f $(DESTDIR)$(bindir)/$$i; done + for i in $(MAN_PAGE_1_LIST); do $(RM) -f $(man1dir)/$$i.1.gz; done + for i in $(MAN_PAGE_5_LIST); do $(RM) -f $(man5dir)/$$i.5.gz; done + +VS2013_WORKSPACE_ZIP=build/win32/vs2013ex-workspace.zip +VS2013_WORKSPACE_FILES=vs2013/bochs.sln vs2013/*.vcxproj + +vs2013workspace: + zip $(VS2013_WORKSPACE_ZIP) $(VS2013_WORKSPACE_FILES) + +######## +# the win32_snap target is used to create a ZIP of bochs sources configured +# for VC++. This ZIP is stuck on the website every once in a while to make +# it easier for VC++ users to compile bochs. First, you should +# run "sh .conf.win32-vcpp" to configure the source code, then do +# "make win32_snap" to unzip the workspace files and create the ZIP. +######## +win32_snap: + unzip $(VS2013_WORKSPACE_ZIP) + $(MAKE) zip + +tar: + NAME=`pwd|$(SED) 's/.*\///'`; (cd ..; $(RM) -f $$NAME.zip; tar cf - $$NAME | $(GZIP_BIN) > $$NAME.tar.gz); ls -l ../$$NAME.tar.gz + +zip: + NAME=`pwd|$(SED) 's/.*\///'`; (cd ..; $(RM) -f $$NAME-msvc-src.zip; $(ZIP) $$NAME-msvc-src.zip -r $$NAME -x \*.svn\* ); ls -l ../$$NAME-msvc-src.zip + +clean: + @RMCOMMAND@ *.o + @RMCOMMAND@ *.a + @RMCOMMAND@ bochs + @RMCOMMAND@ bochs.exe + @RMCOMMAND@ bximage + @RMCOMMAND@ bximage.exe + @RMCOMMAND@ bxhub + @RMCOMMAND@ bxhub.exe + @RMCOMMAND@ niclist + @RMCOMMAND@ niclist.exe + @RMCOMMAND@ bochs.out + @RMCOMMAND@ bochsout.txt + @RMCOMMAND@ *.exp *.lib + @RMCOMMAND@ bochs.def + @RMCOMMAND@ bochs.scpt + @RMCOMMAND@ -rf bochs.app + @RMCOMMAND@ -rf .libs + @RMCOMMAND@ .win32_dll_plugin_target + +local-dist-clean: clean + @RMCOMMAND@ config.h config.status config.log config.cache + @RMCOMMAND@ .dummy `find . -name '*.dsp' -o -name '*.dsw' -o -name '*.opt' -o -name '.DS_Store'` + @RMCOMMAND@ bxversion.h bxversion.rc build/linux/bochs-dlx _rpm_top *.rpm + @RMCOMMAND@ build/win32/nsis/Makefile build/win32/nsis/bochs.nsi + @RMCOMMAND@ build/macosx/Info.plist build/macosx/script_compiled.rsrc + @RMCOMMAND@ libtool + @RMCOMMAND@ ltdlconf.h + +clean_pcidev:: + cd host/linux/pcidev @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_THREE@ + +all-clean: clean @CLEAN_DOCBOOK_VAR@ @CLEAN_PCIDEV_VAR@ + cd iodev @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_ONE@ + cd iodev/display @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd iodev/hdimage @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd iodev/usb @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd iodev/network @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd iodev/sound @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd bx_debug @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_ONE@ + cd cpu @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_ONE@ + cd cpu/avx @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd cpu/cpudb @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd cpu/fpu @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd memory @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_ONE@ + cd gui @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_ONE@ + cd disasm @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_ONE@ + cd @INSTRUMENT_DIR@ @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_TWO@ + cd misc @COMMAND_SEPARATOR@ + $(MAKE) clean + @CD_UP_ONE@ + +dist-clean: local-dist-clean + cd iodev @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_ONE@ + cd iodev/display @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd iodev/hdimage @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd iodev/usb @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd iodev/network @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd iodev/sound @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd bx_debug @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_ONE@ + cd bios @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_ONE@ + cd cpu @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_ONE@ + cd cpu/avx @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd cpu/cpudb @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd cpu/fpu @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd memory @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_ONE@ + cd gui @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_ONE@ + cd disasm @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_ONE@ + cd @INSTRUMENT_DIR@ @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd misc @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_ONE@ + cd doc/docbook @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_TWO@ + cd host/linux/pcidev @COMMAND_SEPARATOR@ + $(MAKE) dist-clean + @CD_UP_THREE@ + @RMCOMMAND@ Makefile + +########################################### +# Build app on MacOS X +########################################### +MACOSX_STUFF=build/macosx +MACOSX_STUFF_SRCDIR=$(srcdir)/$(MACOSX_STUFF) +APP=bochs.app +APP_PLATFORM=MacOS +SCRIPT_EXEC=bochs.scpt +SCRIPT_DATA=$(MACOSX_STUFF_SRCDIR)/script.data +SCRIPT_R=$(MACOSX_STUFF_SRCDIR)/script.r +SCRIPT_APPLESCRIPT=$(MACOSX_STUFF_SRCDIR)/bochs.applescript +SCRIPT_COMPILED_RSRC=$(MACOSX_STUFF)/script_compiled.rsrc +REZ=/Developer/Tools/Rez +CPMAC=/Developer/Tools/CpMac +RINCLUDES=/System/Library/Frameworks/Carbon.framework/Libraries/RIncludes +REZ_ARGS=-append -i $RINCLUDES -d SystemSevenOrLater=1 -useDF +STANDALONE_LIBDIR=`pwd`/$(APP)/Contents/$(APP_PLATFORM)/lib +OSACOMPILE=/usr/bin/osacompile +SETFILE=/Developer/Tools/SetFile + +# On a MacOS X machine, you run rez, osacompile, and setfile to +# produce the script executable, which has both a data fork and a +# resource fork. Ideally, we would just recompile the whole +# executable at build time, but unfortunately this cannot be done on +# the SF compile farm through an ssh connection because osacompile +# needs to be run locally for some reason. Solution: If the script +# sources are changed, rebuild the executable on a MacOSX machine, +# split it into its data and resource forks and check them into SVN +# as separate files. Then at release time, all that's left to do is +# put the data and resource forks back together to make a working script. +# (This can be done through ssh.) +# +# Sources: +# 1. script.r: resources for the script +# 2. script.data: binary data for the script +# 3. bochs.applescript: the source of the script +# +# NOTE: All of this will fail if you aren't building on an HFS+ +# filesystem! On the SF compile farm building in your user directory +# will fail, while doing the build in /tmp will work ok. + +# check if this filesystem supports resource forks at all +test_hfsplus: + $(RM) -rf test_hfsplus + echo data > test_hfsplus + # if you get "Not a directory", then this filesystem doesn't support resources + echo resource > test_hfsplus/rsrc + # test succeeded + $(RM) -rf test_hfsplus + +# Step 1 (must be done locally on MacOSX, only when sources change) +# Compile and pull out just the resource fork. The resource fork is +# checked into SVN as script_compiled.rsrc. Note that we don't need +# to check in the data fork of tmpscript because it is identical to the +# script.data input file. +$(SCRIPT_COMPILED_RSRC): $(SCRIPT_R) $(SCRIPT_APPLESCRIPT) + $(RM) -f tmpscript + $(CP) -f $(SCRIPT_DATA) tmpscript + $(REZ) -append $(SCRIPT_R) -o tmpscript + $(OSACOMPILE) -o tmpscript $(SCRIPT_APPLESCRIPT) + $(CP) tmpscript/rsrc $(SCRIPT_COMPILED_RSRC) + $(RM) -f tmpscript + +# Step 2 (can be done locally or remotely on MacOSX) +# Combine the data fork and resource fork, and set attributes. +$(SCRIPT_EXEC): $(SCRIPT_DATA) $(SCRIPT_COMPILED_RSRC) + rm -f $(SCRIPT_EXEC) + $(CP) $(SCRIPT_DATA) $(SCRIPT_EXEC) + if test ! -f $(SCRIPT_COMPILED_RSRC); then $(CP) $(srcdir)/$(SCRIPT_COMPILED_RSRC) $(SCRIPT_COMPILED_RSRC); fi + $(CP) $(SCRIPT_COMPILED_RSRC) $(SCRIPT_EXEC)/rsrc + $(SETFILE) -t "APPL" -c "aplt" $(SCRIPT_EXEC) + +$(APP)/.build: bochs test_hfsplus $(SCRIPT_EXEC) + rm -f $(APP)/.build + $(MKDIR) -p $(APP) + $(MKDIR) -p $(APP)/Contents + $(CP) -f $(MACOSX_STUFF)/Info.plist $(APP)/Contents + $(CP) -f $(MACOSX_STUFF_SRCDIR)/pbdevelopment.plist $(APP)/Contents + echo -n "APPL????" > $(APP)/Contents/PkgInfo + $(MKDIR) -p $(APP)/Contents/$(APP_PLATFORM) + $(CP) bochs $(APP)/Contents/$(APP_PLATFORM) + $(MKDIR) -p $(APP)/Contents/Resources + $(REZ) $(REZ_ARGS) $(MACOSX_STUFF_SRCDIR)/bochs.r -o $(APP)/Contents/Resources/bochs.rsrc + $(CP) -f $(MACOSX_STUFF_SRCDIR)/bochs-icn.icns $(APP)/Contents/Resources + ls -ld $(APP) $(SCRIPT_EXEC) $(SCRIPT_EXEC)/rsrc + touch $(APP)/.build + +$(APP)/.build_plugins: $(APP)/.build bochs_plugins + rm -f $(APP)/.build_plugins + $(MKDIR) -p $(STANDALONE_LIBDIR); + list=`cd gui && echo *.la`; for i in $$list; do $(LIBTOOL) cp gui/$$i $(STANDALONE_LIBDIR); done; + list=`cd iodev && echo *.la`; for i in $$list; do $(LIBTOOL) cp iodev/$$i $(STANDALONE_LIBDIR); done; + $(LIBTOOL) --finish $(STANDALONE_LIBDIR); + touch $(APP)/.build_plugins + +install_macosx: all download_dlx install_man @INSTALL_DOCBOOK_VAR@ + -mkdir -p $(DESTDIR)$(sharedir) + for i in $(INSTALL_LIST_MACOSX); do if test -e $$i; then $(CPMAC) -r $$i $(DESTDIR)$(sharedir); else $(CPMAC) -r $(srcdir)/$$i $(DESTDIR)$(sharedir); fi; done + $(CPMAC) $(srcdir)/.bochsrc $(DESTDIR)$(sharedir)/bochsrc-sample.txt + -mkdir $(DESTDIR)$(sharedir)/keymaps + $(CPMAC) $(srcdir)/gui/keymaps/*.map $(DESTDIR)$(sharedir)/keymaps + cat $(DLXLINUX_TAR) | (cd $(DESTDIR)$(sharedir) && tar xzvf -) + dlxrc=$(DESTDIR)$(sharedir)/dlxlinux/bochsrc.txt; mv "$$dlxrc" "$$dlxrc.orig" && sed < "$$dlxrc.orig" 's/\/usr\/local\/bochs\/latest/../' > "$$dlxrc" && rm -f "$$dlxrc.orig" + mv $(srcdir)/README $(srcdir)/README.orig + cat $(srcdir)/build/macosx/README.macosx-binary $(srcdir)/README.orig > $(DESTDIR)$(sharedir)/README + rm -f $(DESTDIR)$(sharedir)/README.orig + $(CPMAC) $(SCRIPT_EXEC) $(DESTDIR)$(sharedir)/dlxlinux +# for i in $(TEXT_FILE_LIST); do mv $(srcdir)/$$i $(DESTDIR)$(sharedir)/$$i.txt; done + +########################################### +# dependencies generated by +# gcc -MM -I. -Iinstrument/stubs *.cc | sed -e 's/\.cc/.@CPP_SUFFIX@/g' -e 's,cpu/,cpu/,g' +########################################### +config.o: config.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \ + osdep.h gui/siminterface.h cpudb.h gui/paramtree.h memory/memory-bochs.h \ + pc_system.h gui/gui.h instrument/stubs/instrument.h bxversion.h \ + iodev/iodev.h bochs.h plugin.h extplugin.h param_names.h param_names.h \ + cpudb.h +crc.o: crc.@CPP_SUFFIX@ config.h +gdbstub.o: gdbstub.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \ + osdep.h gui/siminterface.h cpudb.h gui/paramtree.h memory/memory-bochs.h \ + pc_system.h gui/gui.h instrument/stubs/instrument.h param_names.h \ + cpu/cpu.h cpu/decoder/decoder.h cpu/i387.h cpu/fpu/softfloat.h \ + cpu/fpu/tag_w.h cpu/fpu/status_w.h cpu/fpu/control_w.h cpu/crregs.h \ + cpu/descriptor.h cpu/decoder/instr.h cpu/decoder/ia_opcodes.h \ + cpu/lazy_flags.h cpu/tlb.h cpu/icache.h cpu/apic.h cpu/xmm.h cpu/vmx.h \ + cpu/cpuid.h cpu/stack.h cpu/access.h +load32bitOShack.o: load32bitOShack.@CPP_SUFFIX@ bochs.h config.h osdep.h \ + bx_debug/debug.h config.h osdep.h gui/siminterface.h cpudb.h \ + gui/paramtree.h memory/memory-bochs.h pc_system.h gui/gui.h \ + instrument/stubs/instrument.h param_names.h cpu/cpu.h \ + cpu/decoder/decoder.h cpu/i387.h cpu/fpu/softfloat.h cpu/fpu/tag_w.h \ + cpu/fpu/status_w.h cpu/fpu/control_w.h cpu/crregs.h cpu/descriptor.h \ + cpu/decoder/instr.h cpu/decoder/ia_opcodes.h cpu/lazy_flags.h cpu/tlb.h \ + cpu/icache.h cpu/apic.h cpu/xmm.h cpu/vmx.h cpu/cpuid.h cpu/access.h \ + iodev/iodev.h bochs.h plugin.h extplugin.h param_names.h +logio.o: logio.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \ + osdep.h gui/siminterface.h cpudb.h gui/paramtree.h memory/memory-bochs.h \ + pc_system.h gui/gui.h instrument/stubs/instrument.h cpu/cpu.h \ + cpu/decoder/decoder.h cpu/i387.h cpu/fpu/softfloat.h cpu/fpu/tag_w.h \ + cpu/fpu/status_w.h cpu/fpu/control_w.h cpu/crregs.h cpu/descriptor.h \ + cpu/decoder/instr.h cpu/decoder/ia_opcodes.h cpu/lazy_flags.h cpu/tlb.h \ + cpu/icache.h cpu/apic.h cpu/xmm.h cpu/vmx.h cpu/cpuid.h cpu/access.h +main.o: main.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \ + osdep.h gui/siminterface.h cpudb.h gui/paramtree.h memory/memory-bochs.h \ + pc_system.h gui/gui.h instrument/stubs/instrument.h bxversion.h \ + param_names.h gui/textconfig.h cpu/cpu.h cpu/decoder/decoder.h \ + cpu/i387.h cpu/fpu/softfloat.h cpu/fpu/tag_w.h cpu/fpu/status_w.h \ + cpu/fpu/control_w.h cpu/crregs.h cpu/descriptor.h cpu/decoder/instr.h \ + cpu/decoder/ia_opcodes.h cpu/lazy_flags.h cpu/tlb.h cpu/icache.h \ + cpu/apic.h cpu/xmm.h cpu/vmx.h cpu/cpuid.h cpu/access.h iodev/iodev.h \ + bochs.h plugin.h extplugin.h param_names.h +osdep.o: osdep.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \ + osdep.h gui/siminterface.h cpudb.h gui/paramtree.h memory/memory-bochs.h \ + pc_system.h gui/gui.h instrument/stubs/instrument.h +pc_system.o: pc_system.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h \ + config.h osdep.h gui/siminterface.h cpudb.h gui/paramtree.h \ + memory/memory-bochs.h pc_system.h gui/gui.h \ + instrument/stubs/instrument.h cpu/cpu.h cpu/decoder/decoder.h cpu/i387.h \ + cpu/fpu/softfloat.h cpu/fpu/tag_w.h cpu/fpu/status_w.h \ + cpu/fpu/control_w.h cpu/crregs.h cpu/descriptor.h cpu/decoder/instr.h \ + cpu/decoder/ia_opcodes.h cpu/lazy_flags.h cpu/tlb.h cpu/icache.h \ + cpu/apic.h cpu/xmm.h cpu/vmx.h cpu/cpuid.h cpu/access.h iodev/iodev.h \ + bochs.h plugin.h extplugin.h param_names.h +plugin.o: plugin.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \ + osdep.h gui/siminterface.h cpudb.h gui/paramtree.h memory/memory-bochs.h \ + pc_system.h gui/gui.h instrument/stubs/instrument.h iodev/iodev.h \ + bochs.h plugin.h extplugin.h param_names.h plugin.h diff --git a/ports/bochs/config.cc b/ports/bochs/config.cc new file mode 100644 index 0000000..5170795 --- /dev/null +++ b/ports/bochs/config.cc @@ -0,0 +1,3426 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: config.cc 13146 2017-03-24 18:23:07Z vruppert $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002-2017 The Bochs Project +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +#include "bochs.h" +#include "bxversion.h" +#include "iodev/iodev.h" +#include "param_names.h" +#include + +#ifdef HAVE_LOCALE_H +#include +#endif + +#if defined(macintosh) +// Work around a bug in SDL 1.2.4 on MacOS X, which redefines getenv to +// SDL_getenv, but then neglects to provide SDL_getenv. It happens +// because we are defining -Dmacintosh. +#undef getenv +#endif + + +int bochsrc_include_level = 0; +#if BX_PLUGINS +Bit8u bx_user_plugin_count = 0; +#endif + +#define LOG_THIS genlog-> + +extern bx_debug_t bx_dbg; + +static const char *get_builtin_variable(const char *varname); +static int parse_line_unformatted(const char *context, char *line); +static int parse_line_formatted(const char *context, int num_params, char *params[]); +static int parse_bochsrc(const char *rcfile); +static int get_floppy_type_from_image(const char *filename); + +static Bit64s bx_param_handler(bx_param_c *param, int set, Bit64s val) +{ + char pname[BX_PATHNAME_LEN]; + Bit8u device; +//Bit8u channel; + + bx_list_c *base = (bx_list_c*) param->get_parent(); + base->get_param_path(pname, BX_PATHNAME_LEN); + if (!strncmp(pname, "ata.", 4)) { +// channel = pname[4] - '0'; + if (!strcmp(base->get_name(), "master")) { + device = 0; + } else { + device = 1; + } + if (!strcmp(param->get_name(), "type")) { + if (set) { + switch (val) { + case BX_ATA_DEVICE_DISK: + ((bx_param_filename_c*)SIM->get_param("path", base))->set_extension("img"); + break; + case BX_ATA_DEVICE_CDROM: + ((bx_param_filename_c*)SIM->get_param("path", base))->set_extension("iso"); + break; + } + } + } else { + BX_PANIC(("bx_param_handler called with unknown parameter '%s.%s'", pname, param->get_name())); + return -1; + } + } else { + param->get_param_path(pname, BX_PATHNAME_LEN); + if ((!strcmp(pname, BXPN_FLOPPYA_TYPE)) || + (!strcmp(pname, BXPN_FLOPPYB_TYPE))) { + if (set) { + if (val == BX_FLOPPY_AUTO) { + val = get_floppy_type_from_image(SIM->get_param_string("path", base)->getptr()); + SIM->get_param_enum("type", base)->set(val); + } else if (!SIM->get_init_done() && (val != BX_FLOPPY_NONE)) { + switch (val) { + case BX_FLOPPY_2_88: + device = BX_FDD_350ED; + break; + case BX_FLOPPY_720K: + case BX_FLOPPY_1_44: + device = BX_FDD_350HD; + break; + default: + device = BX_FDD_525HD; + } + SIM->get_param_enum("devtype", base)->set(device); + } + } + } else { + BX_PANIC(("bx_param_handler called with unknown parameter '%s'", pname)); + return -1; + } + } + return val; +} + +const char *bx_param_string_handler(bx_param_string_c *param, int set, + const char *oldval, const char *val, int maxlen) +{ + char pname[BX_PATHNAME_LEN]; + + param->get_param_path(pname, BX_PATHNAME_LEN); + if (!strcmp(pname, BXPN_SCREENMODE)) { + if (set == 1) { + BX_INFO(("Screen mode changed to %s", val)); + } + } else if (!strcmp(pname, BXPN_USER_SHORTCUT)) { + if ((set == 1) && (SIM->get_init_done())) { + bx_gui->parse_user_shortcut(val); + } +#if BX_PLUGINS + } else if (!strncmp(pname, "misc.user_plugin", 16)) { + if ((strlen(oldval) > 0) && (strcmp(oldval, "none"))) { + PLUG_unload_user_plugin(oldval); + } + if ((strlen(val) > 0) && (strcmp(val, "none"))) { + PLUG_load_user_plugin(val); + } +#endif + } else { + BX_PANIC(("bx_param_string_handler called with unknown parameter '%s'", pname)); + } + return val; +} + +void bx_init_std_nic_options(const char *name, bx_list_c *menu) +{ + // networking module choices + static const char *eth_module_list[] = { + "null", +#if BX_NETMOD_LINUX + "linux", +#endif +#if BX_NETMOD_TAP + "tap", +#endif +#if BX_NETMOD_TUNTAP + "tuntap", +#endif +#if BX_NETMOD_WIN32 + "win32", +#endif +#if BX_NETMOD_FBSD + "fbsd", +#endif +#if BX_NETMOD_VDE + "vde", +#endif +#if BX_NETMOD_SLIRP + "slirp", +#endif +#if BX_NETMOD_SOCKET + "socket", +#endif + "vnet", + NULL + }; + + bx_param_enum_c *ethmod; + bx_param_string_c *macaddr; + bx_param_filename_c *path, *bootrom; + char descr[120]; + + sprintf(descr, "MAC address of the %s device. Don't use an address of a machine on your net.", name); + macaddr = new bx_param_string_c(menu, + "mac", + "MAC Address", + descr, + "", 6); + macaddr->set_options(macaddr->RAW_BYTES); + macaddr->set_initial_val("\xfe\xfd\xde\xad\xbe\xef"); + macaddr->set_separator(':'); + ethmod = new bx_param_enum_c(menu, + "ethmod", + "Ethernet module", + "Module used for the connection to the real net.", + eth_module_list, + 0, + 0); + ethmod->set_by_name("null"); + ethmod->set_ask_format("Choose ethernet module for the device [%s] "); + new bx_param_string_c(menu, + "ethdev", + "Ethernet device", + "Device used for the connection to the real net. This is only valid if an ethernet module other than 'null' is used.", + "xl0", BX_PATHNAME_LEN); + path = new bx_param_filename_c(menu, + "script", + "Device configuration script", + "Name of the script that is executed after Bochs initializes the network interface (optional).", + "none", BX_PATHNAME_LEN); + path->set_ask_format("Enter new script name, or 'none': [%s] "); + bootrom = new bx_param_filename_c(menu, + "bootrom", + "Boot ROM image", + "Pathname of network boot ROM image to load", + "", BX_PATHNAME_LEN); + bootrom->set_format("Name of boot ROM image: %s"); +} + +void bx_init_usb_options(const char *usb_name, const char *pname, int maxports) +{ + char group[16], name[8], descr[512], label[512]; + + bx_param_c *usb = SIM->get_param("ports.usb"); + sprintf(group, "USB %s", usb_name); + sprintf(label, "%s Configuration", usb_name); + bx_list_c *menu = new bx_list_c(usb, pname, label); + menu->set_options(menu->SHOW_PARENT); + sprintf(label, "Enable %s emulation", usb_name); + sprintf(descr, "Enables the %s emulation", usb_name); + bx_param_bool_c *enabled = new bx_param_bool_c(menu, "enabled", label, descr, 1); + bx_list_c *deplist = new bx_list_c(NULL); + for (int i = 0; i < maxports; i++) { + sprintf(name, "port%d", i+1); + sprintf(label, "Port #%d Configuration", i+1); + sprintf(descr, "Device connected to %s port #%d and it's options", usb_name, i+1); + bx_list_c *port = new bx_list_c(menu, name, label); + port->set_options(port->SERIES_ASK | port->USE_BOX_TITLE); + sprintf(descr, "Device connected to %s port #%d", usb_name, i+1); + bx_param_string_c *device = new bx_param_string_c(port, "device", "Device", + descr, "", BX_PATHNAME_LEN); + sprintf(descr, "Options for device connected to %s port #%d", usb_name, i+1); + bx_param_string_c *options = new bx_param_string_c(port, "options", "Options", + descr, "", BX_PATHNAME_LEN); + port->set_group(group); + deplist->add(port); + deplist->add(device); + deplist->add(options); + } + enabled->set_dependent_list(deplist); +} + +void bx_plugin_ctrl_reset(bx_bool init_done) +{ + bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_PLUGIN_CTRL); + if (init_done) { + for (int i = 0; i < base->get_size(); i++) { + ((bx_param_bool_c*)base->get(i))->set(0); + } + SIM->opt_plugin_ctrl("*", 0); + } + // add the default set of plugins to the list + new bx_param_bool_c(base, "unmapped", "", "", 1); + new bx_param_bool_c(base, "biosdev", "", "", 1); + new bx_param_bool_c(base, "speaker", "", "", 1); + new bx_param_bool_c(base, "extfpuirq", "", "", 1); + new bx_param_bool_c(base, "parallel", "", "", 1); + new bx_param_bool_c(base, "serial", "", "", 1); +#if BX_SUPPORT_GAMEPORT + new bx_param_bool_c(base, "gameport", "", "", 1); +#endif +#if BX_SUPPORT_IODEBUG && BX_DEBUGGER + new bx_param_bool_c(base, "iodebug", "", "", 1); +#endif + if (init_done) { + SIM->opt_plugin_ctrl("*", 1); + } +} + +void bx_init_options() +{ + int i; + bx_list_c *menu; + bx_list_c *deplist; + bx_param_num_c *ioaddr, *ioaddr2, *irq; + bx_param_bool_c *enabled, *readonly; + bx_param_enum_c *mode, *type, *toggle, *status; + bx_param_filename_c *path; + char name[BX_PATHNAME_LEN], descr[512], label[512]; + + bx_param_c *root_param = SIM->get_param("."); + + // general options subtree + menu = new bx_list_c(root_param, "general", ""); + + // config interface option, set in bochsrc or command line + static const char *config_interface_list[] = { +#if BX_USE_WIN32CONFIG + "win32config", +#endif +#if BX_USE_TEXTCONFIG + "textconfig", +#endif +#if BX_WITH_WX + "wx", +#endif + NULL + }; + bx_param_enum_c *sel_config = new bx_param_enum_c(menu, + "config_interface", "Configuration interface", + "Select configuration interface", + config_interface_list, + 0, + 0); + sel_config->set_by_name(BX_DEFAULT_CONFIG_INTERFACE); + + static const char *bochs_start_names[] = { "quick", "load", "edit", "run" }; + + // quick start option, set by command line arg + new bx_param_enum_c(menu, + "start_mode", + "Bochs start types", + "Bochs start types", + bochs_start_names, + BX_RUN_START, + BX_QUICK_START); + + new bx_param_bool_c(menu, + "restore", + "Restore Bochs session", + "Restore Bochs session", + 0); + new bx_param_string_c(menu, + "restore_path", + "Path to data for restore", + "Path to data for restore", + "", + BX_PATHNAME_LEN); + + // benchmarking mode, set by command line arg + new bx_param_num_c(menu, + "benchmark", + "benchmark mode", + "set benchmark mode", + 0, BX_MAX_BIT32U, 0); + + // dump statistics, set by command line arg + new bx_param_num_c(menu, + "dumpstats", + "dumpstats mode", + "dump statistics period", + 0, BX_MAX_BIT32U, 0); + + // subtree for setting up log actions by device in bochsrc + bx_list_c *logfn = new bx_list_c(menu, "logfn", "Logfunctions"); + new bx_list_c(logfn, "debug", ""); + new bx_list_c(logfn, "info", ""); + new bx_list_c(logfn, "error", ""); + new bx_list_c(logfn, "panic", ""); + + // optional plugin control + new bx_list_c(menu, "plugin_ctrl", "Optional Plugin Control"); + bx_plugin_ctrl_reset(0); + + // subtree for special menus + bx_list_c *special_menus = new bx_list_c(root_param, "menu", ""); + +#if BX_SUPPORT_SMP + #define BX_CPU_PROCESSORS_LIMIT 255 + #define BX_CPU_CORES_LIMIT 8 + #define BX_CPU_HT_THREADS_LIMIT 4 +#else + #define BX_CPU_PROCESSORS_LIMIT 1 + #define BX_CPU_CORES_LIMIT 1 + #define BX_CPU_HT_THREADS_LIMIT 1 +#endif + + // cpu subtree + bx_list_c *cpu_param = new bx_list_c(root_param, "cpu", "CPU Options"); + + static const char *cpu_names[] = { +#define bx_define_cpudb(model) #model, +#include "cpudb.h" + NULL + }; +#undef bx_define_cpudb + + new bx_param_enum_c(cpu_param, + "model", "CPU configuration", + "Choose pre-defined CPU configuration", + cpu_names, 0, 0); + + // cpu options + bx_param_num_c *nprocessors = new bx_param_num_c(cpu_param, + "n_processors", "Number of processors in SMP mode", + "Sets the number of processors for multiprocessor emulation", + 1, BX_CPU_PROCESSORS_LIMIT, + 1); + nprocessors->set_enabled(BX_CPU_PROCESSORS_LIMIT > 1); + nprocessors->set_options(bx_param_c::CI_ONLY); + bx_param_num_c *ncores = new bx_param_num_c(cpu_param, + "n_cores", "Number of cores in each processor in SMP mode", + "Sets the number of cores per processor for multiprocessor emulation", + 1, BX_CPU_CORES_LIMIT, + 1); + ncores->set_enabled(BX_CPU_CORES_LIMIT > 1); + ncores->set_options(bx_param_c::CI_ONLY); + bx_param_num_c *nthreads = new bx_param_num_c(cpu_param, + "n_threads", "Number of HT threads per each core in SMP mode", + "Sets the number of HT (Intel(R) HyperThreading Technology) threads per core for multiprocessor emulation", + 1, BX_CPU_HT_THREADS_LIMIT, + 1); + nthreads->set_enabled(BX_CPU_HT_THREADS_LIMIT > 1); + nthreads->set_options(bx_param_c::CI_ONLY); + new bx_param_num_c(cpu_param, + "ips", "Emulated instructions per second (IPS)", + "Emulated instructions per second, used to calibrate bochs emulated time with wall clock time.", + BX_MIN_IPS, BX_MAX_BIT32U, + 4000000); +#if BX_SUPPORT_SMP + new bx_param_num_c(cpu_param, + "quantum", "Quantum ticks in SMP simulation", + "Maximum amount of instructions allowed to execute before returning control to another CPU.", + BX_SMP_QUANTUM_MIN, BX_SMP_QUANTUM_MAX, + 16); +#endif + new bx_param_bool_c(cpu_param, + "reset_on_triple_fault", "Enable CPU reset on triple fault", + "Enable CPU reset if triple fault occured (highly recommended)", + 1); +#if BX_CPU_LEVEL >= 5 + new bx_param_bool_c(cpu_param, + "ignore_bad_msrs", "Ignore RDMSR / WRMSR to unknown MSR register", + "Ignore RDMSR/WRMSR to unknown MSR register", + 1); +#endif + new bx_param_bool_c(cpu_param, + "cpuid_limit_winnt", "Limit max CPUID function to 3", + "Limit max CPUID function reported to 3 to workaround WinNT issue", + 0); +#if BX_SUPPORT_MONITOR_MWAIT + new bx_param_bool_c(cpu_param, + "mwait_is_nop", "Don't put CPU to sleep state by MWAIT", + "Don't put CPU to sleep state by MWAIT", + 0); +#endif +#if BX_CONFIGURE_MSRS + new bx_param_filename_c(cpu_param, + "msrs", + "Configurable MSR definition file", + "Set path to the configurable MSR definition file", + "", BX_PATHNAME_LEN); +#endif + + cpu_param->set_options(menu->SHOW_PARENT); + + // cpuid subtree +#if BX_CPU_LEVEL >= 4 + bx_list_c *cpuid_param = new bx_list_c(root_param, "cpuid", "CPUID Options"); + + new bx_param_num_c(cpuid_param, + "level", "CPU Level", + "CPU level", + (BX_CPU_LEVEL < 5) ? BX_CPU_LEVEL : 5, BX_CPU_LEVEL, + BX_CPU_LEVEL); + + new bx_param_num_c(cpuid_param, + "stepping", "Stepping ID", + "Processor 4-bits stepping ID", + 0, 15, + 3); + + new bx_param_num_c(cpuid_param, + "model", "Model ID", + "Processor model ID, extended model ID", + 0, 255, + 3); + + new bx_param_num_c(cpuid_param, + "family", "Family ID", + "Processor family ID, extended family ID", + BX_CPU_LEVEL, (BX_CPU_LEVEL >= 6) ? 4095 : BX_CPU_LEVEL, + BX_CPU_LEVEL); + + new bx_param_string_c(cpuid_param, + "vendor_string", + "CPUID vendor string", + "Set the CPUID vendor string", +#if BX_CPU_VENDOR_INTEL + "GenuineIntel", +#else + "AuthenticAMD", +#endif + BX_CPUID_VENDOR_LEN+1); + new bx_param_string_c(cpuid_param, + "brand_string", + "CPUID brand string", + "Set the CPUID brand string", +#if BX_CPU_VENDOR_INTEL + " Intel(R) Pentium(R) 4 CPU ", +#else + "AMD Athlon(tm) processor", +#endif + BX_CPUID_BRAND_LEN+1); + +#if BX_CPU_LEVEL >= 5 + new bx_param_bool_c(cpuid_param, + "mmx", "Support for MMX instruction set", + "Support for MMX instruction set", + 1); + + // configure defaults to XAPIC enabled + static const char *apic_names[] = { + "legacy", + "xapic", +#if BX_CPU_LEVEL >= 6 + "xapic_ext", + "x2apic", +#endif + NULL + }; + + new bx_param_enum_c(cpuid_param, + "apic", "APIC configuration", + "Select APIC configuration (Legacy APIC/XAPIC/XAPIC_EXT/X2APIC)", + apic_names, + BX_CPUID_SUPPORT_XAPIC, + BX_CPUID_SUPPORT_LEGACY_APIC); +#endif + +#if BX_CPU_LEVEL >= 6 + // configure defaults to CPU_LEVEL = 6 with SSE2 enabled + static const char *simd_names[] = { + "none", + "sse", + "sse2", + "sse3", + "ssse3", + "sse4_1", + "sse4_2", +#if BX_SUPPORT_AVX + "avx", + "avx2", +#if BX_SUPPORT_EVEX + "avx512", +#endif +#endif + NULL }; + + new bx_param_enum_c(cpuid_param, + "simd", "Support for SIMD instruction set", + "Support for SIMD (SSE/SSE2/SSE3/SSSE3/SSE4_1/SSE4_2/AVX/AVX2/AVX512) instruction set", + simd_names, + BX_CPUID_SUPPORT_SSE2, + BX_CPUID_SUPPORT_NOSSE); + + new bx_param_bool_c(cpuid_param, + "sse4a", "Support for AMD SSE4A instructions", + "Support for AMD SSE4A instructions", + 0); + new bx_param_bool_c(cpuid_param, + "misaligned_sse", "Support for AMD Misaligned SSE mode", + "Support for AMD Misaligned SSE mode", + 0); + + new bx_param_bool_c(cpuid_param, + "sep", "Support for SYSENTER/SYSEXIT instructions", + "Support for SYSENTER/SYSEXIT instructions", + 1); + new bx_param_bool_c(cpuid_param, + "movbe", "Support for MOVBE instruction", + "Support for MOVBE instruction", + 0); + new bx_param_bool_c(cpuid_param, + "adx", "Support for ADX instructions", + "Support for ADCX/ADOX instructions", + 0); + new bx_param_bool_c(cpuid_param, + "aes", "Support for AES instruction set", + "Support for AES instruction set", + 0); + new bx_param_bool_c(cpuid_param, + "sha", "Support for SHA instruction set", + "Support for SHA instruction set", + 0); + new bx_param_bool_c(cpuid_param, + "xsave", "Support for XSAVE extensions", + "Support for XSAVE extensions", + 0); + new bx_param_bool_c(cpuid_param, + "xsaveopt", "Support for XSAVEOPT instruction", + "Support for XSAVEOPT instruction", + 0); +#if BX_SUPPORT_AVX + new bx_param_bool_c(cpuid_param, + "avx_f16c", "Support for AVX F16 convert instructions", + "Support for AVX F16 convert instructions", + 0); + new bx_param_bool_c(cpuid_param, + "avx_fma", "Support for AVX FMA instructions", + "Support for AVX FMA instructions", + 0); + new bx_param_num_c(cpuid_param, + "bmi", "Support for BMI instructions", + "Support for Bit Manipulation Instructions (BMI)", + 0, 2, + 0); + new bx_param_bool_c(cpuid_param, + "xop", "Support for AMD XOP instructions", + "Support for AMD XOP instructions", + 0); + new bx_param_bool_c(cpuid_param, + "fma4", "Support for AMD four operand FMA instructions", + "Support for AMD FMA4 instructions", + 0); + new bx_param_bool_c(cpuid_param, + "tbm", "Support for AMD TBM instructions", + "Support for AMD Trailing Bit Manipulation (TBM) instructions", + 0); +#endif +#if BX_SUPPORT_X86_64 + new bx_param_bool_c(cpuid_param, + "x86_64", "x86-64 and long mode", + "Support for x86-64 and long mode", + 1); + new bx_param_bool_c(cpuid_param, + "1g_pages", "1G pages support in long mode", + "Support for 1G pages in long mode", + 0); + new bx_param_bool_c(cpuid_param, + "pcid", "PCID support in long mode", + "Support for process context ID (PCID) in long mode", + 0); + new bx_param_bool_c(cpuid_param, + "fsgsbase", "FS/GS BASE access instructions support", + "FS/GS BASE access instructions support in long mode", + 0); +#endif + new bx_param_bool_c(cpuid_param, + "smep", "Supervisor Mode Execution Protection support", + "Supervisor Mode Execution Protection support", + 0); + new bx_param_bool_c(cpuid_param, + "smap", "Supervisor Mode Access Prevention support", + "Supervisor Mode Access Prevention support", + 0); +#if BX_SUPPORT_MONITOR_MWAIT + new bx_param_bool_c(cpuid_param, + "mwait", "MONITOR/MWAIT instructions support", + "MONITOR/MWAIT instructions support", + BX_SUPPORT_MONITOR_MWAIT); +#endif +#if BX_SUPPORT_VMX + new bx_param_num_c(cpuid_param, + "vmx", "Support for Intel VMX extensions emulation", + "Support for Intel VMX extensions emulation", + 0, BX_SUPPORT_VMX, + 1); +#endif +#if BX_SUPPORT_SVM + new bx_param_bool_c(cpuid_param, + "svm", "Secure Virtual Machine (SVM) emulation support", + "Secure Virtual Machine (SVM) emulation support", + 0); +#endif +#endif // CPU_LEVEL >= 6 + + cpuid_param->set_options(menu->SHOW_PARENT | menu->USE_SCROLL_WINDOW); + + // CPUID subtree depends on CPU model + SIM->get_param_enum(BXPN_CPU_MODEL)->set_dependent_list(cpuid_param->clone(), 0); + // enable CPUID subtree only for CPU model choice #0 + SIM->get_param_enum(BXPN_CPU_MODEL)->set_dependent_bitmap(0, BX_MAX_BIT64U); + +#endif // CPU_LEVEL >= 4 + + // memory subtree + bx_list_c *memory = new bx_list_c(root_param, "memory", "Memory Options"); + bx_list_c *stdmem = new bx_list_c(memory, "standard", "Standard Options"); + bx_list_c *optrom = new bx_list_c(memory, "optrom", "Optional ROM Images"); + bx_list_c *optram = new bx_list_c(memory, "optram", "Optional RAM Images"); + bx_list_c *ram = new bx_list_c(stdmem, "ram", "RAM size options"); + bx_list_c *rom = new bx_list_c(stdmem, "rom", "BIOS ROM options"); + bx_list_c *vgarom = new bx_list_c(stdmem, "vgarom", "VGABIOS ROM options"); + + // memory options (ram & rom) + bx_param_num_c *ramsize = new bx_param_num_c(ram, + "size", + "Memory size (megabytes)", + "Amount of RAM in megabytes", + 1, ((Bit64u)(1) << BX_PHY_ADDRESS_WIDTH) / (1024*1024), + BX_DEFAULT_MEM_MEGS); + ramsize->set_ask_format("Enter memory size (MB): [%d] "); + + bx_param_num_c *host_ramsize = new bx_param_num_c(ram, + "host_size", + "Host allocated memory size (megabytes)", + "Amount of host allocated memory in megabytes", + 1, 2048, + BX_DEFAULT_MEM_MEGS); + host_ramsize->set_ask_format("Enter host memory size (MB): [%d] "); + ram->set_options(ram->SERIES_ASK); + + path = new bx_param_filename_c(rom, + "file", + "ROM BIOS image", + "Pathname of ROM image to load", + "", BX_PATHNAME_LEN); + path->set_format("Name of ROM BIOS image: %s"); + sprintf(name, "%s/BIOS-bochs-latest", (char *)get_builtin_variable("BXSHARE")); + path->set_initial_val(name); + bx_param_num_c *romaddr = new bx_param_num_c(rom, + "address", + "ROM BIOS address", + "The address at which the ROM image should be loaded", + 0, BX_MAX_BIT32U, + 0); + romaddr->set_base(16); + romaddr->set_format("0x%08x"); + romaddr->set_long_format("ROM BIOS address: 0x%08x"); + new bx_param_string_c(rom, + "options", + "BIOS options", + "Options for the Bochs BIOS", + "", BX_PATHNAME_LEN); + rom->set_options(rom->SERIES_ASK); + + path = new bx_param_filename_c(vgarom, + "file", + "VGA BIOS image", + "Pathname of VGA ROM image to load", + "", BX_PATHNAME_LEN); + path->set_format("Name of VGA BIOS image: %s"); + sprintf(name, "%s/VGABIOS-lgpl-latest", get_builtin_variable("BXSHARE")); + path->set_initial_val(name); + vgarom->set_options(vgarom->SERIES_ASK); + + bx_list_c *optnum; + bx_param_num_c *optaddr; + + for (i=0; iset_format(strdup(label)); + sprintf(descr, "The address at which the optional ROM image #%d should be loaded", i+1); + optaddr = new bx_param_num_c(optnum, + "address", + "Address", + descr, + 0, BX_MAX_BIT32U, + 0); + optaddr->set_base(16); + optaddr->set_format("0x%05x"); + sprintf(label, "Optional ROM #%d address:", i+1); + strcat(label, " 0x%05x"); + optaddr->set_long_format(strdup(label)); + deplist = new bx_list_c(NULL); + deplist->add(optaddr); + path->set_dependent_list(deplist); + optnum->set_options(optnum->SERIES_ASK | optnum->USE_BOX_TITLE); + } + optrom->set_options(optrom->SHOW_PARENT); + + for (i=0; iset_format(strdup(label)); + sprintf(descr, "The address at which the optional RAM image #%d should be loaded", i+1); + optaddr = new bx_param_num_c(optnum, + "address", + "Address", + descr, + 0, BX_MAX_BIT32U, + 0); + optaddr->set_base(16); + optaddr->set_format("0x%05x"); + sprintf(label, "Optional RAM #%d address:", i+1); + strcat(label, " 0x%05x"); + optaddr->set_long_format(strdup(label)); + deplist = new bx_list_c(NULL); + deplist->add(optaddr); + path->set_dependent_list(deplist); + optnum->set_options(optnum->SERIES_ASK | optnum->USE_BOX_TITLE); + } + optram->set_options(optram->SHOW_PARENT); + memory->set_options(memory->SHOW_PARENT | memory->USE_TAB_WINDOW); + + // clock & cmos subtree + bx_list_c *clock_cmos = new bx_list_c(root_param, "clock_cmos", "Clock & CMOS Options"); + + // clock & cmos options + static const char *clock_sync_names[] = { "none", "realtime", "slowdown", "both", NULL }; + + bx_param_enum_c *clock_sync = new bx_param_enum_c(clock_cmos, + "clock_sync", "Synchronisation method", + "Host to guest time synchronization method", + clock_sync_names, + BX_CLOCK_SYNC_NONE, + BX_CLOCK_SYNC_NONE); + bx_param_num_c *time0 = new bx_param_num_c(clock_cmos, + "time0", + "Initial CMOS time for Bochs\n(1:localtime, 2:utc, other:time in seconds)", + "Initial time for Bochs CMOS clock, used if you really want two runs to be identical", + 0, BX_MAX_BIT32U, + BX_CLOCK_TIME0_LOCAL); + bx_param_bool_c *rtc_sync = new bx_param_bool_c(clock_cmos, + "rtc_sync", "Sync RTC speed with realtime", + "If enabled, the RTC runs at realtime speed", + 0); + deplist = new bx_list_c(NULL); + deplist->add(rtc_sync); + clock_sync->set_dependent_list(deplist, 0); + clock_sync->set_dependent_bitmap(BX_CLOCK_SYNC_REALTIME, 1); + clock_sync->set_dependent_bitmap(BX_CLOCK_SYNC_BOTH, 1); + + bx_list_c *cmosimage = new bx_list_c(clock_cmos, "cmosimage", "CMOS Image Options"); + bx_param_bool_c *use_cmosimage = new bx_param_bool_c(cmosimage, + "enabled", "Use a CMOS image", + "Controls the usage of a CMOS image", + 0); + path = new bx_param_filename_c(cmosimage, + "path", "Pathname of CMOS image", + "Pathname of CMOS image", + "", BX_PATHNAME_LEN); + bx_param_bool_c *rtc_init = new bx_param_bool_c(cmosimage, + "rtc_init", "Initialize RTC from image", + "Controls whether to initialize the RTC with values stored in the image", + 0); + deplist = new bx_list_c(NULL); + deplist->add(path); + deplist->add(rtc_init); + use_cmosimage->set_dependent_list(deplist); + + time0->set_ask_format("Enter Initial CMOS time (1:localtime, 2:utc, other:time in seconds): [%d] "); + clock_sync->set_ask_format("Enter Synchronisation method: [%s] "); + clock_cmos->set_options(clock_cmos->SHOW_PARENT); + cmosimage->set_options(cmosimage->SHOW_PARENT); + + // pci subtree + bx_list_c *pci = new bx_list_c(root_param, "pci", "PCI Options"); + + // pci options + static const char *pci_chipset_names[] = { "i430fx", "i440fx", NULL }; + deplist = new bx_list_c(NULL); + + enabled = new bx_param_bool_c(pci, + "enabled", + "Enable PCI Support", + "Controls whether to emulate a PCI chipset", + BX_SUPPORT_PCI); + bx_param_enum_c *pci_chipset = new bx_param_enum_c(pci, + "chipset", "PCI chipset", + "Select PCI chipset to emulate", + pci_chipset_names, + BX_PCI_CHIPSET_I440FX, + BX_PCI_CHIPSET_I430FX); + deplist->add(pci_chipset); + // pci slots + bx_list_c *slot = new bx_list_c(pci, "slot", "PCI Slots"); + deplist->add(slot); + for (i=0; iadd(devname); + } + enabled->set_dependent_list(deplist); + pci->set_options(pci->SHOW_PARENT); + slot->set_options(slot->SHOW_PARENT); + + // display subtree + bx_list_c *display = new bx_list_c(root_param, "display", "Bochs Display & Interface Options"); + + // this is a list of gui libraries that are known to be available at + // compile time. The one that is listed first will be the default, + // which is used unless the user overrides it on the command line or + // in a configuration file. + static const char *display_library_list[] = { +#if BX_WITH_X11 + "x", +#endif +#if BX_WITH_WIN32 + "win32", +#endif +#if BX_WITH_CARBON + "carbon", +#endif +#if BX_WITH_MACOS + "macos", +#endif +#if BX_WITH_AMIGAOS + "amigaos", +#endif +#if BX_WITH_SDL + "sdl", +#endif +#if BX_WITH_SDL2 + "sdl2", +#endif +#if BX_WITH_SVGA + "svga", +#endif +#if BX_WITH_TERM + "term", +#endif +#if BX_WITH_RFB + "rfb", +#endif +#if BX_WITH_VNCSRV + "vncsrv", +#endif +#if BX_WITH_WX + "wx", +#endif +#if BX_WITH_NOGUI + "nogui", +#endif +#if BX_WITH_ESSENCE + "essence", +#endif + NULL + }; + bx_param_enum_c *sel_displaylib = new bx_param_enum_c(display, + "display_library", "VGA Display Library", + "Select VGA Display Library", + display_library_list, + 0, + 0); + sel_displaylib->set_by_name(BX_DEFAULT_DISPLAY_LIBRARY); + sel_displaylib->set_ask_format("Choose which library to use for the Bochs display: [%s] "); + + new bx_param_string_c(display, + "displaylib_options", "Display Library options", + "Options passed to Display Library", + "", + BX_PATHNAME_LEN); + + new bx_param_bool_c(display, + "private_colormap", "Use a private colormap", + "Request that the GUI create and use it's own non-shared colormap. This colormap will be used when in the bochs window. If not enabled, a shared colormap scheme may be used. Not implemented on all GUI's.", + 0); + +#if BX_WITH_AMIGAOS + bx_param_bool_c *fullscreen = new bx_param_bool_c(display, + "fullscreen", "Use full screen mode", + "When enabled, bochs occupies the whole screen instead of just a window.", + 0); + bx_param_string_c *screenmode = new bx_param_string_c(display, + "screenmode", + "Screen mode name", + "Screen mode name", + "", BX_PATHNAME_LEN); + screenmode->set_handler(bx_param_string_handler); +#endif + + new bx_param_bool_c(display, + "vga_realtime", + "VGA timer realtime", + "If enabled, the VGA timer is based on realtime", + 1); + + bx_param_num_c *vga_update_freq = new bx_param_num_c(display, + "vga_update_frequency", + "VGA Update Frequency", + "Number of VGA updates per emulated second", + 1, 60, + 5); + vga_update_freq->set_ask_format ("Type a new value for VGA update frequency: [%d] "); + + bx_param_string_c *vga_extension = new bx_param_string_c(display, + "vga_extension", + "VGA Extension", + "Name of the VGA extension", + "none", BX_PATHNAME_LEN); + vga_extension->set_initial_val("vbe"); + display->set_options(display->SHOW_PARENT); + + // keyboard & mouse subtree + bx_list_c *kbd_mouse = new bx_list_c(root_param, "keyboard_mouse", "Keyboard & Mouse Options"); + bx_list_c *keyboard = new bx_list_c(kbd_mouse, "keyboard", "Keyboard Options"); + bx_list_c *mouse = new bx_list_c(kbd_mouse, "mouse", "Mouse Options"); + + static const char *keyboard_type_names[] = { "xt", "at", "mf", NULL }; + + // keyboard & mouse options + type = new bx_param_enum_c(keyboard, + "type", "Keyboard type", + "Keyboard type reported by the 'identify keyboard' command", + keyboard_type_names, + BX_KBD_MF_TYPE, + BX_KBD_XT_TYPE); + type->set_ask_format ("Enter keyboard type: [%s] "); + + new bx_param_num_c(keyboard, + "serial_delay", "Keyboard serial delay", + "Approximate time in microseconds that it takes one character to be transferred from the keyboard to controller over the serial path.", + 5, BX_MAX_BIT32U, + 250); + new bx_param_num_c(keyboard, + "paste_delay", "Keyboard paste delay", + "Approximate time in microseconds between attemps to paste characters to the keyboard controller.", + 1000, BX_MAX_BIT32U, + 100000); + bx_param_bool_c *use_kbd_mapping = new bx_param_bool_c(keyboard, + "use_mapping", "Use keyboard mapping", + "Controls whether to use the keyboard mapping feature", + 0); + use_kbd_mapping->set_options(bx_param_c::CI_ONLY); + bx_param_filename_c *keymap = new bx_param_filename_c(keyboard, + "keymap", "Keymap filename", + "Pathname of the keymap file used", + "", BX_PATHNAME_LEN); + keymap->set_extension("map"); + deplist = new bx_list_c(NULL); + deplist->add(keymap); + use_kbd_mapping->set_dependent_list(deplist); + + bx_param_string_c *user_shortcut = new bx_param_string_c(keyboard, + "user_shortcut", + "Userbutton shortcut", + "Defines the keyboard shortcut to be sent when you press the 'user' button in the headerbar.", + "none", 20); + user_shortcut->set_handler(bx_param_string_handler); + + static const char *mouse_type_list[] = { + "none", + "ps2", + "imps2", +#if BX_SUPPORT_BUSMOUSE + "inport", + "bus", +#endif + "serial", + "serial_wheel", + "serial_msys", + NULL + }; + type = new bx_param_enum_c(mouse, + "type", "Mouse type", + "The mouse type can be one of these: 'none', 'ps2', 'imps2', 'serial', 'serial_wheel'" +#if BX_SUPPORT_BUSMOUSE + ", 'bus'" +#endif + , + mouse_type_list, + BX_MOUSE_TYPE_PS2, + BX_MOUSE_TYPE_NONE); + type->set_ask_format("Choose the type of mouse [%s] "); + + new bx_param_bool_c(mouse, + "enabled", "Enable mouse capture", + "Controls whether the mouse sends events to the guest. The hardware emulation is always enabled.", + 0); + + static const char *mouse_toggle_list[] = { + "ctrl+mbutton", + "ctrl+f10", + "ctrl+alt", + "f12", + NULL + }; + toggle = new bx_param_enum_c(mouse, + "toggle", "Mouse toggle method", + "The mouse toggle method can be one of these: 'ctrl+mbutton', 'ctrl+f10', 'ctrl+alt'", + mouse_toggle_list, + BX_MOUSE_TOGGLE_CTRL_MB, + BX_MOUSE_TOGGLE_CTRL_MB); + toggle->set_ask_format("Choose the mouse toggle method [%s] "); + + kbd_mouse->set_options(kbd_mouse->SHOW_PARENT); + keyboard->set_options(keyboard->SHOW_PARENT); + mouse->set_options(mouse->SHOW_PARENT); + + // boot parameter subtree + bx_list_c *boot_params = new bx_list_c(root_param, "boot_params", "Boot Options"); + // boot sequence + for (i=0; i<3; i++) { + sprintf(name, "boot_drive%d", i+1); + sprintf(label, "Boot drive #%d", i+1); + sprintf(descr, "Name of drive #%d in boot sequence (A, C or CD)", i+1); + bx_param_enum_c *bootdrive = new bx_param_enum_c(boot_params, + name, + label, + descr, + &bochs_bootdisk_names[(i==0)?BX_BOOT_FLOPPYA:BX_BOOT_NONE], + (i==0)?BX_BOOT_FLOPPYA:BX_BOOT_NONE, + (i==0)?BX_BOOT_FLOPPYA:BX_BOOT_NONE); + bootdrive->set_ask_format("Boot from floppy drive, hard drive or cdrom ? [%s] "); + } + + new bx_param_bool_c(boot_params, + "floppy_sig_check", + "Skip Floppy Boot Signature Check", + "Skips check for the 0xaa55 signature on floppy boot device.", + 0); + + // loader hack + bx_list_c *load32bitos = new bx_list_c(boot_params, "load32bitos", "32-bit OS Loader Hack"); + + static const char *loader_os_names[] = { "none", "linux", "nullkernel", NULL }; + + bx_param_enum_c *whichOS = new bx_param_enum_c(load32bitos, + "which", + "Which operating system?", + "Which OS to boot", + loader_os_names, + Load32bitOSNone, + Load32bitOSNone); + path = new bx_param_filename_c(load32bitos, + "path", + "Pathname of OS to load", + "Pathname of the 32-bit OS to load", + "", BX_PATHNAME_LEN); + bx_param_filename_c *iolog = new bx_param_filename_c(load32bitos, + "iolog", + "Pathname of I/O log file", + "I/O logfile used for initializing the hardware", + "", BX_PATHNAME_LEN); + bx_param_filename_c *initrd = new bx_param_filename_c(load32bitos, + "initrd", + "Pathname of initrd", + "Pathname of the initial ramdisk", + "", BX_PATHNAME_LEN); + whichOS->set_ask_format("Enter OS to load: [%s] "); + path->set_ask_format("Enter pathname of OS: [%s]"); + iolog->set_ask_format("Enter pathname of I/O log: [%s] "); + initrd->set_ask_format("Enter pathname of initrd: [%s] "); + load32bitos->set_options(menu->SERIES_ASK); + whichOS->set_dependent_list(load32bitos->clone(), 1); + whichOS->set_dependent_bitmap(Load32bitOSNone, 0); + whichOS->set(Load32bitOSNone); + boot_params->set_options(menu->SHOW_PARENT); + + // floppy subtree + bx_list_c *floppy = new bx_list_c(root_param, "floppy", "Floppy Options"); + new bx_list_c(floppy, "0", "First Floppy Drive"); + new bx_list_c(floppy, "1", "Second Floppy Drive"); + + bx_param_enum_c *devtype; + // floppy options + for (i = 0; i < 2; i++) { + + bx_list_c *floppyX = (bx_list_c*)floppy->get(i); + + devtype = new bx_param_enum_c(floppyX, + "devtype", + "Type of floppy drive", + "Type of floppy drive", + floppy_devtype_names, + BX_FDD_NONE, + BX_FDD_NONE); + devtype->set_ask_format("What type of floppy drive? [%s] "); + + if (i == 0) { + strcpy(label, "First floppy image/device"); + strcpy(descr, "Pathname of first floppy image file or device. If you're booting from floppy, this should be a bootable floppy."); + } else { + strcpy(label, "Second floppy image/device"); + strcpy(descr, "Pathname of second floppy image file or device."); + } + path = new bx_param_filename_c(floppyX, "path", label, descr, "", BX_PATHNAME_LEN); + path->set_ask_format("Enter new filename, or 'none' for no disk: [%s] "); + path->set_extension("img"); + path->set_initial_val("none"); + + type = new bx_param_enum_c(floppyX, + "type", + "Type of floppy media", + "Type of floppy media", + floppy_type_names, + BX_FLOPPY_NONE, + BX_FLOPPY_NONE); + type->set_ask_format("What type of floppy media? (auto=detect) [%s] "); + type->set_handler(bx_param_handler); + type->set_runtime_param(1); + + readonly = new bx_param_bool_c(floppyX, + "readonly", + "Write Protection", + "Floppy media write protection", + 0); + readonly->set_ask_format("Is media write protected? [%s] "); + + status = new bx_param_enum_c(floppyX, + "status", + "Status", + "Floppy media status (inserted / ejected)", + media_status_names, + BX_EJECTED, + BX_EJECTED); + status->set_ask_format("Is the device inserted or ejected? [%s] "); + + deplist = new bx_list_c(NULL); + deplist->add(path); + devtype->set_dependent_list(deplist, 1); + devtype->set_dependent_bitmap(BX_FDD_NONE, 0); + + deplist = new bx_list_c(NULL); + deplist->add(type); + deplist->add(readonly); + deplist->add(status); + path->set_dependent_list(deplist); + + floppyX->set_options(floppyX->SERIES_ASK | floppyX->USE_BOX_TITLE); + } + + floppy->set_options(floppy->SHOW_PARENT); + + // ATA/ATAPI subtree + bx_list_c *ata = new bx_list_c(root_param, "ata", "ATA/ATAPI Options"); + ata->set_options(ata->USE_TAB_WINDOW); + + // disk options + const char *s_atachannel[] = { + "ATA channel 0", + "ATA channel 1", + "ATA channel 2", + "ATA channel 3", + }; + const char *s_atadevname[2] = { + "master", + "slave", + }; + const char *s_atadevice[4][2] = { + { "First HD/CD on channel 0", + "Second HD/CD on channel 0" }, + { "First HD/CD on channel 1", + "Second HD/CD on channel 1" }, + { "First HD/CD on channel 2", + "Second HD/CD on channel 2" }, + { "First HD/CD on channel 3", + "Second HD/CD on channel 3" } + }; + Bit16u ata_default_ioaddr1[4] = { + 0x1f0, 0x170, 0x1e8, 0x168 + }; + Bit16u ata_default_ioaddr2[4] = { + 0x3f0, 0x370, 0x3e0, 0x360 + }; + Bit8u ata_default_irq[4] = { + 14, 15, 11, 9 + }; + + #define BXP_PARAMS_PER_ATA_DEVICE 12 + + bx_list_c *ata_menu[BX_MAX_ATA_CHANNEL]; + bx_list_c *ata_res[BX_MAX_ATA_CHANNEL]; + + for (Bit8u channel=0; channelset_options(bx_list_c::USE_TAB_WINDOW); + ata_res[channel] = new bx_list_c(ata_menu[channel], "resources", s_atachannel[channel]); + ata_res[channel]->set_options(bx_list_c::SERIES_ASK); + + enabled = new bx_param_bool_c(ata_res[channel], + "enabled", + "Enable ATA channel", + "Controls whether ata channel is installed or not", + 0); + enabled->set_ask_format("Channel is enabled: [%s] "); + + ioaddr = new bx_param_num_c(ata_res[channel], + "ioaddr1", + "I/O Address 1", + "IO adress of ata command block", + 0, 0xffff, + ata_default_ioaddr1[channel]); + ioaddr->set_base(16); + ioaddr->set_ask_format("Enter new ioaddr1: [0x%x] "); + + ioaddr2 = new bx_param_num_c(ata_res[channel], + "ioaddr2", + "I/O Address 2", + "IO adress of ata control block", + 0, 0xffff, + ata_default_ioaddr2[channel]); + ioaddr2->set_base(16); + ioaddr2->set_ask_format("Enter new ioaddr2: [0x%x] "); + + irq = new bx_param_num_c(ata_res[channel], + "irq", + "IRQ", + "IRQ used by this ata channel", + 0, 15, + ata_default_irq[channel]); + irq->set_ask_format("Enter new IRQ: [%d] "); + irq->set_options(irq->USE_SPIN_CONTROL); + + // all items in the ata[channel] menu depend on the enabled flag. + // The menu list is complete, but a few dependent_list items will + // be added later. Use clone() to make a copy of the dependent_list + // so that it can be changed without affecting the menu. + enabled->set_dependent_list(ata_res[channel]->clone()); + + for (Bit8u slave=0; slave<2; slave++) { + menu = new bx_list_c(ata_menu[channel], + s_atadevname[slave], + s_atadevice[channel][slave]); + menu->set_options(menu->SERIES_ASK); + + static const char *atadevice_type_names[] = { "none", "disk", "cdrom", NULL }; + + type = new bx_param_enum_c(menu, + "type", + "Type of ATA device", + "Type of ATA device (disk or cdrom)", + atadevice_type_names, + BX_ATA_DEVICE_NONE, + BX_ATA_DEVICE_NONE); + type->set_ask_format("Enter type of ATA device, disk or cdrom: [%s] "); + + path = new bx_param_filename_c(menu, + "path", + "Path or physical device name", + "Pathname of the image or physical device (cdrom only)", + "", BX_PATHNAME_LEN); + path->set_ask_format("Enter new filename: [%s] "); + path->set_extension("img"); + + mode = new bx_param_enum_c(menu, + "mode", + "Type of disk image", + "Mode of the ATA harddisk", + hdimage_mode_names, + BX_HDIMAGE_MODE_FLAT, + BX_HDIMAGE_MODE_FLAT); + mode->set_ask_format("Enter mode of ATA device, (flat, concat, etc.): [%s] "); + + status = new bx_param_enum_c(menu, + "status", + "Status", + "CD-ROM media status (inserted / ejected)", + media_status_names, + BX_EJECTED, + BX_EJECTED); + status->set_ask_format("Is the device inserted or ejected? [%s] "); + + bx_param_filename_c *journal = new bx_param_filename_c(menu, + "journal", + "Path of journal file", + "Pathname of the journal file", + "", BX_PATHNAME_LEN); + journal->set_ask_format("Enter path of journal file: [%s]"); + deplist = new bx_list_c(NULL); + deplist->add(journal); + mode->set_dependent_list(deplist, 0); + mode->set_dependent_bitmap(BX_HDIMAGE_MODE_UNDOABLE, 1); + mode->set_dependent_bitmap(BX_HDIMAGE_MODE_VOLATILE, 1); + mode->set_dependent_bitmap(BX_HDIMAGE_MODE_VVFAT, 1); + + bx_param_num_c *cylinders = new bx_param_num_c(menu, + "cylinders", + "Cylinders", + "Number of cylinders", + 0, 262143, + 0); + cylinders->set_ask_format("Enter number of cylinders: [%d] "); + bx_param_num_c *heads = new bx_param_num_c(menu, + "heads", + "Heads", + "Number of heads", + 0, 16, + 0); + heads->set_ask_format("Enter number of heads: [%d] "); + bx_param_num_c *spt = new bx_param_num_c(menu, + "spt", + "Sectors per track", + "Number of sectors per track", + 0, 63, + 0); + spt->set_ask_format("Enter number of sectors per track: [%d] "); + + bx_param_string_c *model = new bx_param_string_c(menu, + "model", + "Model name", + "String returned by the 'identify device' command", + "Generic 1234", 41); + model->set_ask_format("Enter new model name: [%s]"); + + static const char *atadevice_biosdetect_names[] = { "auto", "cmos", "none", NULL }; + + bx_param_enum_c *biosdetect = new bx_param_enum_c(menu, + "biosdetect", + "BIOS Detection", + "Type of bios detection", + atadevice_biosdetect_names, + BX_ATA_BIOSDETECT_AUTO, + BX_ATA_BIOSDETECT_AUTO); + biosdetect->set_ask_format("Enter bios detection type: [%s]"); + + static const char *atadevice_translation_names[] = { "none", "lba", "large", "rechs", "auto", NULL }; + + bx_param_enum_c *translation = new bx_param_enum_c(menu, + "translation", + "Translation type", + "How the ata-disk translation is done by the bios", + atadevice_translation_names, + BX_ATA_TRANSLATION_AUTO, + BX_ATA_TRANSLATION_NONE); + translation->set_ask_format("Enter translation type: [%s]"); + + // the master/slave menu depends on the ATA channel's enabled flag + enabled->get_dependent_list()->add(menu); + // the type selector depends on the ATA channel's enabled flag + enabled->get_dependent_list()->add(type); + + // all items depend on the drive type + type->set_dependent_list(menu->clone(), 0); + type->set_dependent_bitmap(BX_ATA_DEVICE_DISK, 0x7e6); + type->set_dependent_bitmap(BX_ATA_DEVICE_CDROM, 0x30a); + + type->set_handler(bx_param_handler); + } + + // Enable two ATA interfaces by default, disable the others. + // Now that the dependence relationships are established, call set() on + // the ata device present params to set all enables correctly. + enabled->set_initial_val(channel<2); + enabled->set(channel<2); + } + + // disk menu + bx_param_c *disk_menu_init_list[] = { + SIM->get_param(BXPN_FLOPPYA), + SIM->get_param(BXPN_FLOPPYB), + SIM->get_param(BXPN_ATA0_RES), + SIM->get_param(BXPN_ATA0_MASTER), + SIM->get_param(BXPN_ATA0_SLAVE), +#if BX_MAX_ATA_CHANNEL>1 + SIM->get_param(BXPN_ATA1_RES), + SIM->get_param(BXPN_ATA1_MASTER), + SIM->get_param(BXPN_ATA1_SLAVE), +#endif +#if BX_MAX_ATA_CHANNEL>2 + SIM->get_param(BXPN_ATA2_RES), + SIM->get_param(BXPN_ATA2_MASTER), + SIM->get_param(BXPN_ATA2_SLAVE), +#endif +#if BX_MAX_ATA_CHANNEL>3 + SIM->get_param(BXPN_ATA3_RES), + SIM->get_param(BXPN_ATA3_MASTER), + SIM->get_param(BXPN_ATA3_SLAVE), +#endif + SIM->get_param("boot_params"), + NULL + }; + menu = new bx_list_c(special_menus, "disk", "Bochs Disk Options", disk_menu_init_list); + menu->set_options(menu->SHOW_PARENT); + +#ifdef WIN32 + // disk menu for win32paramdlg + bx_param_c *disk_menu2_init_list[] = { + SIM->get_param("floppy"), + SIM->get_param("ata.0"), +#if BX_MAX_ATA_CHANNEL>1 + SIM->get_param("ata.1"), +#endif +#if BX_MAX_ATA_CHANNEL>2 + SIM->get_param("ata.2"), +#endif +#if BX_MAX_ATA_CHANNEL>3 + SIM->get_param("ata.3"), +#endif + SIM->get_param("boot_params"), + NULL + }; + menu = new bx_list_c(special_menus, "disk_win32", "Bochs Disk Options", disk_menu2_init_list); + menu->set_options(menu->USE_TAB_WINDOW); +#endif + + // ports subtree + bx_list_c *ports = new bx_list_c(root_param, "ports", "Serial and Parallel Port Options"); + ports->set_options(ports->USE_TAB_WINDOW | ports->SHOW_PARENT); + + // parallel ports + bx_list_c *parallel = new bx_list_c(ports, "parallel", "Parallel Port Options"); + parallel->set_options(parallel->SHOW_PARENT); + // parport options initialized in the devive plugin code + + // serial ports + bx_list_c *serial = new bx_list_c(ports, "serial", "Serial Port Options"); + serial->set_options(serial->SHOW_PARENT); + // serial port options initialized in the devive plugin code + + // usb subtree + bx_list_c *usb = new bx_list_c(ports, "usb", "USB Configuration"); + usb->set_options(usb->USE_TAB_WINDOW | usb->SHOW_PARENT); + // USB host controller options initialized in the devive plugin code + + // network subtree + bx_list_c *network = new bx_list_c(root_param, "network", "Network Configuration"); + network->set_options(network->USE_TAB_WINDOW | network->SHOW_PARENT); + // network device options initialized in the devive plugin code + + // sound subtree + bx_list_c *sound = new bx_list_c(root_param, "sound", "Sound Configuration"); + sound->set_options(sound->USE_TAB_WINDOW | sound->SHOW_PARENT); + bx_list_c *soundlow = new bx_list_c(sound, "lowlevel", "Lowlevel Sound Configuration"); + soundlow->set_options(soundlow->SHOW_PARENT | soundlow->SERIES_ASK); + soundlow->set_enabled(BX_SUPPORT_SOUNDLOW); + +#if BX_SUPPORT_SOUNDLOW + bx_param_enum_c *driver = new bx_param_enum_c(soundlow, + "waveoutdrv", + "Waveout driver", + "This is the waveout driver to use for emulated sound devices", + sound_driver_names, + BX_SOUNDDRV_DUMMY, + BX_SOUNDDRV_DUMMY); + driver->set_by_name(BX_SOUND_LOWLEVEL_NAME); + new bx_param_filename_c(soundlow, + "waveout", + "Wave output device", + "This is the device where the wave output is sent to", + "", BX_PATHNAME_LEN); + driver = new bx_param_enum_c(soundlow, + "waveindrv", + "Wavein driver", + "This is the wavein driver to use for emulated sound devices", + sound_driver_names, + BX_SOUNDDRV_DUMMY, + BX_SOUNDDRV_DUMMY); + driver->set_by_name(BX_SOUND_LOWLEVEL_NAME); + new bx_param_filename_c(soundlow, + "wavein", + "Wave input device", + "This is the device to be used as the wave input source", + "", BX_PATHNAME_LEN); + driver = new bx_param_enum_c(soundlow, + "midioutdrv", + "Midiout driver", + "This is the midiout driver to use for emulated sound devices", + sound_driver_names, + BX_SOUNDDRV_DUMMY, + BX_SOUNDDRV_DUMMY); + driver->set_by_name(BX_SOUND_LOWLEVEL_NAME); + new bx_param_filename_c(soundlow, + "midiout", + "MIDI output device", + "This is the device where the MIDI output is sent to", + "", BX_PATHNAME_LEN); +#endif + // sound device options initialized in the devive plugin code + + // misc options subtree + bx_list_c *misc = new bx_list_c(root_param, "misc", "Configure Everything Else"); + misc->set_options(misc->SHOW_PARENT); + + // port e9 hack + new bx_param_bool_c(misc, + "port_e9_hack", + "Enable port 0xE9 hack", + "Debug messages written to i/o port 0xE9 will be displayed on console", + 0); + + // GDB stub + menu = new bx_list_c(misc, "gdbstub", "GDB Stub Options"); + menu->set_options(menu->SHOW_PARENT | menu->USE_BOX_TITLE); + menu->set_enabled(BX_GDBSTUB); + enabled = new bx_param_bool_c(menu, + "enabled", + "Enable GDB stub", + "", + 0); + enabled->set_enabled(BX_GDBSTUB); + new bx_param_num_c(menu, + "port", + "Port", + "TCP/IP port for GDB stub", + 0, 65535, + 1234); + new bx_param_num_c(menu, + "text_base", + "Text base", + "", + 0, BX_MAX_BIT32U, + 0); + new bx_param_num_c(menu, + "data_base", + "Data base", + "", + 0, BX_MAX_BIT32U, + 0); + new bx_param_num_c(menu, + "bss_base", + "BSS base", + "", + 0, BX_MAX_BIT32U, + 0); + enabled->set_dependent_list(menu->clone()); + +#if BX_PLUGINS + // user plugin options + menu = new bx_list_c(misc, "user_plugin", "User Plugin Options"); + menu->set_options(menu->SHOW_PARENT | menu->USE_BOX_TITLE); + for (i=0; iset_handler(bx_param_string_handler); + } + // user-defined options subtree + bx_list_c *user = new bx_list_c(root_param, "user", "User-defined options"); + user->set_options(user->SHOW_PARENT); +#endif + + // log options subtree + menu = new bx_list_c(root_param, "log", "Logfile Options"); + menu->set_options(menu->SHOW_PARENT); + + // log options + path = new bx_param_filename_c(menu, + "filename", + "Log filename", + "Pathname of bochs log file", + "-", BX_PATHNAME_LEN); + path->set_ask_format("Enter log filename: [%s] "); + path->set_extension("txt"); + + bx_param_string_c *prefix = new bx_param_string_c(menu, + "prefix", + "Log output prefix", + "Prefix prepended to log output", + "%t%e%d", BX_LOGPREFIX_LEN); + prefix->set_ask_format("Enter log prefix: [%s] "); + + path = new bx_param_filename_c(menu, + "debugger_filename", + "Debugger Log filename", + "Pathname of debugger log file", + "-", BX_PATHNAME_LEN); + path->set_ask_format("Enter debugger log filename: [%s] "); + path->set_extension("log"); + path->set_enabled(BX_DEBUGGER); + + // runtime options + menu = new bx_list_c(special_menus, "runtime", "Runtime options"); + bx_list_c *cdrom = new bx_list_c(menu, "cdrom", "CD-ROM options"); + cdrom->set_runtime_param(1); + cdrom->set_options(cdrom->SHOW_PARENT); + usb = new bx_list_c(menu, "usb", "USB options"); + usb->set_runtime_param(1); + usb->set_options(usb->SHOW_PARENT | usb->USE_TAB_WINDOW); + // misc runtime options + misc = new bx_list_c(menu, "misc", "Misc options"); + misc->set_runtime_param(1); + misc->add(SIM->get_param(BXPN_VGA_UPDATE_FREQUENCY)); + misc->add(SIM->get_param(BXPN_MOUSE_ENABLED)); + misc->add(SIM->get_param(BXPN_KBD_PASTE_DELAY)); + misc->add(SIM->get_param(BXPN_USER_SHORTCUT)); + misc->set_options(misc->SHOW_PARENT | misc->SHOW_GROUP_NAME); +} + +void bx_reset_options() +{ + // optional plugin control + bx_plugin_ctrl_reset(1); + + // cpu + SIM->get_param("cpu")->reset(); + +#if BX_CPU_LEVEL >= 4 + // cpuid + SIM->get_param("cpuid")->reset(); +#endif + + // memory (ram & rom) + SIM->get_param("memory")->reset(); + + // clock & cmos + SIM->get_param("clock_cmos")->reset(); + + // pci + SIM->get_param("pci")->reset(); + + // display & interface + SIM->get_param("display")->reset(); + + // keyboard & mouse + SIM->get_param("keyboard_mouse")->reset(); + + // boot + SIM->get_param("boot_params")->reset(); + + // floppy drives + SIM->get_param("floppy")->reset(); + + // ata/atapi drives + SIM->get_param("ata")->reset(); + + // serial/parallel/usb + SIM->get_param("ports")->reset(); + + // network devices + SIM->get_param("network")->reset(); + + // sound devices + SIM->get_param("sound")->reset(); + + // misc + SIM->get_param("misc")->reset(); + + // logfile + SIM->get_param("log")->reset(); + +#if BX_PLUGINS + // user-defined options + SIM->get_param("user")->reset(); + bx_user_plugin_count = 0; +#endif +} + +int bx_read_configuration(const char *rcfile) +{ + // parse rcfile first, then parse arguments in order. + BX_INFO (("reading configuration from %s", rcfile)); + if (parse_bochsrc(rcfile) < 0) { + BX_PANIC (("reading from %s failed", rcfile)); + return -1; + } + // update log actions + for (int level=0; levelget_default_log_action(level); + io->set_log_action(level, action); + } + bx_set_log_actions_by_device(0); + return 0; +} + +int bx_parse_cmdline(int arg, int argc, char *argv[]) +{ + int level, def_action[N_LOGLEV]; + + for (level=0; levelget_default_log_action(level); + } + while (arg < argc) { + BX_INFO (("parsing arg %d, %s", arg, argv[arg])); + parse_line_unformatted("cmdline args", argv[arg]); + arg++; + } + // update log actions if default has been changed + for (level=0; levelget_default_log_action(level); + if (action != def_action[level]) { + io->set_log_action(level, action); + } + } + bx_set_log_actions_by_device(0); + return 0; +} + +char *bx_find_bochsrc() +{ + FILE *fd = NULL; + char rcfile[512]; + Bit32u retry = 0, found = 0; + // try several possibilities for the bochsrc before giving up + while (!found) { + rcfile[0] = 0; + switch (retry++) { + case 0: strcpy (rcfile, ".bochsrc"); break; + case 1: strcpy (rcfile, "bochsrc"); break; + case 2: strcpy (rcfile, "bochsrc.txt"); break; +#ifdef WIN32 + case 3: strcpy (rcfile, "bochsrc.bxrc"); break; +#elif !BX_WITH_MACOS + // only try this on unix + case 3: + { + char *ptr = getenv("HOME"); + if (ptr) snprintf (rcfile, sizeof(rcfile), "%s/.bochsrc", ptr); + } + break; + case 4: strcpy (rcfile, "/etc/bochsrc"); break; +#endif + default: + return NULL; + } + if (rcfile[0]) { + BX_DEBUG (("looking for configuration in %s", rcfile)); + fd = fopen(rcfile, "r"); + if (fd) found = 1; + } + } + assert (fd != NULL && rcfile[0] != 0); + fclose (fd); + return strdup(rcfile); +} + +static int parse_bochsrc(const char *rcfile) +{ + FILE *fd = NULL; + char *ret; + char line[512]; + char context[BX_PATHNAME_LEN]; + Bit32u linenum = 1; + + // try several possibilities for the bochsrc before giving up + + bochsrc_include_level++; + + fd = fopen (rcfile, "r"); + if (fd == NULL) return -1; + + int retval = 0; + do { + ret = fgets(line, sizeof(line)-1, fd); + line[sizeof(line) - 1] = '\0'; + size_t len = strlen(line); + if ((len>0) && (line[len-1] < ' ')) + line[len-1] = '\0'; + if ((ret != NULL) && strlen(line)) { + sprintf(context, "%s:%u", rcfile, linenum); + if (parse_line_unformatted(context, line) < 0) { + retval = -1; + break; // quit parsing after first error + } + } + linenum++; + } while (!feof(fd)); + fclose(fd); + bochsrc_include_level--; + return retval; +} + +static const char *get_builtin_variable(const char *varname) +{ +#ifdef WIN32 + int code; + DWORD size; + DWORD type = 0; + HKEY hkey; + char keyname[80]; + static char data[MAX_PATH]; +#endif + + if (strlen(varname)<1) return NULL; + else { + if (!strcmp(varname, "BXSHARE")) { +#ifdef WIN32 + wsprintf(keyname, "Software\\Bochs %s", VER_STRING); + code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey); + if (code == ERROR_SUCCESS) { + data[0] = 0; + size = MAX_PATH; + if (RegQueryValueEx(hkey, "", NULL, (LPDWORD)&type, (LPBYTE)data, + (LPDWORD)&size) == ERROR_SUCCESS) { + RegCloseKey(hkey); + return data; + } else { + RegCloseKey(hkey); + return NULL; + } + } else { + return NULL; + } +#else + return BX_SHARE_PATH; +#endif + } + return NULL; + } +} + +static int parse_line_unformatted(const char *context, char *line) +{ +#define MAX_PARAMS_LEN 40 + char *ptr; + unsigned i, string_i = 0; + char string[512]; + char *params[MAX_PARAMS_LEN]; + int num_params; + bx_bool inquotes = 0; + bx_bool comment = 0; + + memset(params, 0, sizeof(params)); + if (line == NULL) return 0; + + // if passed nothing but whitespace, just return + for (i=0; i=strlen(line)) + return 0; + + num_params = 0; + + if (!strncmp(line, "#include", 8)) + ptr = strtok(line, " "); + else + ptr = strtok(line, ":"); + while ((ptr) && (!comment)) { + if (!inquotes) { + string_i = 0; + } else { + string[string_i++] = ','; + } + for (i=0; iis_action_name(actstr); + if (action < ACT_IGNORE) { + PARSE_ERR(("%s: %s directive malformed.", context, params[0])); + free(param); + return -1; + } + // exclude some action / level combinations (see siminterface.h) + if (BX_LOG_OPTS_EXCLUDE(level, action)) { + PARSE_ERR(("%s: event type '%s' does not support log action '%s'.", context, params[0], actstr)); + free(param); + return -1; + } + if (def_action) { + SIM->set_default_log_action(level, action); + } else { + sprintf(pname, "general.logfn.%s", params[0]); + base = (bx_list_c*) SIM->get_param(pname); + mparam = (bx_param_num_c*) base->get_by_name(module); + if (mparam != NULL) { + mparam->set(action); + } else { + mparam = new bx_param_num_c(base, module, "", "", -1, BX_MAX_BIT32U, action); + if (mparam == NULL) { + PARSE_ERR(("%s: %s: failed to add log module.", context, params[0])); + } + } + } + } else { + PARSE_ERR(("%s: %s directive malformed.", context, params[0])); + free(param); + return -1; + } + free(param); + } + return 0; +} + +static int parse_debug_symbols(const char *context, const char **params, int num_params) +{ +#if BX_DEBUGGER + Bit32u offset = 0; + const char *filename = 0; + + while (num_params > 0) + { + if (!strncmp(*params, "file=", 5)) { + filename = *params + 5; + } + else if (!strncmp(*params, "offset=", 7)) { + char* end; + offset = strtoul(*params + 7, &end, 0); + if (*end) + PARSE_ERR(("%s: debug_symbols: invalid parameter %s", context, *params)); + } + else { + PARSE_ERR(("%s: debug_symbols: invalid parameter %s", context, *params)); + } + params++; num_params--; + } + + if (!filename) + PARSE_ERR(("%s: debug_symbols: missing file name", context)); + + if (bx_dbg_symbol_command(filename, 1, offset) < 0) + PARSE_ERR(("%s: debug_symbols: failed to load symbols from '%s'", context, filename)); +#endif + return 0; +} + +static int parse_param_bool(const char *input, int len, const char *param) +{ + if (input[len] == '0' || input[len] == '1') { + SIM->get_param_bool(param)->set(input[len] - '0'); + return 0; + } + + return -1; +} + +int bx_parse_param_from_list(const char *context, const char *input, bx_list_c *list) +{ + char *propval, *property, *value; + bx_param_c *param; + int ret = 0; + + if (list == NULL) { + PARSE_WARN(("%s: parameter list == NULL!", context)); + return -1; + } + propval = strdup(input); + property = strtok(propval, "="); + value = strtok(NULL, ""); + if (!strcmp(property, input)) { + PARSE_WARN(("%s: incorrect parameter format", context)); + free(propval); + return -1; + } + param = list->get_by_name(property); + if (param != NULL) { + if ((param->get_options() & param->CI_ONLY) > 0) { + PARSE_WARN(("%s: ignoring hidden parameter '%s'", context, property)); + free(propval); + return 0; + } + int res = param->parse_param(value); + if (res != -1) { + if (res == 0) { + PARSE_WARN(("%s: wrong value for parameter '%s'", context, property)); + ret = -1; + } + } + else { + PARSE_WARN(("%s: parameter '%s': unknown type", context, property)); + ret = -1; + } + } else { + PARSE_WARN(("%s: unknown parameter '%s'", context, property)); + ret = -1; + } + free(propval); + return ret; +} + +int bx_parse_usb_port_params(const char *context, bx_bool devopt, const char *param, int maxports, bx_list_c *base) +{ + int idx, plen; + char tmpname[20]; + + if (!devopt) { + plen = 4; + } else { + plen = 7; + } + idx = param[plen]; + if ((idx < '1') || (idx > '9') || (param[plen + 1] != '=')) { + PARSE_ERR(("%s: usb_%s: portX / optionsX parameter malformed.", context, base->get_name())); + return -1; + } + idx -= '0'; + if (idx > maxports) { + PARSE_ERR(("%s: usb_%s: port number out of range.", context, base->get_name())); + return -1; + } + sprintf(tmpname, "port%d.%s", idx, devopt ? "options" : "device"); + SIM->get_param_string(tmpname, base)->set(¶m[plen + 2]); + return 0; +} + +int bx_parse_nic_params(const char *context, const char *param, bx_list_c *base) +{ + int tmp[6]; + char tmpchar[6]; + int valid = 0; + int n; + + if (!strncmp(param, "enabled=", 8)) { + n = atol(¶m[8]); + SIM->get_param_bool("enabled", base)->set(n); + if (n == 0) valid |= 0x80; + else valid &= 0x7f; + } else if (!strncmp(param, "mac=", 4)) { + n = sscanf(¶m[4], "%x:%x:%x:%x:%x:%x", + &tmp[0],&tmp[1],&tmp[2],&tmp[3],&tmp[4],&tmp[5]); + if (n != 6) { + PARSE_ERR(("%s: '%s' mac address malformed.", context, base->get_name())); + } + for (n=0;n<6;n++) + tmpchar[n] = (unsigned char)tmp[n]; + SIM->get_param_string("mac", base)->set(tmpchar); + valid |= 0x04; + } else if (!strncmp(param, "ethmod=", 7)) { + if (!SIM->get_param_enum("ethmod", base)->set_by_name(¶m[7])) + PARSE_ERR(("%s: ethernet module '%s' not available", context, ¶m[7])); + } else if (bx_parse_param_from_list(context, param, base) < 0) { + PARSE_WARN(("%s: expected parameter '%s' for '%s' ignored.", context, param, base->get_name())); + return -1; + } + return valid; +} + +bx_bool is_deprecated_option(const char *oldparam, const char **newparam) +{ + if ((!strcmp(oldparam, "keyboard_serial_delay")) || + (!strcmp(oldparam, "keyboard_paste_delay")) || + (!strcmp(oldparam, "keyboard_type")) || + (!strcmp(oldparam, "keyboard_mapping")) || + (!strcmp(oldparam, "keyboardmapping"))) { + // replaced v2.6 / removed v2.6.7 + *newparam = "keyboard"; + return 1; + } else if (!strcmp(oldparam, "user_shortcut")) { + // replaced v2.6.1 / removed v2.6.9 + *newparam = "keyboard"; + return 1; +#if BX_SUPPORT_PCIPNIC + } else if (!strcmp(oldparam, "pnic")) { + // replaced v2.6 / removed v2.6.5 + *newparam = "pcipnic"; + return 1; +#endif + } + return 0; +} + +static int parse_line_formatted(const char *context, int num_params, char *params[]) +{ + int i, slot, t; + bx_list_c *base; + const char *newparam; + + if (num_params < 1) return 0; + if (num_params < 2) { + PARSE_ERR(("%s: a bochsrc option needs at least one parameter", context)); + } + + if (!strcmp(params[0], "#include")) { + if (num_params != 2) { + PARSE_ERR(("%s: ignoring malformed #include directive.", context)); + } + if (!strcmp(params[1], context)) { + PARSE_ERR(("%s: cannot include this file again.", context)); + } + if (bochsrc_include_level > 2) { + PARSE_ERR(("%s: maximum include level exceeded (limit = 2).", context)); + } + bx_read_configuration(params[1]); + } else if (!strcmp(params[0], "plugin_ctrl")) { + char *param, *pname, *val; + for (i=1; iopt_plugin_ctrl(pname, atoi(val)); + } else { + PARSE_ERR(("%s: plugin_ctrl directive malformed", context)); + } + } else { + PARSE_ERR(("%s: plugin_ctrl directive malformed", context)); + } + free(param); + } + } else if (!strcmp(params[0], "config_interface")) { + if (num_params != 2) { + PARSE_ERR(("%s: config_interface directive: wrong # args.", context)); + } + if (!SIM->get_param_enum(BXPN_SEL_CONFIG_INTERFACE)->set_by_name(params[1])) + PARSE_ERR(("%s: config_interface '%s' not available", context, params[1])); + } else if (!strcmp(params[0], "display_library")) { + if ((num_params < 2) || (num_params > 3)) { + PARSE_ERR(("%s: display_library directive: wrong # args.", context)); + } + if (!SIM->get_param_enum(BXPN_SEL_DISPLAY_LIBRARY)->set_by_name(params[1])) + PARSE_ERR(("%s: display library '%s' not available", context, params[1])); + if (num_params == 3) { + if (!strncmp(params[2], "options=", 8)) { + SIM->get_param_string(BXPN_DISPLAYLIB_OPTIONS)->set(¶ms[2][8]); + } else { + PARSE_ERR(("%s: display_library directive malformed", context)); + } + } + } else if ((!strcmp(params[0], "floppya")) || + (!strcmp(params[0], "floppyb"))) { + if (!strcmp(params[0], "floppya")) { + base = (bx_list_c*) SIM->get_param(BXPN_FLOPPYA); + } else { + base = (bx_list_c*) SIM->get_param(BXPN_FLOPPYB); + } + for (i=1; iget_param_enum("devtype", base)->set(BX_FDD_350ED); + } + else if (!strcmp(params[i]+5, "1_44")) { + SIM->get_param_enum("devtype", base)->set(BX_FDD_350HD); + } + else if (!strcmp(params[i]+5, "1_2")) { + SIM->get_param_enum("devtype", base)->set(BX_FDD_525HD); + } + else if (!strcmp(params[i]+5, "720k")) { + SIM->get_param_enum("devtype", base)->set(BX_FDD_350DD); + } + else if (!strcmp(params[i]+5, "360k")) { + SIM->get_param_enum("devtype", base)->set(BX_FDD_525DD); + } + else { + PARSE_ERR(("%s: %s: unknown type '%s'.", context, params[0], + params[i]+5)); + } + } + else if (!strncmp(params[i], "2_88=", 5)) { + SIM->get_param_string("path", base)->set(¶ms[i][5]); + SIM->get_param_enum("type", base)->set(BX_FLOPPY_2_88); + } + else if (!strncmp(params[i], "1_44=", 5)) { + SIM->get_param_string("path", base)->set(¶ms[i][5]); + SIM->get_param_enum("type", base)->set(BX_FLOPPY_1_44); + } + else if (!strncmp(params[i], "1_2=", 4)) { + SIM->get_param_string("path", base)->set(¶ms[i][4]); + SIM->get_param_enum("type", base)->set(BX_FLOPPY_1_2); + } + else if (!strncmp(params[i], "720k=", 5)) { + SIM->get_param_string("path", base)->set(¶ms[i][5]); + SIM->get_param_enum("type", base)->set(BX_FLOPPY_720K); + } + else if (!strncmp(params[i], "360k=", 5)) { + SIM->get_param_string("path", base)->set(¶ms[i][5]); + SIM->get_param_enum("type", base)->set(BX_FLOPPY_360K); + } + // use CMOS reserved types? + else if (!strncmp(params[i], "160k=", 5)) { + SIM->get_param_string("path", base)->set(¶ms[i][5]); + SIM->get_param_enum("type", base)->set(BX_FLOPPY_160K); + } + else if (!strncmp(params[i], "180k=", 5)) { + SIM->get_param_string("path", base)->set(¶ms[i][5]); + SIM->get_param_enum("type", base)->set(BX_FLOPPY_180K); + } + else if (!strncmp(params[i], "320k=", 5)) { + SIM->get_param_string("path", base)->set(¶ms[i][5]); + SIM->get_param_enum("type", base)->set(BX_FLOPPY_320K); + } + else if (!strncmp(params[i], "image=", 6)) { + /* "image=" means we should get floppy type from image */ + SIM->get_param_string("path", base)->set(¶ms[i][6]); + t = get_floppy_type_from_image(¶ms[i][6]); + if (t != BX_FLOPPY_UNKNOWN) + SIM->get_param_enum("type", base)->set(t); + else + PARSE_ERR(("%s: %s image size doesn't match one of the supported types.", + context, params[0])); + } + else if (!strcmp(params[i], "status=inserted")) { + SIM->get_param_enum("status", base)->set(BX_INSERTED); + } + else if (!strcmp(params[i], "status=ejected")) { + SIM->get_param_enum("status", base)->set(BX_EJECTED); + } + else if (!strncmp(params[i], "write_protected=", 16)) { + SIM->get_param_bool("readonly", base)->set(atol(¶ms[i][16])); + } + else { + PARSE_ERR(("%s: %s attribute '%s' not understood.", context, params[0], + params[i])); + } + } + } else if ((!strncmp(params[0], "ata", 3)) && (strlen(params[0]) == 4)) { + char tmpname[80]; + Bit8u channel = params[0][3]; + + if ((channel < '0') || (channel > '9')) { + PARSE_ERR(("%s: ataX directive malformed.", context)); + } + channel-='0'; + if (channel >= BX_MAX_ATA_CHANNEL) { + PARSE_ERR(("%s: ataX directive malformed.", context)); + } + + if ((num_params < 2) || (num_params > 5)) { + PARSE_ERR(("%s: ataX directive malformed.", context)); + } + sprintf(tmpname, "ata.%d.resources", channel); + for (i=1; iget_param(tmpname)) < 0) { + PARSE_ERR(("%s: ataX directive malformed.", context)); + } + } + } else if ((!strncmp(params[0], "ata", 3)) && (strlen(params[0]) > 4)) { + // ataX-master, ataX-slave + Bit8u channel = params[0][3]; + int type = -1; + Bit32u cylinders = 0, heads = 0, sectors = 0; + char tmpname[80]; + + if ((channel < '0') || (channel > '9')) { + PARSE_ERR(("%s: ataX-master/slave directive malformed.", context)); + } + channel-='0'; + if (channel >= BX_MAX_ATA_CHANNEL) { + PARSE_ERR(("%s: ataX-master/slave directive malformed.", context)); + } + + if ((strcmp(¶ms[0][4], "-slave")) && + (strcmp(¶ms[0][4], "-master"))) { + PARSE_ERR(("%s: ataX-master/slave directive malformed.", context)); + } + + sprintf(tmpname, "ata.%d.%s", channel, ¶ms[0][5]); + base = (bx_list_c*) SIM->get_param(tmpname); + for (i=1; ifind_by_name(¶ms[i][5]); + if (type < 0) { + PARSE_ERR(("%s: ataX-master/slave: unknown type '%s'", context, ¶ms[i][5])); + } else { + SIM->get_param_enum("type", base)->set(type); + } + } else if (!strncmp(params[i], "cylinders=", 10)) { + cylinders = atol(¶ms[i][10]); + } else if (!strncmp(params[i], "heads=", 6)) { + heads = atol(¶ms[i][6]); + } else if (!strncmp(params[i], "spt=", 4)) { + sectors = atol(¶ms[i][4]); + } else if (!strcmp(params[i], "translation=echs")) { // synonym of large + SIM->get_param_enum("translation", base)->set(BX_ATA_TRANSLATION_LARGE); + } else if (bx_parse_param_from_list(context, params[i], base) < 0) { + PARSE_ERR(("%s: ataX-master/slave directive malformed.", context)); + } + } + + // Check for geometry autodetection mode + if (type == BX_ATA_DEVICE_DISK) { + if (strlen(SIM->get_param_string("path", base)->getptr()) > 0) { + SIM->get_param_num("cylinders", base)->set(cylinders); + if ((cylinders == 0) && (heads == 0) && (sectors == 0)) { + PARSE_WARN(("%s: ataX-master/slave CHS set to 0/0/0 - autodetection enabled", context)); + // using heads = 16 and spt = 63 for autodetection (bximage defaults) + SIM->get_param_num("heads", base)->set(16); + SIM->get_param_num("spt", base)->set(63); + } else { + SIM->get_param_num("heads", base)->set(heads); + SIM->get_param_num("spt", base)->set(sectors); + } + } else { + SIM->get_param_enum("type", base)->set(BX_ATA_DEVICE_NONE); + } + } + } else if (!strcmp(params[0], "boot")) { + char tmppath[80]; + if (num_params < 2) { + PARSE_ERR(("%s: boot directive malformed.", context)); + } + for (i=1; iget_param_enum(tmppath)->set(BX_BOOT_NONE); + } else if (!strcmp(params[i], "a")) { + SIM->get_param_enum(tmppath)->set(BX_BOOT_FLOPPYA); + } else if (!strcmp(params[i], "floppy")) { + SIM->get_param_enum(tmppath)->set(BX_BOOT_FLOPPYA); + } else if (!strcmp(params[i], "c")) { + SIM->get_param_enum(tmppath)->set(BX_BOOT_DISKC); + } else if (!strcmp(params[i], "disk")) { + SIM->get_param_enum(tmppath)->set(BX_BOOT_DISKC); + } else if (!strcmp(params[i], "cdrom")) { + SIM->get_param_enum(tmppath)->set(BX_BOOT_CDROM); + } else if (!strcmp(params[i], "network")) { + SIM->get_param_enum(tmppath)->set(BX_BOOT_NETWORK); + } else { + PARSE_ERR(("%s: boot directive with unknown boot drive '%s'. use 'floppy', 'disk', 'cdrom' or 'network'.", context, params[i])); + } + } + if (SIM->get_param_enum(BXPN_BOOTDRIVE1)->get() == BX_BOOT_NONE) { + PARSE_ERR(("%s: first boot drive must be one of 'floppy', 'disk' or 'cdrom'.", context)); + } + if ((SIM->get_param_enum(BXPN_BOOTDRIVE1)->get() == SIM->get_param_enum(BXPN_BOOTDRIVE2)->get()) || + (SIM->get_param_enum(BXPN_BOOTDRIVE1)->get() == SIM->get_param_enum(BXPN_BOOTDRIVE3)->get()) || + ((SIM->get_param_enum(BXPN_BOOTDRIVE3)->get() != BX_BOOT_NONE) && + (SIM->get_param_enum(BXPN_BOOTDRIVE2)->get() == SIM->get_param_enum(BXPN_BOOTDRIVE3)->get()))) { + PARSE_ERR(("%s: a boot drive appears twice in boot sequence.", context)); + } + } else if (!strcmp(params[0], "floppy_bootsig_check")) { + if (num_params != 2) { + PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context)); + } + if (strncmp(params[1], "disabled=", 9)) { + PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context)); + } + if (parse_param_bool(params[1], 9, BXPN_FLOPPYSIGCHECK) < 0) { + PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context)); + } + } else if (!strcmp(params[0], "log")) { + if (num_params != 2) { + PARSE_ERR(("%s: log directive has wrong # args.", context)); + } + SIM->get_param_string(BXPN_LOG_FILENAME)->set(params[1]); + } else if (!strcmp(params[0], "logprefix")) { + if (num_params != 2) { + PARSE_ERR(("%s: logprefix directive has wrong # args.", context)); + } + SIM->get_param_string(BXPN_LOG_PREFIX)->set(params[1]); + } else if (!strcmp(params[0], "debugger_log")) { + if (num_params != 2) { + PARSE_ERR(("%s: debugger_log directive has wrong # args.", context)); + } + SIM->get_param_string(BXPN_DEBUGGER_LOG_FILENAME)->set(params[1]); + } else if (!strcmp(params[0], "panic")) { + if (num_params < 2) { + PARSE_ERR(("%s: panic directive malformed.", context)); + } + if (parse_log_options(context, num_params, params) < 0) { + return -1; + } + } else if (!strcmp(params[0], "error")) { + if (num_params < 2) { + PARSE_ERR(("%s: error directive malformed.", context)); + } + if (parse_log_options(context, num_params, params) < 0) { + return -1; + } + } else if (!strcmp(params[0], "info")) { + if (num_params < 2) { + PARSE_ERR(("%s: info directive malformed.", context)); + } + if (parse_log_options(context, num_params, params) < 0) { + return -1; + } + } else if (!strcmp(params[0], "debug")) { + if (num_params < 2) { + PARSE_ERR(("%s: debug directive malformed.", context)); + } + if (parse_log_options(context, num_params, params) < 0) { + return -1; + } + } else if (!strcmp(params[0], "cpu")) { + if (num_params < 2) { + PARSE_ERR(("%s: cpu directive malformed.", context)); + } + for (i=1; iget_param_num(BXPN_CPU_NPROCESSORS)->set(processors); + SIM->get_param_num(BXPN_CPU_NCORES)->set(cores); + SIM->get_param_num(BXPN_CPU_NTHREADS)->set(threads); + } else if (bx_parse_param_from_list(context, params[i], (bx_list_c*) SIM->get_param("cpu")) < 0) { + PARSE_ERR(("%s: cpu directive malformed.", context)); + } + } +#if BX_CPU_LEVEL >= 4 + } else if (!strcmp(params[0], "cpuid")) { + if (num_params < 2) { + PARSE_ERR(("%s: cpuid directive malformed.", context)); + } + for (i=1; iget_param("cpuid")) < 0) { + PARSE_ERR(("%s: cpuid directive malformed.", context)); + } + } +#endif + } else if (!strcmp(params[0], "megs")) { + if (num_params != 2) { + PARSE_ERR(("%s: megs directive: wrong # args.", context)); + } + SIM->get_param_num(BXPN_MEM_SIZE)->set(atol(params[1])); + SIM->get_param_num(BXPN_HOST_MEM_SIZE)->set(atol(params[1])); + } else if (!strcmp(params[0], "memory")) { + if (num_params < 3) { + PARSE_ERR(("%s: memory directive malformed.", context)); + } + for (i=1; i 4)) { + PARSE_ERR(("%s: romimage directive: wrong # args.", context)); + } + // set to default value 0 (auto-detect if no specified) + SIM->get_param_num(BXPN_ROM_ADDRESS)->set(0); + for (i=1; i BX_N_OPTROM_IMAGES)) { + PARSE_ERR(("%s: optromimage%d: not supported", context, num)); + } + if (num_params > 3) { + PARSE_ERR(("%s: optromimage%d directive: wrong # args.", context, num)); + } + sprintf(pname, "%s.%d", BXPN_OPTROM_BASE, num); + base = (bx_list_c*) SIM->get_param(pname); + for (i=1; iset(¶ms[i][5]); + } else if (!strncmp(params[i], "address=", 8)) { + if ((params[i][8] == '0') && (params[2][9] == 'x')) + SIM->get_param_num("address", base)->set(strtoul(¶ms[i][8], NULL, 16)); + else + SIM->get_param_num("address", base)->set(strtoul(¶ms[i][8], NULL, 10)); + } else { + PARSE_ERR(("%s: optromimage%d directive malformed.", context, num)); + } + } + } else if (!strncmp(params[0], "optramimage", 11)) { + int num = atoi(¶ms[0][11]); + char pname[16]; + if ((num < 1) || (num > BX_N_OPTRAM_IMAGES)) { + PARSE_ERR(("%s: optramimage%d: not supported", context, num)); + } + if (num_params > 3) { + PARSE_ERR(("%s: optramimage%d directive: wrong # args.", context, num)); + } + sprintf(pname, "%s.%d", BXPN_OPTRAM_BASE, num); + base = (bx_list_c*) SIM->get_param(pname); + for (i=1; iset(¶ms[i][5]); + } else if (!strncmp(params[i], "address=", 8)) { + if ((params[i][8] == '0') && (params[2][9] == 'x')) + SIM->get_param_num("address", base)->set(strtoul(¶ms[i][8], NULL, 16)); + else + SIM->get_param_num("address", base)->set(strtoul(¶ms[i][8], NULL, 10)); + } else { + PARSE_ERR(("%s: optramimage%d directive malformed.", context, num)); + } + } + } else if (!strcmp(params[0], "vga")) { + if (num_params < 2) { + PARSE_ERR(("%s: vga directive malformed.", context)); + } + for (i=1; iget_param_string(BXPN_KBD_KEYMAP)->set(kmap); + } else if (bx_parse_param_from_list(context, params[i], (bx_list_c*) SIM->get_param(BXPN_KEYBOARD)) < 0) { + PARSE_ERR(("%s: keyboard directive malformed.", context)); + } + } + } else if (!strcmp(params[0], "mouse")) { + if (num_params < 2) { + PARSE_ERR(("%s: mouse directive malformed.", context)); + } + for (i=1; iget_param(BXPN_MOUSE)) < 0) { + PARSE_ERR(("%s: mouse directive malformed.", context)); + } + } + } else if (!strcmp(params[0], "private_colormap")) { + if (num_params != 2) { + PARSE_ERR(("%s: private_colormap directive malformed.", context)); + } + if (strncmp(params[1], "enabled=", 8)) { + PARSE_ERR(("%s: private_colormap directive malformed.", context)); + } + if (parse_param_bool(params[1], 8, BXPN_PRIVATE_COLORMAP) < 0) { + PARSE_ERR(("%s: private_colormap directive malformed.", context)); + } + } else if (!strcmp(params[0], "fullscreen")) { +#if BX_WITH_AMIGAOS + if (num_params != 2) { + PARSE_ERR(("%s: fullscreen directive malformed.", context)); + } + if (strncmp(params[1], "enabled=", 8)) { + PARSE_ERR(("%s: fullscreen directive malformed.", context)); + } + if (parse_param_bool(params[1], 8, BXPN_FULLSCREEN) < 0) { + PARSE_ERR(("%s: fullscreen directive malformed.", context)); + } +#endif + } else if (!strcmp(params[0], "screenmode")) { +#if BX_WITH_AMIGAOS + if (num_params != 2) { + PARSE_ERR(("%s: screenmode directive malformed.", context)); + } + if (strncmp(params[1], "name=", 5)) { + PARSE_ERR(("%s: screenmode directive malformed.", context)); + } + SIM->get_param_string(BXPN_SCREENMODE)->set(¶ms[1][5]); +#endif + } else if (!strcmp(params[0], "pci")) { + char tmpdev[80]; + int enabled = -1; + bx_bool chipset = 0; + for (i=1; iget_param_bool(BXPN_PCI_ENABLED)->set(0); + } else if (enabled == 1) { + if (chipset == 1) { + SIM->get_param_bool(BXPN_PCI_ENABLED)->set(1); + } else { + PARSE_ERR(("%s: pci: chipset not specified", context)); + } + } + } else if (!strcmp(params[0], "cmosimage")) { + for (i=1; iget_param_bool(BXPN_CMOSIMAGE_RTC_INIT)->set(0); + } else if (!strcmp(params[i], "rtc_init=image")) { + SIM->get_param_bool(BXPN_CMOSIMAGE_RTC_INIT)->set(1); + } else { + BX_ERROR(("%s: unknown parameter for cmosimage ignored.", context)); + } + } + if (strlen(SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr()) > 0) { + SIM->get_param_bool(BXPN_CMOSIMAGE_ENABLED)->set(1); + } + } else if (!strcmp(params[0], "clock")) { + const char months[] = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec "; + char wday[4], mon[4]; + int n, year; + struct tm tm_time; + for (i=1; iget_param_num(BXPN_CLOCK_TIME0)->set(BX_CLOCK_TIME0_LOCAL); + } + else if (!strcmp(params[i], "time0=utc")) { + SIM->get_param_num(BXPN_CLOCK_TIME0)->set(BX_CLOCK_TIME0_UTC); + } + else if (!strncmp(params[i], "time0=", 6)) { + if (isalpha(params[i][6])) { + memset(&tm_time, 0, sizeof(tm_time)); + n = sscanf(¶ms[i][6], "%3s %3s%3d %2d:%2d:%2d %d", wday, mon, &tm_time.tm_mday, + &tm_time.tm_hour, &tm_time.tm_min, &tm_time.tm_sec, &year); + if ((n == 7) && (year >= 1980) && (strstr(months, mon) != NULL)) { + tm_time.tm_year = year - 1900; + tm_time.tm_mon = 12 - (strlen(strstr(months, mon)) / 4); + SIM->get_param_num(BXPN_CLOCK_TIME0)->set(mktime(&tm_time)); + } else { + PARSE_ERR(("%s: time0 string format malformed.", context)); + } + } else { + SIM->get_param_num(BXPN_CLOCK_TIME0)->set(atoi(¶ms[i][6])); + } + } + else { + BX_ERROR(("%s: unknown parameter for clock ignored.", context)); + } + } + } else if (!strcmp(params[0], "sound")) { +#if BX_SUPPORT_SOUNDLOW + static const char default_drv[] = BX_SOUND_LOWLEVEL_NAME; + const char *driver; + for (i=1; iget_param_enum(BXPN_SOUND_WAVEOUT_DRV)->set_by_name(driver); + SIM->get_param_enum(BXPN_SOUND_WAVEIN_DRV)->set_by_name(driver); + SIM->get_param_enum(BXPN_SOUND_MIDIOUT_DRV)->set_by_name(driver); + } else if (bx_parse_param_from_list(context, params[i], (bx_list_c*) SIM->get_param(BXPN_SOUNDLOW)) < 0) { + BX_ERROR(("%s: unknown parameter for sound ignored.", context)); + } + } +#else + PARSE_ERR(("%s: Bochs is not compiled with lowlevel sound support", context)); +#endif + } else if (!strcmp(params[0], "gdbstub")) { +#if BX_GDBSTUB + if (num_params < 2) { + PARSE_ERR(("%s: gdbstub directive: wrong # args.", context)); + } + base = (bx_list_c*) SIM->get_param(BXPN_GDBSTUB); + for (i=1; iset(0); + BX_INFO(("Disabled gdbstub")); + bx_dbg.gdbstub_enabled = 0; + } + else if (params[i][8] == '1') { + SIM->get_param_bool("enabled", base)->set(1); + BX_INFO(("Enabled gdbstub")); + bx_dbg.gdbstub_enabled = 1; + } + else { + PARSE_ERR(("%s: gdbstub directive malformed.", context)); + } + } + else if (!strncmp(params[i], "port=", 5)) { + SIM->get_param_num("port", base)->set(atoi(¶ms[i][5])); + } + else if (!strncmp(params[i], "text_base=", 10)) { + SIM->get_param_num("text_base", base)->set(atoi(¶ms[i][10])); + } + else if (!strncmp(params[i], "data_base=", 10)) { + SIM->get_param_num("data_base", base)->set(atoi(¶ms[i][10])); + } + else if (!strncmp(params[i], "bss_base=", 9)) { + SIM->get_param_num("bss_base", base)->set(atoi(¶ms[i][9])); + } + else { + PARSE_ERR(("%s: gdbstub directive malformed.", context)); + } + } +#else + PARSE_ERR(("%s: Bochs is not compiled with gdbstub support", context)); +#endif + } else if (!strcmp(params[0], "magic_break")) { +#if BX_DEBUGGER + if (num_params != 2) { + PARSE_ERR(("%s: magic_break directive: wrong # args.", context)); + } + if (strncmp(params[1], "enabled=", 8)) { + PARSE_ERR(("%s: magic_break directive malformed.", context)); + } + if (params[1][8] == '0') { + BX_INFO(("Ignoring magic break points")); + bx_dbg.magic_break_enabled = 0; + } + else if (params[1][8] == '1') { + BX_INFO(("Stopping on magic break points")); + bx_dbg.magic_break_enabled = 1; + } + else { + PARSE_ERR(("%s: magic_break directive malformed.", context)); + } +#else + PARSE_WARN(("%s: Bochs is not compiled with internal debugger support", context)); +#endif + } else if (!strcmp(params[0], "debug_symbols")) { + if (parse_debug_symbols(context, (const char **)(params + 1), num_params - 1) < 0) { + return -1; + } + } else if (!strcmp(params[0], "print_timestamps")) { + if (num_params != 2) { + PARSE_ERR(("%s: print_timestamps directive: wrong # args.", context)); + } + if (strncmp(params[1], "enabled=", 8)) { + PARSE_ERR(("%s: print_timestamps directive malformed.", context)); + } + if (params[1][8] == '0' || params[1][8] == '1') { + bx_dbg.print_timestamps = params[1][8] - '0'; + } + else { + PARSE_ERR(("%s: print_timestamps directive malformed.", context)); + } + } else if (!strcmp(params[0], "port_e9_hack")) { + if (num_params != 2) { + PARSE_ERR(("%s: port_e9_hack directive: wrong # args.", context)); + } + if (strncmp(params[1], "enabled=", 8)) { + PARSE_ERR(("%s: port_e9_hack directive malformed.", context)); + } + if (parse_param_bool(params[1], 8, BXPN_PORT_E9_HACK) < 0) { + PARSE_ERR(("%s: port_e9_hack directive malformed.", context)); + } + } else if (!strcmp(params[0], "load32bitOSImage")) { + if ((num_params!=4) && (num_params!=5)) { + PARSE_ERR(("%s: load32bitOSImage directive: wrong # args.", context)); + } + if (strncmp(params[1], "os=", 3)) { + PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context)); + } + if (!strcmp(¶ms[1][3], "nullkernel")) { + SIM->get_param_enum(BXPN_LOAD32BITOS_WHICH)->set(Load32bitOSNullKernel); + } + else if (!strcmp(¶ms[1][3], "linux")) { + SIM->get_param_enum(BXPN_LOAD32BITOS_WHICH)->set(Load32bitOSLinux); + } + else { + PARSE_ERR(("%s: load32bitOSImage: unsupported OS.", context)); + } + if (strncmp(params[2], "path=", 5)) { + PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context)); + } + if (strncmp(params[3], "iolog=", 6)) { + PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context)); + } + SIM->get_param_string(BXPN_LOAD32BITOS_PATH)->set(¶ms[2][5]); + SIM->get_param_string(BXPN_LOAD32BITOS_IOLOG)->set(¶ms[3][6]); + if (num_params == 5) { + if (strncmp(params[4], "initrd=", 7)) { + PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context)); + } + SIM->get_param_string(BXPN_LOAD32BITOS_INITRD)->set(¶ms[4][7]); + } + PARSE_WARN(("%s: WARNING: This Bochs feature is not maintained yet", context)); + } else if (!strcmp(params[0], "user_plugin")) { +#if BX_PLUGINS + char tmpname[80]; + for (i=1; iget_param_string(tmpname)->set(¶ms[i][5]); + } else { + PARSE_ERR(("%s: too many user plugins", context)); + } + } else { + PARSE_ERR(("%s: unknown user plugin parameter '%s'", context, params[i])); + } + } +#else + PARSE_ERR(("%s: Bochs is not compiled with plugin support", context)); +#endif + } else if (SIM->is_addon_option(params[0])) { + // add-on options handled by registered functions + return SIM->parse_addon_option(context, num_params, ¶ms[0]); + } else if (is_deprecated_option(params[0], &newparam)) { + PARSE_ERR(("%s: '%s' is deprecated - use '%s' option instead.", context, params[0], newparam)); + } else if (SIM->opt_plugin_ctrl(params[0], 1)) { + // treat unknown option as plugin name and try to load it + if (SIM->is_addon_option(params[0])) { + // after loading the plugin a bochsrc option with it's name must exist + return SIM->parse_addon_option(context, num_params, ¶ms[0]); + } else { + PARSE_ERR(("%s: directive '%s' not understood", context, params[0])); + } + } else { + PARSE_ERR(("%s: directive '%s' not understood", context, params[0])); + } + return 0; +} + + +int bx_write_param_list(FILE *fp, bx_list_c *base, const char *optname, bx_bool multiline) +{ + char bxrcline[BX_PATHNAME_LEN], tmpstr[BX_PATHNAME_LEN]; + bx_bool newline = 1; + int p = 0; + + if (base == NULL) return -1; + if (!base->get_enabled()) return -1; + bxrcline[0] = 0; + for (int i = 0; i < base->get_size(); i++) { + if (newline) { + if (strlen(bxrcline) > 0) { + fprintf(fp, "%s\n", bxrcline); + } + if (optname == NULL) { + sprintf(bxrcline, "%s: ", base->get_name()); + } else { + sprintf(bxrcline, "%s: ", optname); + } + newline = 0; + p = 0; + } + bx_param_c *param = base->get(i); + if (param->get_enabled() && ((param->get_options() & param->CI_ONLY) == 0)) { + if (p > 0) { + strcat(bxrcline, ", "); + } + sprintf(tmpstr, "%s=", param->get_name()); + strcat(bxrcline, tmpstr); + switch (param->get_type()) { + case BXT_PARAM_NUM: + if (((bx_param_num_c*)param)->get_base() == BASE_DEC) { + sprintf(tmpstr, FMT_LL "d", ((bx_param_num_c*)param)->get64()); + } else { + sprintf(tmpstr, "0x" FMT_LL "x", ((bx_param_num_c*)param)->get64()); + } + break; + case BXT_PARAM_BOOL: + sprintf(tmpstr, "%d", ((bx_param_bool_c*)param)->get()); + break; + case BXT_PARAM_ENUM: + sprintf(tmpstr, "%s", ((bx_param_enum_c*)param)->get_selected()); + break; + case BXT_PARAM_STRING: + ((bx_param_string_c*)param)->sprint(tmpstr, BX_PATHNAME_LEN, 1); + break; + default: + BX_ERROR(("bx_write_param_list(): unsupported parameter type")); + } + strcat(bxrcline, tmpstr); + p++; + } + if (multiline && (strlen(bxrcline) > 80)) { + newline = 1; + } + } + fprintf(fp, "%s\n", bxrcline); + return 0; +} + +static const char *fdtypes[] = { + "none", "1_2", "1_44", "2_88", "720k", "360k", "160k", "180k", "320k" +}; + +int bx_write_floppy_options(FILE *fp, int drive) +{ + char devtype[80], path[80], type[80], status[80], readonly[80]; + int ftype; + + BX_ASSERT(drive==0 || drive==1); + sprintf(devtype, "floppy.%d.devtype", drive); + sprintf(path, "floppy.%d.path", drive); + sprintf(type, "floppy.%d.type", drive); + sprintf(status, "floppy.%d.status", drive); + sprintf(readonly, "floppy.%d.readonly", drive); + ftype = SIM->get_param_enum(devtype)->get(); + if (ftype == BX_FDD_NONE) { + fprintf(fp, "# no floppy%c\n", (char)'a'+drive); + return 0; + } else { + fprintf(fp, "floppy%c: type=", (char)'a'+drive); + if (ftype == BX_FDD_350ED) { + fprintf(fp, "2_88"); + } else if (ftype == BX_FDD_350HD) { + fprintf(fp, "1_44"); + } else if (ftype == BX_FDD_525HD) { + fprintf(fp, "1_2"); + } else if (ftype == BX_FDD_350DD) { + fprintf(fp, "720k"); + } else if (ftype == BX_FDD_525DD) { + fprintf(fp, "360k"); + } + } + if ((SIM->get_param_enum(type)->get() > BX_FLOPPY_NONE) && + (SIM->get_param_enum(type)->get() <= BX_FLOPPY_LAST)) { + fprintf(fp, ", %s=\"%s\", status=%s, write_protected=%d", + fdtypes[SIM->get_param_enum(type)->get() - BX_FLOPPY_NONE], + SIM->get_param_string(path)->getptr(), + SIM->get_param_enum(status)->get_selected(), + SIM->get_param_bool(readonly)->get()); + } + fprintf(fp, "\n"); + return 0; +} + +int bx_write_usb_options(FILE *fp, int maxports, bx_list_c *base) +{ + int i; + char tmpname[20], tmpstr[BX_PATHNAME_LEN]; + + fprintf(fp, "usb_%s: enabled=%d", base->get_name(), SIM->get_param_bool("enabled", base)->get()); + if (SIM->get_param_bool("enabled", base)->get()) { + for (i = 1; i <= maxports; i++) { + sprintf(tmpname, "port%d.device", i); + SIM->get_param_string(tmpname, base)->sprint(tmpstr, BX_PATHNAME_LEN, 1); + fprintf(fp, ", port%d=%s", i, tmpstr); + sprintf(tmpname, "port%d.options", i); + SIM->get_param_string(tmpname, base)->sprint(tmpstr, BX_PATHNAME_LEN, 1); + fprintf(fp, ", options%d=%s", i, tmpstr); + } + } + fprintf(fp, "\n"); + return 0; +} + +int bx_write_loader_options(FILE *fp) +{ + if (SIM->get_param_enum(BXPN_LOAD32BITOS_WHICH)->get() == Load32bitOSNone) { + fprintf(fp, "# no loader\n"); + return 0; + } + fprintf (fp, "load32bitOSImage: os=%s, path=%s, iolog=%s, initrd=%s\n", + SIM->get_param_enum(BXPN_LOAD32BITOS_WHICH)->get_selected(), + SIM->get_param_string(BXPN_LOAD32BITOS_PATH)->getptr(), + SIM->get_param_string(BXPN_LOAD32BITOS_IOLOG)->getptr(), + SIM->get_param_string(BXPN_LOAD32BITOS_INITRD)->getptr()); + return 0; +} + +int bx_write_clock_cmos_options(FILE *fp) +{ + fprintf(fp, "clock: sync=%s", SIM->get_param_enum(BXPN_CLOCK_SYNC)->get_selected()); + + switch (SIM->get_param_num(BXPN_CLOCK_TIME0)->get()) { + case 0: break; + case BX_CLOCK_TIME0_LOCAL: + fprintf(fp, ", time0=local"); + break; + case BX_CLOCK_TIME0_UTC: + fprintf(fp, ", time0=utc"); + break; + default: + fprintf(fp, ", time0=%u", SIM->get_param_num(BXPN_CLOCK_TIME0)->get()); + } + + fprintf(fp, ", rtc_sync=%d\n", SIM->get_param_bool(BXPN_CLOCK_RTC_SYNC)->get()); + + if (strlen(SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr()) > 0) { + fprintf(fp, "cmosimage: file=%s, ", SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr()); + fprintf(fp, "rtc_init=%s\n", SIM->get_param_bool(BXPN_CMOSIMAGE_RTC_INIT)->get()?"image":"time0"); + } else { + fprintf(fp, "# no cmosimage\n"); + } + return 0; +} + +int bx_write_log_options(FILE *fp, bx_list_c *base) +{ + char pname[20]; + bx_list_c *logfn, *loglev; + bx_param_num_c *mparam; + int action, def_action, level, mod; + + fprintf(fp, "log: %s\n", SIM->get_param_string("filename", base)->getptr()); + fprintf(fp, "logprefix: %s\n", SIM->get_param_string("prefix", base)->getptr()); + + strcpy(pname, "general.logfn"); + logfn = (bx_list_c*) SIM->get_param(pname); + for (level = 0; level < N_LOGLEV; level++) { + loglev = (bx_list_c*) logfn->get(level); + def_action = SIM->get_default_log_action(level); + fprintf(fp, "%s: action=%s", loglev->get_name(), SIM->get_action_name(def_action)); + // stage #1: save log actions of existing modules + for (mod = 0; mod < SIM->get_n_log_modules(); mod++) { + action = SIM->get_log_action(mod, level); + if (action != def_action) { + fprintf(fp, ", %s=%s", SIM->get_logfn_name(mod), SIM->get_action_name(action)); + } + } + // stage #2: save log actions of not yet existing modules (from bochsrc) + for (mod = 0; mod < loglev->get_size(); mod++) { + mparam = (bx_param_num_c*)loglev->get(mod); + action = mparam->get(); + if ((action >= 0) && (action != def_action)) { + fprintf(fp, ", %s=%s", mparam->get_name(), SIM->get_action_name(action)); + } + } + fprintf(fp, "\n"); + } + return 0; +} + +int bx_write_debugger_options(FILE *fp) +{ +#if BX_DEBUGGER + fprintf(fp, "debugger_log: %s\n", SIM->get_param_string(BXPN_DEBUGGER_LOG_FILENAME)->getptr()); + fprintf(fp, "magic_break: enabled=%d\n", bx_dbg.magic_break_enabled); + // TODO: debug symbols +#endif +#if BX_GDBSTUB + bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_GDBSTUB); + bx_bool enabled = SIM->get_param_bool("enabled", base)->get(); + if (enabled) { + fprintf(fp, "gdbstub: enabled=%d, port=%d, text_base=%d, data_base=%d, bss_base=%d\n", + enabled, SIM->get_param_num("port", base)->get(), SIM->get_param_num("text_base", base)->get(), + SIM->get_param_num("data_base", base)->get(), SIM->get_param_num("bss_base", base)->get()); + } else { + fprintf(fp, "# no gdb stub\n"); + } +#endif + return 0; +} + +// return values: +// 0: written ok +// -1: failed +// -2: already exists, and overwrite was off +int bx_write_configuration(const char *rc, int overwrite) +{ + int i; + char pname[16], tmppath[80], tmpdev[80]; + bx_param_string_c *sparam; + bx_list_c *base; + BX_INFO(("write current configuration to %s", rc)); + // check if it exists. If so, only proceed if overwrite is set. + FILE *fp = fopen(rc, "r"); + if (fp != NULL) { + fclose(fp); + if (!overwrite) return -2; + } + fp = fopen(rc, "w"); + if (fp == NULL) return -1; + // finally it's open and we can start writing. + fprintf(fp, "# configuration file generated by Bochs\n"); + bx_write_param_list(fp, (bx_list_c*) SIM->get_param(BXPN_PLUGIN_CTRL), NULL, 0); +#if BX_PLUGINS + // user plugins + for (i=0; iget_param_string(tmpdev)->getptr()) > 0) { + fprintf(fp, "user_plugin: name=%s\n", + SIM->get_param_string(tmpdev)->getptr()); + } + } +#endif + fprintf(fp, "config_interface: %s\n", SIM->get_param_enum(BXPN_SEL_CONFIG_INTERFACE)->get_selected()); + fprintf(fp, "display_library: %s", SIM->get_param_enum(BXPN_SEL_DISPLAY_LIBRARY)->get_selected()); + sparam = SIM->get_param_string(BXPN_DISPLAYLIB_OPTIONS); + if (!sparam->isempty()) + fprintf(fp, ", options=\"%s\"\n", sparam->getptr()); + else + fprintf(fp, "\n"); + fprintf(fp, "memory: host=%d, guest=%d\n", SIM->get_param_num(BXPN_HOST_MEM_SIZE)->get(), + SIM->get_param_num(BXPN_MEM_SIZE)->get()); + + bx_write_param_list(fp, (bx_list_c*) SIM->get_param(BXPN_ROMIMAGE), "romimage", 0); + bx_write_param_list(fp, (bx_list_c*) SIM->get_param(BXPN_VGA_ROMIMAGE), "vgaromimage", 0); + fprintf(fp, "boot: %s", SIM->get_param_enum(BXPN_BOOTDRIVE1)->get_selected()); + for (i=1; i<3; i++) { + sprintf(tmppath, "boot_params.boot_drive%d", i+1); + if (SIM->get_param_enum(tmppath)->get() != BX_BOOT_NONE) { + fprintf(fp, ", %s", SIM->get_param_enum(tmppath)->get_selected()); + } + } + fprintf(fp, "\n"); + fprintf(fp, "floppy_bootsig_check: disabled=%d\n", SIM->get_param_bool(BXPN_FLOPPYSIGCHECK)->get()); + // it would be nice to put this type of function as methods on + // the structs like bx_floppy_options::print or something. + bx_write_floppy_options(fp, 0); + bx_write_floppy_options(fp, 1); + for (Bit8u channel=0; channelget_param(tmppath); + sprintf(tmppath, "ata%d", channel); + bx_write_param_list(fp, (bx_list_c*) SIM->get_param("resources", base), tmppath, 0); + sprintf(tmppath, "ata%d-master", channel); + bx_write_param_list(fp, (bx_list_c*) SIM->get_param("master", base), tmppath, 0); + sprintf(tmppath, "ata%d-slave", channel); + bx_write_param_list(fp, (bx_list_c*) SIM->get_param("slave", base), tmppath, 0); + } + for (i=0; iget_param(pname), tmppath, 0); + } + for (i=0; iget_param(pname), tmppath, 0); + } + // pci + fprintf(fp, "pci: enabled=%d", + SIM->get_param_bool(BXPN_PCI_ENABLED)->get()); + if (SIM->get_param_bool(BXPN_PCI_ENABLED)->get()) { + fprintf(fp, ", chipset=%s", SIM->get_param_enum(BXPN_PCI_CHIPSET)->get_selected()); + for (i=0; iget_param_string(tmpdev); + if (!sparam->isempty()) { + fprintf(fp, ", slot%d=%s", i+1, sparam->getptr()); + } + } + } + fprintf(fp, "\n"); + fprintf(fp, "vga: extension=%s, update_freq=%u, realtime=%u\n", + SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr(), + SIM->get_param_num(BXPN_VGA_UPDATE_FREQUENCY)->get(), + SIM->get_param_bool(BXPN_VGA_REALTIME)->get()); +#if BX_SUPPORT_SMP + fprintf(fp, "cpu: count=%u:%u:%u, ips=%u, quantum=%d, ", + SIM->get_param_num(BXPN_CPU_NPROCESSORS)->get(), SIM->get_param_num(BXPN_CPU_NCORES)->get(), + SIM->get_param_num(BXPN_CPU_NTHREADS)->get(), SIM->get_param_num(BXPN_IPS)->get(), + SIM->get_param_num(BXPN_SMP_QUANTUM)->get()); +#else + fprintf(fp, "cpu: count=1, ips=%u, ", SIM->get_param_num(BXPN_IPS)->get()); +#endif + fprintf(fp, "model=%s, reset_on_triple_fault=%d, cpuid_limit_winnt=%d", + SIM->get_param_enum(BXPN_CPU_MODEL)->get_selected(), + SIM->get_param_bool(BXPN_RESET_ON_TRIPLE_FAULT)->get(), + SIM->get_param_bool(BXPN_CPUID_LIMIT_WINNT)->get()); +#if BX_CPU_LEVEL >= 5 + fprintf(fp, ", ignore_bad_msrs=%d", SIM->get_param_bool(BXPN_IGNORE_BAD_MSRS)->get()); +#endif +#if BX_SUPPORT_MONITOR_MWAIT + fprintf(fp, ", mwait_is_nop=%d", SIM->get_param_bool(BXPN_MWAIT_IS_NOP)->get()); +#endif +#if BX_CONFIGURE_MSRS + sparam = SIM->get_param_string(BXPN_CONFIGURABLE_MSRS_PATH); + if (!sparam->isempty()) + fprintf(fp, ", msrs=\"%s\"", sparam->getptr()); +#endif + fprintf(fp, "\n"); + +#if BX_CPU_LEVEL >= 4 + if (! SIM->get_param_enum(BXPN_CPU_MODEL)->get()) { + // dump only when using BX_GENERIC CPUDB profile + bx_write_param_list(fp, (bx_list_c*) SIM->get_param("cpuid"), NULL, 1); + } +#endif + + fprintf(fp, "print_timestamps: enabled=%d\n", bx_dbg.print_timestamps); + bx_write_debugger_options(fp); + fprintf(fp, "port_e9_hack: enabled=%d\n", SIM->get_param_bool(BXPN_PORT_E9_HACK)->get()); + fprintf(fp, "private_colormap: enabled=%d\n", SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()); +#if BX_WITH_AMIGAOS + fprintf(fp, "fullscreen: enabled=%d\n", SIM->get_param_bool(BXPN_FULLSCREEN)->get()); + fprintf(fp, "screenmode: name=\"%s\"\n", SIM->get_param_string(BXPN_SCREENMODE)->getptr()); +#endif + bx_write_clock_cmos_options(fp); + bx_write_loader_options(fp); + bx_write_log_options(fp, (bx_list_c*) SIM->get_param("log")); + bx_write_param_list(fp, (bx_list_c*) SIM->get_param(BXPN_KEYBOARD), NULL, 0); + bx_write_param_list(fp, (bx_list_c*) SIM->get_param(BXPN_MOUSE), NULL, 0); + bx_write_param_list(fp, (bx_list_c*) SIM->get_param(BXPN_SOUNDLOW),"sound", 0); + SIM->save_addon_options(fp); + fclose(fp); + return 0; +} diff --git a/ports/bochs/config.h.in b/ports/bochs/config.h.in new file mode 100644 index 0000000..7590138 --- /dev/null +++ b/ports/bochs/config.h.in @@ -0,0 +1,935 @@ +// +// Copyright (C) 2001-2017 The Bochs Project +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// + +// +// config.h.in is distributed in the source TAR file. When you run +// the configure script, it generates config.h with some changes +// according to your build environment. For example, in config.h.in, +// SIZEOF_UNSIGNED_CHAR is set to 0. When configure produces config.h +// it will change "0" to the detected value for your system. +// +// config.h contains ONLY preprocessor #defines and a few typedefs. +// It must be included by both C and C++ files, so it must not +// contain anything language dependent such as a class declaration. +// + +#ifndef _BX_CONFIG_H_ +#define _BX_CONFIG_H_ 1 + +/////////////////////////////////////////////////////////////////// +// USER CONFIGURABLE OPTIONS : EDIT ONLY OPTIONS IN THIS SECTION // +/////////////////////////////////////////////////////////////////// + + +#if 1 +// quit_sim is defined in gui/siminterface.h +#define BX_EXIT(x) SIM->quit_sim (x) +#else +// provide the real main and the usual exit. +#define BX_EXIT(x) ::exit(x) +#endif + +// if simulating Linux, this provides a few more debugging options +// such as tracing all system calls. +#define BX_DEBUG_LINUX 0 + +// adds support for the GNU readline library in the debugger command +// prompt. +#define HAVE_LIBREADLINE 0 +#define HAVE_READLINE_HISTORY_H 0 + +// Define to 1 if you have +#define HAVE_LOCALE_H 0 + +// I rebuilt the code which provides timers to IO devices. +// Setting this to 1 will introduce a little code which +// will panic out if cases which shouldn't happen occur. +// Set this to 0 for optimal performance. +#define BX_TIMER_DEBUG 0 + +// Settable A20 line. For efficiency, you can disable +// having a settable A20 line, eliminating conditional +// code for every physical memory access. You'll have +// to tell your software not to mess with the A20 line, +// and accept it as always being on if you change this. +// 1 = use settable A20 line. (normal) +// 0 = A20 is like the rest of the address lines + +#define BX_SUPPORT_A20 1 + +// Processor Instructions Per Second +// To find out what value to use for the 'ips' directive +// in your '.bochsrc' file, set BX_SHOW_IPS to 1, and +// run the software in bochs you plan to use most. Bochs +// will print out periodic IPS ratings. This will change +// based on the processor mode at the time, and various +// other factors. You'll get a reasonable estimate though. +// When you're done, reset BX_SHOW_IPS to 0, do a +// 'make all-clean', then 'make' again. + +#define BX_SHOW_IPS 0 + + +#if (BX_SHOW_IPS) && (defined(__MINGW32__) || defined(_MSC_VER)) +#define SIGALRM 14 +#endif + +// Compile in support for DMA & FLOPPY IO. You'll need this +// if you plan to use the floppy drive emulation. But if +// you're environment doesn't require it, you can change +// it to 0. + +#define BX_DMA_FLOPPY_IO 1 + +// Default number of Megs of memory to emulate. The +// 'megs:' directive in the '.bochsrc' file overrides this, +// allowing per-run settings. + +#define BX_DEFAULT_MEM_MEGS 32 + +// CPU level emulation. Default level is set in the configure script. +// BX_CPU_LEVEL defines the CPU level to emulate. +#define BX_CPU_LEVEL 0 + +// emulate x86-64 instruction set? +#define BX_SUPPORT_X86_64 0 + +// emulate long physical address (>32 bit) +#define BX_PHY_ADDRESS_LONG 0 + +#define BX_HAVE_SLEEP 0 +#define BX_HAVE_MSLEEP 0 +#define BX_HAVE_USLEEP 0 +#define BX_HAVE_NANOSLEEP 0 +#define BX_HAVE_ABORT 0 +#define BX_HAVE_SOCKLEN_T 0 +#define BX_HAVE_SOCKADDR_IN_SIN_LEN 0 +#define BX_HAVE_GETTIMEOFDAY 0 +#if defined(WIN32) +#define BX_HAVE_REALTIME_USEC 1 +#else +#define BX_HAVE_REALTIME_USEC (BX_HAVE_GETTIMEOFDAY) +#endif +#define BX_HAVE_MKSTEMP 0 +#define BX_HAVE_SYS_MMAN_H 0 +#define BX_HAVE_XPM_H 0 +#define BX_HAVE_TIMELOCAL 0 +#define BX_HAVE_GMTIME 0 +#define BX_HAVE_MKTIME 0 +#define BX_HAVE_TMPFILE64 0 +#define BX_HAVE_FSEEK64 0 +#define BX_HAVE_FSEEKO64 0 +#define BX_HAVE_NET_IF_H 0 +#define BX_HAVE___BUILTIN_BSWAP32 0 +#define BX_HAVE___BUILTIN_BSWAP64 0 +#define BX_HAVE_SSIZE_T 0 + +// This turns on Roland Mainz's idle hack. Presently it is specific to the X11 +// and term gui. If people try to enable it elsewhere, give a compile error +// after the gui definition so that they don't waste their time trying. +#define BX_USE_IDLE_HACK 0 + +// Minimum Emulated IPS. +// This is used in the realtime PIT as well as for checking the +// IPS value set in the config file. +#define BX_MIN_IPS 1000000 + +// Minimum and maximum values for SMP quantum variable. Defines +// how many instructions each CPU could execute in one +// shot (one cpu_loop call) +#define BX_SMP_QUANTUM_MIN 1 +#define BX_SMP_QUANTUM_MAX 32 + +// Use Static Member Funtions to eliminate 'this' pointer passing +// If you want the efficiency of 'C', you can make all the +// members of the C++ CPU class to be static. +// This defaults to 1 since it should improve performance, but when +// SMP mode is enabled, it will be turned off by configure. +#define BX_USE_CPU_SMF 1 + +#define BX_USE_MEM_SMF 1 + +// Use static member functions in IO DEVice emulation modules. +// For efficiency, use C like functions for IO handling, +// and declare a device instance at compile time, +// instead of using 'new' and storing the pointer. This +// eliminates some overhead, especially for high-use IO +// devices like the disk drive. +// 1 = Use static member efficiency (normal) +// 0 = Use nonstatic member functions (use only if you need +// multiple instances of a device class + +#define BX_USE_HD_SMF 1 // Hard drive +#define BX_USE_BIOS_SMF 1 // BIOS +#define BX_USE_CMOS_SMF 1 // CMOS +#define BX_USE_DMA_SMF 1 // DMA +#define BX_USE_FD_SMF 1 // Floppy +#define BX_USE_KEY_SMF 1 // Keyboard +#define BX_USE_PAR_SMF 1 // Parallel +#define BX_USE_PIC_SMF 1 // PIC +#define BX_USE_PIT_SMF 1 // PIT +#define BX_USE_SER_SMF 1 // Serial +#define BX_USE_UM_SMF 1 // Unmapped +#define BX_USE_VGA_SMF 1 // VGA +#define BX_USE_SB16_SMF 1 // SB 16 soundcard +#define BX_USE_ES1370_SMF 1 // ES1370 soundcard +#define BX_USE_DEV_SMF 1 // System Devices (port92) +#define BX_USE_PCI_SMF 1 // PCI +#define BX_USE_P2I_SMF 1 // PCI-to-ISA bridge +#define BX_USE_PIDE_SMF 1 // PCI-IDE +#define BX_USE_PCIDEV_SMF 1 // PCI-DEV +#define BX_USE_USB_UHCI_SMF 1 // USB UHCI hub +#define BX_USE_USB_OHCI_SMF 1 // USB OHCI hub +#define BX_USE_USB_EHCI_SMF 1 // USB EHCI hub +#define BX_USE_USB_XHCI_SMF 1 // USB xHCI hub +#define BX_USE_PCIPNIC_SMF 1 // PCI pseudo NIC +#define BX_USE_E1000_SMF 1 // Intel(R) Gigabit Ethernet +#define BX_USE_NE2K_SMF 1 // NE2K +#define BX_USE_EFI_SMF 1 // External FPU IRQ +#define BX_USE_GAMEPORT_SMF 1 // Gameport +#define BX_USE_CIRRUS_SMF 1 // SVGA Cirrus +#define BX_USE_BUSM_SMF 1 // Bus Mouse +#define BX_USE_ACPI_SMF 1 // ACPI + +#define BX_PLUGINS 0 +#define BX_HAVE_LTDL 0 +#define BX_HAVE_DLFCN_H 0 + +#if BX_PLUGINS && \ + ( !BX_USE_HD_SMF || !BX_USE_BIOS_SMF || !BX_USE_CMOS_SMF \ + || !BX_USE_DMA_SMF || !BX_USE_FD_SMF || !BX_USE_KEY_SMF \ + || !BX_USE_PAR_SMF || !BX_USE_PIC_SMF || !BX_USE_PIT_SMF \ + || !BX_USE_SER_SMF || !BX_USE_UM_SMF || !BX_USE_VGA_SMF \ + || !BX_USE_SB16_SMF || !BX_USE_ES1370_SMF || !BX_USE_DEV_SMF \ + || !BX_USE_PCI_SMF || !BX_USE_P2I_SMF || !BX_USE_USB_UHCI_SMF \ + || !BX_USE_USB_OHCI_SMF || !BX_USE_USB_EHCI_SMF || !BX_USE_USB_XHCI_SMF \ + || !BX_USE_PCIPNIC_SMF || !BX_USE_PIDE_SMF || !BX_USE_ACPI_SMF \ + || !BX_USE_NE2K_SMF || !BX_USE_EFI_SMF || !BX_USE_GAMEPORT_SMF \ + || !BX_USE_E1000_SMF || !BX_USE_PCIDEV_SMF || !BX_USE_CIRRUS_SMF) +#error You must use SMF to have plugins +#endif + +#define USE_RAW_SERIAL 0 + +// This option enables RAM file backing for large guest memory with a smaller +// amount host memory, without causing a panic when host memory is exhausted. +#define BX_LARGE_RAMFILE 0 + +// This option defines the number of supported ATA channels. +// There are up to two drives per ATA channel. +#define BX_MAX_ATA_CHANNEL 4 + +#if (BX_MAX_ATA_CHANNEL>4 || BX_MAX_ATA_CHANNEL<1) + #error "BX_MAX_ATA_CHANNEL should be between 1 and 4" +#endif + +// ================================================================= +// BEGIN: OPTIONAL DEBUGGER SECTION +// +// These options are only used if you compile in support for the +// native command line debugging environment. Typically, the debugger +// is not used, and this section can be ignored. +// ================================================================= + +// Compile in support for virtual/linear/physical breakpoints. +// Enable only those you need. Recommend using only linear +// breakpoints, unless you need others. Less supported means +// slightly faster execution time. +#define BX_DBG_MAX_VIR_BPOINTS 16 +#define BX_DBG_MAX_LIN_BPOINTS 16 +#define BX_DBG_MAX_PHY_BPOINTS 16 + +#define BX_DBG_MAX_WATCHPONTS 16 + +// max file pathname size for debugger commands +#define BX_MAX_PATH 256 +// max nesting level for debug scripts including other scripts +#define BX_INFILE_DEPTH 10 +// use this command to include (nest) debug scripts +#define BX_INCLUDE_CMD "source" + +// Make a call to command line debugger extensions. If set to 1, +// a call is made. An external routine has a chance to process +// the command. If it does, than the debugger ignores the command. +#define BX_DBG_EXTENSIONS 0 + +// ================================================================= +// END: OPTIONAL DEBUGGER SECTION +// ================================================================= + +////////////////////////////////////////////////////////////////////// +// END OF USER CONFIGURABLE OPTIONS : DON'T EDIT ANYTHING BELOW !!! // +// THIS IS GENERATED BY THE ./configure SCRIPT // +////////////////////////////////////////////////////////////////////// + + +#define BX_WITH_X11 0 +#define BX_WITH_WIN32 0 +#define BX_WITH_MACOS 0 +#define BX_WITH_CARBON 0 +#define BX_WITH_NOGUI 0 +#define BX_WITH_ESSENCE 0 +#define BX_WITH_TERM 0 +#define BX_WITH_RFB 0 +#define BX_WITH_VNCSRV 0 +#define BX_WITH_AMIGAOS 0 +#define BX_WITH_SDL 0 +#define BX_WITH_SDL2 0 +#define BX_WITH_SVGA 0 +#define BX_WITH_WX 0 + +// BX_USE_TEXTCONFIG should be set to 1 unless Bochs is compiled +// for wxWidgets only. +#define BX_USE_TEXTCONFIG 1 + +// BX_USE_GUI should be set to 1 for all guis with VGA console support +// for 'textconfig'. +#define BX_USE_GUI_CONSOLE 0 + +// BX_USE_WIN32CONFIG should be set to 1 on WIN32 for the guis +// "win32", "sdl" and "sdl2" only. +#if BX_USE_TEXTCONFIG && defined(WIN32) && (BX_WITH_WIN32 || BX_WITH_SDL || BX_WITH_SDL2) + #define BX_USE_WIN32CONFIG 1 +#else + #define BX_USE_WIN32CONFIG 0 +#endif + +// A certain functions must NOT be fastcall even if compiled with fastcall +// option, and those are callbacks from Windows which are defined either +// as cdecl or stdcall. The entry point main() also has to remain cdecl. +#ifndef CDECL +#if defined(_MSC_VER) + #define CDECL __cdecl +#else + #define CDECL +#endif +#endif + +// add special export symbols for win32 DLL building. The main code must +// have __declspec(dllexport) on variables, functions, or classes that the +// plugins can access. The plugins should #define PLUGGABLE which will +// activate the __declspec(dllimport) instead. +#if (defined(WIN32) || defined(__CYGWIN__)) && !defined(BXIMAGE) +# if BX_PLUGINS && defined(BX_PLUGGABLE) +// #warning I will import DLL symbols from Bochs main program. +# define BOCHSAPI __declspec(dllimport) +# elif BX_PLUGINS +// #warning I will export DLL symbols. +# define BOCHSAPI __declspec(dllexport) +# endif +#endif +#ifndef BOCHSAPI +# define BOCHSAPI +#endif + +#if defined(__CYGWIN__) +// Make BOCHSAPI_CYGONLY exactly the same as BOCHSAPI. This symbol +// will be used for any cases where Cygwin requires a special tag +// but VC++ does not. +#define BOCHSAPI_CYGONLY BOCHSAPI +#else +// define the symbol to be empty +#define BOCHSAPI_CYGONLY /*empty*/ +#endif + +#if defined(_MSC_VER) +// Make BOCHSAPI_MSVCONLY exactly the same as BOCHSAPI. This symbol +// will be used for any cases where VC++ requires a special tag +// but Cygwin does not. +#define BOCHSAPI_MSVCONLY BOCHSAPI +#else +// define the symbol to be empty +#define BOCHSAPI_MSVCONLY /*empty*/ +#endif + +#define BX_DEFAULT_CONFIG_INTERFACE "defined_by_configure" +#define BX_DEFAULT_DISPLAY_LIBRARY "defined_by_configure" + +// Roland Mainz's idle hack is presently specific to X11. If people try to +// enable it elsewhere, give a compile error so that they don't waste their +// time trying. +#if (BX_USE_IDLE_HACK && !BX_WITH_X11 && !BX_WITH_TERM) +# error IDLE_HACK will only work with the X11 or term gui. Correct configure args and retry. +#endif + +#define WORDS_BIGENDIAN 0 + +#define SIZEOF_UNSIGNED_CHAR 0 +#define SIZEOF_UNSIGNED_SHORT 0 +#define SIZEOF_UNSIGNED_INT 0 +#define SIZEOF_UNSIGNED_LONG 0 +#define SIZEOF_UNSIGNED_LONG_LONG 0 +#define SIZEOF_INT_P 0 + +#define BX_64BIT_CONSTANTS_USE_LL 1 +#if BX_64BIT_CONSTANTS_USE_LL +// doesn't work on Microsoft Visual C++, maybe others +#define BX_CONST64(x) (x##LL) +#elif defined(_MSC_VER) +#define BX_CONST64(x) (x##I64) +#else +#define BX_CONST64(x) (x) +#endif + +#if defined(WIN32) + typedef unsigned char Bit8u; + typedef signed char Bit8s; + typedef unsigned short Bit16u; + typedef signed short Bit16s; + typedef unsigned int Bit32u; + typedef signed int Bit32s; +#ifdef __GNUC__ + typedef unsigned long long Bit64u; + typedef signed long long Bit64s; +#include +#include +#else + typedef unsigned __int64 Bit64u; + typedef signed __int64 Bit64s; +#endif +#elif BX_WITH_MACOS + typedef unsigned char Bit8u; + typedef signed char Bit8s; + typedef unsigned short Bit16u; + typedef signed short Bit16s; + typedef unsigned int Bit32u; + typedef signed int Bit32s; + typedef unsigned long long Bit64u; + typedef signed long long Bit64s; +#else + +// Unix like platforms + +#if SIZEOF_UNSIGNED_CHAR != 1 +# error "sizeof (unsigned char) != 1" +#else + typedef unsigned char Bit8u; + typedef signed char Bit8s; +#endif + +#if SIZEOF_UNSIGNED_SHORT != 2 +# error "sizeof (unsigned short) != 2" +#else + typedef unsigned short Bit16u; + typedef signed short Bit16s; +#endif + +#if SIZEOF_UNSIGNED_INT == 4 + typedef unsigned int Bit32u; + typedef signed int Bit32s; +#elif SIZEOF_UNSIGNED_LONG == 4 + typedef unsigned long Bit32u; + typedef signed long Bit32s; +#else +# error "can't find sizeof(type) of 4 bytes!" +#endif + +#if SIZEOF_UNSIGNED_LONG == 8 + typedef unsigned long Bit64u; + typedef signed long Bit64s; +#elif SIZEOF_UNSIGNED_LONG_LONG == 8 + typedef unsigned long long Bit64u; + typedef signed long long Bit64s; +#else +# error "can't find data type of 8 bytes" +#endif + +#endif + +#define GET32L(val64) ((Bit32u)(((Bit64u)(val64)) & 0xFFFFFFFF)) +#define GET32H(val64) ((Bit32u)(((Bit64u)(val64)) >> 32)) + +// now that Bit32u and Bit64u exist, defined bx_address +#if BX_SUPPORT_X86_64 +typedef Bit64u bx_address; +#else +typedef Bit32u bx_address; +#endif + +// define physical and linear address types +typedef bx_address bx_lin_address; + +#if BX_SUPPORT_X86_64 +#define BX_LIN_ADDRESS_WIDTH 48 +#else +#define BX_LIN_ADDRESS_WIDTH 32 +#endif + +#if BX_PHY_ADDRESS_LONG +typedef Bit64u bx_phy_address; +#if BX_CPU_LEVEL == 5 + #define BX_PHY_ADDRESS_WIDTH 36 +#else + #define BX_PHY_ADDRESS_WIDTH 40 +#endif +#else +typedef Bit32u bx_phy_address; +#define BX_PHY_ADDRESS_WIDTH 32 +#endif + +// small sanity check +#if BX_PHY_ADDRESS_LONG + #if (BX_PHY_ADDRESS_WIDTH <= 32) + #error "BX_PHY_ADDRESS_LONG implies emulated physical address width > 32 bit" + #endif +#endif + +#define BX_PHY_ADDRESS_MASK ((((Bit64u)(1)) << BX_PHY_ADDRESS_WIDTH) - 1) + +#define BX_PHY_ADDRESS_RESERVED_BITS (~BX_PHY_ADDRESS_MASK) + +// technically, in an 8 bit signed the real minimum is -128, not -127. +// But if you decide to negate -128 you tend to get -128 again, so it's +// better not to use the absolute maximum in the signed range. +#define BX_MAX_BIT64U ( (Bit64u) -1 ) +#define BX_MIN_BIT64U ( 0 ) +#define BX_MAX_BIT64S ( ((Bit64u) -1) >> 1 ) +#define BX_MIN_BIT64S ( (Bit64s)-(((Bit64u) -1) >> 1) - 1) +#define BX_MAX_BIT32U ( (Bit32u) -1 ) +#define BX_MIN_BIT32U ( 0 ) +#define BX_MAX_BIT32S ( ((Bit32u) -1) >> 1 ) +#define BX_MIN_BIT32S ( (Bit32s)-(((Bit32u) -1) >> 1) - 1) +#define BX_MAX_BIT16U ( (Bit16u) -1 ) +#define BX_MIN_BIT16U ( 0 ) +#define BX_MAX_BIT16S ( ((Bit16u) -1) >> 1 ) +#define BX_MIN_BIT16S ( (Bit16s)-(((Bit16u) -1) >> 1) - 1) +#define BX_MAX_BIT8U ( (Bit8u) -1 ) +#define BX_MIN_BIT8U ( 0 ) +#define BX_MAX_BIT8S ( ((Bit8u) -1) >> 1 ) +#define BX_MIN_BIT8S ( (Bit8s)-(((Bit8u) -1) >> 1) - 1) + + +// create an unsigned integer type that is the same size as a pointer. +// You can typecast a pointer to a bx_pr_equiv_t without losing any +// bits (and without getting the compiler excited). +#if SIZEOF_INT_P == 4 + typedef Bit32u bx_ptr_equiv_t; +#elif SIZEOF_INT_P == 8 + typedef Bit64u bx_ptr_equiv_t; +#else +# error "could not define bx_ptr_equiv_t to size of int*" +#endif + +// Use a boolean type that will not conflict with the builtin type +// on any system. +typedef Bit32u bx_bool; + +#define BX_TRUE (1) +#define BX_FALSE (0) + +#if BX_WITH_MACOS +# define bx_ptr_t char * +#else +# define bx_ptr_t void * +#endif + +#if defined(WIN32) +# define BX_LITTLE_ENDIAN +#elif BX_WITH_MACOS +# define BX_BIG_ENDIAN +#else +#if WORDS_BIGENDIAN +# define BX_BIG_ENDIAN +#else +# define BX_LITTLE_ENDIAN +#endif +#endif // defined(WIN32) + + +#if BX_SUPPORT_X86_64 +#ifdef BX_LITTLE_ENDIAN +typedef + struct { + Bit64u lo; + Bit64u hi; + } Bit128u; +typedef + struct { + Bit64u lo; + Bit64s hi; + } Bit128s; +#else // must be Big Endian +typedef + struct { + Bit64u hi; + Bit64u lo; + } Bit128u; +typedef + struct { + Bit64s hi; + Bit64u lo; + } Bit128s; +#endif +#endif // #if BX_SUPPORT_X86_64 + + +// for now only term.cc requires a GUI sighandler. +#define BX_GUI_SIGHANDLER (BX_WITH_TERM) + +#define HAVE_SIGACTION 1 + +// Use BX_CPP_INLINE for all C++ inline functions. +#define BX_CPP_INLINE inline + +#ifdef __GNUC__ + +// Some helpful compiler hints for compilers that allow them; GCC for now. +// +// BX_CPP_AlignN(n): +// Align a construct on an n-byte boundary. +// +// BX_CPP_AttrPrintf(formatArg, firstArg): +// This function takes printf-like arguments, so the compiler can check +// the consistency of the format string and the matching arguments. +// 'formatArg' is the parameter number (starting from 1) of the format +// string argument. 'firstArg' is the parameter number of the 1st argument +// to check against the string argument. NOTE: For non-static member +// functions, the this-ptr is argument number 1 but is invisible on +// the function prototype declaration - but you still have to count it. +// +// BX_CPP_AttrNoReturn(): +// This function never returns. The compiler can optimize-out following +// code accordingly. + +#define BX_CPP_AlignN(n) __attribute__ ((aligned (n))) +#define BX_CPP_AttrPrintf(formatArg, firstArg) \ + __attribute__ ((format (printf, formatArg, firstArg))) +#define BX_CPP_AttrNoReturn() __attribute__ ((noreturn)) + +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif + +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#else + +#define BX_CPP_AlignN(n) /* Not supported. */ +#define BX_CPP_AttrPrintf(formatArg, firstArg) /* Not supported. */ +#define BX_CPP_AttrNoReturn() /* Not supported. */ + +#ifndef likely +#define likely(x) (x) +#endif + +#ifndef unlikely +#define unlikely(x) (x) +#endif + +#endif + +#define BX_GDBSTUB 0 +#define BX_DEBUGGER 0 +#define BX_DISASM 0 +#define BX_DEBUGGER_GUI 0 + +#if (BX_DEBUGGER == 1) && (BX_DISASM == 0) + #error Dissembler is required for BX_DEBUGGER ! +#endif + +#define BX_INSTRUMENTATION 0 + +// enable BX_DEBUG/BX_ERROR/BX_INFO messages +#define BX_NO_LOGGING 0 + +// enable BX_ASSERT checks +#define BX_ASSERT_ENABLE 0 + +// enable statistics collection +#define BX_ENABLE_STATISTICS 0 + +#define BX_SUPPORT_ALIGNMENT_CHECK 0 +#define BX_SUPPORT_FPU 0 +#define BX_SUPPORT_3DNOW 0 +#define BX_SUPPORT_PKEYS 0 +#define BX_SUPPORT_MONITOR_MWAIT 0 +#define BX_SUPPORT_PERFMON 0 +#define BX_SUPPORT_MEMTYPE 0 +#define BX_SUPPORT_SVM 0 +#define BX_SUPPORT_VMX 0 +#define BX_SUPPORT_AVX 0 +#define BX_SUPPORT_EVEX 0 + +#if BX_SUPPORT_SVM && BX_SUPPORT_X86_64 == 0 + #error "SVM require x86-64 support" +#endif + +#if BX_SUPPORT_VMX >= 2 && BX_SUPPORT_X86_64 == 0 + #error "VMX=2 require x86-64 support" +#endif + +#if BX_SUPPORT_AVX && BX_SUPPORT_X86_64 == 0 + #error "AVX require x86-64 support" +#endif + +#if BX_SUPPORT_EVEX && BX_SUPPORT_AVX == 0 + #error "EVEX and AVX-512 support require AVX to be compiled in" +#endif + +#define BX_SUPPORT_REPEAT_SPEEDUPS 0 +#define BX_SUPPORT_HANDLERS_CHAINING_SPEEDUPS 0 +#define BX_ENABLE_TRACE_LINKING 0 + +#if (BX_DEBUGGER || BX_GDBSTUB) && BX_SUPPORT_HANDLERS_CHAINING_SPEEDUPS + #error "Handler-chaining-speedups are not supported together with internal debugger or gdb-stub!" +#endif + +#if BX_SUPPORT_3DNOW + #define BX_CPU_VENDOR_INTEL 0 +#else + #define BX_CPU_VENDOR_INTEL 1 +#endif + +// Maximum CPUID vendor and brand string lengths +#define BX_CPUID_VENDOR_LEN 12 +#define BX_CPUID_BRAND_LEN 48 + +#define BX_CONFIGURE_MSRS 0 + +#if (BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL < 4) + #error Alignment exception check is not supported in i386 ! +#endif + +#if (BX_CONFIGURE_MSRS && BX_CPU_LEVEL < 5) + #error MSRs are supported only with CPU level >= 5 ! +#endif + +#if (!BX_SUPPORT_FPU && BX_CPU_LEVEL > 4) + #error With CPU level > 4, you must enable FPU support ! +#endif + +#if (BX_SUPPORT_FPU && BX_CPU_LEVEL < 3) + #error "FPU cannot be compiled without cpu level >= 3 !" +#endif + +#if (BX_CPU_LEVEL<6 && BX_SUPPORT_VMX) + #error "VMX only supported with CPU_LEVEL >= 6 !" +#endif + +#if BX_SUPPORT_X86_64 +// Sanity checks to ensure that you cannot accidently use conflicting options. + +#if BX_CPU_LEVEL < 6 + #error "X86-64 requires cpu level 6 or greater !" +#endif +#endif + +// We have tested the following combinations: +// * processors=1, bootstrap=0, ioapic_id=1 (uniprocessor system) +// * processors=2, bootstrap=0, ioapic_id=2 +// * processors=4, bootstrap=0, ioapic_id=4 +// * processors=8, bootstrap=0, ioapic_id=8 +#define BX_SUPPORT_SMP 0 +#define BX_BOOTSTRAP_PROCESSOR 0 + +// For P6 and Pentium family processors the local APIC ID feild is 4 bits +// APIC_MAX_ID indicate broadcast so it can't be used as valid APIC ID +#define BX_MAX_SMP_THREADS_SUPPORTED 0xfe /* leave APIC ID for I/O APIC */ + +// include in APIC models, required for a multiprocessor system. +#if BX_SUPPORT_SMP || BX_CPU_LEVEL >= 5 + #define BX_SUPPORT_APIC 1 +#else + #define BX_SUPPORT_APIC 0 +#endif + +#define BX_HAVE_GETENV 0 +#define BX_HAVE_SETENV 0 +#define BX_HAVE_SELECT 0 +#define BX_HAVE_SNPRINTF 0 +#define BX_HAVE_VSNPRINTF 0 +#define BX_HAVE_STRTOULL 0 +#define BX_HAVE_STRTOUQ 0 +#define BX_HAVE_STRDUP 0 +#define BX_HAVE_STRREV 0 +#define BX_HAVE_STRICMP 0 +#define BX_HAVE_STRCASECMP 0 + +// used in term gui +#define BX_HAVE_COLOR_SET 0 +#define BX_HAVE_MVHLINE 0 +#define BX_HAVE_MVVLINE 0 + + +// set if your compiler does not understand __attribute__ after a struct +#define BX_NO_ATTRIBUTES 0 +#if BX_NO_ATTRIBUTES +#define GCC_ATTRIBUTE(x) /* attribute not supported */ +#else +#define GCC_ATTRIBUTE __attribute__ +#endif + +// set to use fast function calls +#define BX_FAST_FUNC_CALL 0 + +// On gcc2.95+ x86 only +#if BX_FAST_FUNC_CALL && defined(__i386__) && defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)) +#if BX_USE_CPU_SMF == 1 +# define BX_CPP_AttrRegparmN(X) __attribute__((regparm(X))) +#else +// FIXME: BX_FAST_FUNC_CALL doesn't work with BX_USE_CPU_SMF = 0 +# define BX_CPP_AttrRegparmN(X) /* Not defined */ +#endif +#else +# define BX_CPP_AttrRegparmN(X) /* Not defined */ +#endif + +// set if you do have , used in bx_debug/dbg_main.c +#define BX_HAVE_SET 0 + +// set if you do have , used in bx_debug/dbg_main.c +#define BX_HAVE_SET_H 0 + +// set if you do have , used in bx_debug/dbg_main.c +#define BX_HAVE_MAP 0 + +// set if you do have , used in bx_debug/dbg_main.c +#define BX_HAVE_MAP_H 0 + +// Support x86 hardware debugger registers and facilities. +// These are the debug facilities offered by the x86 architecture, +// not the optional built-in debugger. +#define BX_X86_DEBUGGER 0 + +// limited i440FX PCI support +#define BX_SUPPORT_PCI 0 + +// Experimental host PCI device mapping +#define BX_SUPPORT_PCIDEV 0 + +#if (BX_SUPPORT_PCIDEV && !BX_SUPPORT_PCI) + #error To enable PCI host device mapping, you must also enable PCI +#endif + +// CLGD54XX emulation +#define BX_SUPPORT_CLGD54XX 0 + +// Experimental 3dfx Voodoo (SST-1/2) emulation +#define BX_SUPPORT_VOODOO 0 + +// USB host controllers +#define BX_SUPPORT_USB_UHCI 0 +#define BX_SUPPORT_USB_OHCI 0 +#define BX_SUPPORT_USB_EHCI 0 +#define BX_SUPPORT_USB_XHCI 0 +#define BX_SUPPORT_PCIUSB \ + (BX_SUPPORT_USB_UHCI || BX_SUPPORT_USB_OHCI || BX_SUPPORT_USB_EHCI || BX_SUPPORT_USB_XHCI) + +#if (BX_SUPPORT_PCIUSB && !BX_SUPPORT_PCI) + #error To enable USB, you must also enable PCI +#endif + +#if (BX_SUPPORT_USB_EHCI && !BX_SUPPORT_USB_UHCI) + #error To enable EHCI, you must also enable UHCI +#endif + +// MS bus mouse support +#define BX_SUPPORT_BUSMOUSE 0 + +#define BX_SUPPORT_CDROM 0 + +#if BX_SUPPORT_CDROM + // This is the C++ class name to use if we are supporting + // low-level CDROM. +# define LOWLEVEL_CDROM cdrom_base_c +#endif + +// NE2K network emulation +#define BX_SUPPORT_NE2K 0 + +// Pseudo PCI NIC +#define BX_SUPPORT_PCIPNIC 0 + +#if (BX_SUPPORT_PCIPNIC && !BX_SUPPORT_PCI) + #error To enable the PCI pseudo NIC, you must also enable PCI +#endif + +// Intel(R) Gigabit Ethernet +#define BX_SUPPORT_E1000 0 + +#if (BX_SUPPORT_E1000 && !BX_SUPPORT_PCI) + #error To enable the E1000 NIC, you must also enable PCI +#endif + +// this enables the lowlevel stuff below if one of the NICs is present +#define BX_NETWORKING 0 + +// which networking modules will be enabled +// determined by configure script +#define BX_NETMOD_FBSD 0 +#define BX_NETMOD_LINUX 0 +#define BX_NETMOD_WIN32 0 +#define BX_NETMOD_TAP 0 +#define BX_NETMOD_TUNTAP 0 +#define BX_NETMOD_VDE 0 +#define BX_NETMOD_SLIRP 0 +#define BX_NETMOD_SOCKET 0 + +// Soundcard and gameport support +#define BX_SUPPORT_SB16 0 +#define BX_SUPPORT_ES1370 0 +#define BX_SUPPORT_GAMEPORT 0 +#define BX_SUPPORT_SOUNDLOW 0 + +// which sound lowlevel modules will be enabled +#define BX_HAVE_SOUND_ALSA 0 +#define BX_HAVE_SOUND_OSS 0 +#define BX_HAVE_SOUND_OSX 0 +#define BX_HAVE_SOUND_SDL 0 +#define BX_HAVE_SOUND_WIN 0 + +#if BX_SUPPORT_SOUNDLOW +// Determines which sound lowlevel driver is to be used as the default. +// Currently the following are available: +// alsa Output for Linux with ALSA PCM and sequencer interface +// oss Output for Linux, to /dev/dsp and /dev/midi00 +// osx Output for MacOSX midi and wave device +// sdl Wave output with SDL/SDL2 +// win Output for Windows midi and wave mappers +// file Wave and midi output to file +// dummy Dummy functions, no output +#define BX_SOUND_LOWLEVEL_NAME "dummy" +// resampling support +#define BX_HAVE_LIBSAMPLERATE 0 +#define BX_HAVE_SOXR_LSR 0 +// SDL2 audio capture support (version >= 2.0.5) +#define BX_HAVE_SDL2_AUDIO_CAPTURE 0 +#endif + +#if (BX_SUPPORT_ES1370 && !BX_SUPPORT_PCI) + #error To enable the ES1370 soundcard, you must also enable PCI +#endif + +// I/O Interface to debugger +#define BX_SUPPORT_IODEBUG 0 + +#ifdef WIN32 +#define BX_FLOPPY0_NAME "Floppy Disk A:" +#define BX_FLOPPY1_NAME "Floppy Disk B:" +#else +#define BX_FLOPPY0_NAME "Floppy Disk 0" +#define BX_FLOPPY1_NAME "Floppy Disk 1" +#endif + +#if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ == 0) +#error "gcc 4.0.0 is known to produce incorrect code which breaks Bochs emulation" +#endif + +#endif // _BX_CONFIG_H diff --git a/ports/bochs/configure.in b/ports/bochs/configure.in new file mode 100644 index 0000000..3f1c6c8 --- /dev/null +++ b/ports/bochs/configure.in @@ -0,0 +1,3273 @@ +dnl // Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.50) +AC_INIT(bochs.h) +AC_REVISION([[$Id: configure.in 13179 2017-04-09 06:45:39Z vruppert $]]) +AC_CONFIG_HEADER(config.h) +AC_CONFIG_HEADER(ltdlconf.h) + +dnl // Put Bochs version information right here so that it gets substituted +dnl // into all the right places. +VERSION="2.6.9" +VER_STRING="2.6.9" +dnl // WIN_VER_STRING format is "a, b, c, d" +dnl // c should be > 90 for pre-release of next version otherwise patch level +dnl // d should be 0 for release and 1 for svn version +WIN_VER_STRING="2, 6, 9, 0" +REL_STRING="Built from SVN snapshot on April 9, 2017" + +changequote(<<, >>) +changequote([, ]) + +dnl Detect host and target +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + +AC_MSG_CHECKING(if you are configuring for another platform) +if test "$cross_compiling" = yes -o "$target_os" = "windows"; then + AC_MSG_RESULT(yes) + cross_configure=1 +else + AC_MSG_RESULT(no) + cross_configure=0 +fi + +# this case statement defines the compile flags which are needed to +# compile bochs on a platform. Don't put things like optimization settings +# into the configure.in file, since people will want to be able to change +# those settings by defining CFLAGS and CXXFLAGS before running configure. +NO_LT=0 +MSVC_TARGET=0 +need_dlcompat_for_plugins=0 +case "$target" in + *-pc-windows* | *-pc-winnt*) + DEFAULT_GUI=win32 # default to win32 gui + NO_LT=1 # do not use libtool at all + case "$target" in + x86_64*) + MSVC_TARGET=64 + ;; + *) + MSVC_TARGET=32 + ;; + esac + ;; + *-cygwin* | *-mingw32*) + NO_LT=1 # do not use libtool at all + if test "$with_term" = yes; then + # ncurses won't compile with -DWIN32 + # also, I can't get it to link without this -DBROKEN_LINKER=1 hack. + # see /usr/include/curses.h for details. + ADD_FLAGS="-DBROKEN_LINKER=1" + else + # default case + ADD_FLAGS="-DWIN32" # required for cygwin/mingw compile+win32 gui + DEFAULT_GUI=win32 # default to win32 gui + fi + ;; + *-macosx* | *-darwin*) + ADD_FLAGS="-fpascal-strings -fno-common -Wno-four-char-constants -Wno-unknown-pragmas -Dmacintosh" # required for macosx compile + DEFAULT_GUI=carbon # default to carbon + need_dlcompat_for_plugins=1 + ;; + *-macos*) + DEFAULT_GUI=macos # macos defaults to macos + ;; + *-amigaos* | *-morphos*) + DEFAULT_GUI=amigaos # amigaos or morphos defaults to amigaos gui + ;; + *-solaris*) + ADD_FLAGS="-D_XOPEN_SOURCE_EXTENDED=1 -D__EXTENSIONS__" # required for correct function prototypes + LIBS="$LIBS -lsocket -lnsl" + DEFAULT_GUI=x11 + ;; + *) + DEFAULT_GUI=x11 + ;; +esac +if test "${ADD_FLAGS:+set}" = set; then + CFLAGS="$CFLAGS $ADD_FLAGS" + CXXFLAGS="$CXXFLAGS $ADD_FLAGS" + CPPFLAGS="$CPPFLAGS $ADD_FLAGS" +fi + +AC_MSG_CHECKING(for standard CFLAGS on this platform) +AC_MSG_RESULT($ADD_FLAGS) + +dnl // make sure the default gui is enabled if no other chosen +if (test "$with_sdl" != yes) && \ + (test "$with_sdl2" != yes) && \ + (test "$with_svga" != yes) && \ + (test "$with_x11" != yes) && \ + (test "$with_win32" != yes) && \ + (test "$with_nogui" != yes) && \ + (test "$with_essence" != yes) && \ + (test "$with_term" != yes) && \ + (test "$with_rfb" != yes) && \ + (test "$with_vncsrv" != yes) && \ + (test "$with_amigaos" != yes) && \ + (test "$with_carbon" != yes) && \ + (test "$with_wx" != yes) && \ + (test "$with_macos" != yes); then + # use DEFAULT_GUI. Set the appropriate variable. + # DEFAULT_GUI must be set to one of the names above. Otherwise, no + # valid $with_* variable will be set and who knows what will happen? + eval "with_${DEFAULT_GUI}=yes" +fi + +AC_PROG_CC +AC_PROG_CXX +AC_PROG_MAKE_SET + +if test "$NO_LT" != 1; then + dnl------------ libtool configuration + dnl Configure libtool, and default to shared libraries. Libtool will only be + dnl used for compiling and linking plugins. + AC_DISABLE_STATIC + dnl Check for dlopen support + AC_LIBTOOL_DLOPEN + dnl Configure libtool + AC_PROG_LIBTOOL + dnl Configure the ltdl library. This must go after AC_PROG_LIBTOOL or + dnl else it disables shared libraries somehow. + AC_LIB_LTDL +else + RANLIB="echo" +fi + +AC_PATH_PROG(PKGCONFIG, pkg-config, not_found) +if test "$PKGCONFIG" = not_found; then + AC_PATH_XTRA +fi + +AC_C_BIGENDIAN +AC_CHECK_SIZEOF(unsigned char) +AC_CHECK_SIZEOF(unsigned short) +AC_CHECK_SIZEOF(unsigned int) +AC_CHECK_SIZEOF(unsigned long) +AC_CHECK_SIZEOF(unsigned long long) +if test "$MSVC_TARGET" = 0; then + AC_CHECK_SIZEOF(int *) +fi +AC_CHECK_FUNCS(getenv, AC_DEFINE(BX_HAVE_GETENV)) +AC_CHECK_FUNCS(setenv, AC_DEFINE(BX_HAVE_SETENV)) +AC_CHECK_FUNCS(snprintf, AC_DEFINE(BX_HAVE_SNPRINTF)) +AC_CHECK_FUNCS(vsnprintf, AC_DEFINE(BX_HAVE_VSNPRINTF)) + +if test "$MSVC_TARGET" = 0; then + AC_CHECK_FUNCS(select, AC_DEFINE(BX_HAVE_SELECT)) + AC_CHECK_TYPE(socklen_t, AC_DEFINE(BX_HAVE_SOCKLEN_T), , [#include + #include ]) + AC_CHECK_FUNCS(strtoull, AC_DEFINE(BX_HAVE_STRTOULL)) + AC_CHECK_FUNCS(strtouq, AC_DEFINE(BX_HAVE_STRTOUQ)) + AC_CHECK_FUNCS(strdup, AC_DEFINE(BX_HAVE_STRDUP)) + AC_CHECK_FUNCS(strrev, AC_DEFINE(BX_HAVE_STRREV)) + AC_CHECK_FUNCS(stricmp, AC_DEFINE(BX_HAVE_STRICMP)) + AC_CHECK_FUNCS(strcasecmp, AC_DEFINE(BX_HAVE_STRCASECMP)) + AC_CHECK_FUNCS(mkstemp, AC_DEFINE(BX_HAVE_MKSTEMP)) + AC_CHECK_HEADER(sys/mman.h, AC_DEFINE(BX_HAVE_SYS_MMAN_H)) + AC_CHECK_FUNCS(gettimeofday, AC_DEFINE(BX_HAVE_GETTIMEOFDAY)) + AC_CHECK_FUNCS(usleep, AC_DEFINE(BX_HAVE_USLEEP)) + + AC_MSG_CHECKING(for __builtin_bswap32) + AC_TRY_LINK([],[ + __builtin_bswap32(0x12345678); + ],[ + AC_DEFINE(BX_HAVE___BUILTIN_BSWAP32, 1, [Define to 1 if you have the '__builtin_bswap32' function.]) + AC_MSG_RESULT(yes) + ],[ + AC_MSG_RESULT(no) + ]) + AC_MSG_CHECKING(for __builtin_bswap64) + AC_TRY_LINK([],[ + __builtin_bswap64(0x12345678); + ],[ + AC_DEFINE(BX_HAVE___BUILTIN_BSWAP64, 1, [Define to 1 if you have the '__builtin_bswap64' function.]) + AC_MSG_RESULT(yes) + ],[ + AC_MSG_RESULT(no) + ]) + AC_CHECK_FUNCS(tmpfile64, AC_DEFINE(BX_HAVE_TMPFILE64)) + AC_CHECK_FUNCS(fseek64, AC_DEFINE(BX_HAVE_FSEEK64)) + AC_CHECK_FUNCS(fseeko64, AC_DEFINE(BX_HAVE_FSEEKO64)) + AC_CHECK_TYPE(ssize_t, AC_DEFINE(BX_HAVE_SSIZE_T), , [#include ]) +else + AC_DEFINE(BX_HAVE_SELECT, 1) + AC_DEFINE(BX_HAVE_SOCKLEN_T, 0) + AC_DEFINE(BX_HAVE_STRTOULL, 1) + AC_DEFINE(BX_HAVE_STRTOUQ, 0) + AC_DEFINE(BX_HAVE_STRDUP, 1) + AC_DEFINE(BX_HAVE_STRREV, 1) + AC_DEFINE(BX_HAVE_STRICMP, 1) + AC_DEFINE(BX_HAVE_STRCASECMP, 0) + AC_DEFINE(BX_HAVE_MKSTEMP, 0) + AC_DEFINE(BX_HAVE_SYS_MMAN_H, 0) + AC_DEFINE(BX_HAVE_GETTIMEOFDAY, 0) + AC_DEFINE(BX_HAVE_USLEEP, 0) + AC_DEFINE(BX_HAVE___BUILTIN_BSWAP32, 0) + AC_DEFINE(BX_HAVE___BUILTIN_BSWAP64, 0) + AC_DEFINE(BX_HAVE_TMPFILE64, 0) + AC_DEFINE(BX_HAVE_FSEEK64, 0) + AC_DEFINE(BX_HAVE_FSEEKO64, 0) + AC_DEFINE(BX_HAVE_SSIZE_T, 0) + AC_DEFINE(BX_HAVE_SETENV, 0) + if test "$MSVC_TARGET" = 64; then + AC_DEFINE(SIZEOF_INT_P, 8) + else + AC_DEFINE(SIZEOF_INT_P, 4) + fi +fi +AC_CHECK_FUNCS(sleep, AC_DEFINE(BX_HAVE_SLEEP)) +AC_CHECK_FUNCS(nanosleep, AC_DEFINE(BX_HAVE_NANOSLEEP)) +AC_CHECK_FUNCS(abort, AC_DEFINE(BX_HAVE_ABORT)) +AC_CHECK_MEMBER(struct sockaddr_in.sin_len, AC_DEFINE(BX_HAVE_SOCKADDR_IN_SIN_LEN), , [#include +#include ]) +AC_CHECK_FUNCS(timelocal, AC_DEFINE(BX_HAVE_TIMELOCAL)) +AC_CHECK_FUNCS(gmtime, AC_DEFINE(BX_HAVE_GMTIME)) +AC_CHECK_FUNCS(mktime, AC_DEFINE(BX_HAVE_MKTIME)) + +dnl As of autoconf 2.53, the standard largefile test fails for Linux/gcc. +dnl It does not put the largefiles arguments into CFLAGS, even though Linux/gcc +dnl does need them. So we do it ourselves. +AC_SYS_LARGEFILE + +dnl we need to define _FILE_OFFSET_BITS or _LARGE_FILES on the compiler command +dnl line because otherwise the system headers risk being included before +dnl config.h which defines these constants leading to inconsistent +dnl sizeof(off_t) in different source files of the same program and linking +dnl problems +case "x$ac_cv_sys_file_offset_bits" in #( + xno | xunknown) ;; + *) + if test "x$ac_cv_sys_file_offset_bits" = "x64"; then + BX_LARGEFILE_FLAGS="-D_FILE_OFFSET_BITS=64 -D_LARGE_FILES" + else + BX_LARGEFILE_FLAGS="-D_LARGE_FILES" + fi + CPPFLAGS="$CPPFLAGS $BX_LARGEFILE_FLAGS" + CFLAGS="$CFLAGS $BX_LARGEFILE_FLAGS" + CXXFLAGS="$CXXFLAGS $BX_LARGEFILE_FLAGS" + ;; +esac +dnl ---end of largefile tests + +AC_MSG_CHECKING(if compiler allows __attribute__) +AC_TRY_COMPILE([], [typedef struct { } __attribute__ ((packed)) junk;], + AC_MSG_RESULT(yes), + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_NO_ATTRIBUTES) + ]) + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_MSG_CHECKING(for set) +AC_TRY_COMPILE([#include ], [], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_HAVE_SET) + ], AC_MSG_RESULT(no)) +AC_MSG_CHECKING(for set.h) +AC_TRY_COMPILE([#include ], [], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_HAVE_SET_H) + ], AC_MSG_RESULT(no)) +AC_MSG_CHECKING(for map) +AC_TRY_COMPILE([#include ], [], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_HAVE_MAP) + ], AC_MSG_RESULT(no)) +AC_MSG_CHECKING(for map.h) +AC_TRY_COMPILE([#include ], [], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_HAVE_MAP_H) + ], AC_MSG_RESULT(no)) +AC_LANG_RESTORE + +dnl Implement a check for each gui library to see if has a chance of compiling. +if test "$with_all_libs" = yes; then + if test "$cross_configure" = 1; then + AC_MSG_WARN([[Using --with-all-libs while cross configuring is very unlikely to be what you want. You should specify the --with-* args yourself.]]) + fi + + if test "$with_amigaos" != yes; then + can_compile_amigaos=1 + AC_CHECK_HEADER([proto/intuition.h], [], [ can_compile_amigaos=0 ]) + AC_CHECK_HEADER([intuition/intuitionbase.h], [], [ can_compile_amigaos=0 ]) + AC_CHECK_HEADER([cybergraphx/cybergraphics.h], [], [ can_compile_amigaos=0 ]) + AC_CHECK_HEADER([devices/trackdisk.h], [], [ can_compile_amigaos=0 ]) + if test $can_compile_amigaos = 1; then + with_amigaos=yes + fi + fi + + if test "$with_macos" != yes; then + can_compile_macos=1 + AC_CHECK_HEADER([Quickdraw.h], [], [ can_compile_macos=0 ]) + AC_CHECK_HEADER([Dialogs.h], [], [ can_compile_macos=0 ]) + if test $can_compile_macos = 1; then + with_macos=yes + fi + fi + + if test "$with_carbon" != yes; then + can_compile_carbon=1 + AC_CHECK_HEADER([Carbon.h], [], [ can_compile_carbon=0 ]) + AC_CHECK_HEADER([ApplicationServices/ApplicationServices.h], [], [ can_compile_carbon=0 ]) + if test $can_compile_carbon = 1; then + with_carbon=yes + fi + fi + + if test "$with_win32" != yes; then + can_compile_win32=1 + AC_CHECK_HEADER([windows.h], [], [ can_compile_win32=0 ]) + AC_CHECK_HEADER([commctrl.h], [], [ can_compile_win32=0 ]) + if test $can_compile_win32 = 1; then + with_win32=yes + fi + fi + + if test "$with_sdl" != yes -a "$with_sdl2" != yes; then + can_compile_sdl=2 + AC_CHECK_HEADER([SDL2/SDL.h], [], [ can_compile_sdl=0 ]) + AC_CHECK_HEADER([SDL2/SDL_main.h], [], [ can_compile_sdl=0 ]) + if test $can_compile_sdl != 2; then + can_compile_sdl=1 + AC_CHECK_HEADER([SDL/SDL.h], [], [ can_compile_sdl=0 ]) + AC_CHECK_HEADER([SDL/SDL_main.h], [], [ can_compile_sdl=0 ]) + if test $can_compile_sdl = 1; then + with_sdl=yes + fi + else + with_sdl2=yes + fi + fi + + if test "$with_svga" != yes; then + can_compile_svga=1 + AC_CHECK_HEADER([vga.h], [], [ can_compile_svga=0 ]) + AC_CHECK_HEADER([vgagl.h], [], [ can_compile_svga=0 ]) + if test $can_compile_svga = 1; then + with_svga=yes + fi + fi + + if test "$with_x11" != yes; then + can_compile_x11=1 + AC_CHECK_HEADER([X11/Xlib.h], [], [ can_compile_x11=0 ]) + AC_CHECK_HEADER([X11/Xutil.h], [], [ can_compile_x11=0 ]) + if test $can_compile_x11 = 1; then + with_x11=yes + fi + fi + + if test "$with_rfb" != yes; then + can_compile_rfb=1 + case $target in + *-pc-windows* | *-pc-winnt* | *-cygwin* | *-mingw32*) + AC_CHECK_HEADER([winsock2.h], [], [ can_compile_rfb=0 ]) + AC_CHECK_HEADER([process.h], [], [ can_compile_rfb=0 ]) + ;; + *) + AC_CHECK_HEADER([sys/socket.h], [], [ can_compile_rfb=0 ]) + AC_CHECK_HEADER([netinet/tcp.h], [], [ can_compile_rfb=0 ]) + AC_CHECK_HEADER([pthread.h], [], [ can_compile_rfb=0 ]) + ;; + esac + if test $can_compile_rfb = 1; then + with_rfb=yes + fi + fi + + if test "$with_vncsrv" != yes; then + can_compile_vncsrv=1 + case $target in + *-pc-windows* | *-pc-winnt* | *-cygwin*) + can_compile_vncsrv=0 + ;; + *-mingw32*) + AC_CHECK_HEADER([rfb/rfb.h], [], [ can_compile_vncsrv=0 ]) + ;; + *) + AC_CHECK_HEADER([rfb/rfb.h], [], [ can_compile_vncsrv=0 ]) + AC_CHECK_HEADER([pthread.h], [], [ can_compile_vncsrv=0 ]) + ;; + esac + if test $can_compile_vncsrv = 1; then + with_vncsrv=yes + fi + fi + + if test "$with_term" != yes; then + can_compile_term=1 + AC_CHECK_HEADER([curses.h], [], [ can_compile_term=0 ]) + AC_CHECK_HEADER([signal.h], [], [ can_compile_term=0 ]) + if test $can_compile_term = 1; then + with_term=yes + fi + fi + + if test "$with_nogui" != yes; then + with_nogui=yes + fi + + if test "$with_essence" != yes; then + with_essence=yes + fi +fi # end of if $with_all_libs = yes + +if test "$with_sdl" = yes -a "$with_sdl2" = yes; then + AC_MSG_ERROR([[--with-sdl and --with-sdl2 are mutually exclusive]]) +fi + +AC_MSG_CHECKING(for idle hack) +AC_ARG_ENABLE(idle-hack, + AS_HELP_STRING([--enable-idle-hack], [use Roland Mainz's idle hack (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_USE_IDLE_HACK, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_USE_IDLE_HACK, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_USE_IDLE_HACK, 0) + ] + ) +AC_SUBST(BX_USE_IDLE_HACK) + +AC_CHECK_HEADER(dlfcn.h, AC_DEFINE(BX_HAVE_DLFCN_H, 1)) +AC_CHECK_HEADER(assert.h, AC_DEFINE(HAVE_ASSERT_H, 1)) + +AC_MSG_CHECKING(for plugins support) +AC_ARG_ENABLE(plugins, + AS_HELP_STRING([--enable-plugins], [enable plugin support (no)]), + [if test "$enableval" = yes; then + bx_plugins=1 + else + bx_plugins=0 + fi], + [ + bx_plugins=0 + ] + ) + +USER_PLUGINS_MAKEFILE='' +if test "$bx_plugins" = 1; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_PLUGINS, 1) + GUI_NON_PLUGIN_OBJS='$(OBJS_THAT_CANNOT_BE_PLUGINS)' + GUI_PLUGIN_OBJS='$(OBJS_THAT_CAN_BE_PLUGINS)' + DEFINE_PLUGIN_PATH='-DBX_PLUGIN_PATH="\"${plugdir}\""' + # and the $(OBJS_THAT_SUPPORT_OTHER_PLUGINS) will be built and linked + if test "$NO_LT" != 1; then + # by special link rules for the plugins that they support. + LIBS="$LIBS $LIBADD_DL" + have_ltdl=0 + AC_CHECK_HEADER(ltdl.h, [AC_CHECK_LIB(ltdl, lt_dlinit, [have_ltdl=1]])) + if test "$have_ltdl" = 1; then + PLUGIN_LIB="-lltdl" + AC_DEFINE(BX_HAVE_LTDL,1) + else + PLUGIN_VAR="ltdl.o" + PLUGIN_LIB="ltdl.o" + fi + fi + PLUGIN_TARGET=bochs_plugins + PLUGIN_TARGET_2=plugins_gcc + INSTALL_PLUGINS_VAR=install_libtool_plugins + NONPLUGIN_GUI_LINK_OPTS='' + if test -d user_plugins; then + USER_PLUGINS_MAKEFILE='user_plugins/Makefile' + fi +else + AC_MSG_RESULT(no) + bx_plugins=0 + AC_DEFINE(BX_PLUGINS, 0) + GUI_NON_PLUGIN_OBJS='$(OBJS_THAT_CANNOT_BE_PLUGINS) $(OBJS_THAT_CAN_BE_PLUGINS) $(OBJS_THAT_SUPPORT_OTHER_PLUGINS)' + GUI_PLUGIN_OBJS='' + NONPLUGIN_GUI_LINK_OPTS='$(GUI_LINK_OPTS)' +fi +AC_SUBST(DEFINE_PLUGIN_PATH) +AC_SUBST(NONPLUGIN_GUI_LINK_OPTS) + +# copy gui variables into iodev variables. Later, we will add to the gui +# objs list, according to which display libraries are enabled. +IODEV_NON_PLUGIN_OBJS=$GUI_NON_PLUGIN_OBJS +IODEV_PLUGIN_OBJS=$GUI_PLUGIN_OBJS +IODEV_EXT_NON_PLUGIN_OBJS=$GUI_NON_PLUGIN_OBJS +IODEV_EXT_PLUGIN_OBJS=$GUI_PLUGIN_OBJS + +# on MacOSX if they enabled plugins, make sure that dlopen() was found. +# It is provided by a library called dlcompat. +if test "$bx_plugins" = 1 -a "$need_dlcompat_for_plugins" = 1; then + have_dlopen=0 + AC_CHECK_LIB(dl, dlopen, [have_dlopen=1]) + AC_MSG_CHECKING(if you have dlcompat, required for MacOSX plugins) + if test "$have_dlopen" = 0; then + AC_MSG_RESULT(no) + AC_MSG_ERROR([To use plugins on MacOSX you must use a library called dlcompat. The configure script was not able to find dlcompat. If it is already installed then you must set up your environment variables to point to it, as is done in .conf.macosx. If you cannot resolve this, you should turn off plugins.]) + else + AC_MSG_RESULT(yes) + fi +fi + +AC_MSG_CHECKING(if compiler allows LL for 64-bit constants) +AC_TRY_COMPILE([], [ { 42LL; } ], + AC_MSG_RESULT(yes), + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_64BIT_CONSTANTS_USE_LL, 0) + ]) + +AC_MSG_CHECKING(for A20 support) +AC_ARG_ENABLE(a20-pin, + AS_HELP_STRING([--enable-a20-pin], [compile in support for A20 pin (yes)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_A20, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_A20, 0) + fi + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_A20, 1) + ] + ) + +use_x86_64=0 +AC_MSG_CHECKING(for x86-64 support) +AC_ARG_ENABLE(x86-64, + AS_HELP_STRING([--enable-x86-64], [compile in support for x86-64 instructions (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + OBJS64='$(OBJS64)' + AC_DEFINE(BX_SUPPORT_X86_64, 1) + use_x86_64=1 + else + AC_MSG_RESULT(no) + OBJS64='' + AC_DEFINE(BX_SUPPORT_X86_64, 0) + fi + ], + [ + AC_MSG_RESULT(no) + OBJS64='' + AC_DEFINE(BX_SUPPORT_X86_64, 0) + ] + ) +AC_SUBST(OBJS64) + +use_smp=0 +AC_MSG_CHECKING(for SMP support) +AC_ARG_ENABLE(smp, + AS_HELP_STRING([--enable-smp], [compile in support for SMP configurations (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_SMP, 1) + AC_DEFINE(BX_USE_CPU_SMF, 0) + use_smp=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_SMP, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_SMP, 0) + ] + ) + +AC_MSG_CHECKING(for cpu level) +AC_ARG_ENABLE(cpu-level, + AS_HELP_STRING([--enable-cpu-level], [select cpu level (3,4,5,6 - default is 6)]), + [case "$enableval" in + 3) + AC_MSG_RESULT(3) + AC_DEFINE(BX_CPU_LEVEL, 3) + ;; + 4) + AC_MSG_RESULT(4) + AC_DEFINE(BX_CPU_LEVEL, 4) + ;; + 5) + AC_MSG_RESULT(5) + AC_DEFINE(BX_CPU_LEVEL, 5) + ;; + 6) + AC_MSG_RESULT(6) + AC_DEFINE(BX_CPU_LEVEL, 6) + ;; + *) + echo " " + echo "ERROR: you must supply a valid CPU level to --enable-cpu-level" + exit 1 + ;; + esac + bx_cpu_level=$enableval + if test "$use_smp" = 1 -a "$enableval" -lt 5; then + echo "ERROR: with >1 processor, use --enable-cpu-level=5 or more" + exit 1 + fi + if test "$use_x86_64" = 1 -a "$enableval" -lt 6; then + echo "ERROR: --enable-cpu-level=6 required for x86-64 emulation" + exit 1 + fi + ], + [ + AC_MSG_RESULT(6) + AC_DEFINE(BX_CPU_LEVEL, 6) + bx_cpu_level=6 + ] + ) + +AC_MSG_CHECKING(for larger than 32 bit physical address emulation) +AC_ARG_ENABLE(long-phy-address, + AS_HELP_STRING([--enable-long-phy-address], [compile in support for physical address larger than 32 bit (yes, if cpu level >= 5)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_PHY_ADDRESS_LONG, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_PHY_ADDRESS_LONG, 0) + fi + ], + [ + if test "$bx_cpu_level" -ge 5; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_PHY_ADDRESS_LONG, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_PHY_ADDRESS_LONG, 0) + fi + ] + ) + +AC_MSG_CHECKING(for large ramfile support) +AC_ARG_ENABLE(large-ramfile, + AS_HELP_STRING([--enable-large-ramfile], [enable large ramfile support (yes)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_LARGE_RAMFILE, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_LARGE_RAMFILE, 0) + fi], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_LARGE_RAMFILE, 1) + ] + ) +AC_SUBST(BX_LARGE_RAMFILE) + +AC_MSG_CHECKING(for repeated IO and mem copy speedups) +AC_ARG_ENABLE(repeat-speedups, + AS_HELP_STRING([--enable-repeat-speedups], [support repeated IO and mem copy speedups (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + speedup_repeat=1 + else + AC_MSG_RESULT(no) + speedup_repeat=0 + fi], + [ + AC_MSG_RESULT(no) + speedup_repeat=0 + ] + ) + +AC_MSG_CHECKING(for gcc / MSVC nmake fast function calls optimization) +AC_ARG_ENABLE(fast-function-calls, + AS_HELP_STRING([--enable-fast-function-calls], [support for fast function calls (no - gcc on x86 and MSVC nmake only)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + speedup_fastcall=1 + else + AC_MSG_RESULT(no) + speedup_fastcall=0 + fi], + [ + AC_MSG_RESULT(no) + speedup_fastcall=0 + ] + ) + +AC_MSG_CHECKING(for handlers chaining speedups) +AC_ARG_ENABLE(handlers-chaining, + AS_HELP_STRING([--enable-handlers-chaining], [support handlers-chaining emulation speedups (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + speedup_handlers_chaining=1 + else + AC_MSG_RESULT(no) + speedup_handlers_chaining=0 + fi], + [ + AC_MSG_RESULT(no) + speedup_handlers_chaining=0 + ] + ) + +AC_MSG_CHECKING(for trace linking speedups support) +AC_ARG_ENABLE(trace-linking, + AS_HELP_STRING([--enable-trace-linking], [enable trace linking speedups support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + enable_trace_linking=1 + else + AC_MSG_RESULT(no) + enable_trace_linking=0 + fi], + [ + AC_MSG_RESULT(no) + enable_trace_linking=0 + ] + ) + +AC_MSG_CHECKING(support for configurable MSR registers) +AC_ARG_ENABLE(configurable-msrs, + AS_HELP_STRING([--enable-configurable-msrs], [support for configurable MSR registers (yes if cpu level >= 5)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_CONFIGURE_MSRS, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_CONFIGURE_MSRS, 0) + fi], + [ + if test "$bx_cpu_level" -ge 5; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_CONFIGURE_MSRS, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_CONFIGURE_MSRS, 0) + fi + ] + ) + +AC_MSG_CHECKING(show IPS) +AC_ARG_ENABLE(show-ips, + AS_HELP_STRING([--enable-show-ips], [show IPS in Bochs status bar / log file (yes)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SHOW_IPS, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SHOW_IPS, 0) + fi], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SHOW_IPS, 1) + ] + ) + +AC_MSG_CHECKING(for use of .cpp as suffix) +AC_ARG_ENABLE(cpp, + AS_HELP_STRING([--enable-cpp], [use .cpp as C++ suffix (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + SUFFIX_LINE='.SUFFIXES: .cpp' + CPP_SUFFIX='cpp' + else + AC_MSG_RESULT(no) + SUFFIX_LINE='.SUFFIXES: .cc' + CPP_SUFFIX='cc' + fi], + [ + AC_MSG_RESULT(no) + SUFFIX_LINE='.SUFFIXES: .cc' + CPP_SUFFIX='cc' + ] + ) +AC_SUBST(SUFFIX_LINE) +AC_SUBST(CPP_SUFFIX) + +if test "$enable_cpp" = yes; then + echo "moving .cc source files to .cpp" + sourcefiles=`find . -name "*.cc" -print` + if test "$sourcefiles" != ""; then + for ccname in $sourcefiles + do + cppname=`echo $ccname | sed -e "s/\.cc$/.cpp/"` + echo "mv $ccname $cppname" + mv $ccname $cppname + done + else + echo "no more .cc source files to rename" + fi +fi + + + +AC_MSG_CHECKING(for Bochs internal debugger support) +AC_ARG_ENABLE(debugger, + AS_HELP_STRING([--enable-debugger], [compile in support for Bochs internal debugger (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_DEBUGGER, 1) + DEBUGGER_VAR='$(DEBUGGER_LIB)' + NO_FLEX_YACC='' + AC_PATH_PROG(FLEX, flex, not_found) + AC_PATH_PROG(YACC, yacc, not_found) + AC_MSG_CHECKING(whether to generate parser / lexer files) + if test "$FLEX" = not_found -o "$YACC" = not_found -o "$MSVC_TARGET" != 0; then + NO_FLEX_YACC='#' + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + AC_SUBST(NO_FLEX_YACC) + bx_debugger=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_DEBUGGER, 0) + DEBUGGER_VAR='' + bx_debugger=0 + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_DEBUGGER, 0) + DEBUGGER_VAR='' + bx_debugger=0 + ] + ) +AC_SUBST(DEBUGGER_VAR) + +AC_MSG_CHECKING(for disassembler support) +AC_ARG_ENABLE(disasm, + AS_HELP_STRING([--enable-disasm], [compile in support for disassembler (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_DISASM, 1) + DISASM_VAR='$(DISASM_LIB)' + else + AC_MSG_RESULT(no) + if test "$bx_debugger" = 1; then + echo "ERROR: debugger is enabled, so --enable-disasm is required" + exit 1 + fi + AC_DEFINE(BX_DISASM, 0) + DISASM_VAR='' + fi], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_DISASM, 1) + DISASM_VAR='$(DISASM_LIB)' + ]) +AC_SUBST(DISASM_VAR) + +AC_MSG_CHECKING(enable Bochs internal debugger GUI) +AC_ARG_ENABLE(debugger-gui, + AS_HELP_STRING([--enable-debugger-gui], [compile in support for Bochs internal debugger GUI (yes, if debugger is on)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + gui_debugger=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_DEBUGGER_GUI, 0) + gui_debugger=0 + fi], + [ + if test "$bx_debugger" = 1; then + AC_MSG_RESULT(yes) + gui_debugger=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_DEBUGGER_GUI, 0) + gui_debugger=0 + fi + ] + ) + +bx_gdb_stub=0 +AC_MSG_CHECKING(for gdb stub enable) +AC_ARG_ENABLE(gdb-stub, + AS_HELP_STRING([--enable-gdb-stub], [enable gdb stub support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_GDBSTUB, 1) + GDBSTUB_VAR='$(GDBSTUB_OBJS)' + bx_gdb_stub=1 + if test "$bx_debugger" = 1; then + AC_MSG_ERROR([[--enable-debugger and --enable-gdb-stub are mutually exclusive]]) + fi + AC_MSG_WARN([This Bochs feature is not maintained yet and may fail]) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_GDBSTUB, 0) + GDBSTUB_VAR='' + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_GDBSTUB, 0) + GDBSTUB_VAR='' + ] + ) +AC_SUBST(GDBSTUB_VAR) + + +AC_MSG_CHECKING(for I/O Interface to the debugger) +IODEBUG_OBJS='' +AC_ARG_ENABLE(iodebug, + AS_HELP_STRING([--enable-iodebug], [enable I/O interface to debugger (yes, if debugger is on)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_IODEBUG, 1) + IODEBUG_OBJS='iodebug.o' + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_IODEBUG, 0) + fi + ], + [ + if test "$bx_debugger" = 1; then + # enable by default if debugger is on + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_IODEBUG, 1) + IODEBUG_OBJS='iodebug.o' + else + AC_MSG_RESULT(no) + fi + ] + ) +AC_SUBST(IODEBUG_OBJS) + + +AC_MSG_CHECKING(for ALL optimizations enabled) +AC_ARG_ENABLE(all-optimizations, + AS_HELP_STRING([--enable-all-optimizations], [compile in all possible optimizations (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + speedups_all=1 + else + AC_MSG_RESULT(no) + speedups_all=0 + fi + ], + [ + AC_MSG_RESULT(no) + speedups_all=0 + ] + ) + +# +# Optimizations section. Decide what the status of various optimizations +# should be based on configure choices and other factors. +# + +if test "$speedups_all" = 1; then + # Configure requested to force all options enabled. + speedup_repeat=1 + speedup_fastcall=1 + speedup_handlers_chaining=1 + enable_trace_linking=1 +fi + +if test "$speedup_repeat" = 1; then + AC_DEFINE(BX_SUPPORT_REPEAT_SPEEDUPS, 1) +else + AC_DEFINE(BX_SUPPORT_REPEAT_SPEEDUPS, 0) +fi + +if test "$speedup_fastcall" = 1; then + AC_DEFINE(BX_FAST_FUNC_CALL, 1) +else + AC_DEFINE(BX_FAST_FUNC_CALL, 0) +fi + +if test "$bx_debugger" = 1 -a "$speedup_handlers_chaining" = 1; then + speedup_handlers_chaining=0 + echo "ERROR: handlers-chaining speedups are not supported with internal debugger or gdbstub yet" +fi + +if test "$bx_gdb_stub" = 1 -a "$speedup_handlers_chaining" = 1; then + speedup_handlers_chaining=0 + echo "ERROR: handlers-chaining speedups are not supported with internal debugger or gdbstub yet" +fi + +if test "$speedup_handlers_chaining" = 1; then + AC_DEFINE(BX_SUPPORT_HANDLERS_CHAINING_SPEEDUPS, 1) +else + AC_DEFINE(BX_SUPPORT_HANDLERS_CHAINING_SPEEDUPS, 0) +fi + +if test "$enable_trace_linking" = 1; then + AC_DEFINE(BX_ENABLE_TRACE_LINKING, 1) +else + AC_DEFINE(BX_ENABLE_TRACE_LINKING, 0) +fi + +READLINE_LIB="" +rl_without_curses_ok=no +rl_with_curses_ok=no + +AC_MSG_CHECKING(whether user wants readline) +AC_ARG_ENABLE(readline, + AS_HELP_STRING([--enable-readline], [use readline library, if available (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + want_readline=yes + else + AC_MSG_RESULT(no) + want_readline=no + fi], + [ + AC_MSG_RESULT(yes) + want_readline=yes + ] + ) + +use_readline=0 +AC_MSG_CHECKING(whether to use readline) +if test "$want_readline" = yes; then + if test "$bx_debugger" = 1; then + + AC_MSG_CHECKING(if readline works without -lcurses) + OLD_LIBS=$LIBS + LIBS="$LIBS -lreadline" + AC_TRY_RUN([ + #include + #include + int main() { rl_initialize(); exit(0); } + ], + [ AC_MSG_RESULT(yes) + rl_without_curses_ok=yes ], + [ AC_MSG_RESULT(no) ] + ) + AC_MSG_CHECKING(if readline works with -lcurses) + LIBS="$LIBS -lcurses" + AC_TRY_RUN([ + #include + #include + int main() { rl_initialize(); exit(0); } + ], + [AC_MSG_RESULT(yes) + rl_with_curses_ok=yes ], + [ AC_MSG_RESULT(no) ] + ) + LIBS=$OLD_LIBS + + if test "$rl_without_curses_ok" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LIBREADLINE, 1) + READLINE_LIB="-lreadline" + use_readline=1 + elif test "$rl_with_curses_ok" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LIBREADLINE, 1) + READLINE_LIB="-lreadline -lcurses" + use_readline=1 + else + AC_MSG_RESULT(no) + echo WARNING: The readline library was disabled because it was not found. + fi + else + AC_MSG_RESULT(no) + fi +else + AC_MSG_RESULT(no) +fi +AC_SUBST(READLINE_LIB) + +AC_CHECK_HEADER(readline/history.h, + AC_DEFINE(HAVE_READLINE_HISTORY_H) + ) + +INSTRUMENT_DIR='instrument/stubs' + +AC_MSG_CHECKING(for instrumentation support) +AC_ARG_ENABLE(instrumentation, + AS_HELP_STRING([--enable-instrumentation=instrument-dir], [compile in support for instrumentation (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_INSTRUMENTATION, 1) + INSTRUMENT_VAR='$(INSTRUMENT_LIB)' + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_INSTRUMENTATION, 0) + INSTRUMENT_VAR='' + else + AC_MSG_RESULT(yes) + AC_DEFINE(BX_INSTRUMENTATION, 1) + INSTRUMENT_DIR=$enableval + INSTRUMENT_VAR='$(INSTRUMENT_LIB)' + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_INSTRUMENTATION, 0) + INSTRUMENT_VAR='' + ] + ) +AC_SUBST(INSTRUMENT_DIR) +AC_SUBST(INSTRUMENT_VAR) + +AC_MSG_CHECKING(enable logging) +AC_ARG_ENABLE(logging, + AS_HELP_STRING([--enable-logging], [enable logging (yes)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_NO_LOGGING, 0) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_NO_LOGGING, 1) + fi], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_NO_LOGGING, 0) + ] + ) + +AC_MSG_CHECKING(enable statistics collection) +AC_ARG_ENABLE(stats, + AS_HELP_STRING([--enable-stats], [enable statistics collection (yes)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_ENABLE_STATISTICS, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_ENABLE_STATISTICS, 0) + fi], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_ENABLE_STATISTICS, 1) + ] + ) + +AC_MSG_CHECKING(enable assert checks) +AC_ARG_ENABLE(assert-checks, + AS_HELP_STRING([--enable-assert-checks], [enable BX_ASSERT checks (yes, if debugger is on)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_ASSERT_ENABLE, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_ASSERT_ENABLE, 0) + fi], + [ + if test "$bx_debugger" = 1; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_ASSERT_ENABLE, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_ASSERT_ENABLE, 0) + fi + ] + ) + +support_fpu=1 +AC_MSG_CHECKING(for FPU emulation) +FPU_VAR='' +AC_ARG_ENABLE(fpu, + AS_HELP_STRING([--enable-fpu], [compile in FPU emulation (yes)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_FPU, 1) + FPU_VAR='$(FPU_LIB)' + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_FPU, 0) + support_fpu=0 + else + echo " " + echo "ERROR: --enable-fpu does not accept a path" + exit 1 + fi + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_FPU, 1) + FPU_VAR='$(FPU_LIB)' + ] + ) +AC_SUBST(FPU_VAR) + +support_vmx=0 +AC_MSG_CHECKING(for VMX support) +AC_ARG_ENABLE(vmx, + AS_HELP_STRING([--enable-vmx], [VMX (virtualization extensions) emulation (--enable-vmx=[no|1|2])]), + [case "$enableval" in + no | 0) + support_vmx=0 + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_VMX, 0) + ;; + yes | 1) + support_vmx=1 + AC_MSG_RESULT(1) + AC_DEFINE(BX_SUPPORT_VMX, 1) + ;; + 2) + support_vmx=2 + AC_MSG_RESULT(2) + AC_DEFINE(BX_SUPPORT_VMX, 2) + ;; + *) + echo "ERROR: --enable-vmx=$enableval not understood. Use --enable-vmx=[no|1|2]" + exit 1 + ;; + esac + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_VMX, 0) + ] + ) + +if test "$support_vmx" -gt 0 -a "$bx_cpu_level" -lt 6; then + AC_MSG_ERROR([for VMX support the CPU level must be set to 6]) +fi + +if test "$support_vmx" -gt 1 -a "$use_x86_64" = 0; then + AC_MSG_ERROR([VMXx2 support require x86-64 enabled]) +fi + +support_svm=0 +AC_MSG_CHECKING(for SVM support) +AC_ARG_ENABLE(svm, + AS_HELP_STRING([--enable-svm], [SVM (AMD: secure virtual machine) emulation (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_SVM, 1) + support_svm=1 + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_SVM, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_SVM, 0) + ] + ) + +if test "$support_svm" -gt 0 -a "$use_x86_64" = 0; then + AC_MSG_ERROR([SVM support require x86-64 enabled]) +fi + +support_pkeys=0 +AC_MSG_CHECKING(for User-Mode Protection Keys support) +AC_ARG_ENABLE(protection-keys, + AS_HELP_STRING([--enable-protection-keys], [User-Mode Protection Keys support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_PKEYS, 1) + support_pkeys=1 + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PKEYS, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PKEYS, 0) + ] + ) + +if test "$support_pkeys" -gt 0 -a "$use_x86_64" = 0; then + AC_MSG_ERROR([User-Mode Protection Keys feature emulation require x86-64 enabled]) +fi + +AC_MSG_CHECKING(for 3DNow! support) +AC_ARG_ENABLE(3dnow, + AS_HELP_STRING([--enable-3dnow], [3DNow! support (no - incomplete)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_3DNOW, 1) + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_3DNOW, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_3DNOW, 0) + ] + ) + +AC_MSG_CHECKING(for alignment check support) +AC_ARG_ENABLE(alignment-check, + AS_HELP_STRING([--enable-alignment-check], [alignment check (#AC) support (yes, if cpu level > 3)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_ALIGNMENT_CHECK, 1) + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_ALIGNMENT_CHECK, 0) + fi + ], + [ + if test "$bx_cpu_level" -gt 3; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_ALIGNMENT_CHECK, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_ALIGNMENT_CHECK, 0) + fi + ] + ) + +AC_MSG_CHECKING(for MONITOR/MWAIT instructions support (experimental)) +AC_ARG_ENABLE(monitor_mwait, + AS_HELP_STRING([--enable-monitor-mwait], [support for MONITOR/MWAIT instructions (yes, if cpu level > 5 - experimental)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_MONITOR_MWAIT, 1) + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_MONITOR_MWAIT, 0) + fi + ], + [ + if test "$bx_cpu_level" -gt 5; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_MONITOR_MWAIT, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_MONITOR_MWAIT, 0) + fi + ] + ) + +AC_MSG_CHECKING(for limited hardware performance monitoring emulation support (experimental)) +AC_ARG_ENABLE(perfmon, + AS_HELP_STRING([--enable-perfmon], [support for limited hardware performance monitoring emulation (yes, if cpu level > 5 - experimental)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_PERFMON, 1) + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PERFMON, 0) + fi + ], + [ + if test "$bx_cpu_level" -gt 5; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_PERFMON, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PERFMON, 0) + fi + ] + ) + +AC_MSG_CHECKING(for memory type support) +AC_ARG_ENABLE(memtype, + AS_HELP_STRING([--enable-memtype], [support for memory type]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_MEMTYPE, 1) + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_MEMTYPE, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_MEMTYPE, 0) + ] + ) + +support_avx=0 +AVX_LIB_VAR='' +AC_MSG_CHECKING(for AVX instructions support) +AC_ARG_ENABLE(avx, + AS_HELP_STRING([--enable-avx], [support for AVX instructions (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AVX_LIB_VAR='$(AVX_LIB)' + AC_DEFINE(BX_SUPPORT_AVX, 1) + support_avx=1 + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_AVX, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_AVX, 0) + ] + ) +AC_SUBST(AVX_LIB_VAR) + +if test "$support_avx" -gt 0 -a "$use_x86_64" = 0; then + AC_MSG_ERROR([for AVX support x86-64 emulation must be compiled in!]) +fi + +support_evex=0 +AC_MSG_CHECKING(for EVEX prefix and AVX-512 extensions support) +AC_ARG_ENABLE(evex, + AS_HELP_STRING([--enable-evex], [support for EVEX prefix and AVX-512 extensions (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_EVEX, 1) + support_evex=1 + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_EVEX, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_EVEX, 0) + ] + ) + +if test "$support_evex" -gt 0 -a "$support_avx" = 0; then + AC_MSG_ERROR([for EVEX and AVX-512 support AVX emulation must be compiled in!]) +fi + +AC_MSG_CHECKING(for x86 debugger support) +AC_ARG_ENABLE(x86-debugger, + AS_HELP_STRING([--enable-x86-debugger], [x86 debugger support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_X86_DEBUGGER, 1) + elif test "$enableval" = no; then + AC_MSG_RESULT(no) + AC_DEFINE(BX_X86_DEBUGGER, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_X86_DEBUGGER, 0) + ] + ) + +dnl devices configuration section + +AC_MSG_CHECKING(for i440FX PCI support) +AC_ARG_ENABLE(pci, + AS_HELP_STRING([--enable-pci], [enable i440FX PCI support (yes)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_PCI, 1) + pci=1 + PCI_OBJS='pci.o pci2isa.o pci_ide.o acpi.o' + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PCI, 0) + pci=0 + PCI_OBJS='' + fi], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_PCI, 1) + pci=1 + PCI_OBJS='pci.o pci2isa.o pci_ide.o acpi.o' + ] + ) +AC_SUBST(PCI_OBJS) + + +AC_MSG_CHECKING(for PCI host device mapping support) +AC_ARG_ENABLE(pcidev, + AS_HELP_STRING([--enable-pcidev], [enable PCI host device mapping support (no - linux host only)]), + [ + if test "$enableval" = "yes"; then + AC_MSG_RESULT(yes) + if test "$pci" != "1"; then + AC_MSG_ERROR([PCI host device mapping requires PCI support]) + fi + case "$target" in + *-linux*) + AC_MSG_NOTICE([Linux detected as host for PCI host device mapping]) + linux_version=`uname -r` + case "$linux_version" in + 2.4*) + PCIDEV_MODULE_MAKE_ALL="all-kernel24" + KERNEL_MODULE_SUFFIX="o" + ;; + 2.6*|3.*) + PCIDEV_MODULE_MAKE_ALL="all-kernel26" + KERNEL_MODULE_SUFFIX="ko" + ;; + *) + AC_MSG_ERROR([Linux kernel 2.4, 2.6 or 3.x is required for PCI host device mapping]) + ;; + esac + KERNELDIR="/lib/modules/$linux_version/build" + LSMOD="lsmod" + INSMOD="insmod" + RMMOD="rmmod" + DEPMOD="depmod" + CLEAN_PCIDEV_VAR=clean_pcidev + AC_SUBST(KERNELDIR) + AC_SUBST(LSMOD) + AC_SUBST(INSMOD) + AC_SUBST(RMMOD) + AC_SUBST(DEPMOD) + AC_SUBST(PCIDEV_MODULE_MAKE_ALL) + AC_SUBST(KERNEL_MODULE_SUFFIX) + AC_SUBST(CLEAN_PCIDEV_VAR) + ;; + *) + AC_MSG_ERROR([PCI host device mapping requires Linux as host]) + ;; + esac + AC_DEFINE(BX_SUPPORT_PCIDEV, 1) + PCI_OBJS="$PCI_OBJS pcidev.o" + AC_MSG_WARN([This Bochs feature is not maintained yet and may fail]) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PCIDEV, 0) + fi + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PCIDEV, 0) + ] +) + +use_usb=0 +USBHC_OBJS='' +UHCICORE_OBJ='' +USBHC_DLL_TARGETS='' +AC_MSG_CHECKING(for USB UHCI support) +AC_ARG_ENABLE(usb, + AS_HELP_STRING([--enable-usb], [enable USB UHCI support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_USB_UHCI, 1) + USBHC_OBJS="usb_uhci.o" + UHCICORE_OBJ="uhci_core.o" + USBHC_DLL_TARGETS="bx_usb_uhci.dll" + use_usb=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_USB_UHCI, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_USB_UHCI, 0) + ] + ) + +AC_MSG_CHECKING(for USB OHCI support) +AC_ARG_ENABLE(usb-ohci, + AS_HELP_STRING([--enable-usb-ohci], [enable USB OHCI support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_USB_OHCI, 1) + USBHC_OBJS="$USBHC_OBJS usb_ohci.o" + USBHC_DLL_TARGETS="$USBHC_DLL_TARGETS bx_usb_ohci.dll" + use_usb=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_USB_OHCI, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_USB_OHCI, 0) + ] + ) + +AC_MSG_CHECKING(for USB EHCI support) +AC_ARG_ENABLE(usb-ehci, + AS_HELP_STRING([--enable-usb-ehci], [enable USB EHCI support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_USB_EHCI, 1) + USBHC_OBJS="$USBHC_OBJS usb_ehci.o" + USBHC_DLL_TARGETS="$USBHC_DLL_TARGETS bx_usb_ehci.dll" + use_usb=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_USB_EHCI, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_USB_EHCI, 0) + ] + ) + +AC_MSG_CHECKING(for USB xHCI support) +AC_ARG_ENABLE(usb-xhci, + AS_HELP_STRING([--enable-usb-xhci], [enable USB xHCI support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_USB_XHCI, 1) + USBHC_OBJS="$USBHC_OBJS usb_xhci.o" + USBHC_DLL_TARGETS="$USBHC_DLL_TARGETS bx_usb_xhci.dll" + use_usb=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_USB_XHCI, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_USB_XHCI, 0) + ] + ) + +if test "$use_usb" = 1; then + if test "$pci" != "1"; then + AC_MSG_ERROR([USB requires PCI support]) + fi + USBCORE_OBJ="usb_common.o" + USBDEV_OBJS="usb_hid.o usb_hub.o usb_msd.o usb_printer.o usb_cbi.o" + SCSI_OBJS="scsi_device.o" + if test "$bx_plugins" = 0; then + USB_LIB_VAR='iodev/usb/libusb.a' + AC_SUBST(USB_LIB_VAR) + fi +fi +AC_SUBST(USBHC_OBJS) +AC_SUBST(UHCICORE_OBJ) +AC_SUBST(USBCORE_OBJ) +AC_SUBST(USBDEV_OBJS) +AC_SUBST(SCSI_OBJS) +AC_SUBST(USBHC_DLL_TARGETS) + + +networking=no +NETDEV_OBJS='' +NETDEV_DLL_TARGETS='' +AC_MSG_CHECKING(for NE2000 support) +AC_ARG_ENABLE(ne2000, + AS_HELP_STRING([--enable-ne2000], [enable NE2000 support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_NE2K, 1) + NETDEV_OBJS='ne2k.o' + NETDEV_DLL_TARGETS="bx_ne2k.dll" + networking=yes + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_NE2K, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_NE2K, 0) + ] + ) + +AC_MSG_CHECKING(for PCI pseudo NIC support) +AC_ARG_ENABLE(pnic, + AS_HELP_STRING([--enable-pnic], [enable PCI pseudo NIC support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_PCIPNIC, 1) + NETDEV_OBJS="$NETDEV_OBJS pcipnic.o" + NETDEV_DLL_TARGETS="$NETDEV_DLL_TARGETS bx_pcipnic.dll" + networking=yes + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PCIPNIC, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_PCIPNIC, 0) + ] + ) + +AC_MSG_CHECKING(for Intel(R) Gigabit Ethernet support) +AC_ARG_ENABLE(e1000, + AS_HELP_STRING([--enable-e1000], [enable Intel(R) Gigabit Ethernet support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + if test "$pci" != "1"; then + AC_MSG_ERROR([E1000 network adapter requires PCI support]) + fi + AC_DEFINE(BX_SUPPORT_E1000, 1) + NETDEV_OBJS="$NETDEV_OBJS e1000.o" + NETDEV_DLL_TARGETS="$NETDEV_DLL_TARGETS bx_e1000.dll" + networking=yes + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_E1000, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_E1000, 0) + ] + ) + +NETLOW_OBJS='' +if test "$networking" = yes; then + NETLOW_OBJS='eth_null.o eth_vnet.o' + ethernet_modules='null vnet' + can_compile_slirp=0 + case "$target" in + *-cygwin* | *-mingw32*) + can_compile_slirp=1 + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS -liphlpapi" + ;; + *-pc-windows* | *-pc-winnt*) + can_compile_slirp=1 + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS iphlpapi.lib" + ;; + *) + AC_CHECK_HEADER([netinet/in.h], [ can_compile_slirp=1 ], []) + ;; + esac + if test $can_compile_slirp = 1; then + NETLOW_OBJS="$NETLOW_OBJS eth_slirp.o" + ethernet_modules="$ethernet_modules slirp" + AC_DEFINE(BX_NETMOD_SLIRP, 1) + NETLOW_OBJS="$NETLOW_OBJS eth_socket.o" + ethernet_modules="$ethernet_modules socket" + AC_DEFINE(BX_NETMOD_SOCKET, 1) + fi + if test "$MSVC_TARGET" = 0; then + AC_CHECK_HEADER(net/bpf.h, [ + NETLOW_OBJS="$NETLOW_OBJS eth_fbsd.o" + ethernet_modules="$ethernet_modules fbsd" + AC_DEFINE(BX_NETMOD_FBSD, 1) + ]) + AC_CHECK_HEADER(netpacket/packet.h, [ + NETLOW_OBJS="$NETLOW_OBJS eth_linux.o" + ethernet_modules="$ethernet_modules linux" + AC_DEFINE(BX_NETMOD_LINUX, 1) + ]) + fi + case "$target" in + *-pc-windows* | *-pc-winnt* | *-cygwin* | *-mingw32*) + NETLOW_OBJS="$NETLOW_OBJS eth_win32.o" + ethernet_modules="$ethernet_modules win32" + AC_DEFINE(BX_NETMOD_WIN32, 1) + ;; + *-macosx* | *-darwin*) + NETLOW_OBJS="$NETLOW_OBJS eth_tuntap.o" + ethernet_modules="$ethernet_modules tuntap" + AC_DEFINE(BX_NETMOD_TUNTAP, 1) + ;; + *) + AC_CHECK_HEADER(net/if.h, [ + use_ethertap=yes + AC_DEFINE(BX_HAVE_NET_IF_H, 1) + ], [], + [ + #include + #include + ]) + AC_CHECK_HEADER(linux/netlink.h, [ + use_ethertap=yes + ], [], + [ + #include + #include + ]) + + if test "$use_ethertap" = yes; then + NETLOW_OBJS="$NETLOW_OBJS eth_tap.o eth_vde.o" + ethernet_modules="$ethernet_modules tap vde" + AC_DEFINE(BX_NETMOD_TAP, 1) + AC_DEFINE(BX_NETMOD_VDE, 1) + fi + + AC_CHECK_HEADER(net/if_tun.h, [ + use_tuntap=yes + ], [], + [ + #include + #include + #include + ]) + AC_CHECK_HEADER(linux/if_tun.h, [ + use_tuntap=yes + ], [], + [ + #include + #include + ]) + if test "$use_tuntap" = yes; then + NETLOW_OBJS="$NETLOW_OBJS eth_tuntap.o" + ethernet_modules="$ethernet_modules tuntap" + AC_DEFINE(BX_NETMOD_TUNTAP, 1) + fi + + ;; + esac + NETWORK_LIB_VAR='iodev/network/libnetwork.a' + AC_SUBST(NETWORK_LIB_VAR) + AC_DEFINE(BX_NETWORKING, 1) + AC_MSG_CHECKING(for ethernet modules) + AC_MSG_RESULT($ethernet_modules) +else + AC_DEFINE(BX_NETWORKING, 0) +fi +AC_SUBST(NETDEV_OBJS) +AC_SUBST(NETLOW_OBJS) +AC_SUBST(NETDEV_DLL_TARGETS) + + +dnl // serial mode 'socket' needs ws2_32.dll in non-plugin mode +if test "$bx_plugins" = 0; then + case $target in + *-pc-windows*) + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS ws2_32.lib" + ;; + *-mingw32* | *-cygwin*) + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS -lws2_32" + ;; + esac +fi + +AC_MSG_CHECKING(for raw serial support) +AC_ARG_ENABLE(raw-serial, + AS_HELP_STRING([--enable-raw-serial], [use raw serial port access (no - incomplete)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(USE_RAW_SERIAL, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(USE_RAW_SERIAL, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(USE_RAW_SERIAL, 0) + ] + ) + +DISPLAY_OBJS='' +DISPLAY_DLL_TARGETS='' +AC_MSG_CHECKING(for CLGD54XX emulation) +AC_ARG_ENABLE(clgd54xx, + AS_HELP_STRING([--enable-clgd54xx], [enable CLGD54XX emulation (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_CLGD54XX, 1) + DISPLAY_OBJS="svga_cirrus.o" + DISPLAY_DLL_TARGETS="bx_svga_cirrus.dll" + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_CLGD54XX, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_CLGD54XX, 0) + ] + ) + +AC_MSG_CHECKING(for 3dfx Voodoo Graphics emulation) +AC_ARG_ENABLE(voodoo, + AS_HELP_STRING([--enable-voodoo], [enable 3dfx Voodoo Graphics emulation (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + if test "$pci" != "1"; then + AC_MSG_ERROR([3dfx Voodoo Graphics emulation requires PCI support]) + fi + AC_DEFINE(BX_SUPPORT_VOODOO, 1) + DISPLAY_OBJS="$DISPLAY_OBJS voodoo.o" + DISPLAY_DLL_TARGETS="$DISPLAY_DLL_TARGETS bx_voodoo.dll" + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_VOODOO, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_VOODOO, 0) + ] + ) +AC_SUBST(DISPLAY_OBJS) +AC_SUBST(DISPLAY_DLL_TARGETS) + + +AC_MSG_CHECKING(for lowlevel CDROM support) +AC_ARG_ENABLE(cdrom, + AS_HELP_STRING([--enable-cdrom], [lowlevel CDROM support (yes)]), + [if test "$enableval" = no; then + bx_cdrom=0 + else + bx_cdrom=1 + fi], + [ bx_cdrom=1 ] + ) + +CDROM_OBJS='cdrom.o' +if test "$bx_cdrom" = 1; then + AC_MSG_RESULT(yes) + case $target in + *-pc-windows* | *-pc-winnt* | *-cygwin* | *-mingw32*) + CDROM_OBJS="$CDROM_OBJS cdrom_win32.o" + AC_DEFINE(LOWLEVEL_CDROM, cdrom_win32_c) + AC_DEFINE(BX_SUPPORT_CDROM, 1) + ;; + *) + AC_CHECK_HEADER(IOKit/storage/IOCDMedia.h, + can_use_osx_cdrom=yes + ) + if test "$with_amigaos" = yes; then + # use the amiga cdrom file instead. + CDROM_OBJS="$CDROM_OBJS cdrom_amigaos.o" + AC_DEFINE(LOWLEVEL_CDROM, cdrom_amigaos_c) + elif test "$can_use_osx_cdrom" = yes; then + # use cdrom_osx + AC_MSG_RESULT(Using OSX IOKit CD Interface) + CDROM_OBJS="$CDROM_OBJS cdrom_osx.o" + AC_DEFINE(LOWLEVEL_CDROM, cdrom_osx_c) + EXTRA_LINK_OPTS="${EXTRA_LINK_OPTS} -framework IOKit -framework CoreFoundation "'$(GUI_LINK_OPTS)' + else + CDROM_OBJS="$CDROM_OBJS cdrom_misc.o" + AC_DEFINE(LOWLEVEL_CDROM, cdrom_misc_c) + fi + AC_DEFINE(BX_SUPPORT_CDROM, 1) + ;; + esac +else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_CDROM, 0) +fi + +AC_SUBST(CDROM_OBJS) + + +SOUNDHW_OBJS='' +SOUNDHW_DLL_TARGETS='' +SOUNDLOW_OBJS='' +GAME_OBJS='' +soundlow_drivers='' +soundlow_default='' +soundcard_present=0 +gameport_present=0 +AC_MSG_CHECKING(for Sound Blaster 16 support) +AC_ARG_ENABLE(sb16, + AS_HELP_STRING([--enable-sb16], [Sound Blaster 16 Support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + SOUNDHW_OBJS='sb16.o' + SOUNDHW_DLL_TARGETS="bx_sb16.dll" + soundcard_present=1 + AC_DEFINE(BX_SUPPORT_SB16, 1) + GAME_OBJS='gameport.o' + gameport_present=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_SB16, 0) + fi], + + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_SB16, 0) + ] + ) + +AC_MSG_CHECKING(for ES1370 soundcard support) +AC_ARG_ENABLE(es1370, + AS_HELP_STRING([--enable-es1370], [enable ES1370 soundcard support (no)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + if test "$pci" != "1"; then + AC_MSG_ERROR([ES1370 soundcard requires PCI support]) + fi + SOUNDHW_OBJS="$SOUNDHW_OBJS es1370.o" + SOUNDHW_DLL_TARGETS="$SOUNDHW_DLL_TARGETS bx_es1370.dll" + soundcard_present=1 + AC_DEFINE(BX_SUPPORT_ES1370, 1) + GAME_OBJS='gameport.o' + gameport_present=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_ES1370, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_ES1370, 0) + ] + ) + +if test "$soundcard_present" = 1; then + AC_DEFINE(BX_SUPPORT_SOUNDLOW, 1) + case "$target" in + *-linux-android*) + SOUNDLOW_OBJS='soundsdl.o' + soundlow_drivers="sdl" + soundlow_default="sdl" + AC_DEFINE(BX_HAVE_SOUND_SDL, 1) + ;; + *-linux* | *-freebsd*) + SOUNDLOW_OBJS='soundoss.o' + soundlow_drivers="oss" + soundlow_default="oss" + AC_DEFINE(BX_HAVE_SOUND_OSS, 1) + bx_have_alsa=0 + AC_CHECK_HEADER([alsa/asoundlib.h], [bx_have_alsa=1]) + if test "$bx_have_alsa" = 1; then + SOUNDLOW_OBJS="$SOUNDLOW_OBJS soundalsa.o" + soundlow_default="alsa" + soundlow_drivers="alsa $soundlow_drivers" + AC_DEFINE(BX_HAVE_SOUND_ALSA, 1) + if test "$bx_plugins" = 1; then + SOUND_LINK_OPTS="$SOUND_LINK_OPTS -lasound" + else + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS -lasound" + fi + fi + ;; + *-pc-windows*) + SOUNDLOW_OBJS='soundwin.o' + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS winmm.lib" + soundlow_drivers="win" + soundlow_default="win" + AC_DEFINE(BX_HAVE_SOUND_WIN, 1) + ;; + *-cygwin* | *-mingw32*) + SOUNDLOW_OBJS='soundwin.o' + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS -lwinmm" + soundlow_drivers="win" + soundlow_default="win" + AC_DEFINE(BX_HAVE_SOUND_WIN, 1) + ;; + *-macosx* | *-macos* | *-apple-darwin*) + SOUNDLOW_OBJS='soundosx.o' + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS -framework CoreServices -framework AudioUnit -framework AudioToolbox" + soundlow_drivers="osx" + soundlow_default="osx" + AC_DEFINE(BX_HAVE_SOUND_OSX, 1) + ;; + *) + SOUNDLOW_OBJS='' + soundlow_default="dummy" + ;; + esac + if test "$with_sdl" = yes; then + SOUNDLOW_OBJS="$SOUNDLOW_OBJS soundsdl.o" + if test "$bx_plugins" = 1; then + SOUND_LINK_OPTS="$SOUND_LINK_OPTS `sdl-config --libs`" + fi + soundlow_drivers="$soundlow_drivers sdl" + if test "$soundlow_default" = "dummy"; then + soundlow_default="sdl" + fi + AC_DEFINE(BX_HAVE_SOUND_SDL, 1) + elif test "$with_sdl2" = yes; then + SOUNDLOW_OBJS="$SOUNDLOW_OBJS soundsdl.o" + if test "$bx_plugins" = 1; then + SOUND_LINK_OPTS="$SOUND_LINK_OPTS `sdl2-config --libs`" + fi + soundlow_drivers="$soundlow_drivers sdl" + if test "$soundlow_default" = "dummy"; then + soundlow_default="sdl" + fi + AC_DEFINE(BX_HAVE_SOUND_SDL, 1) + SDL2_VERSION=`sdl2-config --version` + # SDL version >= 2.0.5 supports audio capture + sdl2_audio_capture=0 + [ + case x$SDL2_VERSION in + x2.0.[0-4]) ;; + x2.0.[5-9]) sdl2_audio_capture=1 ;; + *) ;; + esac + ] + if test "$sdl2_audio_capture" = 1; then + AC_DEFINE(BX_HAVE_SDL2_AUDIO_CAPTURE, 1) + fi + fi + AC_CHECK_HEADER([samplerate.h], [bx_have_libsamplerate=1]) + if test "$bx_have_libsamplerate" = 1; then + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS -lsamplerate" + AC_DEFINE(BX_HAVE_LIBSAMPLERATE, 1) + else + AC_CHECK_HEADER([soxr-lsr.h], [bx_have_soxr_lsr=1]) + if test "$bx_have_soxr_lsr" = 1; then + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS -lsoxr-lsr" + AC_DEFINE(BX_HAVE_SOXR_LSR, 1) + fi + fi + SOUND_LIB_VAR='iodev/sound/libsound.a' + AC_SUBST(SOUND_LIB_VAR) + AC_MSG_CHECKING(for sound lowlevel modules) + AC_MSG_RESULT($soundlow_drivers) + AC_MSG_CHECKING(for default sound lowlevel module) + AC_MSG_RESULT($soundlow_default) + AC_DEFINE_UNQUOTED(BX_SOUND_LOWLEVEL_NAME, "$soundlow_default") +else + AC_DEFINE(BX_SUPPORT_SOUNDLOW, 0) +fi +AC_SUBST(SOUNDHW_OBJS) +AC_SUBST(SOUNDLOW_OBJS) +AC_SUBST(SOUND_LINK_OPTS) +AC_SUBST(SOUNDHW_DLL_TARGETS) + + +AC_MSG_CHECKING(for standard PC gameport support) +AC_ARG_ENABLE(gameport, + AS_HELP_STRING([--enable-gameport], [enable standard PC gameport support (yes, if soundcard present)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_GAMEPORT, 1) + if test "$gameport_present" = 0; then + GAME_OBJS='gameport.o' + case $target in + *-cygwin* | *-mingw32*) + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS -lwinmm" + ;; + esac + fi + else + AC_MSG_RESULT(no) + GAME_OBJS='' + AC_DEFINE(BX_SUPPORT_GAMEPORT, 0) + fi], + [ + if test "$gameport_present" = 1; then + AC_DEFINE(BX_SUPPORT_GAMEPORT, 1) + AC_MSG_RESULT(yes) + else + AC_DEFINE(BX_SUPPORT_GAMEPORT, 0) + AC_MSG_RESULT(no) + fi] + ) +AC_SUBST(GAME_OBJS) + + +BUSM_OBJS='' +bx_busmouse=0 +AC_MSG_CHECKING(for Busmouse support) +AC_ARG_ENABLE(busmouse, + AS_HELP_STRING([--enable-busmouse], [enable Busmouse support (InPort & Standard)]), + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_BUSMOUSE, 1) + BUSM_OBJS='busmouse.o' + bx_busmouse=1 + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_BUSMOUSE, 0) + fi], + [ + AC_DEFINE(BX_SUPPORT_BUSMOUSE, 0) + AC_MSG_RESULT(no)] + ) +AC_SUBST(BUSM_OBJS) + + +AC_PATH_PROG(DOCBOOK2HTML, docbook2html, not_found) +AC_MSG_CHECKING(whether to build docbook documentation) +build_docbook=0 +AC_ARG_ENABLE(docbook, + AS_HELP_STRING([--enable-docbook], [build the Docbook documentation (yes, if docbook present)]), + [ + if test "$enableval" = yes; then build_docbook=1; fi + ], + [ + dnl Not specified. If they have docbook2html, then yes. + if test "$DOCBOOK2HTML" != not_found; then build_docbook=1; fi + ] + ) + +if test $build_docbook = 1; then + AC_MSG_RESULT(yes) + BUILD_DOCBOOK_VAR=build_docbook + INSTALL_DOCBOOK_VAR=install_docbook + CLEAN_DOCBOOK_VAR=clean_docbook + if test "$DOCBOOK2HTML" = not_found; then + echo "ERROR: docbook2html must be installed to build the documentation" + exit 1 + fi +else + AC_MSG_RESULT(no) +fi +AC_SUBST(BUILD_DOCBOOK_VAR) +AC_SUBST(INSTALL_DOCBOOK_VAR) +AC_SUBST(CLEAN_DOCBOOK_VAR) +AC_SUBST(DOCBOOK2HTML) + +PRIMARY_TARGET='bochs' +PLUGIN_LIBNAME_TRANSFORMATION='%.o=libbx_%.la' + +if test "$bx_plugins" = 0; then + HDIMAGE_LIB_VAR='iodev/hdimage/libhdimage.a' + AC_SUBST(HDIMAGE_LIB_VAR) + DISPLAY_LIB_VAR='iodev/display/libdisplay.a' + AC_SUBST(DISPLAY_LIB_VAR) +fi +IODEV_LIB_VAR='iodev/libiodev.a' +NONINLINE_VAR='$(NONINLINE_OBJS)' + +AC_SUBST(IODEV_LIB_VAR) +AC_SUBST(EXTRA_BX_OBJS) +AC_SUBST(NONINLINE_VAR) +AC_SUBST(INLINE_VAR) +AC_SUBST(EXTERNAL_DEPENDENCY) +AC_SUBST(RC_CMD) + + +AC_ARG_WITH(x11, + [ --with-x11 use X11 GUI], + ) + +AC_ARG_WITH(win32, + [ --with-win32 use Win32 GUI], + ) + +AC_ARG_WITH(macos, + [ --with-macos use Macintosh/CodeWarrior environment], + ) + +AC_ARG_WITH(carbon, + [ --with-carbon compile for MacOS X with Carbon GUI], + ) + +AC_ARG_WITH(nogui, + [ --with-nogui no native GUI, just use blank stubs], + ) + +AC_ARG_WITH(essence, + [ --with-essence compile for Essence with the native GUI], + ) + +AC_ARG_WITH(term, + [ --with-term textmode terminal environment], + ) + +AC_ARG_WITH(rfb, + [ --with-rfb use RFB protocol, works with VNC viewer], + ) + +AC_ARG_WITH(vncsrv, + [ --with-vncsrv use LibVNCServer, works with VNC viewer], + ) + +AC_ARG_WITH(amigaos, + [ --with-amigaos use AmigaOS (or MorphOS) GUI], + ) + +AC_ARG_WITH(sdl, + [ --with-sdl use SDL libraries], + ) + +AC_ARG_WITH(sdl2, + [ --with-sdl2 use SDL2 libraries], + ) + +AC_ARG_WITH(svga, + [ --with-svga use SVGALib libraries], + ) + +AC_ARG_WITH(wx, + [ --with-wx use wxWidgets libraries], + ) + +AC_ARG_WITH(all-libs, + [ --with-all-libs compile all guis that Bochs supports], + ) + +dnl // DASH is option prefix for your platform +dnl // SLASH is directory for your platform +dnl // CXXFP is C++ File Prefix; the flag that tells the compiler +dnl // this is a C++ source file +dnl // CFP is C File Prefix; the flag that tells the compiler +dnl // this is a C source file +dnl // OFP is Object File Prefix; the flag that tells the compiler +dnl // generate an object file with this name +DASH="-" +SLASH="/" +CXXFP="" +CFP="" +OFP="-o " +MAKELIB="ar rv \$@" +RMCOMMAND="rm -f " +# first define link variables without libtool +LINK="\$(CXX) -o \$@ \$(CXXFLAGS) \$(LDFLAGS)" +LINK_CONSOLE="\$(CXX) -o \$@ \$(CXXFLAGS_CONSOLE) \$(LDFLAGS)" +# unless NO_LT is set, add libtool to the front of the link command +if test "$NO_LT" != 1; then + LINK="\$(LIBTOOL) --mode=link --tag CXX $LINK" + LINK_CONSOLE="\$(LIBTOOL) --mode=link --tag CXX $LINK_CONSOLE" +fi +EXE="" +COMMAND_SEPARATOR="&& \\" +CD_UP_ONE="echo done" +CD_UP_TWO="echo done" +CD_UP_THREE="echo done" + +INSTALL_TARGET=install_unix +INSTALL_LIST_FOR_PLATFORM= + +# check for existence of and usable version of wxWidgets. This comes +# early so that it could affect which one gets chosen. +if test x$WX_CONFIG = x; then + AC_CHECK_PROG(WX_CONFIG, [ wx-config --version ], wx-config, not_found) +fi +AC_MSG_CHECKING(for wxWidgets configuration script) +AC_MSG_RESULT($WX_CONFIG) + +ok_wx_version=0 +wx_multi_lib=0 +needs_gtk2=0 +wx_needs_gdk2=0 +AC_MSG_CHECKING(for wxWidgets library version) +if test x$WX_CONFIG != xnot_found; then + WX_VERSION=`$WX_CONFIG --version` + WX_BASENAME=`$WX_CONFIG --basename` + [ + # test that version >= 2.3.2. Anybody have a better way to do this? Yuck. + case x$WX_VERSION in + x2.[012]*) ;; # less than version 2.3.x + x2.3.[01]) ;; # less than version 2.3.2 + x2.3.[2-4]*) ok_wx_version=1 ;; # 2.3.2 or greater + x2.[4-5]*) ok_wx_version=1 ;; # version 2.4 / 2.5 + x2.[6-9]*) # version 2.6 or greater + ok_wx_version=1 + wx_multi_lib=1 + case x$WX_BASENAME in + xwx_gtk2|xwx_gtk2u) wx_needs_gdk2=1 ;; + *) ;; + esac + ;; + x[3-9]*) ok_wx_version=1 ;; # version 3 or greater + *) ;; # who knows? + esac + ] +fi +AC_MSG_RESULT($WX_VERSION) +if test "$cross_configure" = 0; then + if test "$ok_wx_version" = 1; then + # detected a usable version + if test "$with_all_libs" = yes; then + with_wx=yes + fi + else + if test "$with_wx" = yes; then + AC_MSG_WARN([Bochs for wxWidgets cannot be compiled here, disabling it]) + fi + with_wx=no + fi +fi + +AC_MSG_CHECKING(for default gui on this platform) +AC_MSG_RESULT($DEFAULT_GUI) + +display_libs="" +GUI_DLL_TARGETS="" +use_gui_console=0 + +# the $with_* variable tells the gui library to use, but does NOT necessarily +# indicate the platform. Settings that depend on the platform should be +# handled later. + +XPM_LIB='' +if test "$with_x11" = yes; then + display_libs="$display_libs X11" + if test "$no_x" = yes; then + echo ERROR: X windows gui was selected, but X windows libraries were not found. + exit 1 + fi + + check_xpm=0 + AC_MSG_CHECKING(whether user wants XPM support) + AC_ARG_ENABLE(xpm, + AS_HELP_STRING([--enable-xpm], [enable the check for XPM support (yes)]), + [if test "$enableval" = yes; then + check_xpm=0 + AC_MSG_RESULT(yes) + check_xpm=1 + else + AC_MSG_RESULT(no) + check_xpm=0 + fi], + [ + AC_MSG_RESULT(yes) + check_xpm=1 + ] + ) + if test $check_xpm = 1; then + AC_CHECK_HEADER(X11/xpm.h, [ + AC_DEFINE(BX_HAVE_XPM_H) + XPM_LIB='-lXpm' + ]) + fi + + if test "$PKGCONFIG" != not_found; then + X_CFLAGS="`pkg-config --cflags x11`" + X_LIBS="`pkg-config --libs x11` $XPM_LIB -lXrandr" + else + X_LIBS="$X_LIBS -lX11 $XPM_LIB -lXrandr" + fi + + AC_DEFINE(BX_WITH_X11, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_X11)" + GUI_CFLAGS="$GUI_CFLAGS \$(X_CFLAGS)" + GUI_CXXFLAGS="$GUI_CXXFLAGS \$(X_CFLAGS)" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_X)" + # The enhanced X debugger depends on GTK2 + if test "$gui_debugger" = 1; then + needs_gtk2=1 + fi + use_gui_console=1 +fi +AC_SUBST(X_CFLAGS) +AC_SUBST(X_LIBS) + +if test "$with_sdl" = yes; then + display_libs="$display_libs sdl" + GUI_DLL_TARGETS="$GUI_DLL_TARGETS bx_sdl.dll" + AC_DEFINE(BX_WITH_SDL, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_SDL)" + # GUI_*FLAGS are added to the compilation of every bochs file, not just + # the files in gui/*.cc. + SDL_CFLAGS=`sdl-config --cflags` + GUI_CFLAGS="$GUI_CFLAGS $SDL_CFLAGS" + GUI_CXXFLAGS="$GUI_CXXFLAGS $SDL_CFLAGS" + GUI_LINK_OPTS_SDL="`sdl-config --libs`" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_SDL)" + # The enhanced X debugger depends on GTK2 + if test "$gui_debugger" = 1 -a "$DEFAULT_GUI" != win32; then + needs_gtk2=1 + fi + if test "$with_win32" != yes -a "$with_wx" != yes; then + case $target in + *-pc-windows*) + RC_CMD="rc /fo" + EXTRA_BX_OBJS="$EXTRA_BX_OBJS win32res.o" + ;; + *-cygwin* | *-mingw32*) + RC_CMD="windres -I. -o " + EXTRA_BX_OBJS="$EXTRA_BX_OBJS win32res.o" + ;; + esac + fi + use_gui_console=1 +fi + +if test "$with_sdl2" = yes; then + display_libs="$display_libs sdl2" + GUI_DLL_TARGETS="$GUI_DLL_TARGETS bx_sdl2.dll" + AC_DEFINE(BX_WITH_SDL2, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_SDL2)" + # GUI_*FLAGS are added to the compilation of every bochs file, not just + # the files in gui/*.cc. + SDL2_CFLAGS=`sdl2-config --cflags` + GUI_CFLAGS="$GUI_CFLAGS $SDL2_CFLAGS" + GUI_CXXFLAGS="$GUI_CXXFLAGS $SDL2_CFLAGS" + GUI_LINK_OPTS_SDL2="`sdl2-config --libs`" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_SDL2)" + # The enhanced X debugger depends on GTK2 + if test "$gui_debugger" = 1 -a "$DEFAULT_GUI" != win32; then + needs_gtk2=1 + fi + if test "$with_win32" != yes -a "$with_wx" != yes; then + case $target in + *-pc-windows*) + RC_CMD="rc /fo" + EXTRA_BX_OBJS="$EXTRA_BX_OBJS win32res.o" + ;; + *-cygwin* | *-mingw32*) + RC_CMD="windres -I. -o " + EXTRA_BX_OBJS="$EXTRA_BX_OBJS win32res.o" + ;; + esac + fi + use_gui_console=1 +fi + +if test "$with_svga" = yes; then + display_libs="$display_libs svga" + AC_DEFINE(BX_WITH_SVGA, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_SVGA)" + # GUI_*FLAGS are added to the compilation of every bochs file, not just + # the files in gui/*.cc. + GUI_CFLAGS="$GUI_CFLAGS" + GUI_CXXFLAGS="$GUI_CXXFLAGS" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_SVGA)" + AC_MSG_WARN([This Bochs feature is not maintained yet and may fail]) +fi + +if test "$with_rfb" = yes; then + display_libs="$display_libs rfb" + GUI_DLL_TARGETS="$GUI_DLL_TARGETS bx_rfb.dll" + AC_DEFINE(BX_WITH_RFB, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_RFB)" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_RFB)" + use_gui_console=1 +fi + +if test "$with_vncsrv" = yes; then + AC_CHECK_PROG(LIBVNCSERVER_CONFIG, [ libvncserver-config --version ], libvncserver-config, not_found) + AC_MSG_CHECKING(for LibVNCServer configuration script) + AC_MSG_RESULT($LIBVNCSERVER_CONFIG_CONFIG) + if test x$LIBVNCSERVER_CONFIG != xnot_found; then + display_libs="$display_libs vncsrv" + AC_DEFINE(BX_WITH_VNCSRV, 1) + VNCSRV_CXXFLAGS="`$LIBVNCSERVER_CONFIG --cflags`" + GUI_LINK_OPTS_VNCSRV="`$LIBVNCSERVER_CONFIG --libs`" + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_VNCSRV)" + GUI_CXXFLAGS="$GUI_CXXFLAGS $VNCSRV_CXXFLAGS" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_VNCSRV)" + else + AC_MSG_WARN([Bochs for LibVNCServer cannot be compiled here, disabling it]) + with_vncsrv=no + fi + use_gui_console=1 +fi + +if test "$with_amigaos" = yes; then + display_libs="$display_libs amigaos" + AC_DEFINE(BX_WITH_AMIGAOS, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_AMIGAOS)" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_AMIGAOS)" +fi + +if test "$with_win32" = yes; then + display_libs="$display_libs win32" + GUI_DLL_TARGETS="$GUI_DLL_TARGETS bx_win32.dll" + AC_DEFINE(BX_WITH_WIN32, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_WIN32)" + case $target in + *-pc-windows*) + if test "$with_wx" != yes; then + RC_CMD="rc /fo" + EXTRA_BX_OBJS="$EXTRA_BX_OBJS win32res.o" + fi + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_WIN32_VCPP)" + ;; + *-cygwin* | *-mingw32*) + if test "$with_wx" != yes; then + RC_CMD="windres -I. -o " + EXTRA_BX_OBJS="$EXTRA_BX_OBJS win32res.o" + fi + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_WIN32)" + ;; + *) echo Unsupported compile setup: GUI library is win32, but target is neither windows nor cygwin. + ;; + esac +fi + +if test "$with_macos" = yes; then + display_libs="$display_libs macos" + AC_DEFINE(BX_WITH_MACOS, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_MACOS)" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_MACOS)" + AC_MSG_WARN([This Bochs feature is not maintained yet and may fail]) +fi + +if test "$with_carbon" = yes; then + display_libs="$display_libs carbon" + AC_DEFINE(BX_WITH_CARBON, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_CARBON)" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_CARBON)" + if test "$bx_plugins" = 1; then + PRIMARY_TARGET=bochs.app/.build_plugins # only for carbon application + else + PRIMARY_TARGET=bochs.app/.build # only for carbon application + fi + INSTALL_TARGET='install_macosx' + AC_MSG_WARN([This Bochs feature is not maintained yet and may fail]) +fi + +if test "$with_term" = yes; then + display_libs="$display_libs term" + AC_DEFINE(BX_WITH_TERM, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_TERM)" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_TERM)" + use_curses=yes +fi + +if test "$with_wx" = yes; then + display_libs="$display_libs wxWidgets" + if test "$cross_configure" = 1; then + true # do not insist, if configuring for another machine + else + if test x$ok_wx_version != x1; then + echo ERROR: A usable version of wxWidgets was not found. + echo Upgrade the library or choose another gui. + exit 1 + fi + fi + AC_DEFINE(BX_WITH_WX, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_WX)" + SPECIFIC_GUI_SUPPORT_OBJS="$SPECIFIC_GUI_SUPPORT_OBJS \$(GUI_OBJS_WX_SUPPORT)" + WX_CFLAGS="`$WX_CONFIG --cflags`" + WX_CXXFLAGS="`$WX_CONFIG --cxxflags`" + if test "$wx_needs_gdk2" = 1; then + GDK_CFLAGS="`pkg-config --cflags gdk-2.0`" + WX_CFLAGS="$WX_CFLAGS $GDK_CFLAGS" + WX_CXXFLAGS="$WX_CXXFLAGS $GDK_CFLAGS" + fi + if test "$wx_multi_lib" = 1; then + GUI_LINK_OPTS_WX="`$WX_CONFIG --libs core,base`" + else + GUI_LINK_OPTS_WX="`$WX_CONFIG --libs`" + fi + # GUI_C*FLAGS are added to the compilation of every bochs file, not just + # the files in gui/*.cc. They are not used when building other things + # such as bximage. + GUI_CFLAGS="$GUI_CFLAGS $WX_CFLAGS" + GUI_CXXFLAGS="$GUI_CXXFLAGS $WX_CXXFLAGS" + GUI_LINK_OPTS="$GUI_LINK_OPTS \$(GUI_LINK_OPTS_WX)" + # using debugger with readline is failing due to thread/signal handler + # problems. + case $target in + *-pc-windows* | *-cygwin* | *-mingw32*) + EXTRA_BX_OBJS="$EXTRA_BX_OBJS wxbochs_resources.o" + GUI_LINK_OPTS_WX="$GUI_LINK_OPTS_WX" + ;; + *) + # This is required for XStringToKeysym + if test "$with_x11" != yes -a "$bx_plugins" != 1; then + GUI_LINK_OPTS="$GUI_LINK_OPTS -lX11" + fi + ;; + esac + # The enhanced X debugger depends on GTK2 + if test "$gui_debugger" = 1 -a "$DEFAULT_GUI" != win32; then + needs_gtk2=1 + fi +fi + +if test "$with_nogui" = yes; then + display_libs="$display_libs nogui" + GUI_DLL_TARGETS="$GUI_DLL_TARGETS bx_nogui.dll" + AC_DEFINE(BX_WITH_NOGUI, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_NOGUI)" +fi + +if test "$with_essence" = yes; then + display_libs="$display_libs essence" + GUI_DLL_TARGETS="$GUI_DLL_TARGETS bx_essence.dll" + AC_DEFINE(BX_WITH_ESSENCE, 1) + SPECIFIC_GUI_OBJS="$SPECIFIC_GUI_OBJS \$(GUI_OBJS_ESSENCE)" +fi + +AC_MSG_CHECKING(for display libraries) +AC_MSG_RESULT($display_libs) + +if test "$display_libs" = ""; then + echo "No display libraries were selected. Use --with-* options to enable" + echo "individual display libraries, or --with-all-libs to detect the ones" + echo "that Bochs supports." + exit 1 +fi + +# some display libraries and the enhanced debugger may depend on the GTK+ software package +bx_have_gtk2=0 +if test "$needs_gtk2" = 1; then + # pkg-config is required to set TOOLKIT_CXXFLAGS and LIBS + if test "$PKGCONFIG" != not_found; then + pkg-config --exists gtk+-2.0 + if test x$? = x0; then + TOOLKIT_CXXFLAGS="`pkg-config --cflags gtk+-2.0`" + LIBS="$LIBS `pkg-config --libs gtk+-2.0`" + bx_have_gtk2=1 + fi + else + echo "ERROR: pkg-config was not found, or unable to access the gtk+-2.0 package." + echo "Install pkg-config and the gtk+ development package," + echo "or disable the gui debugger, or the wxWidgets display library (whichever is being used)." + exit 1 + fi +fi + +dnl To use wxWidgets you must select it as both the configuration interface +dnl and the display library. In the simplest case where the user has +dnl only configured with --with-wx, set both defaults to wxWidgets. +dnl Without this setting, the config interface would default to the text +dnl mode config interface, and then the wxWidgets display library would not +dnl be usable. +if test "$display_libs" = " wxWidgets"; then + AC_MSG_CHECKING(for default configuration interface) + AC_MSG_RESULT(wxWidgets) + AC_MSG_CHECKING(for default display library) + AC_MSG_RESULT(wxWidgets) + AC_DEFINE(BX_DEFAULT_CONFIG_INTERFACE, "wx") + AC_DEFINE(BX_DEFAULT_DISPLAY_LIBRARY, "wx") + AC_DEFINE(BX_USE_TEXTCONFIG, 0) +else + AC_DEFINE(BX_USE_TEXTCONFIG, 1) +fi + +if test "$use_gui_console" = 1; then + AC_DEFINE(BX_USE_GUI_CONSOLE, 1) +else + AC_DEFINE(BX_USE_GUI_CONSOLE, 0) +fi + +if test "$bx_plugins" = 1; then + # every item in this list will be compiled as a plugin. Do not include + # support objs; they will be mentioned in plugin-specific makefile rules. + GUI_PLUGIN_OBJS="$GUI_PLUGIN_OBJS $SPECIFIC_GUI_OBJS" +else + # include support objs + GUI_NON_PLUGIN_OBJS="$GUI_NON_PLUGIN_OBJS $SPECIFIC_GUI_OBJS $SPECIFIC_GUI_SUPPORT_OBJS" +fi + +AC_SUBST(GUI_CFLAGS) +AC_SUBST(GUI_CXXFLAGS) +AC_SUBST(WX_CONFIG) +AC_SUBST(WX_CFLAGS) +AC_SUBST(WX_CXXFLAGS) +AC_SUBST(TOOLKIT_CXXFLAGS) + +AC_CHECK_PROGS(WGET, wget curl fetch, not_found) +if test "$WGET" = not_found; then + AC_MSG_WARN([cannot find wget (or equivalent) command]) +fi +# everybody has to re-invent the wheel. differently. +test "${WGET}" = "curl" && WGET="curl -O" + +# modify settings based on target platform +case "$target" in + *-macosx*) + AC_DEFINE(BX_HAVE_STRDUP, 0) + ;; + *-macos*) + AC_DEFINE(BX_HAVE_STRDUP, 0) + AC_DEFINE(BX_PLUGINS, 0) + AC_DEFINE(BX_HAVE_DLFCN_H, 0) + AC_DEFINE(BX_HAVE_SOCKLEN_T, 0) + AC_DEFINE(BX_HAVE_SELECT, 0) + AC_DEFINE(BX_HAVE_GETTIMEOFDAY, 0) + AC_DEFINE(BX_NO_ATTRIBUTES, 1) + AC_DEFINE(BX_NETMOD_TUNTAP, 0) + AC_DEFINE(BX_NETMOD_TAP, 0) + ;; + *-pc-windows*) + INSTALL_TARGET='install_win32' + CC="cl" + CXX="$CC" + #C_OPT="/Zi" # for debugging + if test "$speedup_fastcall" = 1; then + C_OPT="/O2 /Gr" # optimize for speed, using fastcall everywhere + else + C_OPT="/O2" # optimize for speed, no fastcall + fi + if test "$bx_debugger" = 1; then + C_OPT="$C_OPT /EHsc" + else + C_OPT="$C_OPT /EHs-c-" + fi + if test "$bx_plugins" = 1; then + CFLAGS="/nologo /MD /W3 /DNDEBUG /DWIN32 /D_WINDOWS /D_CRT_SECURE_NO_WARNINGS $C_OPT" + else + CFLAGS="/nologo /MT /W3 /DNDEBUG /DWIN32 /D_WINDOWS /D_CRT_SECURE_NO_WARNINGS $C_OPT" + fi + CXXFLAGS="$CFLAGS" + DASH="/" + SLASH="\\" + CXXFP="/Tp" + CFP="/Tc" + OFP="/Fo" + MAKE=nmake + MAKELIB="lib /nologo /subsystem:console,\"5.01\" /verbose /out:\$@" + RMCOMMAND="-del" + #L_OPT="/debug" # for debugging + L_OPT="" # no debug info + LINK="link $L_OPT /nologo /subsystem:console,\"5.01\" /incremental:no /out:\$@ " + LINK_CONSOLE=$LINK + EXE=".exe" + PRIMARY_TARGET="bochs.exe" + BXIMAGE_LINK_OPTS="user32.lib" + # also compile bxhub and niclist if networking is on + if test "$networking" = yes; then + OPTIONAL_TARGET="$OPTIONAL_TARGET bxhub.exe niclist.exe" + BXHUB_FLAG="/DBXHUB" + BXHUB_LINK_OPTS="ws2_32.lib" + fi + COMMAND_SEPARATOR="" + CD_UP_ONE="cd .." + CD_UP_TWO="cd ..\.." + CD_UP_THREE="cd ..\..\.." + have_gettimeofday=0 # even though it may exist in build environment + AC_DEFINE(BX_64BIT_CONSTANTS_USE_LL, 0) + AC_DEFINE(BX_CPP_INLINE, __forceinline) + AC_DEFINE(BX_NO_ATTRIBUTES, 1) + AC_DEFINE(HAVE_LIBREADLINE, 0) + AC_DEFINE(HAVE_READLINE_HISTORY_H, 0) + READLINE_LIB=""; + AC_DEFINE(BX_HAVE_DLFCN_H, 0) + AC_DEFINE(BX_NETMOD_TAP, 0) + ;; + *-cygwin*) + EXE=".exe" + PRIMARY_TARGET="bochs.exe" + BXIMAGE_LINK_OPTS="-luser32" + if test "$networking" = yes; then + OPTIONAL_TARGET="$OPTIONAL_TARGET bxhub.exe niclist.exe" + BXHUB_FLAG="-DBXHUB" + BXHUB_LINK_OPTS="-lws2_32" + fi + AC_DEFINE(BX_HAVE_SELECT, 1) + ;; + *-pc-mingw*) + BXIMAGE_LINK_OPTS="-luser32" + if test "$networking" = yes; then + OPTIONAL_TARGET="$OPTIONAL_TARGET bxhub niclist" + BXHUB_FLAG="-DBXHUB" + BXHUB_LINK_OPTS="-lws2_32" + fi + AC_DEFINE(BX_HAVE_SELECT, 1) + ;; + *) + if test "$networking" = yes; then + OPTIONAL_TARGET="$OPTIONAL_TARGET bxhub" + BXHUB_FLAG="-DBXHUB" + fi + ;; +esac + +# bximage specific settings +case "$target" in + *-pc-windows*) + BXIMAGE_FLAG="/DBXIMAGE" + CXXFLAGS_CONSOLE="/nologo /MT /W3 /EHs-c- /DNDEBUG /DWIN32 /D_WINDOWS /D_CRT_SECURE_NO_WARNINGS $C_OPT" + ;; + *) + BXIMAGE_FLAG="-DBXIMAGE" + CXXFLAGS_CONSOLE="$CXXFLAGS" + ;; +esac +AC_SUBST(BXIMAGE_FLAG) +AC_SUBST(BXIMAGE_LINK_OPTS) +AC_SUBST(BXHUB_FLAG) +AC_SUBST(BXHUB_LINK_OPTS) +AC_SUBST(CXXFLAGS_CONSOLE) + +ENH_DBG_OBJS="" +if test "$gui_debugger" = 1; then + if test "$bx_have_gtk2" = 1; then + ENH_DBG_OBJS="enh_dbg.o gtk_enh_dbg_osdep.o" + AC_DEFINE(BX_DEBUGGER_GUI, 1) + elif test "$DEFAULT_GUI" = win32 -o "$with_win32" = yes; then + ENH_DBG_OBJS="enh_dbg.o win32_enh_dbg_osdep.o" + AC_DEFINE(BX_DEBUGGER_GUI, 1) + else + AC_MSG_WARN([The Bochs debugger gui cannot be compiled here, disabling it]) + fi +fi +AC_SUBST(ENH_DBG_OBJS) + +DIALOG_OBJS="" +EXPORT_DYNAMIC="-export-dynamic" +case $target in + *-pc-windows* | *-pc-winnt*) + if test "$bx_plugins" = 1; then + # set variables for building DLL plugins + PLUGIN_VAR="" + PLUGIN_LIBNAME_TRANSFORMATION='%.o=bx_%.dll' + INSTALL_PLUGINS_VAR=install_dll_plugins + WIN32_DLL_IMPORT_LIB="bochs.lib" + LINK_DLL="link /dll /nologo /subsystem:console,\"5.01\" /incremental:no /out:\$@" + LIBS="$LIBS advapi32.lib comctl32.lib comdlg32.lib gdi32.lib shell32.lib user32.lib" + PLUGIN_TARGET_2=plugins_msvc + LINK_VAR="_VCPP" + EXT_MSVC_DLL_RULES="!INCLUDE makeincl.vc" + echo -e "# DLL PLUGIN TEST\n" > iodev/makeincl.vc + IODEV_DLL_TARGETS="" + IODEV_DLL_LIST="biosdev cmos dma extfpuirq harddrv ioapic parallel pic speaker unmapped" + if test "$pci" = "1"; then + IODEV_DLL_LIST="$IODEV_DLL_LIST acpi pci pci2isa pci_ide" + fi + if test "$bx_debugger" = 1; then + IODEV_DLL_LIST="$IODEV_DLL_LIST iodebug" + fi + if test "$bx_busmouse" = 1; then + IODEV_DLL_LIST="$IODEV_DLL_LIST busmouse" + fi + for i in $IODEV_DLL_LIST + do + echo -e "bx_$i.dll: $i.o" >> iodev/makeincl.vc + echo -e "\tlink /dll /nologo /subsystem:console,\"5.01\" /incremental:no /out:\$@ $i.o \$(WIN32_DLL_IMPORT_LIBRARY)\n" >> iodev/makeincl.vc + IODEV_DLL_TARGETS="$IODEV_DLL_TARGETS bx_$i.dll" + done + else + if test "$with_win32" != yes; then + LIBS="$LIBS comctl32.lib" + fi + fi + DIALOG_OBJS="win32dialog.o win32paramdlg.o scrollwin.o" + EXPORT_DYNAMIC="" + ;; + *-cygwin* | *-mingw*) + if test "$bx_plugins" = 1; then + # set variables for building DLL plugins + PRIMARY_TARGET=".win32_dll_plugin_target" + PLUGIN_LIBNAME_TRANSFORMATION='%.o=bx_%.dll' + INSTALL_PLUGINS_VAR=install_dll_plugins + WIN32_DLL_IMPORT_LIB="dllexports.a" + LINK_DLL="\$(CXX) \$(CXXFLAGS) -shared -o \$@" + else + if test "$with_win32" != yes; then + LIBS="$LIBS -lcomctl32" + fi + fi + DIALOG_OBJS="win32dialog.o win32paramdlg.o scrollwin.o" + EXPORT_DYNAMIC="" + ;; +esac +AC_SUBST(DIALOG_OBJS) +AC_SUBST(EXPORT_DYNAMIC) + +if test "$use_curses" = yes -a "$cross_configure" = 0; then + AC_CHECK_LIB(curses, mvaddch, GUI_LINK_OPTS_TERM='-lcurses') + AC_CHECK_LIB(ncurses, mvaddch, GUI_LINK_OPTS_TERM='-lncurses') + AC_CHECK_LIB(termlib, mvaddch, GUI_LINK_OPTS_TERM='-ltermlib') + AC_CHECK_LIB(pdcurses, mvaddch, GUI_LINK_OPTS_TERM='-lpdcurses') + if test "$GUI_LINK_OPTS_TERM" = ""; then + echo Curses library not found: tried curses, ncurses, termlib and pdcurses. + exit 1 + fi +fi + +if test "$with_term" = yes; then + old_LIBS="$LIBS" + LIBS="$LIBS $GUI_LINK_OPTS_TERM" + AC_CHECK_FUNCS(color_set, AC_DEFINE(BX_HAVE_COLOR_SET, 1)) + AC_CHECK_FUNCS(mvhline, AC_DEFINE(BX_HAVE_MVHLINE, 1)) + AC_CHECK_FUNCS(mvvline, AC_DEFINE(BX_HAVE_MVVLINE, 1)) + LIBS="$old_LIBS" +fi + +if test "$with_rfb" = yes; then + # we need the socket function + case $target in + *-pc-windows* | *-pc-winnt*) + RFB_LIBS="$RFB_LIBS ws2_32.lib" + have_socket=yes + ;; + *-mingw32*) + RFB_LIBS="$RFB_LIBS -lws2_32" + have_socket=yes + ;; + *-cygwin*) + # is this okay without a check ? + have_socket=yes + ;; + *) + AC_CHECK_FUNCS(socket, have_socket=yes) + if test "$have_socket" != yes; then + AC_CHECK_LIB(socket, socket, + [ + RFB_LIBS="$RFB_LIBS -lsocket" + have_socket=yes + ]) + fi + ;; + esac + if test "$have_socket" != yes; then + echo 'ERROR: socket function required for RFB compile' + exit 1 + fi +fi + +# The ACX_PTHREAD function was written by +# Steven G. Johnson and +# Alejandro Forero Cuervo +# I found it in the ac-archive project on Source Forge. + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +acx_pthread_ok=no + +# First, check if the POSIX threads header, pthread.h, is available. +# If it isn't, don't bother looking for the threads libraries. +AC_CHECK_HEADER(pthread.h, , acx_pthread_ok=noheader) + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *solaris* | alpha*-osf*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi + +])dnl ACX_PTHREAD + +pthread_ok=no +ACX_PTHREAD([ + pthread_ok=yes + #echo Using PTHREAD_LIBS=$PTHREAD_LIBS + #echo Using PTHREAD_CFLAGS=$PTHREAD_CFLAGS + #echo Using PTHREAD_CC=$PTHREAD_CC + ]) + + +# since some features need the pthread library, check that it was found. +# But on win32 platforms, the pthread library is not needed. +if test "$cross_configure" = 0; then + # assuming that the GUI debuggers require pthreads or are for Win32 + if test "$pthread_ok" = yes; then + if test "$with_rfb" = yes; then + RFB_LIBS="$RFB_LIBS $PTHREAD_LIBS" + fi + if test "$with_vncsrv" = yes; then + GUI_LINK_OPTS_VNCSRV="$GUI_LINK_OPTS_VNCSRV $PTHREAD_LIBS" + fi + if test "$soundcard_present" = 1; then + if test "$bx_plugins" = 1; then + SOUND_LINK_OPTS="$SOUND_LINK_OPTS $PTHREAD_LIBS" + else + DEVICE_LINK_OPTS="$DEVICE_LINK_OPTS $PTHREAD_LIBS" + fi + fi + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" + CC="$PTHREAD_CC" + else + case "$target" in + *-pc-windows* | *-pc-winnt* | *-cygwin* | *-mingw32*) + # pthread not needed for win32 platform + ;; + *) + echo ERROR: the pthread library is required, but could not be found.; exit 1 + esac + fi +fi + +dnl // DEPRECATED configure options - force users to remove them + +dnl AC_MSG_CHECKING(for misaligned SSE support (deprecated)) +dnl AC_ARG_ENABLE(misaligned-sse, +dnl AS_HELP_STRING([--enable-misaligned-sse], [misaligned SSE support (deprecated)]), +dnl [AC_MSG_RESULT($enableval) +dnl AC_MSG_ERROR([DEPRECATED - moved to runtime .bochsrc option]) +dnl ], +dnl [ +dnl AC_MSG_RESULT(no) +dnl ]) + +# Create some subdirectories for when you run configure from some other +# directory (part #1). +if test ! -d instrument; then mkdir instrument; fi +if test ! -d build; then mkdir build; fi +if test ! -d build/linux; then mkdir build/linux; fi +if test ! -d build/win32; then mkdir build/win32; fi +if test ! -d build/win32/nsis; then mkdir build/win32/nsis; fi + +AC_SUBST(INSTALL_TARGET) +AC_SUBST(INSTALL_LIST_FOR_PLATFORM) +AC_SUBST(RFB_LIBS) +AC_SUBST(GUI_LINK_OPTS_VNCSRV) +AC_SUBST(GUI_LINK_OPTS_SDL) +AC_SUBST(GUI_LINK_OPTS_SDL2) +AC_SUBST(GUI_OBJS) +AC_SUBST(DEVICE_LINK_OPTS) +AC_SUBST(GUI_LINK_OPTS) +AC_SUBST(GUI_LINK_OPTS_TERM) +AC_SUBST(GUI_LINK_OPTS_WX) +AC_SUBST(DASH) +AC_SUBST(SLASH) +AC_SUBST(CXXFP) +AC_SUBST(CFP) +AC_SUBST(OFP) +AC_SUBST(MAKELIB) +AC_SUBST(RMCOMMAND) +AC_SUBST(LINK) +AC_SUBST(LINK_CONSOLE) +AC_SUBST(LINK_DLL) +AC_SUBST(LINK_VAR) +AC_SUBST(EXE) +AC_SUBST(PRIMARY_TARGET) +AC_SUBST(OPTIONAL_TARGET) +AC_SUBST(PLUGIN_LIBNAME_TRANSFORMATION) +AC_SUBST(COMMAND_SEPARATOR) +AC_SUBST(CD_UP_ONE) +AC_SUBST(CD_UP_TWO) +AC_SUBST(CD_UP_THREE) +AC_SUBST(VERSION) +AC_SUBST(VER_STRING) +AC_SUBST(WIN_VER_STRING) +AC_SUBST(REL_STRING) +AC_SUBST(EXTRA_LINK_OPTS) +AC_SUBST(GUI_NON_PLUGIN_OBJS) +AC_SUBST(GUI_PLUGIN_OBJS) +AC_SUBST(IODEV_NON_PLUGIN_OBJS) +AC_SUBST(IODEV_PLUGIN_OBJS) +AC_SUBST(IODEV_EXT_NON_PLUGIN_OBJS) +AC_SUBST(IODEV_EXT_PLUGIN_OBJS) +AC_SUBST(PLUGIN_VAR) +AC_SUBST(PLUGIN_LIB) +AC_SUBST(PLUGIN_TARGET) +AC_SUBST(PLUGIN_TARGET_2) +AC_SUBST(EXT_MSVC_DLL_RULES) +AC_SUBST(GUI_DLL_TARGETS) +AC_SUBST(IODEV_DLL_TARGETS) +AC_SUBST(WIN32_DLL_IMPORT_LIB) +AC_SUBST(INSTALL_PLUGINS_VAR) + +AC_PATH_PROG(GZIP, gzip) +AC_PATH_PROG(TAR, tar) + +AC_OUTPUT(Makefile iodev/Makefile iodev/display/Makefile iodev/hdimage/Makefile \ + iodev/usb/Makefile iodev/network/Makefile iodev/sound/Makefile \ + bx_debug/Makefile bios/Makefile cpu/Makefile cpu/avx/Makefile \ + cpu/cpudb/Makefile cpu/fpu/Makefile memory/Makefile gui/Makefile \ + disasm/Makefile ${INSTRUMENT_DIR}/Makefile misc/Makefile \ + doc/docbook/Makefile build/linux/bochs-dlx bxversion.h bxversion.rc \ + build/macosx/Info.plist build/win32/nsis/Makefile \ + build/win32/nsis/bochs.nsi host/linux/pcidev/Makefile ${USER_PLUGINS_MAKEFILE}) + +# Create some subdirectories for when you run configure from some other +# directory (part #2). +if test ! -d cpu/cpudb/amd; then mkdir cpu/cpudb/amd; fi +if test ! -d cpu/cpudb/intel; then mkdir cpu/cpudb/intel; fi +if test ! -d cpu/decoder; then mkdir cpu/decoder; fi +if test ! -d iodev/network/slirp; then mkdir iodev/network/slirp; fi diff --git a/ports/bochs/essence.cc b/ports/bochs/essence.cc new file mode 100644 index 0000000..6b757a3 --- /dev/null +++ b/ports/bochs/essence.cc @@ -0,0 +1,478 @@ +// added by nakst. + +/* +TODO +clipboard, headerbar, new graphics layer +scroll, +timing/signals + +mouse grab, +move mouse, +mouse buttons, +*/ + +#define BX_PLUGGABLE + +#include "bochs.h" +#include "plugin.h" +#include "param_names.h" +#include "iodev.h" + +#if BX_WITH_ESSENCE +#include "icon_bochs.h" + +// For the VGA font. +#include "sdl.h" + +#define LOG_THIS theGui-> + +#define ES_INSTANCE_TYPE Instance +#include + +class bx_essence_gui_c : public bx_gui_c { +public: + bx_essence_gui_c (void) {} + DECLARE_GUI_VIRTUAL_METHODS() +}; + +// declare one instance of the gui object and call macro to insert the +// plugin code +static bx_essence_gui_c *theGui = NULL; +IMPLEMENT_GUI_PLUGIN_CODE(essence) + +struct Instance : EsInstance { + EsElement *display; + uint32_t *vmem; + int vmemWidth, vmemHeight; +}; + +extern bx_startup_flags_t bx_startup_flags; +EsHandle openEvent; +Instance *instance; +char *configurationFile; + +#define MAX_VGA_COLORS 256 +unsigned long col_vals[MAX_VGA_COLORS]; // 256 VGA colors +int text_cols, text_rows; + +volatile bool repaintQueued; + +void QueueRepaint() { + EsMessageMutexAcquire(); + + if (!repaintQueued) { + repaintQueued = true; + EsElementRepaint(instance->display, true, {}); + } + + EsMessageMutexRelease(); +} + +uint32_t ConvertScancode(uint32_t scancode) { + switch (scancode) { + case ES_SCANCODE_0: scancode = BX_KEY_0; break; + case ES_SCANCODE_1: scancode = BX_KEY_1; break; + case ES_SCANCODE_2: scancode = BX_KEY_2; break; + case ES_SCANCODE_3: scancode = BX_KEY_3; break; + case ES_SCANCODE_4: scancode = BX_KEY_4; break; + case ES_SCANCODE_5: scancode = BX_KEY_5; break; + case ES_SCANCODE_6: scancode = BX_KEY_6; break; + case ES_SCANCODE_7: scancode = BX_KEY_7; break; + case ES_SCANCODE_8: scancode = BX_KEY_8; break; + case ES_SCANCODE_9: scancode = BX_KEY_9; break; + case ES_SCANCODE_A: scancode = BX_KEY_A; break; + case ES_SCANCODE_B: scancode = BX_KEY_B; break; + case ES_SCANCODE_PUNCTUATION_1: scancode = BX_KEY_BACKSLASH; break; + case ES_SCANCODE_BACKSPACE: scancode = BX_KEY_BACKSPACE; break; + case ES_SCANCODE_C: scancode = BX_KEY_C; break; + case ES_SCANCODE_CAPS_LOCK: scancode = BX_KEY_CAPS_LOCK; break; + case ES_SCANCODE_COMMA: scancode = BX_KEY_COMMA; break; + case ES_SCANCODE_D: scancode = BX_KEY_D; break; + case ES_SCANCODE_DELETE: scancode = BX_KEY_DELETE; break; + case ES_SCANCODE_DOWN_ARROW: scancode = BX_KEY_DOWN; break; + case ES_SCANCODE_E: scancode = BX_KEY_E; break; + case ES_SCANCODE_END: scancode = BX_KEY_END; break; + case ES_SCANCODE_ENTER: scancode = BX_KEY_ENTER; break; + case ES_SCANCODE_EQUALS: scancode = BX_KEY_EQUALS; break; + case ES_SCANCODE_ESCAPE: scancode = BX_KEY_ESC; break; + case ES_SCANCODE_F: scancode = BX_KEY_F; break; + case ES_SCANCODE_F1: scancode = BX_KEY_F1; break; + case ES_SCANCODE_F10: scancode = BX_KEY_F10; break; + case ES_SCANCODE_F11: scancode = BX_KEY_F11; break; + case ES_SCANCODE_F12: scancode = BX_KEY_F12; break; + case ES_SCANCODE_F2: scancode = BX_KEY_F2; break; + case ES_SCANCODE_F3: scancode = BX_KEY_F3; break; + case ES_SCANCODE_F4: scancode = BX_KEY_F4; break; + case ES_SCANCODE_F5: scancode = BX_KEY_F5; break; + case ES_SCANCODE_F6: scancode = BX_KEY_F6; break; + case ES_SCANCODE_F7: scancode = BX_KEY_F7; break; + case ES_SCANCODE_F8: scancode = BX_KEY_F8; break; + case ES_SCANCODE_F9: scancode = BX_KEY_F9; break; + case ES_SCANCODE_G: scancode = BX_KEY_G; break; + case ES_SCANCODE_H: scancode = BX_KEY_H; break; + case ES_SCANCODE_HOME: scancode = BX_KEY_HOME; break; + case ES_SCANCODE_I: scancode = BX_KEY_I; break; + case ES_SCANCODE_INSERT: scancode = BX_KEY_INSERT; break; + case ES_SCANCODE_J: scancode = BX_KEY_J; break; + case ES_SCANCODE_K: scancode = BX_KEY_K; break; + case ES_SCANCODE_L: scancode = BX_KEY_L; break; + case ES_SCANCODE_M: scancode = BX_KEY_M; break; + case ES_SCANCODE_N: scancode = BX_KEY_N; break; + case ES_SCANCODE_O: scancode = BX_KEY_O; break; + case ES_SCANCODE_P: scancode = BX_KEY_P; break; + case ES_SCANCODE_PAGE_DOWN: scancode = BX_KEY_PAGE_DOWN; break; + case ES_SCANCODE_PAGE_UP: scancode = BX_KEY_PAGE_UP; break; + case ES_SCANCODE_PAUSE: scancode = BX_KEY_PAUSE; break; + case ES_SCANCODE_PERIOD: scancode = BX_KEY_PERIOD; break; + case ES_SCANCODE_PRINT_SCREEN: scancode = BX_KEY_PRINT; break; + case ES_SCANCODE_Q: scancode = BX_KEY_Q; break; + case ES_SCANCODE_R: scancode = BX_KEY_R; break; + case ES_SCANCODE_S: scancode = BX_KEY_S; break; + case ES_SCANCODE_SCROLL_LOCK: scancode = BX_KEY_SCRL_LOCK; break; + case ES_SCANCODE_PUNCTUATION_3: scancode = BX_KEY_SEMICOLON; break; + case ES_SCANCODE_SLASH: scancode = BX_KEY_SLASH; break; + case ES_SCANCODE_SPACE: scancode = BX_KEY_SPACE; break; + case ES_SCANCODE_T: scancode = BX_KEY_T; break; + case ES_SCANCODE_TAB: scancode = BX_KEY_TAB; break; + case ES_SCANCODE_U: scancode = BX_KEY_U; break; + case ES_SCANCODE_UP_ARROW: scancode = BX_KEY_UP; break; + case ES_SCANCODE_V: scancode = BX_KEY_V; break; + case ES_SCANCODE_W: scancode = BX_KEY_W; break; + case ES_SCANCODE_X: scancode = BX_KEY_X; break; + case ES_SCANCODE_Y: scancode = BX_KEY_Y; break; + case ES_SCANCODE_Z: scancode = BX_KEY_Z; break; + case ES_SCANCODE_NUM_0: scancode = BX_KEY_KP_INSERT; break; + case ES_SCANCODE_NUM_1: scancode = BX_KEY_KP_END; break; + case ES_SCANCODE_NUM_2: scancode = BX_KEY_KP_DOWN; break; + case ES_SCANCODE_NUM_3: scancode = BX_KEY_KP_PAGE_DOWN; break; + case ES_SCANCODE_NUM_4: scancode = BX_KEY_KP_LEFT; break; + case ES_SCANCODE_NUM_5: scancode = BX_KEY_KP_5; break; + case ES_SCANCODE_NUM_6: scancode = BX_KEY_KP_RIGHT; break; + case ES_SCANCODE_NUM_7: scancode = BX_KEY_KP_HOME; break; + case ES_SCANCODE_NUM_8: scancode = BX_KEY_KP_UP; break; + case ES_SCANCODE_NUM_9: scancode = BX_KEY_KP_PAGE_UP; break; + case ES_SCANCODE_NUM_ADD: scancode = BX_KEY_KP_ADD; break; + case ES_SCANCODE_NUM_DIVIDE: scancode = BX_KEY_KP_DIVIDE; break; + case ES_SCANCODE_NUM_ENTER: scancode = BX_KEY_KP_ENTER; break; + case ES_SCANCODE_NUM_LOCK: scancode = BX_KEY_NUM_LOCK; break; + case ES_SCANCODE_NUM_MULTIPLY: scancode = BX_KEY_KP_MULTIPLY; break; + case ES_SCANCODE_NUM_POINT: scancode = BX_KEY_KP_DELETE; break; + case ES_SCANCODE_NUM_SUBTRACT: scancode = BX_KEY_KP_SUBTRACT; break; + case ES_SCANCODE_WWW_BACK: scancode = BX_KEY_INT_BACK; break; + case ES_SCANCODE_WWW_STARRED: scancode = BX_KEY_INT_FAV; break; + case ES_SCANCODE_WWW_FORWARD: scancode = BX_KEY_INT_FORWARD; break; + case ES_SCANCODE_WWW_HOME: scancode = BX_KEY_INT_HOME; break; + case ES_SCANCODE_MM_EMAIL: scancode = BX_KEY_INT_MAIL; break; + case ES_SCANCODE_WWW_SEARCH: scancode = BX_KEY_INT_SEARCH; break; + case ES_SCANCODE_WWW_STOP: scancode = BX_KEY_INT_STOP; break; + case ES_SCANCODE_MM_CALC: scancode = BX_KEY_POWER_CALC; break; + case ES_SCANCODE_MM_FILES: scancode = BX_KEY_POWER_MYCOMP; break; + case ES_SCANCODE_ACPI_POWER: scancode = BX_KEY_POWER_POWER; break; + case ES_SCANCODE_ACPI_SLEEP: scancode = BX_KEY_POWER_SLEEP; break; + case ES_SCANCODE_ACPI_WAKE: scancode = BX_KEY_POWER_WAKE; break; + case ES_SCANCODE_LEFT_ALT: scancode = BX_KEY_ALT_L; break; + case ES_SCANCODE_LEFT_ARROW: scancode = BX_KEY_LEFT; break; + case ES_SCANCODE_LEFT_BRACE: scancode = BX_KEY_LEFT_BRACKET; break; + case ES_SCANCODE_LEFT_CTRL: scancode = BX_KEY_CTRL_L; break; + case ES_SCANCODE_LEFT_FLAG: scancode = BX_KEY_WIN_L; break; + case ES_SCANCODE_LEFT_SHIFT: scancode = BX_KEY_SHIFT_L; break; + case ES_SCANCODE_RIGHT_ALT: scancode = BX_KEY_ALT_R; break; + case ES_SCANCODE_RIGHT_ARROW: scancode = BX_KEY_RIGHT; break; + case ES_SCANCODE_RIGHT_BRACE: scancode = BX_KEY_RIGHT_BRACKET; break; + case ES_SCANCODE_RIGHT_CTRL: scancode = BX_KEY_CTRL_R; break; + case ES_SCANCODE_RIGHT_SHIFT: scancode = BX_KEY_SHIFT_R; break; + case ES_SCANCODE_CONTEXT_MENU: scancode = BX_KEY_MENU; break; + case ES_SCANCODE_PUNCTUATION_5: scancode = BX_KEY_GRAVE; break; + case ES_SCANCODE_HYPHEN: scancode = BX_KEY_MINUS; break; + case ES_SCANCODE_PUNCTUATION_4: scancode = BX_KEY_SINGLE_QUOTE; break; + } + + return scancode; +} + +int CanvasCallback(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_PAINT) { + int ox = message->painter->width / 2 - instance->vmemWidth / 2; + int oy = message->painter->height / 2 - instance->vmemHeight / 2; + EsRectangle bounds = { ox, ox + instance->vmemWidth, oy, oy + instance->vmemHeight }; + EsDrawBitmap(message->painter, bounds, instance->vmem, instance->vmemWidth * 4, 0xFFFF); + repaintQueued = false; + } else if (message->type == ES_MSG_KEY_DOWN) { + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_CTRL) { + theGui->toggle_mouse_enable(); + } else { + DEV_kbd_gen_scancode(ConvertScancode(message->keyboard.scancode)); + } + } else if (message->type == ES_MSG_KEY_UP) { + if (message->keyboard.scancode == ES_SCANCODE_RIGHT_CTRL) { + } else { + DEV_kbd_gen_scancode(ConvertScancode(message->keyboard.scancode) | BX_KEY_RELEASED); + } + } else { + return 0; + } + + return ES_HANDLED; +} + +void SetDimensions(int width, int height) { + instance->vmemWidth = width; + instance->vmemHeight = height; + instance->vmem = (uint32_t *) EsHeapReallocate(instance->vmem, width * height * 4, true); + EsElementRepaint(instance->display, true, {}); +} + +void MessageLoopThread(EsGeneric) { + EsPrint("Reached message loop thread...\n"); + EsMessageMutexAcquire(); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + instance = EsInstanceCreate(message, "Bochs"); + EsWindowSetTitle(instance->window, "Bochs", -1); + EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_DEVELOPMENT); + instance->display = EsCustomElementCreate(instance->window, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE); + instance->display->messageUser = CanvasCallback; + SetDimensions(640, 480); + } else if (message->type == ES_MSG_INSTANCE_OPEN) { + size_t fileSize; + char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize); + + if (!file) { + EsInstanceOpenComplete(message, false); + } else { + FILE *f = fopen(configurationFile, "wb"); + fwrite(file, 1, fileSize, f); + fclose(f); + EsEventSet(openEvent); + EsInstanceOpenComplete(message, true); + } + } else if (message->type == ES_MSG_INSTANCE_DESTROY) { + // TODO Tell the emulator to stop. + unlink(configurationFile); + } + } +} + +void bx_essence_gui_c::specific_init(int argc, char **argv, unsigned headerbar_y) +{ + put("ESSENCE"); + EsPrint("Starting Essence GUI...\n"); + + for(int i=0;i<256;i++) for(int j=0;j<16;j++) vga_charmap[i*32+j] = sdl_font8x16[i][j]; +} + +void bx_essence_gui_c::handle_events(void) +{ + // We handle events on a separate thread. +} + +void bx_essence_gui_c::flush(void) +{ + QueueRepaint(); +} + +void bx_essence_gui_c::clear_screen(void) +{ + EsMemoryZero(instance->vmem, instance->vmemWidth * 4 * guest_yres); + QueueRepaint(); +} + +static unsigned prev_cursor_x=0; +static unsigned prev_cursor_y=0; + +void bx_essence_gui_c::text_update(Bit8u *old_text, Bit8u *new_text, + unsigned long cursor_x, unsigned long cursor_y, + bx_vga_tminfo_t *tm_info) +{ + uint32_t text_palette[16]; + + for (int i=0; i<16; i++) { + text_palette[i] = col_vals[tm_info->actl_palette[i]]; + } + + int left = text_cols, right = 0, top = text_rows, bottom = 0; + + for (int j = 0; j < text_rows; j++) { + for (int i = 0; i < text_cols; i++) { + if (old_text[0] != new_text[0] || old_text[1] != new_text[1] || (prev_cursor_x == i && prev_cursor_y == j) || (cursor_x == i && cursor_y == j)) { + if (i < left) left = i; + if (i < top) top = i; + if (i > right) right = i; + if (i > bottom) bottom = i; + + bool cursorHere = (cursor_x == i && cursor_y == j); + uint32_t foreground, background; + + if (cursorHere) { + foreground = text_palette[new_text[1] >> 4], background = text_palette[new_text[1] & 0x0F]; + } else { + foreground = text_palette[new_text[1] & 0x0F], background = text_palette[new_text[1] >> 4]; + } + + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 9; x++) { + instance->vmem[guest_xres * (y + j * 16) + (x + i * 9)] + = (x != 9 && (vga_charmap[new_text[0] * 32 + y] & (1 << (7 - x)))) + ? foreground : background; + } + } + } + + old_text += 2; + new_text += 2; + } + } + + QueueRepaint(); + prev_cursor_x = cursor_x; + prev_cursor_y = cursor_y; +} + +int bx_essence_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes) +{ + // TODO. + UNUSED(bytes); + UNUSED(nbytes); + return 0; +} + +int bx_essence_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len) +{ + // TODO. + UNUSED(text_snapshot); + UNUSED(len); + return 0; +} + +bx_bool bx_essence_gui_c::palette_change(Bit8u index, Bit8u red, Bit8u green, Bit8u blue) +{ + col_vals[index] = (red << 16) | (green << 8) | blue; + return 1; +} + +void bx_essence_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0) +{ + unsigned x, y, x_size, y_size; + unsigned color, offset; + + if ((x0 + x_tilesize) > guest_xres) { + x_size = guest_xres - x0; + } else { + x_size = x_tilesize; + } + + if ((y0 + y_tilesize) > guest_yres) { + y_size = guest_yres - y0; + } else { + y_size = y_tilesize; + } + + switch (guest_bpp) { + case 8: // 8 bits per pixel + for (y=0; yvmem[guest_xres * (y + y0) + (x + x0)] = color; + } + } + break; + default: + BX_PANIC(("X_graphics_tile_update: bits_per_pixel %u handled by new graphics API", + (unsigned) guest_bpp)); + return; + } + + QueueRepaint(); +} + +void bx_essence_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp) +{ + guest_textmode = (fheight > 0); + guest_xres = x; + guest_yres = y; + guest_bpp = bpp; + if (guest_textmode) { + text_cols = guest_xres / fwidth; + text_rows = guest_yres / fheight; + } + EsPrint("dimension_update: %d, %d, %d, %d, %d\n", x, y, fwidth, fheight, bpp); + EsMessageMutexAcquire(); + SetDimensions(x, y); + EsMessageMutexRelease(); +} + +unsigned bx_essence_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim) +{ + // TODO. + UNUSED(bmap); + UNUSED(xdim); + UNUSED(ydim); + return(0); +} + +unsigned bx_essence_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void)) +{ + // TODO. + UNUSED(bmap_id); + UNUSED(alignment); + UNUSED(f); + return(0); +} + +void bx_essence_gui_c::show_headerbar(void) +{ + // TODO. +} + +void bx_essence_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id) +{ + // TODO. + UNUSED(hbar_id); + UNUSED(bmap_id); +} + +void bx_essence_gui_c::exit(void) +{ + // We don't need to do anything. +} + +void bx_essence_gui_c::mouse_enabled_changed_specific(bx_bool val) +{ + // TODO. +} + +int bxmain(); + +int main() { +#if 1 + int output = open("bochs_output.txt", O_WRONLY | O_CREAT); + dup2(output, 1); + dup2(output, 2); + printf("in main()...\n"); + const char *temporaryFolder = getenv("TMPDIR"); + configurationFile = (char *) malloc(strlen(temporaryFolder) + 32); + strcpy(configurationFile, temporaryFolder); + strcat(configurationFile, "/"); + char *_argv[] = { "bochs", "-f", configurationFile, "-q" }; + size_t offset = strlen(configurationFile); + for (int i = 0; i < 8; i++) configurationFile[i + offset] = (EsRandomU8() % 26) + 'a'; + configurationFile[offset + 8] = 0; + strcat(configurationFile, ".txt"); + bx_startup_flags.argc = 4; + bx_startup_flags.argv = _argv; + openEvent = EsEventCreate(true); + EsMessageMutexRelease(); + EsThreadCreate(MessageLoopThread, nullptr, 0); + EsWaitSingle(openEvent); +#else + char *_argv[] = { "bochs" }; + bx_startup_flags.argc = 1; + bx_startup_flags.argv = _argv; +#endif + return bxmain(); +} + +#endif /* if BX_WITH_ESSENCE */ diff --git a/ports/bochs/gui_Makefile.in b/ports/bochs/gui_Makefile.in new file mode 100644 index 0000000..fe3b8d6 --- /dev/null +++ b/ports/bochs/gui_Makefile.in @@ -0,0 +1,443 @@ +# Copyright (C) 2001-2014 The Bochs Project +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Makefile for the gui component of bochs + + +@SUFFIX_LINE@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +srcdir = @srcdir@ +VPATH = @srcdir@ +bindir = @bindir@ +libdir = @libdir@ +datarootdir = @datarootdir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man5dir = $(mandir)/man5 +docdir = $(datarootdir)/doc/bochs +sharedir = $(datarootdir)/bochs +top_builddir = .. +top_srcdir = @top_srcdir@ + +SHELL = @SHELL@ + +@SET_MAKE@ + +CXX = @CXX@ +CXXFLAGS = $(BX_INCDIRS) @CXXFLAGS@ @GUI_CXXFLAGS@ +LOCAL_CXXFLAGS = @TOOLKIT_CXXFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +RANLIB = @RANLIB@ +PLUGIN_PATH=@libdir@ +top_builddir = .. +LIBTOOL=@LIBTOOL@ +WIN32_DLL_IMPORT_LIBRARY=../@WIN32_DLL_IMPORT_LIB@ +BX_INCDIRS = -I.. -I$(srcdir)/.. -I../iodev -I$(srcdir)/../iodev -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@ + +GUI_OBJS_X11 = x.o +GUI_OBJS_SDL = sdl.o +GUI_OBJS_SDL2 = sdl2.o +GUI_OBJS_SVGA = svga.o +GUI_OBJS_WIN32 = win32.o +GUI_OBJS_MACOS = macintosh.o +GUI_OBJS_CARBON = carbon.o +GUI_OBJS_NOGUI = nogui.o +GUI_OBJS_ESSENCE = essence.o +GUI_OBJS_TERM = term.o +GUI_OBJS_RFB = rfb.o +GUI_OBJS_VNCSRV = vncsrv.o +GUI_OBJS_AMIGAOS = amigaos.o +GUI_OBJS_WX = wx.o +GUI_OBJS_WX_SUPPORT = wxmain.o wxdialog.o + +GUI_DLL_TARGETS = @GUI_DLL_TARGETS@ +OBJS_THAT_CANNOT_BE_PLUGINS = keymap.o gui.o siminterface.o paramtree.o textconfig.o @ENH_DBG_OBJS@ @DIALOG_OBJS@ +OBJS_THAT_CAN_BE_PLUGINS = @GUI_OBJS@ + +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +GUI_LINK_OPTS_X = $(X_LIBS) $(X_PRE_LIBS) +GUI_LINK_OPTS_SDL = @GUI_LINK_OPTS_SDL@ +GUI_LINK_OPTS_SDL2 = @GUI_LINK_OPTS_SDL2@ +GUI_LINK_OPTS_SVGA = -lvga -lvgagl +GUI_LINK_OPTS_RFB = @RFB_LIBS@ +GUI_LINK_OPTS_RFB_VCPP = user32.lib @RFB_LIBS@ +GUI_LINK_OPTS_VNCSRV = @GUI_LINK_OPTS_VNCSRV@ +GUI_LINK_OPTS_AMIGAOS = +GUI_LINK_OPTS_WIN32 = -luser32 -lgdi32 -lcomdlg32 -lcomctl32 +GUI_LINK_OPTS_WIN32_VCPP = user32.lib gdi32.lib winmm.lib comdlg32.lib comctl32.lib +GUI_LINK_OPTS_MACOS = +GUI_LINK_OPTS_CARBON = -framework Carbon +GUI_LINK_OPTS_NOGUI = +GUI_LINK_OPTS_ESSENCE = +GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@ +GUI_LINK_OPTS_WX = @GUI_LINK_OPTS_WX@ +GUI_LINK_OPTS = @GUI_LINK_OPTS@ @DEVICE_LINK_OPTS@ + +NONPLUGIN_OBJS = @GUI_NON_PLUGIN_OBJS@ +PLUGIN_OBJS = @GUI_PLUGIN_OBJS@ + +# +# -------- end configurable options -------------------------- +# + +all: libgui.a + +plugins: @PLUGIN_TARGET_2@ + +plugins_gcc: $(PLUGIN_OBJS:@PLUGIN_LIBNAME_TRANSFORMATION@) + +plugins_msvc: $(GUI_DLL_TARGETS) + +libgui.a: $(NONPLUGIN_OBJS) + @RMCOMMAND@ libgui.a + @MAKELIB@ $(NONPLUGIN_OBJS) + $(RANLIB) libgui.a + +# standard compile rule for C++ files +.@CPP_SUFFIX@.o: + $(CXX) @DASH@c $(CXXFLAGS) $(LOCAL_CXXFLAGS) @CXXFP@$< @OFP@$@ + +##### building plugins with libtool +%.lo: %.@CPP_SUFFIX@ + $(LIBTOOL) --mode=compile --tag CXX $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $< -o $@ + +libbx_%.la: %.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) + +libbx_x.la: x.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_X) + +libbx_sdl.la: sdl.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_SDL) + +libbx_sdl2.la: sdl2.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_SDL2) + +libbx_svga.la: svga.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_SVGA) + +libbx_rfb.la: rfb.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_RFB) + +libbx_vncsrv.la: vncsrv.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_VNCSRV) + +libbx_amigaos.la: amigaos.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_AMIGAOS) + +libbx_win32.la: win32.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_WIN32) + +libbx_macos.la: macos.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_MACOS) + +libbx_carbon.la: carbon.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_CARBON) + +libbx_nogui.la: nogui.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_NOGUI) + +libbx_essence.la: essence.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_ESSENCE) + +libbx_term.la: term.lo + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_TERM) + +# special link rules for plugins that require more than one object file +libbx_wx.la: $(GUI_OBJS_WX:.o=.lo) $(GUI_OBJS_WX_SUPPORT:.o=.lo) + $(LIBTOOL) --mode=link --tag CXX $(CXX) -module $(GUI_OBJS_WX:.o=.lo) $(GUI_OBJS_WX_SUPPORT:.o=.lo) -o libbx_wx.la -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_WX) + +#### building DLLs for win32 (Cygwin and MinGW/MSYS) +bx_%.dll: %.o + $(CXX) $(CXXFLAGS) -shared -o $@ $< $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_WIN32) + +bx_wx.dll: $(GUI_OBJS_WX) $(GUI_OBJS_WX_SUPPORT) + $(CXX) $(CXXFLAGS) -shared -o bx_wx.dll $(GUI_OBJS_WX) $(GUI_OBJS_WX_SUPPORT) $(WIN32_DLL_IMPORT_LIBRARY) `wx-config --libs` -luser32 -lgdi32 -lcomdlg32 -lcomctl32 + +bx_sdl.dll: $(GUI_OBJS_SDL) + $(CXX) $(CXXFLAGS) -shared -o bx_sdl.dll $(GUI_OBJS_SDL) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_SDL) + +bx_sdl2.dll: $(GUI_OBJS_SDL2) + $(CXX) $(CXXFLAGS) -shared -o bx_sdl2.dll $(GUI_OBJS_SDL2) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_SDL2) + +bx_vncsrv.dll: $(GUI_OBJS_VNCSRV) + $(CXX) $(CXXFLAGS) -shared -o bx_vncsrv.dll $(GUI_OBJS_VNCSRV) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_VNCSRV) + +# special link rules for plugins with Cygwin, MinGW/MSYS and MSVC nmake +bx_nogui.dll: $(GUI_OBJS_NOGUI) + @LINK_DLL@ $(GUI_OBJS_NOGUI) $(WIN32_DLL_IMPORT_LIBRARY) + +bx_essence.dll: $(GUI_OBJS_ESSENCE) + @LINK_DLL@ $(GUI_OBJS_ESSENCE) $(WIN32_DLL_IMPORT_LIBRARY) + +bx_rfb.dll: $(GUI_OBJS_RFB) + @LINK_DLL@ $(GUI_OBJS_RFB) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_RFB@LINK_VAR@) + +bx_win32.dll: $(GUI_OBJS_WIN32) + @LINK_DLL@ $(GUI_OBJS_WIN32) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_WIN32@LINK_VAR@) + +##### end DLL section + +clean: + @RMCOMMAND@ -rf .libs *.la *.a *.lo *.o *.dll *.exp *.lib + +dist-clean: clean + @RMCOMMAND@ Makefile + +########################################### +# all other dependencies generated by +# gcc -MM -I.. -I../iodev -I../instrument/stubs *.cc | \ +# sed -e 's/\.cc/.@CPP_SUFFIX@/g' +# gcc -MM -I.. -I../iodev -I../instrument/stubs *.cc | \ +# sed -e 's/\.cc/.@CPP_SUFFIX@/g' -e 's/\.o:/.lo:/g' +# +# This means that every source file is listed twice, once with a .o rule +# and then again with an identical .lo rule. The .lo rules are used when +# building plugins. +########################################### +amigaos.o: amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \ + ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \ + ../gui/gui.h ../instrument/stubs/instrument.h ../bxversion.h \ + ../param_names.h ../iodev/iodev.h ../plugin.h ../extplugin.h +carbon.o: carbon.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h keymap.h ../iodev/iodev.h ../plugin.h \ + ../extplugin.h ../param_names.h +essence.o: essence.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \ + ../param_names.h icon_bochs.h +enh_dbg.o: enh_dbg.@CPP_SUFFIX@ ../config.h +gtk_enh_dbg_osdep.o: gtk_enh_dbg_osdep.@CPP_SUFFIX@ ../config.h +gui.o: gui.@CPP_SUFFIX@ ../iodev/iodev.h ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \ + ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \ + ../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \ + ../param_names.h ../iodev/virt_timer.h keymap.h ../gui/bitmaps/floppya.h \ + ../gui/bitmaps/floppyb.h ../gui/bitmaps/mouse.h ../gui/bitmaps/reset.h \ + ../gui/bitmaps/power.h ../gui/bitmaps/snapshot.h ../gui/bitmaps/copy.h \ + ../gui/bitmaps/paste.h ../gui/bitmaps/configbutton.h \ + ../gui/bitmaps/cdromd.h ../gui/bitmaps/userbutton.h \ + ../gui/bitmaps/saverestore.h +keymap.o: keymap.@CPP_SUFFIX@ ../param_names.h ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \ + ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \ + ../gui/gui.h ../instrument/stubs/instrument.h keymap.h +macintosh.o: macintosh.@CPP_SUFFIX@ ../param_names.h ../bochs.h ../config.h \ + ../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h \ + ../pc_system.h ../gui/gui.h ../instrument/stubs/instrument.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h +nogui.o: nogui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \ + ../param_names.h icon_bochs.h +paramtree.o: paramtree.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \ + ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \ + ../gui/gui.h ../instrument/stubs/instrument.h paramtree.h +rfb.o: rfb.@CPP_SUFFIX@ ../param_names.h ../iodev/iodev.h ../bochs.h ../config.h \ + ../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h \ + ../pc_system.h ../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h \ + ../extplugin.h keymap.h icon_bochs.h font/vga.bitmap.h sdl.h rfb.h \ + rfbkeys.h +scrollwin.o: scrollwin.@CPP_SUFFIX@ ../config.h +sdl2.o: sdl2.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h +sdl.o: sdl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h icon_bochs.h sdl.h sdlkeys.h +siminterface.o: siminterface.@CPP_SUFFIX@ ../param_names.h ../iodev/iodev.h \ + ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h ../config.h \ + ../osdep.h ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h \ + ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \ + ../iodev/virt_timer.h +svga.o: svga.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h ../iodev/iodev.h \ + ../plugin.h ../extplugin.h +term.o: term.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h ../iodev/iodev.h \ + ../plugin.h ../extplugin.h +textconfig.o: textconfig.@CPP_SUFFIX@ ../config.h ../osdep.h ../param_names.h \ + textconfig.h siminterface.h ../cpudb.h paramtree.h ../extplugin.h +vncsrv.o: vncsrv.@CPP_SUFFIX@ ../param_names.h ../iodev/iodev.h ../bochs.h \ + ../config.h ../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h \ + ../pc_system.h ../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h \ + ../extplugin.h keymap.h icon_bochs.h font/vga.bitmap.h sdl.h rfb.h \ + rfbkeys.h +win32.o: win32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h +win32dialog.o: win32dialog.@CPP_SUFFIX@ win32dialog.h ../config.h +win32_enh_dbg_osdep.o: win32_enh_dbg_osdep.@CPP_SUFFIX@ ../config.h +win32paramdlg.o: win32paramdlg.@CPP_SUFFIX@ win32dialog.h ../config.h +wx.o: wx.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h font/vga.bitmap.h wxmain.h +wxdialog.o: wxdialog.@CPP_SUFFIX@ ../config.h ../param_names.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../bxversion.h \ + wxdialog.h wxmain.h +wxmain.o: wxmain.@CPP_SUFFIX@ ../config.h ../param_names.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../bxversion.h \ + wxdialog.h wxmain.h ../extplugin.h bitmaps/cdromd.xpm bitmaps/copy.xpm \ + bitmaps/floppya.xpm bitmaps/floppyb.xpm bitmaps/paste.xpm \ + bitmaps/power.xpm bitmaps/reset.xpm bitmaps/snapshot.xpm \ + bitmaps/mouse.xpm bitmaps/userbutton.xpm bitmaps/saverestore.xpm +x.o: x.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h enh_dbg.h icon_bochs.xpm \ + font/vga.bitmap.h +amigaos.lo: amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \ + ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \ + ../gui/gui.h ../instrument/stubs/instrument.h ../bxversion.h \ + ../param_names.h ../iodev/iodev.h ../plugin.h ../extplugin.h +carbon.lo: carbon.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h keymap.h ../iodev/iodev.h ../plugin.h \ + ../extplugin.h ../param_names.h +essence.lo: essence.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \ + ../param_names.h icon_bochs.h +enh_dbg.lo: enh_dbg.@CPP_SUFFIX@ ../config.h +gtk_enh_dbg_osdep.lo: gtk_enh_dbg_osdep.@CPP_SUFFIX@ ../config.h +gui.lo: gui.@CPP_SUFFIX@ ../iodev/iodev.h ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \ + ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \ + ../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \ + ../param_names.h ../iodev/virt_timer.h keymap.h ../gui/bitmaps/floppya.h \ + ../gui/bitmaps/floppyb.h ../gui/bitmaps/mouse.h ../gui/bitmaps/reset.h \ + ../gui/bitmaps/power.h ../gui/bitmaps/snapshot.h ../gui/bitmaps/copy.h \ + ../gui/bitmaps/paste.h ../gui/bitmaps/configbutton.h \ + ../gui/bitmaps/cdromd.h ../gui/bitmaps/userbutton.h \ + ../gui/bitmaps/saverestore.h +keymap.lo: keymap.@CPP_SUFFIX@ ../param_names.h ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \ + ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \ + ../gui/gui.h ../instrument/stubs/instrument.h keymap.h +macintosh.lo: macintosh.@CPP_SUFFIX@ ../param_names.h ../bochs.h ../config.h \ + ../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h \ + ../pc_system.h ../gui/gui.h ../instrument/stubs/instrument.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h +nogui.lo: nogui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \ + ../param_names.h icon_bochs.h +paramtree.lo: paramtree.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \ + ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \ + ../gui/gui.h ../instrument/stubs/instrument.h paramtree.h +rfb.lo: rfb.@CPP_SUFFIX@ ../param_names.h ../iodev/iodev.h ../bochs.h ../config.h \ + ../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h \ + ../pc_system.h ../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h \ + ../extplugin.h keymap.h icon_bochs.h font/vga.bitmap.h sdl.h rfb.h \ + rfbkeys.h +scrollwin.lo: scrollwin.@CPP_SUFFIX@ ../config.h +sdl2.lo: sdl2.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h +sdl.lo: sdl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h icon_bochs.h sdl.h sdlkeys.h +siminterface.lo: siminterface.@CPP_SUFFIX@ ../param_names.h ../iodev/iodev.h \ + ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h ../config.h \ + ../osdep.h ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h \ + ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \ + ../iodev/virt_timer.h +svga.lo: svga.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h ../iodev/iodev.h \ + ../plugin.h ../extplugin.h +term.lo: term.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h ../iodev/iodev.h \ + ../plugin.h ../extplugin.h +textconfig.lo: textconfig.@CPP_SUFFIX@ ../config.h ../osdep.h ../param_names.h \ + textconfig.h siminterface.h ../cpudb.h paramtree.h ../extplugin.h +vncsrv.lo: vncsrv.@CPP_SUFFIX@ ../param_names.h ../iodev/iodev.h ../bochs.h \ + ../config.h ../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h \ + ../pc_system.h ../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h \ + ../extplugin.h keymap.h icon_bochs.h font/vga.bitmap.h sdl.h rfb.h \ + rfbkeys.h +win32.lo: win32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h +win32dialog.lo: win32dialog.@CPP_SUFFIX@ win32dialog.h ../config.h +win32_enh_dbg_osdep.lo: win32_enh_dbg_osdep.@CPP_SUFFIX@ ../config.h +win32paramdlg.lo: win32paramdlg.@CPP_SUFFIX@ win32dialog.h ../config.h +wx.lo: wx.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h font/vga.bitmap.h wxmain.h +wxdialog.lo: wxdialog.@CPP_SUFFIX@ ../config.h ../param_names.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../bxversion.h \ + wxdialog.h wxmain.h +wxmain.lo: wxmain.@CPP_SUFFIX@ ../config.h ../param_names.h ../osdep.h \ + ../gui/siminterface.h ../cpudb.h ../gui/paramtree.h ../bxversion.h \ + wxdialog.h wxmain.h ../extplugin.h bitmaps/cdromd.xpm bitmaps/copy.xpm \ + bitmaps/floppya.xpm bitmaps/floppyb.xpm bitmaps/paste.xpm \ + bitmaps/power.xpm bitmaps/reset.xpm bitmaps/snapshot.xpm \ + bitmaps/mouse.xpm bitmaps/userbutton.xpm bitmaps/saverestore.xpm +x.lo: x.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \ + ../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \ + ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h ../gui/gui.h \ + ../instrument/stubs/instrument.h ../param_names.h keymap.h \ + ../iodev/iodev.h ../plugin.h ../extplugin.h enh_dbg.h icon_bochs.xpm \ + font/vga.bitmap.h diff --git a/ports/bochs/main.cc b/ports/bochs/main.cc new file mode 100644 index 0000000..d45f60e --- /dev/null +++ b/ports/bochs/main.cc @@ -0,0 +1,1529 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: main.cc 13076 2017-02-18 16:28:04Z vruppert $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2017 The Bochs Project +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +#include "bochs.h" +#include "bxversion.h" +#include "param_names.h" +#include "gui/textconfig.h" +#if BX_USE_WIN32CONFIG +#include "gui/win32dialog.h" +#endif +#include "cpu/cpu.h" +#include "iodev/iodev.h" + +#ifdef HAVE_LOCALE_H +#include +#endif + +#if BX_WITH_SDL || BX_WITH_SDL2 +// since SDL redefines main() to SDL_main(), we must include SDL.h so that the +// C language prototype is found. Otherwise SDL_main() will get its name +// mangled and not match what the SDL library is expecting. +#include + +#if defined(macintosh) +// Work around a bug in SDL 1.2.4 on MacOS X, which redefines getenv to +// SDL_getenv, but then neglects to provide SDL_getenv. It happens +// because we are defining -Dmacintosh. +#undef getenv +#endif +#endif + +#if BX_WITH_CARBON +#include +#endif + +extern "C" { +#include +} + +#if BX_GUI_SIGHANDLER +bx_bool bx_gui_sighandler = 0; +#endif + +int bx_init_main(int argc, char *argv[]); +void bx_init_hardware(void); +void bx_init_options(void); +void bx_init_bx_dbg(void); + +static const char *divider = "========================================================================"; + +bx_startup_flags_t bx_startup_flags; +bx_bool bx_user_quit; +Bit8u bx_cpu_count; +#if BX_SUPPORT_APIC +Bit32u apic_id_mask; // determinted by XAPIC option +bx_bool simulate_xapic; +#endif + +/* typedefs */ + +#define LOG_THIS genlog-> + +bx_pc_system_c bx_pc_system; + +bx_debug_t bx_dbg; + +typedef BX_CPU_C *BX_CPU_C_PTR; + +#if BX_SUPPORT_SMP +// multiprocessor simulation, we need an array of cpus +BOCHSAPI BX_CPU_C_PTR *bx_cpu_array = NULL; +#else +// single processor simulation, so there's one of everything +BOCHSAPI BX_CPU_C bx_cpu; +#endif + +BOCHSAPI BX_MEM_C bx_mem; + +char *bochsrc_filename = NULL; + +void bx_print_header() +{ + printf("%s\n", divider); + char buffer[128]; + sprintf (buffer, "Bochs x86 Emulator %s\n", VER_STRING); + bx_center_print(stdout, buffer, 72); + if (REL_STRING[0]) { + sprintf(buffer, "%s\n", REL_STRING); + bx_center_print(stdout, buffer, 72); +#ifdef __DATE__ +#ifdef __TIME__ + sprintf(buffer, "Compiled on %s at %s\n", __DATE__, __TIME__); +#else + sprintf(buffer, "Compiled on %s\n", __DATE__); +#endif + bx_center_print(stdout, buffer, 72); +#endif + } + printf("%s\n", divider); +} + +#if BX_WITH_CARBON +/* Original code by Darrell Walisser - dwaliss1@purdue.edu */ + +static void setupWorkingDirectory(char *path) +{ + char parentdir[MAXPATHLEN]; + char *c; + + strncpy (parentdir, path, MAXPATHLEN); + c = (char*) parentdir; + + while (*c != '\0') /* go to end */ + c++; + + while (*c != '/') /* back up to parent */ + c--; + + *c = '\0'; /* cut off last part (binary name) */ + + /* chdir to the binary app's parent */ + int n; + n = chdir (parentdir); + if (n) BX_PANIC(("failed to change dir to parent")); + /* chdir to the .app's parent */ + n = chdir ("../../../"); + if (n) BX_PANIC(("failed to change to ../../..")); +} + +/* Panic button to display fatal errors. + Completely self contained, can't rely on carbon.cc being available */ +static void carbonFatalDialog(const char *error, const char *exposition) +{ + DialogRef alertDialog; + CFStringRef cfError; + CFStringRef cfExposition; + DialogItemIndex index; + AlertStdCFStringAlertParamRec alertParam = {0}; + fprintf(stderr, "Entering carbonFatalDialog: %s\n", error); + + // Init libraries + InitCursor(); + // Assemble dialog + cfError = CFStringCreateWithCString(NULL, error, kCFStringEncodingASCII); + if(exposition != NULL) + { + cfExposition = CFStringCreateWithCString(NULL, exposition, kCFStringEncodingASCII); + } + else { cfExposition = NULL; } + alertParam.version = kStdCFStringAlertVersionOne; + alertParam.defaultText = CFSTR("Quit"); + alertParam.position = kWindowDefaultPosition; + alertParam.defaultButton = kAlertStdAlertOKButton; + // Display Dialog + CreateStandardAlert( + kAlertStopAlert, + cfError, + cfExposition, /* can be NULL */ + &alertParam, /* can be NULL */ + &alertDialog); + RunStandardAlert(alertDialog, NULL, &index); + // Cleanup + CFRelease(cfError); + if(cfExposition != NULL) { CFRelease(cfExposition); } +} +#endif + +#if BX_DEBUGGER +void print_tree(bx_param_c *node, int level, bx_bool xml) +{ + int i; + char tmpstr[BX_PATHNAME_LEN]; + + for (i=0; i", node->get_name()); + else + dbg_printf("%s = ", node->get_name()); + + switch (node->get_type()) { + case BXT_PARAM_NUM: + if (((bx_param_num_c*)node)->get_base() == BASE_DEC) { + dbg_printf("" FMT_LL "d", ((bx_param_num_c*)node)->get64()); + if (! xml) dbg_printf(" (number)"); + } else { + dbg_printf("0x" FMT_LL "x", ((bx_param_num_c*)node)->get64()); + if (! xml) dbg_printf(" (hex number)"); + } + break; + case BXT_PARAM_BOOL: + dbg_printf("%s", ((bx_param_bool_c*)node)->get()?"true":"false"); + if (! xml) dbg_printf(" (boolean)"); + break; + case BXT_PARAM_ENUM: + dbg_printf("'%s'", ((bx_param_enum_c*)node)->get_selected()); + if (! xml) dbg_printf(" (enum)"); + break; + case BXT_PARAM_STRING: + ((bx_param_string_c*)node)->sprint(tmpstr, BX_PATHNAME_LEN, 0); + if (((bx_param_string_c*)node)->get_options() & bx_param_string_c::RAW_BYTES) { + dbg_printf("'%s'", tmpstr); + if (! xml) dbg_printf(" (raw byte string)"); + } else { + dbg_printf("'%s'", tmpstr); + if (! xml) dbg_printf(" (string)"); + } + break; + case BXT_LIST: + { + dbg_printf("\n"); + bx_list_c *list = (bx_list_c*)node; + for (i=0; i < list->get_size(); i++) { + print_tree(list->get(i), level+1, xml); + } + if (xml) { + for (i=0; iget_size()); + break; + default: + dbg_printf("(unknown parameter type)"); + } + + if (xml) dbg_printf("", node->get_name()); + dbg_printf("\n"); +} +#endif + +#if BX_ENABLE_STATISTICS +void print_statistics_tree(bx_param_c *node, int level) +{ + for (int i=0; iget_type()) { + case BXT_PARAM_NUM: + { + bx_param_num_c* param = (bx_param_num_c*) node; + printf("%s = " FMT_LL "d\n", node->get_name(), param->get64()); + param->set(0); // clear the statistic + } + break; + case BXT_PARAM_BOOL: + BX_PANIC(("boolean statistics are not supported !")); + break; + case BXT_PARAM_ENUM: + BX_PANIC(("enum statistics are not supported !")); + break; + case BXT_PARAM_STRING: + BX_PANIC(("string statistics are not supported !")); + break; + case BXT_LIST: + { + bx_list_c *list = (bx_list_c*)node; + if (list->get_size() > 0) { + printf("%s = \n", node->get_name()); + for (int i=0; i < list->get_size(); i++) { + print_statistics_tree(list->get(i), level+1); + } + } + break; + } + case BXT_PARAM_DATA: + BX_PANIC(("binary data statistics are not supported !")); + break; + default: + BX_PANIC(("%s (unknown parameter type)\n", node->get_name())); + break; + } +} +#endif + +int bxmain(void) +{ +#ifdef HAVE_LOCALE_H + // Initialize locale (for isprint() and other functions) + setlocale (LC_ALL, ""); +#endif + bx_init_siminterface(); // create the SIM object + static jmp_buf context; + if (setjmp (context) == 0) { + SIM->set_quit_context (&context); + BX_INSTR_INIT_ENV(); + if (bx_init_main(bx_startup_flags.argc, bx_startup_flags.argv) < 0) { + BX_INSTR_EXIT_ENV(); + return 0; + } + // read a param to decide which config interface to start. + // If one exists, start it. If not, just begin. + bx_param_enum_c *ci_param = SIM->get_param_enum(BXPN_SEL_CONFIG_INTERFACE); + const char *ci_name = ci_param->get_selected(); + if (!strcmp(ci_name, "textconfig")) { +#if BX_USE_TEXTCONFIG + init_text_config_interface(); // in textconfig.h +#else + BX_PANIC(("configuration interface 'textconfig' not present")); +#endif + } + else if (!strcmp(ci_name, "win32config")) { +#if BX_USE_WIN32CONFIG + init_win32_config_interface(); +#else + BX_PANIC(("configuration interface 'win32config' not present")); +#endif + } +#if BX_WITH_WX + else if (!strcmp(ci_name, "wx")) { + PLUG_load_gui_plugin("wx"); + } +#endif + else { + BX_PANIC(("unsupported configuration interface '%s'", ci_name)); + } + ci_param->set_enabled(0); + int status = SIM->configuration_interface(ci_name, CI_START); + if (status == CI_ERR_NO_TEXT_CONSOLE) + BX_PANIC(("Bochs needed the text console, but it was not usable")); + // user quit the config interface, so just quit + } else { + // quit via longjmp + } + SIM->set_quit_context(NULL); +#if defined(WIN32) + if (!bx_user_quit) { + // ask user to press ENTER before exiting, so that they can read messages + // before the console window is closed. This isn't necessary after pressing + // the power button. + fprintf(stderr, "\nBochs is exiting. Press ENTER when you're ready to close this window.\n"); + char buf[16]; + fgets(buf, sizeof(buf), stdin); + } +#endif + BX_INSTR_EXIT_ENV(); + return SIM->get_exit_code(); +} + +#if defined(__WXMSW__) + +// win32 applications get the whole command line in one long string. +// This function is used to split up the string into argc and argv, +// so that the command line can be used on win32 just like on every +// other platform. +// +// I'm sure other people have written this same function, and they may have +// done it better, but I don't know where to find it. -BBD +#ifndef MAX_ARGLEN +#define MAX_ARGLEN 80 +#endif +int split_string_into_argv(char *string, int *argc_out, char **argv, int max_argv) +{ + char *buf0 = new char[strlen(string)+1]; + strcpy (buf0, string); + char *buf = buf0; + int in_double_quote = 0, in_single_quote = 0; + for (int i=0; i= max_argv) { + fprintf (stderr, "too many arguments. Increase MAX_ARGUMENTS\n"); + return -1; + } + argv[argc] = new char[MAX_ARGLEN]; + outp = &argv[argc][0]; + while (*p==' ') p++; + break; + case '"': + if (in_single_quote) goto do_default; + in_double_quote = !in_double_quote; + p++; + break; + case '\'': + if (in_double_quote) goto do_default; + in_single_quote = !in_single_quote; + p++; + break; + do_default: + default: + if (outp-&argv[argc][0] >= MAX_ARGLEN) { + //fprintf (stderr, "command line arg %d exceeded max size %d\n", argc, MAX_ARGLEN); + return -1; + } + *(outp++) = *(p++); + } + } + if (in_single_quote) { + fprintf (stderr, "end of string with mismatched single quote (')\n"); + return -1; + } + if (in_double_quote) { + fprintf (stderr, "end of string with mismatched double quote (\")\n"); + return -1; + } + *argc_out = argc; + return 0; +} +#endif /* if defined(__WXMSW__) */ + +#if defined(__WXMSW__) || ((BX_WITH_SDL || BX_WITH_SDL2) && defined(WIN32)) +// The RedirectIOToConsole() function is copied from an article called "Adding +// Console I/O to a Win32 GUI App" in Windows Developer Journal, December 1997. +// It creates a console window. +// +// NOTE: It could probably be written so that it can safely be called for all +// win32 builds. +int RedirectIOToConsole() +{ + int hConHandle; + long lStdHandle; + FILE *fp; + // allocate a console for this app + FreeConsole(); + if (!AllocConsole()) { + MessageBox(NULL, "Failed to create text console", "Error", MB_ICONERROR); + return 0; + } + // redirect unbuffered STDOUT to the console + lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen(hConHandle, "w"); + *stdout = *fp; + setvbuf(stdout, NULL, _IONBF, 0); + // redirect unbuffered STDIN to the console + lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen(hConHandle, "r"); + *stdin = *fp; + setvbuf(stdin, NULL, _IONBF, 0); + // redirect unbuffered STDERR to the console + lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen(hConHandle, "w"); + *stderr = *fp; + setvbuf(stderr, NULL, _IONBF, 0); + return 1; +} +#endif /* if defined(__WXMSW__) || ((BX_WITH_SDL || BX_WITH_SDL2) && defined(WIN32)) */ + +#if defined(__WXMSW__) +// only used for wxWidgets/win32. +// This works ok in Cygwin with a standard wxWidgets compile. In +// VC++ wxWidgets must be compiled with -DNOMAIN=1. +int WINAPI WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR m_lpCmdLine, int nCmdShow) +{ + bx_startup_flags.hInstance = hInstance; + bx_startup_flags.hPrevInstance = hPrevInstance; + bx_startup_flags.m_lpCmdLine = m_lpCmdLine; + bx_startup_flags.nCmdShow = nCmdShow; + int max_argv = 20; + bx_startup_flags.argv = (char**) malloc (max_argv * sizeof (char*)); + split_string_into_argv(m_lpCmdLine, &bx_startup_flags.argc, bx_startup_flags.argv, max_argv); + int arg = 1; + bx_bool bx_noconsole = 0; + while (arg < bx_startup_flags.argc) { + if (!strcmp("-noconsole", bx_startup_flags.argv[arg])) { + bx_noconsole = 1; + break; + } + arg++; + } + + if (!bx_noconsole) { + if (!RedirectIOToConsole()) { + return 1; + } + SetConsoleTitle("Bochs for Windows (wxWidgets port) - Console"); + } + return bxmain(); +} +#endif + +#if !defined(__WXMSW__) && !defined(BX_WITH_ESSENCE) +// normal main function, presently in for all cases except for +// wxWidgets under win32. +int CDECL main(int argc, char *argv[]) +{ + bx_startup_flags.argc = argc; + bx_startup_flags.argv = argv; +#ifdef WIN32 + int arg = 1; + bx_bool bx_noconsole = 0; + while (arg < argc) { + if (!strcmp("-noconsole", argv[arg])) { + bx_noconsole = 1; + break; + } + arg++; + } + + if (bx_noconsole) { + FreeConsole(); + } else { +#if BX_WITH_SDL || BX_WITH_SDL2 + // if SDL/win32, try to create a console window. + if (!RedirectIOToConsole()) { + return 1; + } +#endif + SetConsoleTitle("Bochs for Windows - Console"); + } +#endif + return bxmain(); +} +#endif + +void print_usage(void) +{ + fprintf(stderr, + "Usage: bochs [flags] [bochsrc options]\n\n" + " -n no configuration file\n" + " -f configfile specify configuration file\n" + " -q quick start (skip configuration interface)\n" + " -benchmark N run bochs in benchmark mode for N millions of emulated ticks\n" +#if BX_ENABLE_STATISTICS + " -dumpstats N dump bochs stats every N millions of emulated ticks\n" +#endif + " -r path restore the Bochs state from path\n" + " -log filename specify Bochs log file name\n" +#if BX_DEBUGGER + " -rc filename execute debugger commands stored in file\n" + " -dbglog filename specify Bochs internal debugger log file name\n" +#endif +#ifdef WIN32 + " -noconsole disable console window\n" +#endif + " --help display this help and exit\n" + " --help features display available features / devices and exit\n" +#if BX_CPU_LEVEL > 4 + " --help cpu display supported CPU models and exit\n" +#endif + "\nFor information on Bochs configuration file arguments, see the\n" +#if (!defined(WIN32)) && !BX_WITH_MACOS + "bochsrc section in the user documentation or the man page of bochsrc.\n"); +#else + "bochsrc section in the user documentation.\n"); +#endif +} + +int bx_init_main(int argc, char *argv[]) +{ + // To deal with initialization order problems inherent in C++, use the macros + // SAFE_GET_IOFUNC and SAFE_GET_GENLOG to retrieve "io" and "genlog" in all + // constructors or functions called by constructors. The macros test for + // NULL and create the object if necessary, then return it. Ensure that io + // and genlog get created, by making one reference to each macro right here. + // All other code can reference io and genlog directly. Because these + // objects are required for logging, and logging is so fundamental to + // knowing what the program is doing, they are never free()d. + SAFE_GET_IOFUNC(); // never freed + SAFE_GET_GENLOG(); // never freed + + // initalization must be done early because some destructors expect + // the bochs config options to exist by the time they are called. + bx_init_bx_dbg(); + bx_init_options(); + + bx_print_header(); + + SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_RUN_START); + + // interpret the args that start with -, like -q, -f, etc. + int arg = 1, load_rcfile=1; + while (arg < argc) { + // parse next arg + if (!strcmp("--help", argv[arg]) || !strncmp("-h", argv[arg], 2) +#if defined(WIN32) + || !strncmp("/?", argv[arg], 2) +#endif + ) { + if ((arg+1) < argc) { + if (!strcmp("features", argv[arg+1])) { + fprintf(stderr, "Supported features:\n\n"); +#if BX_SUPPORT_CLGD54XX + fprintf(stderr, "cirrus\n"); +#endif +#if BX_SUPPORT_VOODOO + fprintf(stderr, "voodoo\n"); +#endif +#if BX_SUPPORT_PCI + fprintf(stderr, "pci\n"); +#endif +#if BX_SUPPORT_PCIDEV + fprintf(stderr, "pcidev\n"); +#endif +#if BX_SUPPORT_NE2K + fprintf(stderr, "ne2k\n"); +#endif +#if BX_SUPPORT_PCIPNIC + fprintf(stderr, "pcipnic\n"); +#endif +#if BX_SUPPORT_E1000 + fprintf(stderr, "e1000\n"); +#endif +#if BX_SUPPORT_SB16 + fprintf(stderr, "sb16\n"); +#endif +#if BX_SUPPORT_ES1370 + fprintf(stderr, "es1370\n"); +#endif +#if BX_SUPPORT_USB_OHCI + fprintf(stderr, "usb_ohci\n"); +#endif +#if BX_SUPPORT_USB_UHCI + fprintf(stderr, "usb_uhci\n"); +#endif +#if BX_SUPPORT_USB_EHCI + fprintf(stderr, "usb_ehci\n"); +#endif +#if BX_SUPPORT_USB_XHCI + fprintf(stderr, "usb_xhci\n"); +#endif +#if BX_GDBSTUB + fprintf(stderr, "gdbstub\n"); +#endif + fprintf(stderr, "\n"); + arg++; + } +#if BX_CPU_LEVEL > 4 + else if (!strcmp("cpu", argv[arg+1])) { + int i = 0; + fprintf(stderr, "Supported CPU models:\n\n"); + do { + fprintf(stderr, "%s\n", SIM->get_param_enum(BXPN_CPU_MODEL)->get_choice(i)); + } while (i++ < SIM->get_param_enum(BXPN_CPU_MODEL)->get_max()); + fprintf(stderr, "\n"); + arg++; + } +#endif + } else { + print_usage(); + } + SIM->quit_sim(0); + } + else if (!strcmp("-n", argv[arg])) { + load_rcfile = 0; + } + else if (!strcmp("-q", argv[arg])) { + SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START); + } + else if (!strcmp("-log", argv[arg])) { + if (++arg >= argc) BX_PANIC(("-log must be followed by a filename")); + else SIM->get_param_string(BXPN_LOG_FILENAME)->set(argv[arg]); + } +#if BX_DEBUGGER + else if (!strcmp("-dbglog", argv[arg])) { + if (++arg >= argc) BX_PANIC(("-dbglog must be followed by a filename")); + else SIM->get_param_string(BXPN_DEBUGGER_LOG_FILENAME)->set(argv[arg]); + } +#endif + else if (!strcmp("-f", argv[arg])) { + if (++arg >= argc) BX_PANIC(("-f must be followed by a filename")); + else bochsrc_filename = argv[arg]; + } + else if (!strcmp("-qf", argv[arg])) { + SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START); + if (++arg >= argc) BX_PANIC(("-qf must be followed by a filename")); + else bochsrc_filename = argv[arg]; + } + else if (!strcmp("-benchmark", argv[arg])) { + SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START); + if (++arg >= argc) BX_PANIC(("-benchmark must be followed by a number")); + else SIM->get_param_num(BXPN_BOCHS_BENCHMARK)->set(atoi(argv[arg])); + } +#if BX_ENABLE_STATISTICS + else if (!strcmp("-dumpstats", argv[arg])) { + if (++arg >= argc) BX_PANIC(("-dumpstats must be followed by a number")); + else SIM->get_param_num(BXPN_DUMP_STATS)->set(atoi(argv[arg])); + } +#endif + else if (!strcmp("-r", argv[arg])) { + if (++arg >= argc) BX_PANIC(("-r must be followed by a path")); + else { + SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START); + SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(1); + SIM->get_param_string(BXPN_RESTORE_PATH)->set(argv[arg]); + } + } +#ifdef WIN32 + else if (!strcmp("-noconsole", argv[arg])) { + // already handled in main() / WinMain() + } +#endif +#if BX_WITH_CARBON + else if (!strncmp("-psn", argv[arg], 4)) { + // "-psn" is passed if we are launched by double-clicking + // ugly hack. I don't know how to open a window to print messages in, + // so put them in /tmp/early-bochs-out.txt. Sorry. -bbd + io->init_log("/tmp/early-bochs-out.txt"); + BX_INFO(("I was launched by double clicking. Fixing home directory.")); + arg = argc; // ignore all other args. + setupWorkingDirectory (argv[0]); + // there is no stdin/stdout so disable the text-based config interface. + SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START); + char cwd[MAXPATHLEN]; + getwd (cwd); + BX_INFO(("Now my working directory is %s", cwd)); + // if it was started from command line, there could be some args still. + for (int a=0; a= argc) BX_PANIC(("-rc must be followed by a filename")); + else bx_dbg_set_rcfile(argv[arg]); + } +#endif + else if (argv[arg][0] == '-') { + print_usage(); + BX_PANIC(("command line arg '%s' was not understood", argv[arg])); + } + else { + // the arg did not start with -, so stop interpreting flags + break; + } + arg++; + } +#if BX_WITH_CARBON + if(!getenv("BXSHARE")) + { + CFBundleRef mainBundle; + CFURLRef bxshareDir; + char bxshareDirPath[MAXPATHLEN]; + BX_INFO(("fixing default bxshare location ...")); + // set bxshare to the directory that contains our application + mainBundle = CFBundleGetMainBundle(); + BX_ASSERT(mainBundle != NULL); + bxshareDir = CFBundleCopyBundleURL(mainBundle); + BX_ASSERT(bxshareDir != NULL); + // translate this to a unix style full path + if(!CFURLGetFileSystemRepresentation(bxshareDir, true, (UInt8 *)bxshareDirPath, MAXPATHLEN)) + { + BX_PANIC(("Unable to work out bxshare path! (Most likely path too long!)")); + return -1; + } + char *c; + c = (char*) bxshareDirPath; + while (*c != '\0') /* go to end */ + c++; + while (*c != '/') /* back up to parent */ + c--; + *c = '\0'; /* cut off last part (binary name) */ + setenv("BXSHARE", bxshareDirPath, 1); + BX_INFO(("now my BXSHARE is %s", getenv("BXSHARE"))); + CFRelease(bxshareDir); + } +#endif +#if BX_PLUGINS + // set a default plugin path, in case the user did not specify one +#if BX_WITH_CARBON + // if there is no stdin, then we must create our own LTDL_LIBRARY_PATH. + // also if there is no LTDL_LIBRARY_PATH, but we have a bundle since we're here + // This is here so that it is available whenever --with-carbon is defined but + // the above code might be skipped, as in --with-sdl --with-carbon + if(!isatty(STDIN_FILENO) || !getenv("LTDL_LIBRARY_PATH")) + { + CFBundleRef mainBundle; + CFURLRef libDir; + char libDirPath[MAXPATHLEN]; + if(!isatty(STDIN_FILENO)) + { + // there is no stdin/stdout so disable the text-based config interface. + SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START); + } + BX_INFO(("fixing default lib location ...")); + // locate the lib directory within the application bundle. + // our libs have been placed in bochs.app/Contents/(current platform aka MacOS)/lib + // This isn't quite right, but they are platform specific and we haven't put + // our plugins into true frameworks and bundles either + mainBundle = CFBundleGetMainBundle(); + BX_ASSERT(mainBundle != NULL); + libDir = CFBundleCopyAuxiliaryExecutableURL(mainBundle, CFSTR("lib")); + BX_ASSERT(libDir != NULL); + // translate this to a unix style full path + if(!CFURLGetFileSystemRepresentation(libDir, true, (UInt8 *)libDirPath, MAXPATHLEN)) + { + BX_PANIC(("Unable to work out ltdl library path within bochs bundle! (Most likely path too long!)")); + return -1; + } + setenv("LTDL_LIBRARY_PATH", libDirPath, 1); + BX_INFO(("now my LTDL_LIBRARY_PATH is %s", getenv("LTDL_LIBRARY_PATH"))); + CFRelease(libDir); + } +#elif BX_HAVE_GETENV && BX_HAVE_SETENV + if (getenv("LTDL_LIBRARY_PATH") != NULL) { + BX_INFO(("LTDL_LIBRARY_PATH is set to '%s'", getenv("LTDL_LIBRARY_PATH"))); + } else { + BX_INFO(("LTDL_LIBRARY_PATH not set. using compile time default '%s'", + BX_PLUGIN_PATH)); + setenv("LTDL_LIBRARY_PATH", BX_PLUGIN_PATH, 1); + } +#endif +#endif /* if BX_PLUGINS */ +#if BX_HAVE_GETENV && BX_HAVE_SETENV + if (getenv("BXSHARE") != NULL) { + BX_INFO(("BXSHARE is set to '%s'", getenv("BXSHARE"))); + } else { + BX_INFO(("BXSHARE not set. using compile time default '%s'", + BX_SHARE_PATH)); + setenv("BXSHARE", BX_SHARE_PATH, 1); + } +#else + // we don't have getenv or setenv. Do nothing. +#endif + + // initialize plugin system. This must happen before we attempt to + // load any modules. + plugin_startup(); +#if BX_SUPPORT_PCIUSB + // USB HC devices depend on USB core symbols, so we have to load it here. + // The devices init() unloads it if not used. + PLUG_load_plugin(usb_common, PLUGTYPE_CORE); +#endif + + int norcfile = 1; + + if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) { + load_rcfile = 0; + norcfile = 0; + } + // load pre-defined optional plugins before parsing configuration + SIM->opt_plugin_ctrl("*", 1); + SIM->init_save_restore(); + SIM->init_statistics(); + if (load_rcfile) { + // parse configuration file and command line arguments +#ifdef WIN32 + int length; + if (bochsrc_filename != NULL) { + lstrcpy(bx_startup_flags.initial_dir, bochsrc_filename); + length = lstrlen(bx_startup_flags.initial_dir); + while ((length > 1) && (bx_startup_flags.initial_dir[length-1] != 92)) length--; + bx_startup_flags.initial_dir[length] = 0; + } else { + bx_startup_flags.initial_dir[0] = 0; + } +#endif + if (bochsrc_filename == NULL) bochsrc_filename = bx_find_bochsrc (); + if (bochsrc_filename) + norcfile = bx_read_configuration(bochsrc_filename); + } + + if (norcfile) { + // No configuration was loaded, so the current settings are unusable. + // Switch off quick start so that we will drop into the configuration + // interface. + if (SIM->get_param_enum(BXPN_BOCHS_START)->get() == BX_QUICK_START) { + if (!SIM->test_for_text_console()) + BX_PANIC(("Unable to start Bochs without a bochsrc.txt and without a text console")); + else + BX_ERROR(("Switching off quick start, because no configuration file was found.")); + } + SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_LOAD_START); + } + + if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) { + if (arg < argc) { + BX_ERROR(("WARNING: bochsrc options are ignored in restore mode!")); + } + } + else { + // parse the rest of the command line. This is done after reading the + // configuration file so that the command line arguments can override + // the settings from the file. + if (bx_parse_cmdline(arg, argc, argv)) { + BX_PANIC(("There were errors while parsing the command line")); + return -1; + } + } + return 0; +} + +bx_bool load_and_init_display_lib(void) +{ + if (bx_gui != NULL) { + // bx_gui has already been filled in. This happens when you start + // the simulation for the second time. + // Also, if you load wxWidgets as the configuration interface. Its + // plugin_init will install wxWidgets as the bx_gui. + return 1; + } + BX_ASSERT(bx_gui == NULL); + bx_param_enum_c *ci_param = SIM->get_param_enum(BXPN_SEL_CONFIG_INTERFACE); + const char *ci_name = ci_param->get_selected(); + bx_param_enum_c *gui_param = SIM->get_param_enum(BXPN_SEL_DISPLAY_LIBRARY); + const char *gui_name = gui_param->get_selected(); + if (!strcmp(ci_name, "wx")) { + BX_ERROR(("change of the config interface to wx not implemented yet")); + } + if (!strcmp(gui_name, "wx")) { + // they must not have used wx as the configuration interface, or bx_gui + // would already be initialized. Sorry, it doesn't work that way. + BX_ERROR(("wxWidgets was not used as the configuration interface, so it cannot be used as the display library")); + // choose another, hopefully different! + gui_param->set(0); + gui_name = gui_param->get_selected(); + if (!strcmp (gui_name, "wx")) { + BX_PANIC(("no alternative display libraries are available")); + return 0; + } + BX_ERROR(("changing display library to '%s' instead", gui_name)); + } + PLUG_load_gui_plugin(gui_name); + +#if BX_GUI_SIGHANDLER + // set the flag for guis requiring a GUI sighandler. + // useful when guis are compiled as plugins + // only term for now + if (!strcmp(gui_name, "term")) { + bx_gui_sighandler = 1; + } +#endif + + return (bx_gui != NULL); +} + +int bx_begin_simulation(int argc, char *argv[]) +{ + bx_user_quit = 0; + if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) { + if (!SIM->restore_config()) { + BX_PANIC(("cannot restore configuration")); + SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(0); + } + } else { + // make sure all optional plugins have been loaded + SIM->opt_plugin_ctrl("*", 1); + } + + // deal with gui selection + if (!load_and_init_display_lib()) { + BX_PANIC(("no gui module was loaded")); + return 0; + } + + bx_cpu_count = SIM->get_param_num(BXPN_CPU_NPROCESSORS)->get() * + SIM->get_param_num(BXPN_CPU_NCORES)->get() * + SIM->get_param_num(BXPN_CPU_NTHREADS)->get(); + +#if BX_SUPPORT_APIC + simulate_xapic = (SIM->get_param_enum(BXPN_CPUID_APIC)->get() >= BX_CPUID_SUPPORT_XAPIC); + + // For P6 and Pentium family processors the local APIC ID feild is 4 bits + // APIC_MAX_ID indicate broadcast so it can't be used as valid APIC ID + apic_id_mask = simulate_xapic ? 0xFF : 0xF; + + // leave one APIC ID to I/O APIC + unsigned max_smp_threads = apic_id_mask - 1; + if (bx_cpu_count > max_smp_threads) { + BX_PANIC(("cpu: too many SMP threads defined, only %u threads supported by %sAPIC", + max_smp_threads, simulate_xapic ? "x" : "legacy ")); + } +#endif + + BX_ASSERT(bx_cpu_count > 0); + + bx_init_hardware(); + + if (SIM->get_param_enum(BXPN_LOAD32BITOS_WHICH)->get()) { + void bx_load32bitOSimagehack(void); + bx_load32bitOSimagehack(); + } + + SIM->set_init_done(1); + + // update headerbar buttons since drive status can change during init + bx_gui->update_drive_status_buttons(); + + // iniialize statusbar and set all items inactive + if (!SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) { + bx_gui->statusbar_setitem(-1, 0); + } else { + SIM->get_param_string(BXPN_RESTORE_PATH)->set("none"); + } + + // The set handler for mouse_enabled does not actually update the gui + // until init_done is set. This forces the set handler to be called, + // which sets up the mouse enabled GUI-specific stuff correctly. + // Not a great solution but it works. BBD + SIM->get_param_bool(BXPN_MOUSE_ENABLED)->set(SIM->get_param_bool(BXPN_MOUSE_ENABLED)->get()); + +#if BX_DEBUGGER + // If using the debugger, it will take control and call + // bx_init_hardware() and cpu_loop() + bx_dbg_main(); +#else +#if BX_GDBSTUB + // If using gdbstub, it will take control and call + // bx_init_hardware() and cpu_loop() + if (bx_dbg.gdbstub_enabled) bx_gdbstub_init(); + else +#endif + { + if (BX_SMP_PROCESSORS == 1) { + // only one processor, run as fast as possible by not messing with + // quantums and loops. + while (1) { + BX_CPU(0)->cpu_loop(); + if (bx_pc_system.kill_bochs_request) + break; + } + // for one processor, the only reason for cpu_loop to return is + // that kill_bochs_request was set by the GUI interface. + } +#if BX_SUPPORT_SMP + else { + // SMP simulation: do a few instructions on each processor, then switch + // to another. Increasing quantum speeds up overall performance, but + // reduces granularity of synchronization between processors. + // Current implementation uses dynamic quantum, each processor will + // execute exactly one trace then quit the cpu_loop and switch to + // the next processor. + + static int quantum = SIM->get_param_num(BXPN_SMP_QUANTUM)->get(); + Bit32u executed = 0, processor = 0; + + while (1) { + // do some instructions in each processor + Bit64u icount = BX_CPU(processor)->icount_last_sync = BX_CPU(processor)->get_icount(); + BX_CPU(processor)->cpu_run_trace(); + + // see how many instruction it was able to run + Bit32u n = (Bit32u)(BX_CPU(processor)->get_icount() - icount); + if (n == 0) n = quantum; // the CPU was halted + executed += n; + + if (++processor == BX_SMP_PROCESSORS) { + processor = 0; + BX_TICKN(executed / BX_SMP_PROCESSORS); + executed %= BX_SMP_PROCESSORS; + } + + if (bx_pc_system.kill_bochs_request) + break; + } + } +#endif /* BX_SUPPORT_SMP */ + } +#endif /* BX_DEBUGGER == 0 */ + BX_INFO(("cpu loop quit, shutting down simulator")); + bx_atexit(); + return(0); +} + +void bx_stop_simulation(void) +{ + // in wxWidgets, the whole simulator is running in a separate thread. + // our only job is to end the thread as soon as possible, NOT to shut + // down the whole application with an exit. + BX_CPU(0)->async_event = 1; + bx_pc_system.kill_bochs_request = 1; + // the cpu loop will exit very soon after this condition is set. +} + +void bx_sr_after_restore_state(void) +{ +#if BX_SUPPORT_SMP == 0 + BX_CPU(0)->after_restore_state(); +#else + for (unsigned i=0; iafter_restore_state(); + } +#endif + DEV_after_restore_state(); +} + +void bx_set_log_actions_by_device(bx_bool panic_flag) +{ + int id, l, m, val; + bx_list_c *loglev, *level; + bx_param_num_c *action; + + loglev = (bx_list_c*) SIM->get_param("general.logfn"); + for (l = 0; l < loglev->get_size(); l++) { + level = (bx_list_c*) loglev->get(l); + for (m = 0; m < level->get_size(); m++) { + action = (bx_param_num_c*) level->get(m); + id = SIM->get_logfn_id(action->get_name()); + val = action->get(); + if (id < 0) { + if (panic_flag) { + BX_PANIC(("unknown log function module '%s'", action->get_name())); + } + } else if (val >= 0) { + SIM->set_log_action(id, l, val); + // mark as 'done' + action->set(-1); + } + } + } +} + +void bx_init_hardware() +{ + int i; + char pname[16]; + bx_list_c *base; + + // all configuration has been read, now initialize everything. + + bx_pc_system.initialize(SIM->get_param_num(BXPN_IPS)->get()); + + if (SIM->get_param_string(BXPN_LOG_FILENAME)->getptr()[0]!='-') { + BX_INFO(("using log file %s", SIM->get_param_string(BXPN_LOG_FILENAME)->getptr())); + io->init_log(SIM->get_param_string(BXPN_LOG_FILENAME)->getptr()); + } + + io->set_log_prefix(SIM->get_param_string(BXPN_LOG_PREFIX)->getptr()); + + // Output to the log file the cpu and device settings + // This will by handy for bug reports + BX_INFO(("Bochs x86 Emulator %s", VER_STRING)); + BX_INFO((" %s", REL_STRING)); +#ifdef __DATE__ +#ifdef __TIME__ + BX_INFO(("Compiled on %s at %s", __DATE__, __TIME__)); +#else + BX_INFO(("Compiled on %s", __DATE__)); +#endif +#endif + BX_INFO(("System configuration")); + BX_INFO((" processors: %d (cores=%u, HT threads=%u)", BX_SMP_PROCESSORS, + SIM->get_param_num(BXPN_CPU_NCORES)->get(), SIM->get_param_num(BXPN_CPU_NTHREADS)->get())); + BX_INFO((" A20 line support: %s", BX_SUPPORT_A20?"yes":"no")); +#if BX_CONFIGURE_MSRS + const char *msrs_file = SIM->get_param_string(BXPN_CONFIGURABLE_MSRS_PATH)->getptr(); + if ((strlen(msrs_file) > 0) && strcmp(msrs_file, "none")) + BX_INFO((" load configurable MSRs from file \"%s\"", msrs_file)); +#endif + BX_INFO(("IPS is set to %d", (Bit32u) SIM->get_param_num(BXPN_IPS)->get())); + BX_INFO(("CPU configuration")); +#if BX_SUPPORT_SMP + BX_INFO((" SMP support: yes, quantum=%d", SIM->get_param_num(BXPN_SMP_QUANTUM)->get())); +#else + BX_INFO((" SMP support: no")); +#endif + + unsigned cpu_model = SIM->get_param_enum(BXPN_CPU_MODEL)->get(); + if (! cpu_model) { +#if BX_CPU_LEVEL >= 5 + unsigned cpu_level = SIM->get_param_num(BXPN_CPUID_LEVEL)->get(); + BX_INFO((" level: %d", cpu_level)); + BX_INFO((" APIC support: %s", SIM->get_param_enum(BXPN_CPUID_APIC)->get_selected())); +#else + BX_INFO((" level: %d", BX_CPU_LEVEL)); + BX_INFO((" APIC support: no")); +#endif + BX_INFO((" FPU support: %s", BX_SUPPORT_FPU?"yes":"no")); +#if BX_CPU_LEVEL >= 5 + bx_bool mmx_enabled = SIM->get_param_bool(BXPN_CPUID_MMX)->get(); + BX_INFO((" MMX support: %s", mmx_enabled?"yes":"no")); + BX_INFO((" 3dnow! support: %s", BX_SUPPORT_3DNOW?"yes":"no")); +#endif +#if BX_CPU_LEVEL >= 6 + bx_bool sep_enabled = SIM->get_param_bool(BXPN_CPUID_SEP)->get(); + BX_INFO((" SEP support: %s", sep_enabled?"yes":"no")); + BX_INFO((" SIMD support: %s", SIM->get_param_enum(BXPN_CPUID_SIMD)->get_selected())); + bx_bool xsave_enabled = SIM->get_param_bool(BXPN_CPUID_XSAVE)->get(); + bx_bool xsaveopt_enabled = SIM->get_param_bool(BXPN_CPUID_XSAVEOPT)->get(); + BX_INFO((" XSAVE support: %s %s", + xsave_enabled?"xsave":"no", xsaveopt_enabled?"xsaveopt":"")); + bx_bool aes_enabled = SIM->get_param_bool(BXPN_CPUID_AES)->get(); + BX_INFO((" AES support: %s", aes_enabled?"yes":"no")); + bx_bool sha_enabled = SIM->get_param_bool(BXPN_CPUID_SHA)->get(); + BX_INFO((" SHA support: %s", sha_enabled?"yes":"no")); + bx_bool movbe_enabled = SIM->get_param_bool(BXPN_CPUID_MOVBE)->get(); + BX_INFO((" MOVBE support: %s", movbe_enabled?"yes":"no")); + bx_bool adx_enabled = SIM->get_param_bool(BXPN_CPUID_ADX)->get(); + BX_INFO((" ADX support: %s", adx_enabled?"yes":"no")); +#if BX_SUPPORT_X86_64 + bx_bool x86_64_enabled = SIM->get_param_bool(BXPN_CPUID_X86_64)->get(); + BX_INFO((" x86-64 support: %s", x86_64_enabled?"yes":"no")); + bx_bool xlarge_enabled = SIM->get_param_bool(BXPN_CPUID_1G_PAGES)->get(); + BX_INFO((" 1G paging support: %s", xlarge_enabled?"yes":"no")); +#else + BX_INFO((" x86-64 support: no")); +#endif +#if BX_SUPPORT_MONITOR_MWAIT + bx_bool mwait_enabled = SIM->get_param_bool(BXPN_CPUID_MWAIT)->get(); + BX_INFO((" MWAIT support: %s", mwait_enabled?"yes":"no")); +#endif +#if BX_SUPPORT_VMX + unsigned vmx_enabled = SIM->get_param_num(BXPN_CPUID_VMX)->get(); + if (vmx_enabled) { + BX_INFO((" VMX support: %d", vmx_enabled)); + } + else { + BX_INFO((" VMX support: no")); + } +#endif +#if BX_SUPPORT_SVM + bx_bool svm_enabled = SIM->get_param_bool(BXPN_CPUID_SVM)->get(); + BX_INFO((" SVM support: %s", svm_enabled?"yes":"no")); +#endif +#endif // BX_CPU_LEVEL >= 6 + } + else { + BX_INFO((" Using pre-defined CPU configuration: %s", + SIM->get_param_enum(BXPN_CPU_MODEL)->get_selected())); + } + + BX_INFO(("Optimization configuration")); + BX_INFO((" RepeatSpeedups support: %s", BX_SUPPORT_REPEAT_SPEEDUPS?"yes":"no")); + BX_INFO((" Fast function calls: %s", BX_FAST_FUNC_CALL?"yes":"no")); + BX_INFO((" Handlers Chaining speedups: %s", BX_SUPPORT_HANDLERS_CHAINING_SPEEDUPS?"yes":"no")); + BX_INFO(("Devices configuration")); + BX_INFO((" PCI support: %s", BX_SUPPORT_PCI?"i440FX i430FX":"no")); +#if BX_SUPPORT_NE2K || BX_SUPPORT_E1000 + BX_INFO((" Networking support:%s%s", + BX_SUPPORT_NE2K?" NE2000":"", BX_SUPPORT_E1000?" E1000":"")); +#else + BX_INFO((" Networking: no")); +#endif +#if BX_SUPPORT_SB16 || BX_SUPPORT_ES1370 + BX_INFO((" Sound support:%s%s", + BX_SUPPORT_SB16?" SB16":"", BX_SUPPORT_ES1370?" ES1370":"")); +#else + BX_INFO((" Sound support: no")); +#endif +#if BX_SUPPORT_PCIUSB + BX_INFO((" USB support:%s%s%s%s", + BX_SUPPORT_USB_UHCI?" UHCI":"", BX_SUPPORT_USB_OHCI?" OHCI":"", + BX_SUPPORT_USB_EHCI?" EHCI":"", BX_SUPPORT_USB_XHCI?" xHCI":"")); +#else + BX_INFO((" USB support: no")); +#endif + BX_INFO((" VGA extension support: vbe%s%s", + BX_SUPPORT_CLGD54XX?" cirrus":"", BX_SUPPORT_VOODOO?" voodoo":"")); + + // Check if there is a romimage + if (SIM->get_param_string(BXPN_ROM_PATH)->isempty()) { + BX_ERROR(("No romimage to load. Is your bochsrc file loaded/valid ?")); + } + + // set one shot timer for benchmark mode if needed, the timer will fire + // once and kill Bochs simulation after predefined amount of emulated + // ticks + int benchmark_mode = SIM->get_param_num(BXPN_BOCHS_BENCHMARK)->get(); + if (benchmark_mode) { + BX_INFO(("Bochs benchmark mode is ON (~%d millions of ticks)", benchmark_mode)); + bx_pc_system.register_timer_ticks(&bx_pc_system, bx_pc_system_c::benchmarkTimer, + (Bit64u) benchmark_mode * 1000000, 0 /* one shot */, 1, "benchmark.timer"); + } + +#if BX_ENABLE_STATISTICS + // set periodic timer for dumping statistics collected during Bochs run + int dumpstats = SIM->get_param_num(BXPN_DUMP_STATS)->get(); + if (dumpstats) { + BX_INFO(("Dump statistics every %d millions of ticks", dumpstats)); + bx_pc_system.register_timer_ticks(&bx_pc_system, bx_pc_system_c::dumpStatsTimer, + (Bit64u) dumpstats * 1000000, 1 /* continuous */, 1, "dumpstats.timer"); + } +#endif + + // set up memory and CPU objects + bx_param_num_c *bxp_memsize = SIM->get_param_num(BXPN_MEM_SIZE); + Bit64u memSize = bxp_memsize->get64() * BX_CONST64(1024*1024); + + bx_param_num_c *bxp_host_memsize = SIM->get_param_num(BXPN_HOST_MEM_SIZE); + Bit64u hostMemSize = bxp_host_memsize->get64() * BX_CONST64(1024*1024); + + // do not allocate more host memory than needed for emulation of guest RAM + if (memSize < hostMemSize) hostMemSize = memSize; + + BX_MEM(0)->init_memory(memSize, hostMemSize); + + // First load the system BIOS (VGABIOS loading moved to the vga code) + BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_ROM_PATH)->getptr(), + SIM->get_param_num(BXPN_ROM_ADDRESS)->get(), 0); + + // Then load the optional ROM images + for (i=0; iget_param(pname); + if (!SIM->get_param_string("file", base)->isempty()) + BX_MEM(0)->load_ROM(SIM->get_param_string("file", base)->getptr(), + SIM->get_param_num("address", base)->get(), 2); + } + + // Then load the optional RAM images + for (i=0; iget_param(pname); + if (!SIM->get_param_string("file", base)->isempty()) + BX_MEM(0)->load_RAM(SIM->get_param_string("file", base)->getptr(), + SIM->get_param_num("address", base)->get()); + } + +#if BX_SUPPORT_SMP == 0 + BX_CPU(0)->initialize(); + BX_CPU(0)->sanity_checks(); + BX_CPU(0)->register_state(); + BX_INSTR_INITIALIZE(0); +#else + bx_cpu_array = new BX_CPU_C_PTR[BX_SMP_PROCESSORS]; + + for (unsigned i=0; iinitialize(); // assign local apic id in 'initialize' method + BX_CPU(i)->sanity_checks(); + BX_CPU(i)->register_state(); + BX_INSTR_INITIALIZE(i); + } +#endif + + DEV_init_devices(); + // unload optional plugins which are unused and marked for removal + SIM->opt_plugin_ctrl("*", 0); + bx_pc_system.register_state(); + DEV_register_state(); + if (!SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) { + bx_set_log_actions_by_device(1); + } + + // will enable A20 line and reset CPU and devices + bx_pc_system.Reset(BX_RESET_HARDWARE); + + if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) { + if (SIM->restore_hardware()) { + if (!SIM->restore_logopts()) { + BX_PANIC(("cannot restore log options")); + SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(0); + } + bx_sr_after_restore_state(); + } else { + BX_PANIC(("cannot restore hardware state")); + SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(0); + } + } + + bx_gui->init_signal_handlers(); + bx_pc_system.start_timers(); + + BX_DEBUG(("bx_init_hardware is setting signal handlers")); +// if not using debugger, then we can take control of SIGINT. +#if !BX_DEBUGGER + signal(SIGINT, bx_signal_handler); +#endif + +#if BX_SHOW_IPS +#if !defined(WIN32) + if (!SIM->is_wx_selected()) { + signal(SIGALRM, bx_signal_handler); + alarm(1); + } +#endif +#endif +} + +void bx_init_bx_dbg(void) +{ +#if BX_DEBUGGER + bx_dbg_init_infile(); +#endif + memset(&bx_dbg, 0, sizeof(bx_debug_t)); +} + +int bx_atexit(void) +{ + if (!SIM->get_init_done()) return 1; // protect from reentry + + // in case we ended up in simulation mode, change back to config mode + // so that the user can see any messages left behind on the console. + SIM->set_display_mode(DISP_MODE_CONFIG); + +#if BX_DEBUGGER == 0 + if (SIM && SIM->get_init_done()) { + for (int cpu=0; cpuatexit(); + } +#endif + + BX_MEM(0)->cleanup_memory(); + + bx_pc_system.exit(); + + // restore signal handling to defaults +#if BX_DEBUGGER == 0 + BX_INFO(("restoring default signal behavior")); + signal(SIGINT, SIG_DFL); +#endif + +#if BX_SHOW_IPS +#if !defined(__MINGW32__) && !defined(_MSC_VER) + if (!SIM->is_wx_selected()) { + alarm(0); + signal(SIGALRM, SIG_DFL); + } +#endif +#endif + + SIM->cleanup_save_restore(); + SIM->cleanup_statistics(); + SIM->set_init_done(0); + + return 0; +} + +#if BX_SHOW_IPS +void bx_show_ips_handler(void) +{ + static Bit64u ticks_count = 0; + static Bit64u counts = 0; + + // amount of system ticks passed from last time the handler was called + Bit64u ips_count = bx_pc_system.time_ticks() - ticks_count; + if (ips_count) { + bx_gui->show_ips((Bit32u) ips_count); + ticks_count = bx_pc_system.time_ticks(); + counts++; + if (bx_dbg.print_timestamps) { + printf("IPS: %u\taverage = %u\t\t(%us)\n", + (unsigned) ips_count, (unsigned) (ticks_count/counts), (unsigned) counts); + fflush(stdout); + } + } + return; +} +#endif + +void CDECL bx_signal_handler(int signum) +{ + // in a multithreaded environment, a signal such as SIGINT can be sent to all + // threads. This function is only intended to handle signals in the + // simulator thread. It will simply return if called from any other thread. + // Otherwise the BX_PANIC() below can be called in multiple threads at + // once, leading to multiple threads trying to display a dialog box, + // leading to GUI deadlock. + if (!SIM->is_sim_thread()) { + BX_INFO(("bx_signal_handler: ignored sig %d because it wasn't called from the simulator thread", signum)); + return; + } +#if BX_GUI_SIGHANDLER + if (bx_gui_sighandler) { + // GUI signal handler gets first priority, if the mask says it's wanted + if ((1<get_sighandler_mask()) { + bx_gui->sighandler(signum); + return; + } + } +#endif + +#if BX_SHOW_IPS + if (signum == SIGALRM) { + bx_show_ips_handler(); +#if !defined(WIN32) + if (!SIM->is_wx_selected()) { + signal(SIGALRM, bx_signal_handler); + alarm(1); + } +#endif + return; + } +#endif + +#if BX_GUI_SIGHANDLER + if (bx_gui_sighandler) { + if ((1<get_sighandler_mask()) { + bx_gui->sighandler(signum); + return; + } + } +#endif + + BX_PANIC(("SIGNAL %u caught", signum)); +} diff --git a/ports/bochs/plugin.cc b/ports/bochs/plugin.cc new file mode 100644 index 0000000..8325d9f --- /dev/null +++ b/ports/bochs/plugin.cc @@ -0,0 +1,970 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: plugin.cc 13160 2017-03-30 18:08:15Z vruppert $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002-2017 The Bochs Project +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +///////////////////////////////////////////////////////////////////////// +// +// This file defines the plugin and plugin-device registration functions and +// the device registration functions. It handles dynamic loading of modules, +// using the LTDL library for cross-platform support. +// +// This file is based on the plugin.c file from plex86, but with significant +// changes to make it work in Bochs. +// Plex86 is Copyright (C) 1999-2000 The plex86 developers team +// +///////////////////////////////////////////////////////////////////////// + +#include "bochs.h" +#include "iodev/iodev.h" +#include "plugin.h" + +#define LOG_THIS genlog-> + +#define PLUGIN_INIT_FMT_STRING "lib%s_LTX_plugin_init" +#define PLUGIN_FINI_FMT_STRING "lib%s_LTX_plugin_fini" +#define GUI_PLUGIN_INIT_FMT_STRING "lib%s_gui_plugin_init" +#define GUI_PLUGIN_FINI_FMT_STRING "lib%s_gui_plugin_fini" +#define SOUND_PLUGIN_INIT_FMT_STRING "lib%s_sound_plugin_init" +#define SOUND_PLUGIN_FINI_FMT_STRING "lib%s_sound_plugin_fini" +#define NET_PLUGIN_INIT_FMT_STRING "lib%s_net_plugin_init" +#define NET_PLUGIN_FINI_FMT_STRING "lib%s_net_plugin_fini" +#define PLUGIN_PATH "" + +#ifndef WIN32 +#define PLUGIN_FILENAME_FORMAT "libbx_%s.so" +#define SOUND_PLUGIN_FILENAME_FORMAT "libbx_sound%s.so" +#define NET_PLUGIN_FILENAME_FORMAT "libbx_eth_%s.so" +#else +#define PLUGIN_FILENAME_FORMAT "bx_%s.dll" +#define SOUND_PLUGIN_FILENAME_FORMAT "bx_sound%s.dll" +#define NET_PLUGIN_FILENAME_FORMAT "bx_eth_%s.dll" +#endif + +logfunctions *pluginlog; + +extern "C" { + +void (*pluginRegisterIRQ)(unsigned irq, const char* name) = 0; +void (*pluginUnregisterIRQ)(unsigned irq, const char* name) = 0; + +void (*pluginSetHRQ)(unsigned val) = 0; +void (*pluginSetHRQHackCallback)(void (*callback)(void)) = 0; + +int (*pluginRegisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback, + unsigned base, const char *name, Bit8u mask) = 0; +int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback, + unsigned base, const char *name, Bit8u mask) = 0; +int (*pluginUnregisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback, + unsigned base, Bit8u mask) = 0; +int (*pluginUnregisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback, + unsigned base, Bit8u mask) = 0; +int (*pluginRegisterIOReadHandlerRange)(void *thisPtr, ioReadHandler_t callback, + unsigned base, unsigned end, const char *name, Bit8u mask) = 0; +int (*pluginRegisterIOWriteHandlerRange)(void *thisPtr, ioWriteHandler_t callback, + unsigned base, unsigned end, const char *name, Bit8u mask) = 0; +int (*pluginUnregisterIOReadHandlerRange)(void *thisPtr, ioReadHandler_t callback, + unsigned begin, unsigned end, Bit8u mask) = 0; +int (*pluginUnregisterIOWriteHandlerRange)(void *thisPtr, ioWriteHandler_t callback, + unsigned begin, unsigned end, Bit8u mask) = 0; +int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback, + const char *name, Bit8u mask) = 0; +int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback, + const char *name, Bit8u mask) = 0; + +void (*pluginHRQHackCallback)(void); +unsigned pluginHRQ = 0; + +plugin_t *plugins = NULL; /* Head of the linked list of plugins */ +#if BX_PLUGINS +static void plugin_init_one(plugin_t *plugin); +#endif + +device_t *devices = NULL; /* Head of the linked list of registered devices */ +device_t *core_devices = NULL; /* Head of the linked list of registered core devices */ + +plugin_t *current_plugin_context = NULL; + +/************************************************************************/ +/* Builtins declarations */ +/************************************************************************/ + + static void +builtinRegisterIRQ(unsigned irq, const char* name) +{ +#if 0 + pluginlog->panic("builtinRegisterIRQ called, no pic plugin loaded?"); +#else + bx_devices.register_irq(irq, name); +#endif +} + + static void +builtinUnregisterIRQ(unsigned irq, const char* name) +{ +#if 0 + pluginlog->panic("builtinUnregisterIRQ called, no pic plugin loaded?"); +#else + bx_devices.unregister_irq(irq, name); +#endif +} + + static void +builtinSetHRQ(unsigned val) +{ +#if 0 + pluginlog->panic("builtinSetHRQ called, no plugin loaded?"); +#else + pluginHRQ = val; +#endif +} + + static void +builtinSetHRQHackCallback(void (*callback)(void)) +{ +#if 0 + pluginlog->panic("builtinSetHRQHackCallback called, no plugin loaded?"); +#else + pluginHRQHackCallback = callback; +#endif +} + + static int +builtinRegisterIOReadHandler(void *thisPtr, ioReadHandler_t callback, + unsigned base, const char *name, Bit8u mask) +{ + int ret; + BX_ASSERT(mask<8); + ret = bx_devices.register_io_read_handler (thisPtr, callback, base, name, mask); + pluginlog->ldebug("plugin %s registered I/O read address at %04x", name, base); + return ret; +} + + static int +builtinRegisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback, + unsigned base, const char *name, Bit8u mask) +{ + int ret; + BX_ASSERT(mask<8); + ret = bx_devices.register_io_write_handler (thisPtr, callback, base, name, mask); + pluginlog->ldebug("plugin %s registered I/O write address at %04x", name, base); + return ret; +} + + static int +builtinUnregisterIOReadHandler(void *thisPtr, ioReadHandler_t callback, + unsigned base, Bit8u mask) +{ + int ret; + BX_ASSERT(mask<8); + ret = bx_devices.unregister_io_read_handler (thisPtr, callback, base, mask); + pluginlog->ldebug("plugin unregistered I/O read address at %04x", base); + return ret; +} + + static int +builtinUnregisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback, + unsigned base, Bit8u mask) +{ + int ret; + BX_ASSERT(mask<8); + ret = bx_devices.unregister_io_write_handler (thisPtr, callback, base, mask); + pluginlog->ldebug("plugin unregistered I/O write address at %04x", base); + return ret; +} + + static int +builtinRegisterIOReadHandlerRange(void *thisPtr, ioReadHandler_t callback, + unsigned base, unsigned end, const char *name, Bit8u mask) +{ + int ret; + BX_ASSERT(mask<8); + ret = bx_devices.register_io_read_handler_range (thisPtr, callback, base, end, name, mask); + pluginlog->ldebug("plugin %s registered I/O read addresses %04x to %04x", name, base, end); + return ret; +} + + static int +builtinRegisterIOWriteHandlerRange(void *thisPtr, ioWriteHandler_t callback, + unsigned base, unsigned end, const char *name, Bit8u mask) +{ + int ret; + BX_ASSERT(mask<8); + ret = bx_devices.register_io_write_handler_range (thisPtr, callback, base, end, name, mask); + pluginlog->ldebug("plugin %s registered I/O write addresses %04x to %04x", name, base, end); + return ret; +} + + static int +builtinUnregisterIOReadHandlerRange(void *thisPtr, ioReadHandler_t callback, + unsigned begin, unsigned end, Bit8u mask) +{ + int ret; + BX_ASSERT(mask<8); + ret = bx_devices.unregister_io_read_handler_range (thisPtr, callback, begin, end, mask); + pluginlog->ldebug("plugin unregistered I/O read addresses %04x to %04x", begin, end); + return ret; +} + + static int +builtinUnregisterIOWriteHandlerRange(void *thisPtr, ioWriteHandler_t callback, + unsigned begin, unsigned end, Bit8u mask) +{ + int ret; + BX_ASSERT(mask<8); + ret = bx_devices.unregister_io_write_handler_range (thisPtr, callback, begin, end, mask); + pluginlog->ldebug("plugin unregistered I/O write addresses %04x to %04x", begin, end); + return ret; +} + + static int +builtinRegisterDefaultIOReadHandler(void *thisPtr, ioReadHandler_t callback, + const char *name, Bit8u mask) +{ + BX_ASSERT(mask<8); + bx_devices.register_default_io_read_handler (thisPtr, callback, name, mask); + pluginlog->ldebug("plugin %s registered default I/O read ", name); + return 0; +} + + static int +builtinRegisterDefaultIOWriteHandler(void *thisPtr, ioWriteHandler_t callback, + const char *name, Bit8u mask) +{ + BX_ASSERT(mask<8); + bx_devices.register_default_io_write_handler (thisPtr, callback, name, mask); + pluginlog->ldebug("plugin %s registered default I/O write ", name); + return 0; +} + +#if BX_PLUGINS +/************************************************************************/ +/* Plugin initialization / deinitialization */ +/************************************************************************/ + +void plugin_init_one(plugin_t *plugin) +{ + /* initialize the plugin */ + if (plugin->plugin_init(plugin, plugin->type)) + { + pluginlog->info("Plugin initialization failed for %s", plugin->name); + plugin_abort(); + } + + plugin->initialized = 1; +} + + +plugin_t *plugin_unload(plugin_t *plugin) +{ + plugin_t *dead_plug; + + if (plugin->initialized) + plugin->plugin_fini(); + +#if defined(WIN32) + FreeLibrary(plugin->handle); +#else + lt_dlclose(plugin->handle); +#endif + delete [] plugin->name; + + dead_plug = plugin; + plugin = plugin->next; + delete dead_plug; + + return plugin; +} + +void plugin_load(char *name, plugintype_t type) +{ + plugin_t *plugin, *temp; +#if defined(WIN32) + char dll_path_list[MAX_PATH]; +#endif + + if (plugins != NULL) { + temp = plugins; + + while (temp != NULL) { + if (!strcmp(name, temp->name)) { + BX_PANIC(("plugin '%s' already loaded", name)); + return; + } + temp = temp->next; + } + } + + plugin = new plugin_t; + + plugin->type = type; + plugin->name = name; + plugin->initialized = 0; + + char plugin_filename[BX_PATHNAME_LEN], tmpname[BX_PATHNAME_LEN]; + if (type == PLUGTYPE_SOUND) { + sprintf(tmpname, SOUND_PLUGIN_FILENAME_FORMAT, name); + } else if (type == PLUGTYPE_NETWORK) { + sprintf(tmpname, NET_PLUGIN_FILENAME_FORMAT, name); + } else { + sprintf(tmpname, PLUGIN_FILENAME_FORMAT, name); + } + sprintf(plugin_filename, "%s%s", PLUGIN_PATH, tmpname); + + // Set context so that any devices that the plugin registers will + // be able to see which plugin created them. The registration will + // be called from either dlopen (global constructors) or plugin_init. + BX_ASSERT(current_plugin_context == NULL); + current_plugin_context = plugin; +#if defined(WIN32) + char *ptr; + plugin->handle = LoadLibrary(plugin_filename); + if (!plugin->handle) { + if (GetEnvironmentVariable("LTDL_LIBRARY_PATH", dll_path_list, MAX_PATH)) { + ptr = strtok(dll_path_list, ";"); + while ((ptr) && !plugin->handle) { + sprintf(plugin_filename, "%s\\%s", ptr, tmpname); + plugin->handle = LoadLibrary(plugin_filename); + ptr = strtok(NULL, ";"); + } + } + } + BX_INFO(("DLL handle is %p", plugin->handle)); + if (!plugin->handle) { + current_plugin_context = NULL; + BX_PANIC(("LoadLibrary failed for module '%s' (%s): error=%d", name, + plugin_filename, GetLastError())); + delete plugin; + return; + } +#else + plugin->handle = lt_dlopen(plugin_filename); + BX_INFO(("lt_dlhandle is %p", plugin->handle)); + if (!plugin->handle) { + current_plugin_context = NULL; + BX_PANIC(("dlopen failed for module '%s' (%s): %s", name, plugin_filename, + lt_dlerror())); + delete plugin; + return; + } +#endif + + if (type == PLUGTYPE_GUI) { + sprintf(tmpname, GUI_PLUGIN_INIT_FMT_STRING, name); + } else if (type == PLUGTYPE_SOUND) { + sprintf(tmpname, SOUND_PLUGIN_INIT_FMT_STRING, name); + } else if (type == PLUGTYPE_NETWORK) { + sprintf(tmpname, NET_PLUGIN_INIT_FMT_STRING, name); + } else if (type != PLUGTYPE_USER) { + sprintf(tmpname, PLUGIN_INIT_FMT_STRING, name); + } else { + sprintf(tmpname, PLUGIN_INIT_FMT_STRING, "user"); + } +#if defined(WIN32) + plugin->plugin_init = (plugin_init_t) GetProcAddress(plugin->handle, tmpname); + if (plugin->plugin_init == NULL) { + pluginlog->panic("could not find plugin_init: error=%d", GetLastError()); + plugin_abort(); + } +#else + plugin->plugin_init = (plugin_init_t) lt_dlsym(plugin->handle, tmpname); + if (plugin->plugin_init == NULL) { + pluginlog->panic("could not find plugin_init: %s", lt_dlerror()); + plugin_abort(); + } +#endif + + if (type == PLUGTYPE_GUI) { + sprintf(tmpname, GUI_PLUGIN_FINI_FMT_STRING, name); + } else if (type == PLUGTYPE_SOUND) { + sprintf(tmpname, SOUND_PLUGIN_FINI_FMT_STRING, name); + } else if (type == PLUGTYPE_NETWORK) { + sprintf(tmpname, NET_PLUGIN_FINI_FMT_STRING, name); + } else if (type != PLUGTYPE_USER) { + sprintf(tmpname, PLUGIN_FINI_FMT_STRING, name); + } else { + sprintf(tmpname, PLUGIN_FINI_FMT_STRING, "user"); + } +#if defined(WIN32) + plugin->plugin_fini = (plugin_fini_t) GetProcAddress(plugin->handle, tmpname); + if (plugin->plugin_fini == NULL) { + pluginlog->panic("could not find plugin_fini: error=%d", GetLastError()); + plugin_abort(); + } +#else + plugin->plugin_fini = (plugin_fini_t) lt_dlsym(plugin->handle, tmpname); + if (plugin->plugin_fini == NULL) { + pluginlog->panic("could not find plugin_fini: %s", lt_dlerror()); + plugin_abort(); + } +#endif + pluginlog->info("loaded plugin %s",plugin_filename); + + /* Insert plugin at the _end_ of the plugin linked list. */ + plugin->next = NULL; + + if (!plugins) { + /* Empty list, this become the first entry. */ + plugins = plugin; + } else { + /* Non-empty list. Add to end. */ + temp = plugins; + + while (temp->next) + temp = temp->next; + + temp->next = plugin; + } + + plugin_init_one(plugin); + + // check that context didn't change. This should only happen if we + // need a reentrant plugin_load. + BX_ASSERT(current_plugin_context == plugin); + current_plugin_context = NULL; +} + +void plugin_abort(void) +{ + pluginlog->panic("plugin load aborted"); +} + +#endif /* end of #if BX_PLUGINS */ + +/************************************************************************/ +/* Plugin system: initialisation of plugins entry points */ +/************************************************************************/ + + void +plugin_startup(void) +{ + pluginRegisterIRQ = builtinRegisterIRQ; + pluginUnregisterIRQ = builtinUnregisterIRQ; + + pluginSetHRQHackCallback = builtinSetHRQHackCallback; + pluginSetHRQ = builtinSetHRQ; + + pluginRegisterIOReadHandler = builtinRegisterIOReadHandler; + pluginRegisterIOWriteHandler = builtinRegisterIOWriteHandler; + + pluginUnregisterIOReadHandler = builtinUnregisterIOReadHandler; + pluginUnregisterIOWriteHandler = builtinUnregisterIOWriteHandler; + + pluginRegisterIOReadHandlerRange = builtinRegisterIOReadHandlerRange; + pluginRegisterIOWriteHandlerRange = builtinRegisterIOWriteHandlerRange; + + pluginUnregisterIOReadHandlerRange = builtinUnregisterIOReadHandlerRange; + pluginUnregisterIOWriteHandlerRange = builtinUnregisterIOWriteHandlerRange; + + pluginRegisterDefaultIOReadHandler = builtinRegisterDefaultIOReadHandler; + pluginRegisterDefaultIOWriteHandler = builtinRegisterDefaultIOWriteHandler; + + pluginlog = new logfunctions(); + pluginlog->put("PLUGIN"); +#if BX_PLUGINS && !defined(WIN32) + int status = lt_dlinit(); + if (status != 0) { + BX_ERROR(("initialization error in ltdl library (for loading plugins)")); + BX_PANIC(("error message was: %s", lt_dlerror())); + } +#endif +} + + +/************************************************************************/ +/* Plugin system: Device registration */ +/************************************************************************/ + +void pluginRegisterDeviceDevmodel(plugin_t *plugin, plugintype_t type, bx_devmodel_c *devmodel, const char *name) +{ + device_t **devlist; + + device_t *device = new device_t; + + device->name = name; + BX_ASSERT(devmodel != NULL); + device->devmodel = devmodel; + device->plugin = plugin; // this can be NULL + device->next = NULL; + device->plugtype = type; + + switch (type) { + case PLUGTYPE_CORE: + devlist = &core_devices; + break; + case PLUGTYPE_STANDARD: + case PLUGTYPE_OPTIONAL: + case PLUGTYPE_USER: + default: + devlist = &devices; + break; + } + + if (!*devlist) { + /* Empty list, this become the first entry. */ + *devlist = device; + } else { + /* Non-empty list. Add to end. */ + device_t *temp = *devlist; + + while (temp->next) + temp = temp->next; + + temp->next = device; + } +} + +/************************************************************************/ +/* Plugin system: Remove registered plugin device */ +/************************************************************************/ + +void pluginUnregisterDeviceDevmodel(const char *name) +{ + device_t *device, *prev = NULL; + + for (device = devices; device; device = device->next) { + if (!strcmp(name, device->name)) { + if (prev == NULL) { + devices = device->next; + } else { + prev->next = device->next; + } + delete device; + break; + } else { + prev = device; + } + } +} + +/************************************************************************/ +/* Plugin system: Check if a plugin is loaded */ +/************************************************************************/ + +bx_bool pluginDevicePresent(const char *name) +{ + device_t *device; + + for (device = devices; device; device = device->next) + { + if (!strcmp(name, device->name)) return 1; + } + + return 0; +} + +#if BX_PLUGINS +/************************************************************************/ +/* Plugin system: Load one plugin */ +/************************************************************************/ + +int bx_load_plugin(const char *name, plugintype_t type) +{ + char *namecopy = new char[1+strlen(name)]; + strcpy(namecopy, name); + plugin_load(namecopy, type); + return 1; +} + +void bx_unload_plugin(const char *name, bx_bool devflag) +{ + plugin_t *plugin, *prev = NULL; + + for (plugin = plugins; plugin; plugin = plugin->next) { + if (!strcmp(plugin->name, name)) { + if (devflag) { + pluginUnregisterDeviceDevmodel(plugin->name); + } + plugin = plugin_unload(plugin); + if (prev == NULL) { + plugins = plugin; + } else { + prev->next = plugin; + } + break; + } else { + prev = plugin; + } + } +} + +#endif /* end of #if BX_PLUGINS */ + +/*************************************************************************/ +/* Plugin system: Execute init function of all registered plugin-devices */ +/*************************************************************************/ + +void bx_init_plugins() +{ + device_t *device; + + for (device = core_devices; device; device = device->next) { + pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name); + device->devmodel->init(); + } + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_STANDARD) { + pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name); + device->devmodel->init(); + } + } + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_OPTIONAL) { + pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name); + device->devmodel->init(); + } + } +#if BX_PLUGINS + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_USER) { + pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name); + device->devmodel->init(); + } + } +#endif +} + +/**************************************************************************/ +/* Plugin system: Execute reset function of all registered plugin-devices */ +/**************************************************************************/ + +void bx_reset_plugins(unsigned signal) +{ + device_t *device; + + for (device = core_devices; device; device = device->next) { + pluginlog->info("reset of '%s' plugin device by virtual method",device->name); + device->devmodel->reset(signal); + } + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_STANDARD) { + pluginlog->info("reset of '%s' plugin device by virtual method",device->name); + device->devmodel->reset(signal); + } + } + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_OPTIONAL) { + pluginlog->info("reset of '%s' plugin device by virtual method",device->name); + device->devmodel->reset(signal); + } + } +#if BX_PLUGINS + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_USER) { + pluginlog->info("reset of '%s' plugin device by virtual method",device->name); + device->devmodel->reset(signal); + } + } +#endif +} + +/*******************************************************/ +/* Plugin system: Unload all registered plugin-devices */ +/*******************************************************/ + +void bx_unload_plugins() +{ + device_t *device, *next; + + device = devices; + while (device != NULL) { + if (device->plugin != NULL) { +#if BX_PLUGINS + bx_unload_plugin(device->name, 0); +#endif + } else { +#if !BX_PLUGINS + if (!bx_unload_opt_plugin(device->name, 0)) { + delete device->devmodel; + } +#endif + } + next = device->next; + delete device; + device = next; + } + devices = NULL; +} + +void bx_unload_core_plugins() +{ + device_t *device, *next; + + device = core_devices; + while (device != NULL) { + if (device->plugin != NULL) { +#if BX_PLUGINS + bx_unload_plugin(device->name, 0); +#endif + } else { + delete device->devmodel; + } + next = device->next; + delete device; + device = next; + } + core_devices = NULL; +} + +/**************************************************************************/ +/* Plugin system: Register device state of all registered plugin-devices */ +/**************************************************************************/ + +void bx_plugins_register_state() +{ + device_t *device; + + for (device = core_devices; device; device = device->next) { + pluginlog->info("register state of '%s' plugin device by virtual method",device->name); + device->devmodel->register_state(); + } + for (device = devices; device; device = device->next) { + pluginlog->info("register state of '%s' plugin device by virtual method",device->name); + device->devmodel->register_state(); + } +} + +/***************************************************************************/ +/* Plugin system: Execute code after restoring state of all plugin devices */ +/***************************************************************************/ + +void bx_plugins_after_restore_state() +{ + device_t *device; + + for (device = core_devices; device; device = device->next) { + device->devmodel->after_restore_state(); + } + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_STANDARD) { + device->devmodel->after_restore_state(); + } + } + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_OPTIONAL) { + device->devmodel->after_restore_state(); + } + } +#if BX_PLUGINS + for (device = devices; device; device = device->next) { + if (device->plugtype == PLUGTYPE_USER) { + device->devmodel->after_restore_state(); + } + } +#endif +} + +#if !BX_PLUGINS + +// Special code for loading gui, optional and sound plugins when plugin support +// is turned off. + +typedef struct { + const char* name; + plugintype_t type; + plugin_init_t plugin_init; + plugin_fini_t plugin_fini; + bx_bool status; +} builtin_plugin_t; + +#define BUILTIN_GUI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_GUI, lib##mod##_gui_plugin_init, lib##mod##_gui_plugin_fini, 0} +#define BUILTIN_OPT_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_OPTIONAL, lib##mod##_LTX_plugin_init, lib##mod##_LTX_plugin_fini, 0} +#define BUILTIN_SND_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_SOUND, lib##mod##_sound_plugin_init, lib##mod##_sound_plugin_fini, 0} +#define BUILTIN_NET_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_NETWORK, lib##mod##_net_plugin_init, lib##mod##_net_plugin_fini, 0} + +static builtin_plugin_t builtin_plugins[] = { +#if BX_WITH_AMIGAOS + BUILTIN_GUI_PLUGIN_ENTRY(amigaos), +#endif +#if BX_WITH_CARBON + BUILTIN_GUI_PLUGIN_ENTRY(carbon), +#endif +#if BX_WITH_MACOS + BUILTIN_GUI_PLUGIN_ENTRY(macos), +#endif +#if BX_WITH_NOGUI + BUILTIN_GUI_PLUGIN_ENTRY(nogui), +#endif +#if BX_WITH_ESSENCE + BUILTIN_GUI_PLUGIN_ENTRY(essence), +#endif +#if BX_WITH_RFB + BUILTIN_GUI_PLUGIN_ENTRY(rfb), +#endif +#if BX_WITH_SDL + BUILTIN_GUI_PLUGIN_ENTRY(sdl), +#endif +#if BX_WITH_SDL2 + BUILTIN_GUI_PLUGIN_ENTRY(sdl2), +#endif +#if BX_WITH_SVGA + BUILTIN_GUI_PLUGIN_ENTRY(svga), +#endif +#if BX_WITH_TERM + BUILTIN_GUI_PLUGIN_ENTRY(term), +#endif +#if BX_WITH_VNCSRV + BUILTIN_GUI_PLUGIN_ENTRY(vncsrv), +#endif +#if BX_WITH_WIN32 + BUILTIN_GUI_PLUGIN_ENTRY(win32), +#endif +#if BX_WITH_WX + BUILTIN_GUI_PLUGIN_ENTRY(wx), +#endif +#if BX_WITH_X11 + BUILTIN_GUI_PLUGIN_ENTRY(x), +#endif + BUILTIN_OPT_PLUGIN_ENTRY(unmapped), + BUILTIN_OPT_PLUGIN_ENTRY(biosdev), + BUILTIN_OPT_PLUGIN_ENTRY(speaker), + BUILTIN_OPT_PLUGIN_ENTRY(extfpuirq), + BUILTIN_OPT_PLUGIN_ENTRY(parallel), + BUILTIN_OPT_PLUGIN_ENTRY(serial), +#if BX_SUPPORT_BUSMOUSE + BUILTIN_OPT_PLUGIN_ENTRY(busmouse), +#endif +#if BX_SUPPORT_E1000 + BUILTIN_OPT_PLUGIN_ENTRY(e1000), +#endif +#if BX_SUPPORT_ES1370 + BUILTIN_OPT_PLUGIN_ENTRY(es1370), +#endif +#if BX_SUPPORT_GAMEPORT + BUILTIN_OPT_PLUGIN_ENTRY(gameport), +#endif +#if BX_SUPPORT_IODEBUG + BUILTIN_OPT_PLUGIN_ENTRY(iodebug), +#endif +#if BX_SUPPORT_NE2K + BUILTIN_OPT_PLUGIN_ENTRY(ne2k), +#endif +#if BX_SUPPORT_PCIDEV + BUILTIN_OPT_PLUGIN_ENTRY(pcidev), +#endif +#if BX_SUPPORT_PCIPNIC + BUILTIN_OPT_PLUGIN_ENTRY(pcipnic), +#endif +#if BX_SUPPORT_SB16 + BUILTIN_OPT_PLUGIN_ENTRY(sb16), +#endif +#if BX_SUPPORT_USB_UHCI + BUILTIN_OPT_PLUGIN_ENTRY(usb_uhci), +#endif +#if BX_SUPPORT_USB_OHCI + BUILTIN_OPT_PLUGIN_ENTRY(usb_ohci), +#endif +#if BX_SUPPORT_USB_EHCI + BUILTIN_OPT_PLUGIN_ENTRY(usb_ehci), +#endif +#if BX_SUPPORT_USB_XHCI + BUILTIN_OPT_PLUGIN_ENTRY(usb_xhci), +#endif +#if BX_SUPPORT_VOODOO + BUILTIN_OPT_PLUGIN_ENTRY(voodoo), +#endif +#if BX_SUPPORT_SOUNDLOW + BUILTIN_SND_PLUGIN_ENTRY(dummy), + BUILTIN_SND_PLUGIN_ENTRY(file), +#if BX_HAVE_SOUND_ALSA + BUILTIN_SND_PLUGIN_ENTRY(alsa), +#endif +#if BX_HAVE_SOUND_OSS + BUILTIN_SND_PLUGIN_ENTRY(oss), +#endif +#if BX_HAVE_SOUND_OSX + BUILTIN_SND_PLUGIN_ENTRY(osx), +#endif +#if BX_HAVE_SOUND_SDL + BUILTIN_SND_PLUGIN_ENTRY(sdl), +#endif +#if BX_HAVE_SOUND_WIN + BUILTIN_SND_PLUGIN_ENTRY(win), +#endif +#endif +#if BX_NETWORKING +#if BX_NETMOD_FBSD + BUILTIN_NET_PLUGIN_ENTRY(fbsd), +#endif +#if BX_NETMOD_LINUX + BUILTIN_NET_PLUGIN_ENTRY(linux), +#endif + BUILTIN_NET_PLUGIN_ENTRY(null), +#if BX_NETMOD_SLIRP + BUILTIN_NET_PLUGIN_ENTRY(slirp), +#endif +#if BX_NETMOD_SOCKET + BUILTIN_NET_PLUGIN_ENTRY(socket), +#endif +#if BX_NETMOD_TAP + BUILTIN_NET_PLUGIN_ENTRY(tap), +#endif +#if BX_NETMOD_TUNTAP + BUILTIN_NET_PLUGIN_ENTRY(tuntap), +#endif +#if BX_NETMOD_VDE + BUILTIN_NET_PLUGIN_ENTRY(vde), +#endif + BUILTIN_NET_PLUGIN_ENTRY(vnet), +#if BX_NETMOD_WIN32 + BUILTIN_NET_PLUGIN_ENTRY(win32), +#endif +#endif + {"NULL", PLUGTYPE_GUI, NULL, NULL, 0} +}; + +int bx_load_plugin2(const char *name, plugintype_t type) +{ + int i = 0; + while (strcmp(builtin_plugins[i].name, "NULL")) { + if ((!strcmp(name, builtin_plugins[i].name)) && + (type == builtin_plugins[i].type)) { + if (builtin_plugins[i].status == 0) { + builtin_plugins[i].plugin_init(NULL, type); + builtin_plugins[i].status = 1; + } + return 1; + } + i++; + }; + return 0; +} + +int bx_unload_opt_plugin(const char *name, bx_bool devflag) +{ + int i = 0; + while (strcmp(builtin_plugins[i].name, "NULL")) { + if ((!strcmp(name, builtin_plugins[i].name)) && + (builtin_plugins[i].type == PLUGTYPE_OPTIONAL)) { + if (builtin_plugins[i].status == 1) { + if (devflag) { + pluginUnregisterDeviceDevmodel(builtin_plugins[i].name); + } + builtin_plugins[i].plugin_fini(); + builtin_plugins[i].status = 0; + } + return 1; + } + i++; + }; + return 0; +} + +#endif + +} diff --git a/ports/bochs/plugin.h b/ports/bochs/plugin.h new file mode 100644 index 0000000..6045ea3 --- /dev/null +++ b/ports/bochs/plugin.h @@ -0,0 +1,468 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: plugin.h 13167 2017-03-31 21:32:58Z vruppert $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002-2017 The Bochs Project +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +///////////////////////////////////////////////////////////////////////// +// +// This file provides macros and types needed for plugins. It is based on +// the plugin.h file from plex86, but with significant changes to make +// it work in Bochs. +// Plex86 is Copyright (C) 1999-2000 The plex86 developers team +// +///////////////////////////////////////////////////////////////////////// + +#ifndef __PLUGIN_H +#define __PLUGIN_H + +#include "extplugin.h" + +class bx_devices_c; +BOCHSAPI extern logfunctions *pluginlog; + +#ifdef __cplusplus +extern "C" { +#endif + +#define BX_PLUGIN_UNMAPPED "unmapped" +#define BX_PLUGIN_BIOSDEV "biosdev" +#define BX_PLUGIN_CMOS "cmos" +#define BX_PLUGIN_VGA "vga" +#define BX_PLUGIN_CIRRUS "svga_cirrus" +#define BX_PLUGIN_FLOPPY "floppy" +#define BX_PLUGIN_PARALLEL "parallel" +#define BX_PLUGIN_SERIAL "serial" +#define BX_PLUGIN_KEYBOARD "keyboard" +#define BX_PLUGIN_BUSMOUSE "busmouse" +#define BX_PLUGIN_HARDDRV "harddrv" +#define BX_PLUGIN_HDIMAGE "hdimage" +#define BX_PLUGIN_DMA "dma" +#define BX_PLUGIN_PIC "pic" +#define BX_PLUGIN_PIT "pit" +#define BX_PLUGIN_PCI "pci" +#define BX_PLUGIN_PCI2ISA "pci2isa" +#define BX_PLUGIN_PCI_IDE "pci_ide" +#define BX_PLUGIN_SB16 "sb16" +#define BX_PLUGIN_ES1370 "es1370" +#define BX_PLUGIN_NE2K "ne2k" +#define BX_PLUGIN_EXTFPUIRQ "extfpuirq" +#define BX_PLUGIN_PCIDEV "pcidev" +#define BX_PLUGIN_USB_COMMON "usb_common" +#define BX_PLUGIN_USB_UHCI "usb_uhci" +#define BX_PLUGIN_USB_OHCI "usb_ohci" +#define BX_PLUGIN_USB_EHCI "usb_ehci" +#define BX_PLUGIN_USB_XHCI "usb_xhci" +#define BX_PLUGIN_PCIPNIC "pcipnic" +#define BX_PLUGIN_E1000 "e1000" +#define BX_PLUGIN_GAMEPORT "gameport" +#define BX_PLUGIN_SPEAKER "speaker" +#define BX_PLUGIN_ACPI "acpi" +#define BX_PLUGIN_IODEBUG "iodebug" +#define BX_PLUGIN_IOAPIC "ioapic" +#define BX_PLUGIN_VOODOO "voodoo" + + +#define BX_REGISTER_DEVICE_DEVMODEL(a,b,c,d) pluginRegisterDeviceDevmodel(a,b,c,d) +#define BX_UNREGISTER_DEVICE_DEVMODEL(a) pluginUnregisterDeviceDevmodel(a) +#define PLUG_device_present(a) pluginDevicePresent(a) + +#if BX_PLUGINS + +#define PLUG_load_plugin(name,type) {bx_load_plugin(#name,type);} +#define PLUG_load_gui_plugin(name) bx_load_plugin(name,PLUGTYPE_GUI) +#define PLUG_load_opt_plugin(name) bx_load_plugin(name,PLUGTYPE_OPTIONAL) +#define PLUG_load_snd_plugin(name) bx_load_plugin(name,PLUGTYPE_SOUND) +#define PLUG_load_net_plugin(name) bx_load_plugin(name,PLUGTYPE_NETWORK) +#define PLUG_load_user_plugin(name) {bx_load_plugin(name,PLUGTYPE_USER);} +#define PLUG_unload_plugin(name) {bx_unload_plugin(#name,1);} +#define PLUG_unload_opt_plugin(name) bx_unload_plugin(name,1) +#define PLUG_unload_snd_plugin(name) bx_unload_plugin(name,0) +#define PLUG_unload_net_plugin(name) bx_unload_plugin(name,0) +#define PLUG_unload_user_plugin(name) {bx_unload_plugin(name,1);} + +#define DEV_register_ioread_handler(b,c,d,e,f) pluginRegisterIOReadHandler(b,c,d,e,f) +#define DEV_register_iowrite_handler(b,c,d,e,f) pluginRegisterIOWriteHandler(b,c,d,e,f) +#define DEV_unregister_ioread_handler(b,c,d,e) pluginUnregisterIOReadHandler(b,c,d,e) +#define DEV_unregister_iowrite_handler(b,c,d,e) pluginUnregisterIOWriteHandler(b,c,d,e) +#define DEV_register_ioread_handler_range(b,c,d,e,f,g) pluginRegisterIOReadHandlerRange(b,c,d,e,f,g) +#define DEV_register_iowrite_handler_range(b,c,d,e,f,g) pluginRegisterIOWriteHandlerRange(b,c,d,e,f,g) +#define DEV_unregister_ioread_handler_range(b,c,d,e,f) pluginUnregisterIOReadHandlerRange(b,c,d,e,f) +#define DEV_unregister_iowrite_handler_range(b,c,d,e,f) pluginUnregisterIOWriteHandlerRange(b,c,d,e,f) +#define DEV_register_default_ioread_handler(b,c,d,e) pluginRegisterDefaultIOReadHandler(b,c,d,e) +#define DEV_register_default_iowrite_handler(b,c,d,e) pluginRegisterDefaultIOWriteHandler(b,c,d,e) + +#define DEV_register_irq(b,c) pluginRegisterIRQ(b,c) +#define DEV_unregister_irq(b,c) pluginUnregisterIRQ(b,c) + +#else + +// When plugins are off, PLUG_load_plugin will call the plugin_init function +// directly. +#define PLUG_load_plugin(name,type) {lib##name##_LTX_plugin_init(NULL,type);} +#define PLUG_load_gui_plugin(name) bx_load_plugin2(name,PLUGTYPE_GUI) +#define PLUG_load_opt_plugin(name) bx_load_plugin2(name,PLUGTYPE_OPTIONAL) +#define PLUG_load_snd_plugin(name) bx_load_plugin2(name,PLUGTYPE_SOUND) +#define PLUG_load_net_plugin(name) bx_load_plugin2(name,PLUGTYPE_NETWORK) +#define PLUG_unload_plugin(name) {lib##name##_LTX_plugin_fini();} +#define PLUG_unload_opt_plugin(name) bx_unload_opt_plugin(name,1); + +#define DEV_register_ioread_handler(b,c,d,e,f) bx_devices.register_io_read_handler(b,c,d,e,f) +#define DEV_register_iowrite_handler(b,c,d,e,f) bx_devices.register_io_write_handler(b,c,d,e,f) +#define DEV_unregister_ioread_handler(b,c,d,e) bx_devices.unregister_io_read_handler(b,c,d,e) +#define DEV_unregister_iowrite_handler(b,c,d,e) bx_devices.unregister_io_write_handler(b,c,d,e) +#define DEV_register_ioread_handler_range(b,c,d,e,f,g) bx_devices.register_io_read_handler_range(b,c,d,e,f,g) +#define DEV_register_iowrite_handler_range(b,c,d,e,f,g) bx_devices.register_io_write_handler_range(b,c,d,e,f,g) +#define DEV_unregister_ioread_handler_range(b,c,d,e,f) bx_devices.unregister_io_read_handler_range(b,c,d,e,f) +#define DEV_unregister_iowrite_handler_range(b,c,d,e,f) bx_devices.unregister_io_write_handler_range(b,c,d,e,f) +#define DEV_register_default_ioread_handler(b,c,d,e) bx_devices.register_default_io_read_handler(b,c,d,e) +#define DEV_register_default_iowrite_handler(b,c,d,e) bx_devices.register_default_io_write_handler(b,c,d,e) +#define DEV_register_irq(b,c) bx_devices.register_irq(b,c) +#define DEV_unregister_irq(b,c) bx_devices.unregister_irq(b,c) + +#endif // #if BX_PLUGINS + +///////// Common device macros +#define DEV_init_devices() {bx_devices.init(BX_MEM(0)); } +#define DEV_reset_devices(type) {bx_devices.reset(type); } +#define DEV_register_state() {bx_devices.register_state(); } +#define DEV_after_restore_state() {bx_devices.after_restore_state(); } +#define DEV_register_timer(a,b,c,d,e,f) bx_pc_system.register_timer(a,b,c,d,e,f) + +///////// Removable devices macros +#define DEV_optional_key_enq(a) (bx_devices.optional_key_enq(a)) +#define DEV_register_removable_keyboard(a,b) (bx_devices.register_removable_keyboard(a,b)) +#define DEV_unregister_removable_keyboard(a) (bx_devices.unregister_removable_keyboard(a)) +#define DEV_register_default_mouse(a,b,c) (bx_devices.register_default_mouse(a,b,c)) +#define DEV_register_removable_mouse(a,b,c) (bx_devices.register_removable_mouse(a,b,c)) +#define DEV_unregister_removable_mouse(a) (bx_devices.unregister_removable_mouse(a)) + +///////// I/O APIC macros +#define DEV_ioapic_present() (bx_devices.pluginIOAPIC != &bx_devices.stubIOAPIC) +#define DEV_ioapic_set_enabled(a,b) (bx_devices.pluginIOAPIC->set_enabled(a,b)) +#define DEV_ioapic_receive_eoi(a) (bx_devices.pluginIOAPIC->receive_eoi(a)) +#define DEV_ioapic_set_irq_level(a,b) (bx_devices.pluginIOAPIC->set_irq_level(a,b)) + +///////// CMOS macros +#define DEV_cmos_get_reg(a) (bx_devices.pluginCmosDevice->get_reg(a)) +#define DEV_cmos_set_reg(a,b) (bx_devices.pluginCmosDevice->set_reg(a,b)) +#define DEV_cmos_checksum() (bx_devices.pluginCmosDevice->checksum_cmos()) + +///////// keyboard macros +#define DEV_kbd_gen_scancode(key) (bx_devices.gen_scancode(key)) +#define DEV_kbd_paste_bytes(bytes, count) \ + (bx_devices.pluginKeyboard->paste_bytes(bytes,count)) +#define DEV_kbd_release_keys() (bx_devices.pluginKeyboard->release_keys()) + +///////// mouse macros +#define DEV_mouse_enabled_changed(en) (bx_devices.mouse_enabled_changed(en)) +#define DEV_mouse_motion(dx, dy, dz, bs, absxy) (bx_devices.mouse_motion(dx, dy, dz, bs, absxy)) + +///////// hard drive macros +#define DEV_hd_read_handler(a, b, c) \ + (bx_devices.pluginHardDrive->virt_read_handler(b, c)) +#define DEV_hd_write_handler(a, b, c, d) \ + (bx_devices.pluginHardDrive->virt_write_handler(b, c, d)) +#define DEV_hd_get_first_cd_handle() \ + (bx_devices.pluginHardDrive->get_first_cd_handle()) +#define DEV_hd_get_cd_media_status(handle) \ + (bx_devices.pluginHardDrive->get_cd_media_status(handle)) +#define DEV_hd_set_cd_media_status(handle, status) \ + (bx_devices.pluginHardDrive->set_cd_media_status(handle, status)) +#define DEV_hd_bmdma_read_sector(a,b,c) bx_devices.pluginHardDrive->bmdma_read_sector(a,b,c) +#define DEV_hd_bmdma_write_sector(a,b) bx_devices.pluginHardDrive->bmdma_write_sector(a,b) +#define DEV_hd_bmdma_complete(a) bx_devices.pluginHardDrive->bmdma_complete(a) +#define DEV_hdimage_init_image(a,b,c) bx_devices.pluginHDImageCtl->init_image(a,b,c) +#define DEV_hdimage_init_cdrom(a) bx_devices.pluginHDImageCtl->init_cdrom(a) + +#define DEV_bulk_io_quantum_requested() (bx_devices.bulkIOQuantumsRequested) +#define DEV_bulk_io_quantum_transferred() (bx_devices.bulkIOQuantumsTransferred) +#define DEV_bulk_io_host_addr() (bx_devices.bulkIOHostAddr) + +///////// FLOPPY macro +#define DEV_floppy_set_media_status(drive, status) bx_devices.pluginFloppyDevice->set_media_status(drive, status) + +///////// DMA macros +#define DEV_dma_register_8bit_channel(channel, dmaRead, dmaWrite, name) \ + (bx_devices.pluginDmaDevice->registerDMA8Channel(channel, dmaRead, dmaWrite, name)) +#define DEV_dma_register_16bit_channel(channel, dmaRead, dmaWrite, name) \ + (bx_devices.pluginDmaDevice->registerDMA16Channel(channel, dmaRead, dmaWrite, name)) +#define DEV_dma_unregister_channel(channel) \ + (bx_devices.pluginDmaDevice->unregisterDMAChannel(channel)) +#define DEV_dma_set_drq(channel, val) \ + (bx_devices.pluginDmaDevice->set_DRQ(channel, val)) +#define DEV_dma_get_tc() \ + (bx_devices.pluginDmaDevice->get_TC()) +#define DEV_dma_raise_hlda() \ + (bx_devices.pluginDmaDevice->raise_HLDA()) + +///////// PIC macros +#define DEV_pic_lower_irq(b) (bx_devices.pluginPicDevice->lower_irq(b)) +#define DEV_pic_raise_irq(b) (bx_devices.pluginPicDevice->raise_irq(b)) +#define DEV_pic_set_mode(a,b) (bx_devices.pluginPicDevice->set_mode(a,b)) +#define DEV_pic_iac() (bx_devices.pluginPicDevice->IAC()) + +///////// VGA macros +#define DEV_vga_mem_read(addr) (bx_devices.pluginVgaDevice->mem_read(addr)) +#define DEV_vga_mem_write(addr, val) (bx_devices.pluginVgaDevice->mem_write(addr, val)) +#define DEV_vga_redraw_area(left, top, right, bottom) \ + (bx_devices.pluginVgaDevice->redraw_area(left, top, right, bottom)) +#define DEV_vga_get_text_snapshot(rawsnap, height, width) \ + (bx_devices.pluginVgaDevice->get_text_snapshot(rawsnap, height, width)) +#define DEV_vga_refresh(a) \ + (bx_devices.pluginVgaDevice->refresh_display(bx_devices.pluginVgaDevice,a)) +#define DEV_vga_set_override(a,b) (bx_devices.pluginVgaDevice->set_override(a,b)) + +///////// PCI macros +#define DEV_register_pci_handlers(a,b,c,d) \ + (bx_devices.register_pci_handlers(a,b,c,d)) +#define DEV_pci_get_confAddr() bx_devices.pci_get_confAddr() +#define DEV_pci_set_irq(a,b,c) bx_devices.pluginPci2IsaBridge->pci_set_irq(a,b,c) +#define DEV_pci_set_base_mem(a,b,c,d,e,f) \ + (bx_devices.pci_set_base_mem(a,b,c,d,e,f)) +#define DEV_pci_set_base_io(a,b,c,d,e,f,g,h) \ + (bx_devices.pci_set_base_io(a,b,c,d,e,f,g,h)) +#define DEV_ide_bmdma_present() bx_devices.pluginPciIdeController->bmdma_present() +#define DEV_ide_bmdma_set_irq(a) bx_devices.pluginPciIdeController->bmdma_set_irq(a) +#define DEV_ide_bmdma_start_transfer(a) \ + bx_devices.pluginPciIdeController->bmdma_start_transfer(a) +#define DEV_acpi_generate_smi(a) bx_devices.pluginACPIController->generate_smi(a) + +///////// Speaker macros +#define DEV_speaker_beep_on(frequency) bx_devices.pluginSpeaker->beep_on(frequency) +#define DEV_speaker_beep_off() bx_devices.pluginSpeaker->beep_off() + +///////// Memory macros +#define DEV_register_memory_handlers(param,rh,wh,b,e) \ + bx_devices.mem->registerMemoryHandlers(param,rh,wh,b,e) +#define DEV_unregister_memory_handlers(param,b,e) \ + bx_devices.mem->unregisterMemoryHandlers(param,b,e) +#define DEV_mem_set_memory_type(a,b,c) \ + bx_devices.mem->set_memory_type((memory_area_t)a,b,c) +#define DEV_mem_set_bios_write(a) bx_devices.mem->set_bios_write(a) + +///////// USB device macros +#define DEV_usb_init_device(a,b,c,d) (usbdev_type)bx_devices.pluginUsbDevCtl->init_device(a,b,(void**)c,d) +#define DEV_usb_send_msg(a,b) bx_devices.pluginUsbDevCtl->usb_send_msg((void*)a,b) + +///////// Sound module macros +#define DEV_sound_get_waveout(a) (bx_soundmod_ctl.get_waveout(a)) +#define DEV_sound_get_wavein() (bx_soundmod_ctl.get_wavein()) +#define DEV_sound_get_midiout(a) (bx_soundmod_ctl.get_midiout(a)) + +///////// Networking module macro +#define DEV_net_init_module(a,b,c,d) \ + ((eth_pktmover_c*)bx_netmod_ctl.init_module(a,(void*)b,(void*)c,d)) + +///////// Gameport macro +#define DEV_gameport_set_enabled(a) bx_devices.pluginGameport->set_enabled(a) + + +#if BX_HAVE_DLFCN_H +#include +#endif + +typedef Bit32u (*ioReadHandler_t)(void *, Bit32u, unsigned); +typedef void (*ioWriteHandler_t)(void *, Bit32u, Bit32u, unsigned); + +extern plugin_t *plugins; + +typedef struct _device_t +{ + const char *name; + plugin_t *plugin; + plugintype_t plugtype; + + class bx_devmodel_c *devmodel; // BBD hack + + struct _device_t *next; +} device_t; + + +extern device_t *devices; + +void plugin_startup(void); + +/* === Device Stuff === */ +typedef void (*deviceInitMem_t)(BX_MEM_C *); +typedef void (*deviceInitDev_t)(void); +typedef void (*deviceReset_t)(unsigned); + +BOCHSAPI void pluginRegisterDeviceDevmodel(plugin_t *plugin, plugintype_t type, bx_devmodel_c *dev, const char *name); +BOCHSAPI void pluginUnregisterDeviceDevmodel(const char *name); +BOCHSAPI bx_bool pluginDevicePresent(const char *name); + +/* === IO port stuff === */ +BOCHSAPI extern int (*pluginRegisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback, + unsigned base, const char *name, Bit8u mask); +BOCHSAPI extern int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback, + unsigned base, const char *name, Bit8u mask); +BOCHSAPI extern int (*pluginUnregisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback, + unsigned base, Bit8u mask); +BOCHSAPI extern int (*pluginUnregisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback, + unsigned base, Bit8u mask); +BOCHSAPI extern int (*pluginRegisterIOReadHandlerRange)(void *thisPtr, ioReadHandler_t callback, + unsigned base, unsigned end, const char *name, Bit8u mask); +BOCHSAPI extern int (*pluginRegisterIOWriteHandlerRange)(void *thisPtr, ioWriteHandler_t callback, + unsigned base, unsigned end, const char *name, Bit8u mask); +BOCHSAPI extern int (*pluginUnregisterIOReadHandlerRange)(void *thisPtr, ioReadHandler_t callback, + unsigned begin, unsigned end, Bit8u mask); +BOCHSAPI extern int (*pluginUnregisterIOWriteHandlerRange)(void *thisPtr, ioWriteHandler_t callback, + unsigned begin, unsigned end, Bit8u mask); +BOCHSAPI extern int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback, + const char *name, Bit8u mask); +BOCHSAPI extern int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback, + const char *name, Bit8u mask); + +/* === IRQ stuff === */ +BOCHSAPI extern void (*pluginRegisterIRQ)(unsigned irq, const char *name); +BOCHSAPI extern void (*pluginUnregisterIRQ)(unsigned irq, const char *name); + +/* === HRQ stuff === */ +BOCHSAPI extern void (*pluginSetHRQ)(unsigned val); +BOCHSAPI extern void (*pluginSetHRQHackCallback)(void (*callback)(void)); + +void plugin_abort(void); + +int bx_load_plugin(const char *name, plugintype_t type); +extern void bx_unload_plugin(const char *name, bx_bool devflag); +extern void bx_init_plugins(void); +extern void bx_reset_plugins(unsigned); +extern void bx_unload_plugins(void); +extern void bx_unload_core_plugins(void); +extern void bx_plugins_register_state(void); +extern void bx_plugins_after_restore_state(void); + +#if !BX_PLUGINS +int bx_load_plugin2(const char *name, plugintype_t type); +int bx_unload_opt_plugin(const char *name, bx_bool devflag); +#endif + +// every plugin must define these, within the extern"C" block, so that +// a non-mangled function symbol is available in the shared library. +void plugin_fini(void); +int plugin_init(plugin_t *plugin, plugintype_t type); + +// still in extern "C" +#if BX_PLUGINS && defined(_MSC_VER) +#define DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(mod) \ + extern "C" __declspec(dllexport) int __cdecl lib##mod##_LTX_plugin_init(plugin_t *plugin, plugintype_t type); \ + extern "C" __declspec(dllexport) void __cdecl lib##mod##_LTX_plugin_fini(void); +#define DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(mod) \ + extern "C" __declspec(dllexport) int __cdecl lib##mod##_gui_plugin_init(plugin_t *plugin, plugintype_t type); \ + extern "C" __declspec(dllexport) void __cdecl lib##mod##_gui_plugin_fini(void); +#define DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(mod) \ + extern "C" __declspec(dllexport) int __cdecl lib##mod##_sound_plugin_init(plugin_t *plugin, plugintype_t type); \ + extern "C" __declspec(dllexport) void __cdecl lib##mod##_sound_plugin_fini(void); +#define DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(mod) \ + extern "C" __declspec(dllexport) int __cdecl lib##mod##_net_plugin_init(plugin_t *plugin, plugintype_t type); \ + extern "C" __declspec(dllexport) void __cdecl lib##mod##_net_plugin_fini(void); +#else +#define DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(mod) \ + int CDECL lib##mod##_LTX_plugin_init(plugin_t *plugin, plugintype_t type); \ + void CDECL lib##mod##_LTX_plugin_fini(void); +#define DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(mod) \ + int CDECL lib##mod##_gui_plugin_init(plugin_t *plugin, plugintype_t type); \ + void CDECL lib##mod##_gui_plugin_fini(void); +#define DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(mod) \ + int CDECL lib##mod##_sound_plugin_init(plugin_t *plugin, plugintype_t type); \ + void CDECL lib##mod##_sound_plugin_fini(void); +#define DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(mod) \ + int CDECL lib##mod##_net_plugin_init(plugin_t *plugin, plugintype_t type); \ + void CDECL lib##mod##_net_plugin_fini(void); +#endif + +// device plugins +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(harddrv) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(hdimage) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(keyboard) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(busmouse) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(serial) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(unmapped) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(biosdev) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(cmos) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(dma) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pic) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pit) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(vga) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(svga_cirrus) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(floppy) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(parallel) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pci) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pci2isa) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pci_ide) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pcidev) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(usb_common) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(usb_uhci) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(usb_ohci) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(usb_ehci) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(usb_xhci) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(sb16) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(es1370) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(netmod) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(ne2k) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pcipnic) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(e1000) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(extfpuirq) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(gameport) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(speaker) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(acpi) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(iodebug) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(ioapic) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(voodoo) +DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(user) +// gui plugins +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(amigaos) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(carbon) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(macintosh) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(nogui) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(essence) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(rfb) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(sdl) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(sdl2) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(svga) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(term) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(vncsrv) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(win32) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(wx) +DECLARE_PLUGIN_INIT_FINI_FOR_GUI_MODULE(x) +// sound driver plugins +DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(alsa) +DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(dummy) +DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(file) +DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(oss) +DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(osx) +DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(sdl) +DECLARE_PLUGIN_INIT_FINI_FOR_SOUND_MODULE(win) +// network driver plugins +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(fbsd) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(linux) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(null) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(slirp) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(socket) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(tap) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(tuntap) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(vde) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(vnet) +DECLARE_PLUGIN_INIT_FINI_FOR_NET_MODULE(win32) + + +#ifdef __cplusplus +} +#endif + +#endif /* __PLUGIN_H */ diff --git a/ports/bochs/port.sh b/ports/bochs/port.sh new file mode 100755 index 0000000..355737d --- /dev/null +++ b/ports/bochs/port.sh @@ -0,0 +1,31 @@ +set -e + +SYSROOT=`realpath root` +VERSION=2.6.9 +NAME=bochs +URL="https://netix.dl.sourceforge.net/project/$NAME/$NAME/$VERSION/$NAME-$VERSION.tar.gz" +SOURCE="bin/$NAME-$VERSION.tar.gz" + +if [ ! -f $SOURCE ]; then curl $URL > $SOURCE; fi +tar -xzf $SOURCE +mv $NAME-$VERSION bin/$NAME + +cd bin/$NAME + +cp ../../ports/bochs/config.cc . +cp ../../ports/bochs/config.h.in . +cp ../../ports/bochs/configure.in . +cp ../../ports/bochs/main.cc . +cp ../../ports/bochs/Makefile.in . +cp ../../ports/bochs/plugin.cc . +cp ../../ports/bochs/plugin.h . +cp ../../ports/bochs/essence.cc gui +cp ../../ports/bochs/gui_Makefile.in gui/Makefile.in + +autoconf +./configure --with-essence CC=x86_64-essence-gcc CXX=x86_64-essence-g++ CFLAGS=" -O2 -D _GNU_SOURCE " CXXFLAGS=" -O2 -D _GNU_SOURCE " --host=x86_64-essence --prefix=/Applications/POSIX --exec-prefix=/Applications/POSIX --enable-cpu-level=6 --enable-x86-64 --enable-all-optimizations +make -j 4 +make DESTDIR=$SYSROOT install + +cd ../.. +rm -r bin/$NAME diff --git a/ports/busybox/config b/ports/busybox/config new file mode 100644 index 0000000..e2e3a4c --- /dev/null +++ b/ports/busybox/config @@ -0,0 +1,1182 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.33.1 +# Wed Jul 14 11:33:34 2021 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Settings +# +CONFIG_DESKTOP=y +# CONFIG_EXTRA_COMPAT is not set +# CONFIG_FEDORA_COMPAT is not set +# CONFIG_INCLUDE_SUSv2 is not set +CONFIG_LONG_OPTS=y +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_LFS=y +# CONFIG_PAM is not set +CONFIG_FEATURE_DEVPTS=y +CONFIG_FEATURE_UTMP=y +CONFIG_FEATURE_WTMP=y +# CONFIG_FEATURE_PIDFILE is not set +CONFIG_PID_FILE_PATH="" +CONFIG_BUSYBOX=y +CONFIG_FEATURE_SHOW_SCRIPT=y +CONFIG_FEATURE_INSTALLER=y +# CONFIG_INSTALL_NO_USR is not set +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y +CONFIG_FEATURE_PREFER_APPLETS=y +CONFIG_BUSYBOX_EXEC_PATH="/Applications/POSIX/bin/busybox" +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_CLEAN_UP is not set +# CONFIG_FEATURE_SYSLOG_INFO is not set +# CONFIG_FEATURE_SYSLOG is not set + +# +# Build Options +# +CONFIG_STATIC=y +# CONFIG_PIE is not set +CONFIG_NOMMU=y +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +CONFIG_CROSS_COMPILER_PREFIX="x86_64-essence-" +CONFIG_EXTRA_CFLAGS="" +CONFIG_EXTRA_LDFLAGS="" +CONFIG_EXTRA_LDLIBS="" +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_STACK_OPTIMIZATION_386=y +CONFIG_STATIC_LIBGCC=y + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +CONFIG_DEBUG_PESSIMIZE=y +# CONFIG_DEBUG_SANITIZE is not set +# CONFIG_UNIT_TEST is not set +# CONFIG_WERROR is not set +# CONFIG_WARN_SIMPLE_MSG is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Library Tuning +# +# CONFIG_FEATURE_USE_BSS_TAIL is not set +CONFIG_FLOAT_DURATION=y +CONFIG_FEATURE_RTMINMAX=y +CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS=y +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_SHA3_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set +# CONFIG_FEATURE_ETC_NETWORKS is not set +# CONFIG_FEATURE_ETC_SERVICES is not set +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=255 +CONFIG_FEATURE_EDITING_SAVEHISTORY=y +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +CONFIG_FEATURE_REVERSE_SEARCH=y +CONFIG_FEATURE_TAB_COMPLETION=y +CONFIG_FEATURE_USERNAME_COMPLETION=y +CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +CONFIG_FEATURE_EDITING_WINCH=y +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +# CONFIG_LOCALE_SUPPORT is not set +CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=767 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +# CONFIG_FEATURE_USE_SENDFILE is not set +CONFIG_FEATURE_COPYBUF_KB=4 +CONFIG_FEATURE_SKIP_ROOTFS=y +CONFIG_MONOTONIC_SYSCALL=y +CONFIG_IOCTL_HEX2STR_ERROR=y +CONFIG_FEATURE_HWIB=y + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +# CONFIG_FEATURE_SEAMLESS_Z is not set +# CONFIG_AR is not set +# CONFIG_FEATURE_AR_LONG_FILENAMES is not set +# CONFIG_FEATURE_AR_CREATE is not set +# CONFIG_UNCOMPRESS is not set +CONFIG_GUNZIP=y +CONFIG_ZCAT=y +CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y +CONFIG_BUNZIP2=y +CONFIG_BZCAT=y +CONFIG_UNLZMA=y +CONFIG_LZCAT=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZCAT=y +CONFIG_XZ=y +CONFIG_BZIP2=y +CONFIG_BZIP2_SMALL=8 +CONFIG_FEATURE_BZIP2_DECOMPRESS=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_GZIP_FAST=0 +# CONFIG_FEATURE_GZIP_LEVELS is not set +CONFIG_FEATURE_GZIP_DECOMPRESS=y +CONFIG_LZOP=y +# CONFIG_UNLZOP is not set +# CONFIG_LZOPCAT is not set +# CONFIG_LZOP_COMPR_HIGH is not set +CONFIG_RPM=y +CONFIG_RPM2CPIO=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +CONFIG_FEATURE_TAR_TO_COMMAND=y +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNZIP=y +CONFIG_FEATURE_UNZIP_CDF=y +CONFIG_FEATURE_UNZIP_BZIP2=y +CONFIG_FEATURE_UNZIP_LZMA=y +CONFIG_FEATURE_UNZIP_XZ=y +# CONFIG_FEATURE_LZMA_FAST is not set + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAT=y +CONFIG_FEATURE_CATN=y +CONFIG_FEATURE_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_FEATURE_CP_REFLINK=y +CONFIG_CUT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_FEATURE_DATE_NANO is not set +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_FEATURE_DD_STATUS=y +CONFIG_DF=y +CONFIG_FEATURE_DF_FANCY=y +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +CONFIG_EXPAND=y +CONFIG_UNEXPAND=y +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FACTOR=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_HOSTID=y +CONFIG_ID=y +CONFIG_GROUPS=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y +CONFIG_LINK=y +CONFIG_LN=y +CONFIG_LOGNAME=y +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_WIDTH=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +# CONFIG_FEATURE_LS_COLOR is not set +# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set +CONFIG_MD5SUM=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SHA3SUM=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y +CONFIG_MKDIR=y +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MKTEMP=y +CONFIG_MV=y +CONFIG_NICE=y +CONFIG_NL=y +CONFIG_NOHUP=y +CONFIG_NPROC=y +CONFIG_OD=y +CONFIG_PASTE=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +CONFIG_SEQ=y +CONFIG_SHRED=y +CONFIG_SHUF=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +CONFIG_STAT=y +CONFIG_FEATURE_STAT_FORMAT=y +CONFIG_FEATURE_STAT_FILESYSTEM=y +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_SYNC=y +CONFIG_FEATURE_SYNC_FANCY=y +CONFIG_FSYNC=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TEST=y +CONFIG_TEST1=y +CONFIG_TEST2=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TIMEOUT=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_NODEREF=y +CONFIG_FEATURE_TOUCH_SUSV3=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_TRUE=y +CONFIG_TRUNCATE=y +CONFIG_TTY=y +CONFIG_UNAME=y +CONFIG_UNAME_OSNAME="GNU/Linux" +CONFIG_BB_ARCH=y +CONFIG_UNIQ=y +CONFIG_UNLINK=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_BASE32=y +CONFIG_BASE64=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +CONFIG_WHOAMI=y +CONFIG_WHO=y +CONFIG_W=y +CONFIG_USERS=y +CONFIG_YES=y + +# +# Common options +# +CONFIG_FEATURE_VERBOSE=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Console Utilities +# +# CONFIG_CHVT is not set +# CONFIG_CLEAR is not set +# CONFIG_DEALLOCVT is not set +# CONFIG_DUMPKMAP is not set +# CONFIG_FGCONSOLE is not set +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set +# CONFIG_LOADKMAP is not set +# CONFIG_OPENVT is not set +# CONFIG_RESET is not set +# CONFIG_RESIZE is not set +# CONFIG_FEATURE_RESIZE_PRINT is not set +# CONFIG_SETCONSOLE is not set +# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +# CONFIG_SETKEYCODES is not set +# CONFIG_SETLOGCONS is not set +# CONFIG_SHOWKEY is not set + +# +# Debian Utilities +# +# CONFIG_PIPE_PROGRESS is not set +# CONFIG_RUN_PARTS is not set +# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set +# CONFIG_FEATURE_RUN_PARTS_FANCY is not set +# CONFIG_START_STOP_DAEMON is not set +# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set +# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set +# CONFIG_WHICH is not set + +# +# klibc-utils +# +# CONFIG_MINIPS is not set +# CONFIG_NUKE is not set +# CONFIG_RESUME is not set +# CONFIG_RUN_INIT is not set + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_PATCH=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +# CONFIG_FEATURE_VI_8BIT is not set +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_ASK_TERMINAL=y +CONFIG_FEATURE_VI_UNDO=y +CONFIG_FEATURE_VI_UNDO_QUEUE=y +CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_EXECUTABLE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_EXEC_PLUS=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_QUIT=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_EMPTY=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_EGREP=y +CONFIG_FGREP=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y +CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y +CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y +CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y + +# +# Init Utilities +# +# CONFIG_BOOTCHARTD is not set +# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set +# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set +# CONFIG_HALT is not set +# CONFIG_POWEROFF is not set +# CONFIG_REBOOT is not set +# CONFIG_FEATURE_WAIT_FOR_INIT is not set +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +# CONFIG_INIT is not set +# CONFIG_LINUXRC is not set +# CONFIG_FEATURE_USE_INITTAB is not set +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +# CONFIG_FEATURE_INIT_SCTTY is not set +# CONFIG_FEATURE_INIT_SYSLOG is not set +# CONFIG_FEATURE_INIT_QUIET is not set +# CONFIG_FEATURE_INIT_COREDUMPS is not set +CONFIG_INIT_TERMINAL_TYPE="" +# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set + +# +# Login/Password Management Utilities +# +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set +# CONFIG_USE_BB_CRYPT is not set +# CONFIG_USE_BB_CRYPT_SHA is not set +# CONFIG_ADDGROUP is not set +# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set +# CONFIG_ADD_SHELL is not set +# CONFIG_REMOVE_SHELL is not set +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_LAST_ID=0 +CONFIG_FIRST_SYSTEM_ID=0 +CONFIG_LAST_SYSTEM_ID=0 +# CONFIG_CHPASSWD is not set +CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="" +# CONFIG_CRYPTPW is not set +# CONFIG_MKPASSWD is not set +# CONFIG_DELUSER is not set +# CONFIG_DELGROUP is not set +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +# CONFIG_GETTY is not set +# CONFIG_LOGIN is not set +# CONFIG_LOGIN_SESSION_AS_CHILD is not set +# CONFIG_LOGIN_SCRIPTS is not set +# CONFIG_FEATURE_NOLOGIN is not set +# CONFIG_FEATURE_SECURETTY is not set +# CONFIG_PASSWD is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set +# CONFIG_SU is not set +# CONFIG_FEATURE_SU_SYSLOG is not set +# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set +# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Linux Ext2 FS Progs +# +# CONFIG_CHATTR is not set +# CONFIG_FSCK is not set +# CONFIG_LSATTR is not set +# CONFIG_TUNE2FS is not set + +# +# Linux Module Utilities +# +# CONFIG_MODPROBE_SMALL is not set +# CONFIG_DEPMOD is not set +# CONFIG_INSMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODINFO is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_RMMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set +# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set +# CONFIG_FEATURE_MODUTILS_ALIAS is not set +# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set +CONFIG_DEFAULT_MODULES_DIR="" +CONFIG_DEFAULT_DEPMOD_FILE="" + +# +# Linux System Utilities +# +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +# CONFIG_BLKDISCARD is not set +# CONFIG_BLKID is not set +# CONFIG_FEATURE_BLKID_TYPE is not set +# CONFIG_BLOCKDEV is not set +# CONFIG_CAL is not set +# CONFIG_CHRT is not set +# CONFIG_DMESG is not set +# CONFIG_FEATURE_DMESG_PRETTY is not set +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +# CONFIG_FALLOCATE is not set +# CONFIG_FATATTR is not set +# CONFIG_FBSET is not set +# CONFIG_FEATURE_FBSET_FANCY is not set +# CONFIG_FEATURE_FBSET_READMODE is not set +# CONFIG_FDFORMAT is not set +# CONFIG_FDISK is not set +# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set +# CONFIG_FEATURE_FDISK_WRITABLE is not set +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +# CONFIG_FEATURE_FDISK_ADVANCED is not set +# CONFIG_FINDFS is not set +# CONFIG_FLOCK is not set +# CONFIG_FDFLUSH is not set +# CONFIG_FREERAMDISK is not set +# CONFIG_FSCK_MINIX is not set +# CONFIG_FSFREEZE is not set +# CONFIG_FSTRIM is not set +# CONFIG_GETOPT is not set +# CONFIG_FEATURE_GETOPT_LONG is not set +# CONFIG_HEXDUMP is not set +# CONFIG_HD is not set +# CONFIG_XXD is not set +# CONFIG_HWCLOCK is not set +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IONICE is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_FANCY is not set +# CONFIG_LOSETUP is not set +# CONFIG_LSPCI is not set +# CONFIG_LSUSB is not set +# CONFIG_MDEV is not set +# CONFIG_FEATURE_MDEV_CONF is not set +# CONFIG_FEATURE_MDEV_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set +# CONFIG_FEATURE_MDEV_EXEC is not set +# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set +# CONFIG_FEATURE_MDEV_DAEMON is not set +# CONFIG_MESG is not set +# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set +# CONFIG_MKE2FS is not set +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_REISER is not set +# CONFIG_MKDOSFS is not set +# CONFIG_MKFS_VFAT is not set +# CONFIG_MKSWAP is not set +# CONFIG_FEATURE_MKSWAP_UUID is not set +# CONFIG_MORE is not set +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_FEATURE_MOUNT_OTHERTAB is not set +# CONFIG_MOUNTPOINT is not set +# CONFIG_NOLOGIN is not set +# CONFIG_NOLOGIN_DEPENDENCIES is not set +# CONFIG_NSENTER is not set +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +# CONFIG_RDEV is not set +# CONFIG_READPROFILE is not set +# CONFIG_RENICE is not set +# CONFIG_REV is not set +# CONFIG_RTCWAKE is not set +# CONFIG_SCRIPT is not set +# CONFIG_SCRIPTREPLAY is not set +# CONFIG_SETARCH is not set +# CONFIG_LINUX32 is not set +# CONFIG_LINUX64 is not set +# CONFIG_SETPRIV is not set +# CONFIG_FEATURE_SETPRIV_DUMP is not set +# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set +# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set +# CONFIG_SETSID is not set +# CONFIG_SWAPON is not set +# CONFIG_FEATURE_SWAPON_DISCARD is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +# CONFIG_SWAPOFF is not set +# CONFIG_FEATURE_SWAPONOFF_LABEL is not set +# CONFIG_SWITCH_ROOT is not set +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +# CONFIG_FEATURE_TASKSET_CPULIST is not set +# CONFIG_UEVENT is not set +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +# CONFIG_UNSHARE is not set +# CONFIG_WALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set +# CONFIG_VOLUMEID is not set +# CONFIG_FEATURE_VOLUMEID_BCACHE is not set +# CONFIG_FEATURE_VOLUMEID_BTRFS is not set +# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set +# CONFIG_FEATURE_VOLUMEID_EROFS is not set +# CONFIG_FEATURE_VOLUMEID_EXFAT is not set +# CONFIG_FEATURE_VOLUMEID_EXT is not set +# CONFIG_FEATURE_VOLUMEID_F2FS is not set +# CONFIG_FEATURE_VOLUMEID_FAT is not set +# CONFIG_FEATURE_VOLUMEID_HFS is not set +# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set +# CONFIG_FEATURE_VOLUMEID_JFS is not set +# CONFIG_FEATURE_VOLUMEID_LFS is not set +# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set +# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set +# CONFIG_FEATURE_VOLUMEID_LUKS is not set +# CONFIG_FEATURE_VOLUMEID_MINIX is not set +# CONFIG_FEATURE_VOLUMEID_NILFS is not set +# CONFIG_FEATURE_VOLUMEID_NTFS is not set +# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set +# CONFIG_FEATURE_VOLUMEID_REISERFS is not set +# CONFIG_FEATURE_VOLUMEID_ROMFS is not set +# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set +# CONFIG_FEATURE_VOLUMEID_SYSV is not set +# CONFIG_FEATURE_VOLUMEID_UBIFS is not set +# CONFIG_FEATURE_VOLUMEID_UDF is not set +# CONFIG_FEATURE_VOLUMEID_XFS is not set + +# +# Miscellaneous Utilities +# +# CONFIG_ADJTIMEX is not set +# CONFIG_BBCONFIG is not set +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +# CONFIG_BC is not set +# CONFIG_DC is not set +# CONFIG_FEATURE_DC_BIG is not set +# CONFIG_FEATURE_DC_LIBM is not set +# CONFIG_FEATURE_BC_INTERACTIVE is not set +# CONFIG_FEATURE_BC_LONG_OPTIONS is not set +# CONFIG_BEEP is not set +CONFIG_FEATURE_BEEP_FREQ=0 +CONFIG_FEATURE_BEEP_LENGTH_MS=0 +# CONFIG_CHAT is not set +# CONFIG_FEATURE_CHAT_NOFAIL is not set +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set +# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set +# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set +# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set +# CONFIG_FEATURE_CHAT_CLR_ABORT is not set +# CONFIG_CONSPY is not set +# CONFIG_CROND is not set +# CONFIG_FEATURE_CROND_D is not set +# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set +# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set +CONFIG_FEATURE_CROND_DIR="" +# CONFIG_CRONTAB is not set +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +# CONFIG_DEVMEM is not set +# CONFIG_FBSPLASH is not set +# CONFIG_FLASHCP is not set +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_HDPARM is not set +# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set +# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set +# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set +# CONFIG_HEXEDIT is not set +# CONFIG_I2CGET is not set +# CONFIG_I2CSET is not set +# CONFIG_I2CDUMP is not set +# CONFIG_I2CDETECT is not set +# CONFIG_I2CTRANSFER is not set +# CONFIG_INOTIFYD is not set +# CONFIG_LESS is not set +CONFIG_FEATURE_LESS_MAXLINES=0 +# CONFIG_FEATURE_LESS_BRACKETS is not set +# CONFIG_FEATURE_LESS_FLAGS is not set +# CONFIG_FEATURE_LESS_TRUNCATE is not set +# CONFIG_FEATURE_LESS_MARKS is not set +# CONFIG_FEATURE_LESS_REGEXP is not set +# CONFIG_FEATURE_LESS_WINCH is not set +# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set +# CONFIG_FEATURE_LESS_DASHCMD is not set +# CONFIG_FEATURE_LESS_LINENUMS is not set +# CONFIG_FEATURE_LESS_RAW is not set +# CONFIG_FEATURE_LESS_ENV is not set +# CONFIG_LSSCSI is not set +# CONFIG_MAKEDEVS is not set +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +# CONFIG_FEATURE_MAKEDEVS_TABLE is not set +# CONFIG_MAN is not set +# CONFIG_MICROCOM is not set +# CONFIG_MIM is not set +# CONFIG_MT is not set +# CONFIG_NANDWRITE is not set +# CONFIG_NANDDUMP is not set +# CONFIG_PARTPROBE is not set +# CONFIG_RAIDAUTORUN is not set +# CONFIG_READAHEAD is not set +# CONFIG_RFKILL is not set +# CONFIG_RUNLEVEL is not set +# CONFIG_RX is not set +# CONFIG_SETFATTR is not set +# CONFIG_SETSERIAL is not set +# CONFIG_STRINGS is not set +# CONFIG_TIME is not set +# CONFIG_TS is not set +# CONFIG_TTYSIZE is not set +# CONFIG_UBIRENAME is not set +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set +# CONFIG_VOLNAME is not set +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_FEATURE_UNIX_LOCAL is not set +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +# CONFIG_FEATURE_TLS_SHA1 is not set +# CONFIG_ARP is not set +# CONFIG_ARPING is not set +# CONFIG_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set +# CONFIG_DNSD is not set +# CONFIG_ETHER_WAKE is not set +# CONFIG_FTPD is not set +# CONFIG_FEATURE_FTPD_WRITE is not set +# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set +# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set +# CONFIG_FTPGET is not set +# CONFIG_FTPPUT is not set +# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set +# CONFIG_HOSTNAME is not set +# CONFIG_DNSDOMAINNAME is not set +# CONFIG_HTTPD is not set +# CONFIG_FEATURE_HTTPD_RANGES is not set +# CONFIG_FEATURE_HTTPD_SETUID is not set +# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set +# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set +# CONFIG_FEATURE_HTTPD_CGI is not set +# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set +# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set +# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set +# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set +# CONFIG_FEATURE_HTTPD_PROXY is not set +# CONFIG_FEATURE_HTTPD_GZIP is not set +# CONFIG_FEATURE_HTTPD_ETAG is not set +# CONFIG_FEATURE_HTTPD_LAST_MODIFIED is not set +# CONFIG_FEATURE_HTTPD_DATE is not set +# CONFIG_FEATURE_HTTPD_ACL_IP is not set +# CONFIG_IFCONFIG is not set +# CONFIG_FEATURE_IFCONFIG_STATUS is not set +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +# CONFIG_FEATURE_IFCONFIG_HW is not set +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set +# CONFIG_IFENSLAVE is not set +# CONFIG_IFPLUGD is not set +# CONFIG_IFUP is not set +# CONFIG_IFDOWN is not set +CONFIG_IFUPDOWN_IFSTATE_PATH="" +# CONFIG_FEATURE_IFUPDOWN_IP is not set +# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set +# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set +# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set +# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +# CONFIG_INETD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set +# CONFIG_FEATURE_INETD_RPC is not set +# CONFIG_IP is not set +# CONFIG_IPADDR is not set +# CONFIG_IPLINK is not set +# CONFIG_IPROUTE is not set +# CONFIG_IPTUNNEL is not set +# CONFIG_IPRULE is not set +# CONFIG_IPNEIGH is not set +# CONFIG_FEATURE_IP_ADDRESS is not set +# CONFIG_FEATURE_IP_LINK is not set +# CONFIG_FEATURE_IP_ROUTE is not set +CONFIG_FEATURE_IP_ROUTE_DIR="" +# CONFIG_FEATURE_IP_TUNNEL is not set +# CONFIG_FEATURE_IP_RULE is not set +# CONFIG_FEATURE_IP_NEIGH is not set +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +# CONFIG_IPCALC is not set +# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set +# CONFIG_FEATURE_IPCALC_FANCY is not set +# CONFIG_FAKEIDENTD is not set +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +# CONFIG_NBDCLIENT is not set +# CONFIG_NC is not set +# CONFIG_NETCAT is not set +# CONFIG_NC_SERVER is not set +# CONFIG_NC_EXTRA is not set +# CONFIG_NC_110_COMPAT is not set +# CONFIG_NETSTAT is not set +# CONFIG_FEATURE_NETSTAT_WIDE is not set +# CONFIG_FEATURE_NETSTAT_PRG is not set +# CONFIG_NSLOOKUP is not set +# CONFIG_FEATURE_NSLOOKUP_BIG is not set +# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set +# CONFIG_NTPD is not set +# CONFIG_FEATURE_NTPD_SERVER is not set +# CONFIG_FEATURE_NTPD_CONF is not set +# CONFIG_FEATURE_NTP_AUTH is not set +# CONFIG_PING is not set +# CONFIG_PING6 is not set +# CONFIG_FEATURE_FANCY_PING is not set +# CONFIG_PSCAN is not set +# CONFIG_ROUTE is not set +# CONFIG_SLATTACH is not set +# CONFIG_SSL_CLIENT is not set +# CONFIG_TC is not set +# CONFIG_FEATURE_TC_INGRESS is not set +# CONFIG_TCPSVD is not set +# CONFIG_UDPSVD is not set +# CONFIG_TELNET is not set +# CONFIG_FEATURE_TELNET_TTYPE is not set +# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set +# CONFIG_FEATURE_TELNET_WIDTH is not set +# CONFIG_TELNETD is not set +# CONFIG_FEATURE_TELNETD_STANDALONE is not set +# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set +# CONFIG_TFTP is not set +# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set +# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set +# CONFIG_TFTPD is not set +# CONFIG_FEATURE_TFTP_GET is not set +# CONFIG_FEATURE_TFTP_PUT is not set +# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set +# CONFIG_TFTP_DEBUG is not set +# CONFIG_TLS is not set +# CONFIG_TRACEROUTE is not set +# CONFIG_TRACEROUTE6 is not set +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +# CONFIG_TUNCTL is not set +# CONFIG_FEATURE_TUNCTL_UG is not set +# CONFIG_VCONFIG is not set +# CONFIG_WGET is not set +# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +# CONFIG_FEATURE_WGET_STATUSBAR is not set +# CONFIG_FEATURE_WGET_AUTHENTICATION is not set +# CONFIG_FEATURE_WGET_TIMEOUT is not set +# CONFIG_FEATURE_WGET_HTTPS is not set +# CONFIG_FEATURE_WGET_OPENSSL is not set +# CONFIG_WHOIS is not set +# CONFIG_ZCIP is not set +# CONFIG_UDHCPD is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +CONFIG_DHCPD_LEASES_FILE="" +# CONFIG_DUMPLEASES is not set +# CONFIG_DHCPRELAY is not set +# CONFIG_UDHCPC is not set +# CONFIG_FEATURE_UDHCPC_ARPING is not set +# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set +CONFIG_UDHCPC_DEFAULT_SCRIPT="" +# CONFIG_UDHCPC6 is not set +# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set +# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set +# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set +# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set +# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_UDHCP_DEBUG=0 +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 +# CONFIG_FEATURE_UDHCP_RFC3397 is not set +# CONFIG_FEATURE_UDHCP_8021Q is not set +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" + +# +# Print Utilities +# +# CONFIG_LPD is not set +# CONFIG_LPR is not set +# CONFIG_LPQ is not set + +# +# Mail Utilities +# +# CONFIG_MAKEMIME is not set +# CONFIG_POPMAILDIR is not set +# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set +# CONFIG_REFORMIME is not set +# CONFIG_FEATURE_REFORMIME_COMPAT is not set +# CONFIG_SENDMAIL is not set +CONFIG_FEATURE_MIME_CHARSET="" + +# +# Process Utilities +# +# CONFIG_FREE is not set +# CONFIG_FUSER is not set +# CONFIG_IOSTAT is not set +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set +# CONFIG_KILLALL5 is not set +# CONFIG_LSOF is not set +# CONFIG_MPSTAT is not set +# CONFIG_NMETER is not set +# CONFIG_PGREP is not set +# CONFIG_PKILL is not set +# CONFIG_PIDOF is not set +# CONFIG_FEATURE_PIDOF_SINGLE is not set +# CONFIG_FEATURE_PIDOF_OMIT is not set +# CONFIG_PMAP is not set +# CONFIG_POWERTOP is not set +# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set +# CONFIG_PS is not set +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_LONG is not set +# CONFIG_FEATURE_PS_TIME is not set +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_PSTREE is not set +# CONFIG_PWDX is not set +# CONFIG_SMEMCAP is not set +# CONFIG_BB_SYSCTL is not set +# CONFIG_TOP is not set +# CONFIG_FEATURE_TOP_INTERACTIVE is not set +# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set +# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set +# CONFIG_FEATURE_TOP_SMP_CPU is not set +# CONFIG_FEATURE_TOP_DECIMALS is not set +# CONFIG_FEATURE_TOP_SMP_PROCESS is not set +# CONFIG_FEATURE_TOPMEM is not set +# CONFIG_UPTIME is not set +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set +# CONFIG_WATCH is not set +# CONFIG_FEATURE_SHOW_THREADS is not set + +# +# Runit Utilities +# +# CONFIG_CHPST is not set +# CONFIG_SETUIDGID is not set +# CONFIG_ENVUIDGID is not set +# CONFIG_ENVDIR is not set +# CONFIG_SOFTLIMIT is not set +# CONFIG_RUNSV is not set +# CONFIG_RUNSVDIR is not set +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +# CONFIG_SV is not set +CONFIG_SV_DEFAULT_SERVICE_DIR="" +# CONFIG_SVC is not set +# CONFIG_SVOK is not set +# CONFIG_SVLOGD is not set +# CONFIG_CHCON is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RUNCON is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SESTATUS is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_RESTORECON is not set +# CONFIG_SETSEBOOL is not set + +# +# Shells +# +# CONFIG_SH_IS_ASH is not set +CONFIG_SH_IS_HUSH=y +# CONFIG_SH_IS_NONE is not set +# CONFIG_BASH_IS_ASH is not set +# CONFIG_BASH_IS_HUSH is not set +CONFIG_BASH_IS_NONE=y +# CONFIG_SHELL_ASH is not set +# CONFIG_ASH is not set +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set +# CONFIG_ASH_INTERNAL_GLOB is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_BASH_SOURCE_CURDIR is not set +# CONFIG_ASH_BASH_NOT_FOUND_HOOK is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_ASH_EXPAND_PRMT is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set +# CONFIG_ASH_MAIL is not set +# CONFIG_ASH_ECHO is not set +# CONFIG_ASH_PRINTF is not set +# CONFIG_ASH_TEST is not set +# CONFIG_ASH_HELP is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_CMDCMD is not set +CONFIG_CTTYHACK=y +CONFIG_HUSH=y +CONFIG_SHELL_HUSH=y +CONFIG_HUSH_BASH_COMPAT=y +CONFIG_HUSH_BRACE_EXPANSION=y +CONFIG_HUSH_LINENO_VAR=y +# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set +CONFIG_HUSH_INTERACTIVE=y +CONFIG_HUSH_SAVEHISTORY=y +CONFIG_HUSH_JOB=y +CONFIG_HUSH_TICK=y +CONFIG_HUSH_IF=y +CONFIG_HUSH_LOOPS=y +CONFIG_HUSH_CASE=y +CONFIG_HUSH_FUNCTIONS=y +CONFIG_HUSH_LOCAL=y +CONFIG_HUSH_RANDOM_SUPPORT=y +CONFIG_HUSH_MODE_X=y +CONFIG_HUSH_ECHO=y +CONFIG_HUSH_PRINTF=y +CONFIG_HUSH_TEST=y +CONFIG_HUSH_HELP=y +CONFIG_HUSH_EXPORT=y +CONFIG_HUSH_EXPORT_N=y +CONFIG_HUSH_READONLY=y +CONFIG_HUSH_KILL=y +CONFIG_HUSH_WAIT=y +CONFIG_HUSH_COMMAND=y +CONFIG_HUSH_TRAP=y +CONFIG_HUSH_TYPE=y +CONFIG_HUSH_TIMES=y +CONFIG_HUSH_READ=y +CONFIG_HUSH_SET=y +CONFIG_HUSH_UNSET=y +CONFIG_HUSH_ULIMIT=y +CONFIG_HUSH_UMASK=y +CONFIG_HUSH_GETOPTS=y +# CONFIG_HUSH_MEMLEAK is not set + +# +# Options common to all shells +# +CONFIG_FEATURE_SH_MATH=y +CONFIG_FEATURE_SH_MATH_64=y +CONFIG_FEATURE_SH_MATH_BASE=y +CONFIG_FEATURE_SH_EXTRA_QUIET=y +CONFIG_FEATURE_SH_STANDALONE=y +# CONFIG_FEATURE_SH_NOFORK is not set +CONFIG_FEATURE_SH_READ_FRAC=y +CONFIG_FEATURE_SH_HISTFILESIZE=y +CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y + +# +# System Logging Utilities +# +# CONFIG_KLOGD is not set +# CONFIG_FEATURE_KLOGD_KLOGCTL is not set +# CONFIG_LOGGER is not set +# CONFIG_LOGREAD is not set +# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set +# CONFIG_FEATURE_SYSLOGD_DUP is not set +# CONFIG_FEATURE_SYSLOGD_CFG is not set +# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 +# CONFIG_FEATURE_KMSG_SYSLOG is not set diff --git a/ports/busybox/port.sh b/ports/busybox/port.sh new file mode 100755 index 0000000..df5b16a --- /dev/null +++ b/ports/busybox/port.sh @@ -0,0 +1,19 @@ +set -e + +SYSROOT=`realpath root` +VERSION=1.33.1 +NAME=busybox +URL="https://www.busybox.net/downloads/$NAME-$VERSION.tar.bz2" +SOURCE="bin/$NAME-$VERSION.tar.bz2" + +if [ ! -f $SOURCE ]; then curl $URL > $SOURCE; fi +tar -xjf $SOURCE +mv $NAME-$VERSION bin/$NAME + +cd bin/$NAME +cp ../../ports/$NAME/config .config +sed -i "51 i CONFIG_SYSROOT=\"$SYSROOT\"" .config +make -j 4 +cp busybox $SYSROOT/Applications/POSIX/bin +cd ../.. +rm -r bin/$NAME diff --git a/ports/ffmpeg/port.sh b/ports/ffmpeg/port.sh new file mode 100755 index 0000000..458eb8c --- /dev/null +++ b/ports/ffmpeg/port.sh @@ -0,0 +1,21 @@ +set -e + +SYSROOT=`realpath root` + +if [ ! -f "bin/ffmpeg.tar.xz" ]; then + curl https://ffmpeg.org/releases/ffmpeg-4.3.1.tar.xz > bin/ffmpeg.tar.xz +fi + +tar -xJf bin/ffmpeg.tar.xz +mv ffmpeg-4.3.1 bin/ffmpeg + +mkdir bin/build-ffmpeg + +cd bin/build-ffmpeg +../ffmpeg/configure --disable-all --cc=x86_64-essence-gcc --cxx=x86_64-essence-g++ --enable-cross-compile --enable-avcodec --enable-avformat --enable-swscale --enable-decoder=h264 --enable-parser=h264 --enable-decoder=aac --enable-parser=aac --enable-demuxer=mov --enable-protocol=file --disable-pthreads --prefix=/Applications/POSIX +# --disable-optimizations +make -j 4 +make DESTDIR=$SYSROOT install +cd ../.. + +rm -r bin/ffmpeg bin/build-ffmpeg diff --git a/ports/freetype/FTL.TXT b/ports/freetype/FTL.TXT new file mode 100644 index 0000000..c406d15 --- /dev/null +++ b/ports/freetype/FTL.TXT @@ -0,0 +1,169 @@ + The FreeType Project LICENSE + ---------------------------- + + 2006-Jan-27 + + Copyright 1996-2002, 2006 by + David Turner, Robert Wilhelm, and Werner Lemberg + + + +Introduction +============ + + The FreeType Project is distributed in several archive packages; + some of them may contain, in addition to the FreeType font engine, + various tools and contributions which rely on, or relate to, the + FreeType Project. + + This license applies to all files found in such packages, and + which do not fall under their own explicit license. The license + affects thus the FreeType font engine, the test programs, + documentation and makefiles, at the very least. + + This license was inspired by the BSD, Artistic, and IJG + (Independent JPEG Group) licenses, which all encourage inclusion + and use of free software in commercial and freeware products + alike. As a consequence, its main points are that: + + o We don't promise that this software works. However, we will be + interested in any kind of bug reports. (`as is' distribution) + + o You can use this software for whatever you want, in parts or + full form, without having to pay us. (`royalty-free' usage) + + o You may not pretend that you wrote this software. If you use + it, or only parts of it, in a program, you must acknowledge + somewhere in your documentation that you have used the + FreeType code. (`credits') + + We specifically permit and encourage the inclusion of this + software, with or without modifications, in commercial products. + We disclaim all warranties covering The FreeType Project and + assume no liability related to The FreeType Project. + + + Finally, many people asked us for a preferred form for a + credit/disclaimer to use in compliance with this license. We thus + encourage you to use the following text: + + """ + Portions of this software are copyright © The FreeType + Project (www.freetype.org). All rights reserved. + """ + + Please replace with the value from the FreeType version you + actually use. + + +Legal Terms +=========== + +0. Definitions +-------------- + + Throughout this license, the terms `package', `FreeType Project', + and `FreeType archive' refer to the set of files originally + distributed by the authors (David Turner, Robert Wilhelm, and + Werner Lemberg) as the `FreeType Project', be they named as alpha, + beta or final release. + + `You' refers to the licensee, or person using the project, where + `using' is a generic term including compiling the project's source + code as well as linking it to form a `program' or `executable'. + This program is referred to as `a program using the FreeType + engine'. + + This license applies to all files distributed in the original + FreeType Project, including all source code, binaries and + documentation, unless otherwise stated in the file in its + original, unmodified form as distributed in the original archive. + If you are unsure whether or not a particular file is covered by + this license, you must contact us to verify this. + + The FreeType Project is copyright (C) 1996-2000 by David Turner, + Robert Wilhelm, and Werner Lemberg. All rights reserved except as + specified below. + +1. No Warranty +-------------- + + THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO + USE, OF THE FREETYPE PROJECT. + +2. Redistribution +----------------- + + This license grants a worldwide, royalty-free, perpetual and + irrevocable right and license to use, execute, perform, compile, + display, copy, create derivative works of, distribute and + sublicense the FreeType Project (in both source and object code + forms) and derivative works thereof for any purpose; and to + authorize others to exercise some or all of the rights granted + herein, subject to the following conditions: + + o Redistribution of source code must retain this license file + (`FTL.TXT') unaltered; any additions, deletions or changes to + the original files must be clearly indicated in accompanying + documentation. The copyright notices of the unaltered, + original files must be preserved in all copies of source + files. + + o Redistribution in binary form must provide a disclaimer that + states that the software is based in part of the work of the + FreeType Team, in the distribution documentation. We also + encourage you to put an URL to the FreeType web page in your + documentation, though this isn't mandatory. + + These conditions apply to any software derived from or based on + the FreeType Project, not just the unmodified files. If you use + our work, you must acknowledge us. However, no fee need be paid + to us. + +3. Advertising +-------------- + + Neither the FreeType authors and contributors nor you shall use + the name of the other for commercial, advertising, or promotional + purposes without specific prior written permission. + + We suggest, but do not require, that you use one or more of the + following phrases to refer to this software in your documentation + or advertising materials: `FreeType Project', `FreeType Engine', + `FreeType library', or `FreeType Distribution'. + + As you have not signed this license, you are not required to + accept it. However, as the FreeType Project is copyrighted + material, only this license, or another one contracted with the + authors, grants you the right to use, distribute, and modify it. + Therefore, by using, distributing, or modifying the FreeType + Project, you indicate that you understand and accept all the terms + of this license. + +4. Contacts +----------- + + There are two mailing lists related to FreeType: + + o freetype@nongnu.org + + Discusses general use and applications of FreeType, as well as + future and wanted additions to the library and distribution. + If you are looking for support, start in this list if you + haven't found anything to help you in the documentation. + + o freetype-devel@nongnu.org + + Discusses bugs, as well as engine internals, design issues, + specific licenses, porting, etc. + + Our home page can be found at + + https://www.freetype.org + + +--- end of FTL.TXT --- diff --git a/ports/freetype/build.sh b/ports/freetype/build.sh new file mode 100755 index 0000000..62277d0 --- /dev/null +++ b/ports/freetype/build.sh @@ -0,0 +1,26 @@ +if [ ! -d "bin/freetype" ]; then + echo " Downloading and building FreeType..." + + if [ ! -f "bin/freetype-2.9.tar" ]; then + curl https://mirrors.up.pt/pub/nongnu/freetype/freetype-2.9.tar.gz > bin/freetype-2.9.tar.gz 2> bin/freetype_dl.txt + gunzip bin/freetype-2.9.tar.gz + fi + + tar -xf bin/freetype-2.9.tar + mv freetype-2.9 bin/freetype + + cp ports/freetype/patch-ftoption.h bin/freetype/include/freetype/config/ftoption.h + cp ports/freetype/patch-ftstdlib.h bin/freetype/include/freetype/config/ftstdlib.h + cp ports/freetype/patch-modules.cfg bin/freetype/modules.cfg + + cd bin/freetype + ./configure --without-zlib --without-bzip2 --without-png --without-harfbuzz \ + CC=x86_64-essence-gcc CFLAGS="-g -ffreestanding -DARCH_X86_64 -Wno-unused-function" \ + LDFLAGS="-nostdlib -lgcc" --host=x86_64-essence > ../freetype_configure.txt + make ANSIFLAGS="" > /dev/null + cd ../.. +fi + +cp -p bin/freetype/objs/.libs/libfreetype.a root/Applications/POSIX/lib +cp -p bin/freetype/include/ft2build.h root/Applications/POSIX/include +cp -p -r bin/freetype/include/freetype root/Applications/POSIX/include diff --git a/ports/freetype/patch-ftoption.h b/ports/freetype/patch-ftoption.h new file mode 100644 index 0000000..98d06bb --- /dev/null +++ b/ports/freetype/patch-ftoption.h @@ -0,0 +1,970 @@ +/***************************************************************************/ +/* */ +/* ftoption.h */ +/* */ +/* User-selectable configuration macros (specification only). */ +/* */ +/* Copyright 1996-2018 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FTOPTION_H_ +#define FTOPTION_H_ + + +#include + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* USER-SELECTABLE CONFIGURATION MACROS */ + /* */ + /* This file contains the default configuration macro definitions for */ + /* a standard build of the FreeType library. There are three ways to */ + /* use this file to build project-specific versions of the library: */ + /* */ + /* - You can modify this file by hand, but this is not recommended in */ + /* cases where you would like to build several versions of the */ + /* library from a single source directory. */ + /* */ + /* - You can put a copy of this file in your build directory, more */ + /* precisely in `$BUILD/freetype/config/ftoption.h', where `$BUILD' */ + /* is the name of a directory that is included _before_ the FreeType */ + /* include path during compilation. */ + /* */ + /* The default FreeType Makefiles and Jamfiles use the build */ + /* directory `builds/' by default, but you can easily change */ + /* that for your own projects. */ + /* */ + /* - Copy the file to `$BUILD/ft2build.h' and modify it */ + /* slightly to pre-define the macro FT_CONFIG_OPTIONS_H used to */ + /* locate this file during the build. For example, */ + /* */ + /* #define FT_CONFIG_OPTIONS_H */ + /* #include */ + /* */ + /* will use `$BUILD/myftoptions.h' instead of this file for macro */ + /* definitions. */ + /* */ + /* Note also that you can similarly pre-define the macro */ + /* FT_CONFIG_MODULES_H used to locate the file listing of the modules */ + /* that are statically linked to the library at compile time. By */ + /* default, this file is . */ + /* */ + /* We highly recommend using the third method whenever possible. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*#***********************************************************************/ + /* */ + /* If you enable this configuration option, FreeType recognizes an */ + /* environment variable called `FREETYPE_PROPERTIES', which can be used */ + /* to control the various font drivers and modules. The controllable */ + /* properties are listed in the section @properties. */ + /* */ + /* `FREETYPE_PROPERTIES' has the following syntax form (broken here into */ + /* multiple lines for better readability). */ + /* */ + /* { */ + /* */ + /* ':' */ + /* '=' */ + /* */ + /* ':' */ + /* '=' */ + /* ... */ + /* } */ + /* */ + /* Example: */ + /* */ + /* FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ */ + /* cff:no-stem-darkening=1 \ */ + /* autofitter:warping=1 */ + /* */ +// #define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + + + /*************************************************************************/ + /* */ + /* Uncomment the line below if you want to activate LCD rendering */ + /* technology similar to ClearType in this build of the library. This */ + /* technology triples the resolution in the direction color subpixels. */ + /* To mitigate color fringes inherent to this technology, you also need */ + /* to explicitly set up LCD filtering. */ + /* */ + /* Note that this feature is covered by several Microsoft patents */ + /* and should not be activated in any default build of the library. */ + /* When this macro is not defined, FreeType offers alternative LCD */ + /* rendering technology that produces excellent output without LCD */ + /* filtering. */ + /* */ +/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + + /*************************************************************************/ + /* */ + /* Many compilers provide a non-ANSI 64-bit data type that can be used */ + /* by FreeType to speed up some computations. However, this will create */ + /* some problems when compiling the library in strict ANSI mode. */ + /* */ + /* For this reason, the use of 64-bit integers is normally disabled when */ + /* the __STDC__ macro is defined. You can however disable this by */ + /* defining the macro FT_CONFIG_OPTION_FORCE_INT64 here. */ + /* */ + /* For most compilers, this will only create compilation warnings when */ + /* building the library. */ + /* */ + /* ObNote: The compiler-specific 64-bit integers are detected in the */ + /* file `ftconfig.h' either statically or through the */ + /* `configure' script on supported platforms. */ + /* */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + + + /*************************************************************************/ + /* */ + /* If this macro is defined, do not try to use an assembler version of */ + /* performance-critical functions (e.g. FT_MulFix). You should only do */ + /* that to verify that the assembler function works properly, or to */ + /* execute benchmark tests of the various implementations. */ +/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */ + + + /*************************************************************************/ + /* */ + /* If this macro is defined, try to use an inlined assembler version of */ + /* the `FT_MulFix' function, which is a `hotspot' when loading and */ + /* hinting glyphs, and which should be executed as fast as possible. */ + /* */ + /* Note that if your compiler or CPU is not supported, this will default */ + /* to the standard and portable implementation found in `ftcalc.c'. */ + /* */ +#define FT_CONFIG_OPTION_INLINE_MULFIX + + + /*************************************************************************/ + /* */ + /* LZW-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `compress' program. This is mostly used to parse many of the PCF */ + /* files that come with various X11 distributions. The implementation */ + /* uses NetBSD's `zopen' to partially uncompress the file on the fly */ + /* (see src/lzw/ftgzip.c). */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ +// #define FT_CONFIG_OPTION_USE_LZW + + + /*************************************************************************/ + /* */ + /* Gzip-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `gzip' program. This is mostly used to parse many of the PCF files */ + /* that come with XFree86. The implementation uses `zlib' to */ + /* partially uncompress the file on the fly (see src/gzip/ftgzip.c). */ + /* */ + /* Define this macro if you want to enable this `feature'. See also */ + /* the macro FT_CONFIG_OPTION_SYSTEM_ZLIB below. */ + /* */ +// #define FT_CONFIG_OPTION_USE_ZLIB + + + /*************************************************************************/ + /* */ + /* ZLib library selection */ + /* */ + /* This macro is only used when FT_CONFIG_OPTION_USE_ZLIB is defined. */ + /* It allows FreeType's `ftgzip' component to link to the system's */ + /* installation of the ZLib library. This is useful on systems like */ + /* Unix or VMS where it generally is already available. */ + /* */ + /* If you let it undefined, the component will use its own copy */ + /* of the zlib sources instead. These have been modified to be */ + /* included directly within the component and *not* export external */ + /* function names. This allows you to link any program with FreeType */ + /* _and_ ZLib without linking conflicts. */ + /* */ + /* Do not #undef this macro here since the build system might define */ + /* it for certain configurations only. */ + /* */ + /* If you use a build system like cmake or the `configure' script, */ + /* options set by those programs have precendence, overwriting the */ + /* value here with the configured one. */ + /* */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + + /*************************************************************************/ + /* */ + /* Bzip2-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `bzip2' program. This is mostly used to parse many of the PCF */ + /* files that come with XFree86. The implementation uses `libbz2' to */ + /* partially uncompress the file on the fly (see src/bzip2/ftbzip2.c). */ + /* Contrary to gzip, bzip2 currently is not included and need to use */ + /* the system available bzip2 implementation. */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ + /* If you use a build system like cmake or the `configure' script, */ + /* options set by those programs have precendence, overwriting the */ + /* value here with the configured one. */ + /* */ +/* #define FT_CONFIG_OPTION_USE_BZIP2 */ + + + /*************************************************************************/ + /* */ + /* Define to disable the use of file stream functions and types, FILE, */ + /* fopen() etc. Enables the use of smaller system libraries on embedded */ + /* systems that have multiple system libraries, some with or without */ + /* file stream support, in the cases where file stream support is not */ + /* necessary such as memory loading of font files. */ + /* */ + #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT + + + /*************************************************************************/ + /* */ + /* PNG bitmap support. */ + /* */ + /* FreeType now handles loading color bitmap glyphs in the PNG format. */ + /* This requires help from the external libpng library. Uncompressed */ + /* color bitmaps do not need any external libraries and will be */ + /* supported regardless of this configuration. */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ + /* If you use a build system like cmake or the `configure' script, */ + /* options set by those programs have precendence, overwriting the */ + /* value here with the configured one. */ + /* */ +/* #define FT_CONFIG_OPTION_USE_PNG */ + + + /*************************************************************************/ + /* */ + /* HarfBuzz support. */ + /* */ + /* FreeType uses the HarfBuzz library to improve auto-hinting of */ + /* OpenType fonts. If available, many glyphs not directly addressable */ + /* by a font's character map will be hinted also. */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ + /* If you use a build system like cmake or the `configure' script, */ + /* options set by those programs have precendence, overwriting the */ + /* value here with the configured one. */ + /* */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + /*************************************************************************/ + /* */ + /* Glyph Postscript Names handling */ + /* */ + /* By default, FreeType 2 is compiled with the `psnames' module. This */ + /* module is in charge of converting a glyph name string into a */ + /* Unicode value, or return a Macintosh standard glyph name for the */ + /* use with the TrueType `post' table. */ + /* */ + /* Undefine this macro if you do not want `psnames' compiled in your */ + /* build of FreeType. This has the following effects: */ + /* */ + /* - The TrueType driver will provide its own set of glyph names, */ + /* if you build it to support postscript names in the TrueType */ + /* `post' table, but will not synthesize a missing Unicode charmap. */ + /* */ + /* - The Type 1 driver will not be able to synthesize a Unicode */ + /* charmap out of the glyphs found in the fonts. */ + /* */ + /* You would normally undefine this configuration macro when building */ + /* a version of FreeType that doesn't contain a Type 1 or CFF driver. */ + /* */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + /*************************************************************************/ + /* */ + /* Postscript Names to Unicode Values support */ + /* */ + /* By default, FreeType 2 is built with the `PSNames' module compiled */ + /* in. Among other things, the module is used to convert a glyph name */ + /* into a Unicode value. This is especially useful in order to */ + /* synthesize on the fly a Unicode charmap from the CFF/Type 1 driver */ + /* through a big table named the `Adobe Glyph List' (AGL). */ + /* */ + /* Undefine this macro if you do not want the Adobe Glyph List */ + /* compiled in your `PSNames' module. The Type 1 driver will not be */ + /* able to synthesize a Unicode charmap out of the glyphs found in the */ + /* fonts. */ + /* */ + + + /*************************************************************************/ + /* */ + /* Support for Mac fonts */ + /* */ + /* Define this macro if you want support for outline fonts in Mac */ + /* format (mac dfont, mac resource, macbinary containing a mac */ + /* resource) on non-Mac platforms. */ + /* */ + /* Note that the `FOND' resource isn't checked. */ + /* */ + + + /*************************************************************************/ + /* */ + /* Guessing methods to access embedded resource forks */ + /* */ + /* Enable extra Mac fonts support on non-Mac platforms (e.g. */ + /* GNU/Linux). */ + /* */ + /* Resource forks which include fonts data are stored sometimes in */ + /* locations which users or developers don't expected. In some cases, */ + /* resource forks start with some offset from the head of a file. In */ + /* other cases, the actual resource fork is stored in file different */ + /* from what the user specifies. If this option is activated, */ + /* FreeType tries to guess whether such offsets or different file */ + /* names must be used. */ + /* */ + /* Note that normal, direct access of resource forks is controlled via */ + /* the FT_CONFIG_OPTION_MAC_FONTS option. */ + /* */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + + + /*************************************************************************/ + /* */ + /* Allow the use of FT_Incremental_Interface to load typefaces that */ + /* contain no glyph data, but supply it via a callback function. */ + /* This is required by clients supporting document formats which */ + /* supply font data incrementally as the document is parsed, such */ + /* as the Ghostscript interpreter for the PostScript language. */ + /* */ +#define FT_CONFIG_OPTION_INCREMENTAL + + + /*************************************************************************/ + /* */ + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ + /* */ +#define FT_RENDER_POOL_SIZE 16384L + + + /*************************************************************************/ + /* */ + /* FT_MAX_MODULES */ + /* */ + /* The maximum number of modules that can be registered in a single */ + /* FreeType library object. 32 is the default. */ + /* */ +#define FT_MAX_MODULES 32 + + + /*************************************************************************/ + /* */ + /* Debug level */ + /* */ + /* FreeType can be compiled in debug or trace mode. In debug mode, */ + /* errors are reported through the `ftdebug' component. In trace */ + /* mode, additional messages are sent to the standard output during */ + /* execution. */ + /* */ + /* Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode. */ + /* Define FT_DEBUG_LEVEL_TRACE to build it in trace mode. */ + /* */ + /* Don't define any of these macros to compile in `release' mode! */ + /* */ + /* Do not #undef these macros here since the build system might define */ + /* them for certain configurations only. */ + /* */ +/* #define FT_DEBUG_LEVEL_ERROR */ +/* #define FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /* */ + /* Autofitter debugging */ + /* */ + /* If FT_DEBUG_AUTOFIT is defined, FreeType provides some means to */ + /* control the autofitter behaviour for debugging purposes with global */ + /* boolean variables (consequently, you should *never* enable this */ + /* while compiling in `release' mode): */ + /* */ + /* _af_debug_disable_horz_hints */ + /* _af_debug_disable_vert_hints */ + /* _af_debug_disable_blue_hints */ + /* */ + /* Additionally, the following functions provide dumps of various */ + /* internal autofit structures to stdout (using `printf'): */ + /* */ + /* af_glyph_hints_dump_points */ + /* af_glyph_hints_dump_segments */ + /* af_glyph_hints_dump_edges */ + /* af_glyph_hints_get_num_segments */ + /* af_glyph_hints_get_segment_offset */ + /* */ + /* As an argument, they use another global variable: */ + /* */ + /* _af_debug_hints */ + /* */ + /* Please have a look at the `ftgrid' demo program to see how those */ + /* variables and macros should be used. */ + /* */ + /* Do not #undef these macros here since the build system might define */ + /* them for certain configurations only. */ + /* */ +/* #define FT_DEBUG_AUTOFIT */ + + + /*************************************************************************/ + /* */ + /* Memory Debugging */ + /* */ + /* FreeType now comes with an integrated memory debugger that is */ + /* capable of detecting simple errors like memory leaks or double */ + /* deletes. To compile it within your build of the library, you */ + /* should define FT_DEBUG_MEMORY here. */ + /* */ + /* Note that the memory debugger is only activated at runtime when */ + /* when the _environment_ variable `FT2_DEBUG_MEMORY' is defined also! */ + /* */ + /* Do not #undef this macro here since the build system might define */ + /* it for certain configurations only. */ + /* */ +/* #define FT_DEBUG_MEMORY */ + + + /*************************************************************************/ + /* */ + /* Module errors */ + /* */ + /* If this macro is set (which is _not_ the default), the higher byte */ + /* of an error code gives the module in which the error has occurred, */ + /* while the lower byte is the real error code. */ + /* */ + /* Setting this macro makes sense for debugging purposes only, since */ + /* it would break source compatibility of certain programs that use */ + /* FreeType 2. */ + /* */ + /* More details can be found in the files ftmoderr.h and fterrors.h. */ + /* */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + + + /*************************************************************************/ + /* */ + /* Position Independent Code */ + /* */ + /* If this macro is set (which is _not_ the default), FreeType2 will */ + /* avoid creating constants that require address fixups. Instead the */ + /* constants will be moved into a struct and additional intialization */ + /* code will be used. */ + /* */ + /* Setting this macro is needed for systems that prohibit address */ + /* fixups, such as BREW. [Note that standard compilers like gcc or */ + /* clang handle PIC generation automatically; you don't have to set */ + /* FT_CONFIG_OPTION_PIC, which is only necessary for very special */ + /* compilers.] */ + /* */ + /* Note that FT_CONFIG_OPTION_PIC support is not available for all */ + /* modules (see `modules.cfg' for a complete list). For building with */ + /* FT_CONFIG_OPTION_PIC support, do the following. */ + /* */ + /* 0. Clone the repository. */ + /* 1. Define FT_CONFIG_OPTION_PIC. */ + /* 2. Remove all subdirectories in `src' that don't have */ + /* FT_CONFIG_OPTION_PIC support. */ + /* 3. Comment out the corresponding modules in `modules.cfg'. */ + /* 4. Compile. */ + /* */ +/* #define FT_CONFIG_OPTION_PIC */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */ + /* embedded bitmaps in all formats using the SFNT module (namely */ + /* TrueType & OpenType). */ + /* */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */ + /* load and enumerate the glyph Postscript names in a TrueType or */ + /* OpenType file. */ + /* */ + /* Note that when you do not compile the `PSNames' module by undefining */ + /* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will */ + /* contain additional code used to read the PS Names table from a font. */ + /* */ + /* (By default, the module uses `PSNames' to extract glyph names.) */ + /* */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to */ + /* access the internal name table in a SFNT-based format like TrueType */ + /* or OpenType. The name table contains various strings used to */ + /* describe the font, like family name, copyright, version, etc. It */ + /* does not contain any glyph name though. */ + /* */ + /* Accessing SFNT names is done through the functions declared in */ + /* `ftsnames.h'. */ + /* */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /*************************************************************************/ + /* */ + /* TrueType CMap support */ + /* */ + /* Here you can fine-tune which TrueType CMap table format shall be */ + /* supported. */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_13 +#define TT_CONFIG_CMAP_FORMAT_14 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */ + /* a bytecode interpreter in the TrueType driver. */ + /* */ + /* By undefining this, you will only compile the code necessary to load */ + /* TrueType glyphs without hinting. */ + /* */ + /* Do not #undef this macro here, since the build system might */ + /* define it for certain configurations only. */ + /* */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */ + /* subpixel hinting support into the TrueType driver. This modifies the */ + /* TrueType hinting mechanism when anything but FT_RENDER_MODE_MONO is */ + /* requested. */ + /* */ + /* In particular, it modifies the bytecode interpreter to interpret (or */ + /* not) instructions in a certain way so that all TrueType fonts look */ + /* like they do in a Windows ClearType (DirectWrite) environment. See */ + /* [1] for a technical overview on what this means. See `ttinterp.h' */ + /* for more details on the LEAN option. */ + /* */ + /* There are three possible values. */ + /* */ + /* Value 1: */ + /* This value is associated with the `Infinality' moniker, */ + /* contributed by an individual nicknamed Infinality with the goal of */ + /* making TrueType fonts render better than on Windows. A high */ + /* amount of configurability and flexibility, down to rules for */ + /* single glyphs in fonts, but also very slow. Its experimental and */ + /* slow nature and the original developer losing interest meant that */ + /* this option was never enabled in default builds. */ + /* */ + /* The corresponding interpreter version is v38. */ + /* */ + /* Value 2: */ + /* The new default mode for the TrueType driver. The Infinality code */ + /* base was stripped to the bare minimum and all configurability */ + /* removed in the name of speed and simplicity. The configurability */ + /* was mainly aimed at legacy fonts like Arial, Times New Roman, or */ + /* Courier. Legacy fonts are fonts that modify vertical stems to */ + /* achieve clean black-and-white bitmaps. The new mode focuses on */ + /* applying a minimal set of rules to all fonts indiscriminately so */ + /* that modern and web fonts render well while legacy fonts render */ + /* okay. */ + /* */ + /* The corresponding interpreter version is v40. */ + /* */ + /* Value 3: */ + /* Compile both, making both v38 and v40 available (the latter is the */ + /* default). */ + /* */ + /* By undefining these, you get rendering behavior like on Windows */ + /* without ClearType, i.e., Windows XP without ClearType enabled and */ + /* Win9x (interpreter version v35). Or not, depending on how much */ + /* hinting blood and testing tears the font designer put into a given */ + /* font. If you define one or both subpixel hinting options, you can */ + /* switch between between v35 and the ones you define (using */ + /* `FT_Property_Set'). */ + /* */ + /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */ + /* defined. */ + /* */ + /* [1] https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ + /* */ +/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */ +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2 +/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */ + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED to compile the */ + /* TrueType glyph loader to use Apple's definition of how to handle */ + /* component offsets in composite glyphs. */ + /* */ + /* Apple and MS disagree on the default behavior of component offsets */ + /* in composites. Apple says that they should be scaled by the scaling */ + /* factors in the transformation matrix (roughly, it's more complex) */ + /* while MS says they should not. OpenType defines two bits in the */ + /* composite flags array which can be used to disambiguate, but old */ + /* fonts will not have them. */ + /* */ + /* https://www.microsoft.com/typography/otspec/glyf.htm */ + /* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html */ + /* */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_GX_VAR_SUPPORT if you want to include */ + /* support for Apple's distortable font technology (fvar, gvar, cvar, */ + /* and avar tables). This has many similarities to Type 1 Multiple */ + /* Masters support. */ + /* */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BDF if you want to include support for */ + /* an embedded `BDF ' table within SFNT-based bitmap formats. */ + /* */ +#define TT_CONFIG_OPTION_BDF + + + /*************************************************************************/ + /* */ + /* Option TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES controls the maximum */ + /* number of bytecode instructions executed for a single run of the */ + /* bytecode interpreter, needed to prevent infinite loops. You don't */ + /* want to change this except for very special situations (e.g., making */ + /* a library fuzzer spend less time to handle broken fonts). */ + /* */ + /* It is not expected that this value is ever modified by a configuring */ + /* script; instead, it gets surrounded with #ifndef ... #endif so that */ + /* the value can be set as a preprocessor option on the compiler's */ + /* command line. */ + /* */ +#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES +#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES 1000000L +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* T1_MAX_DICT_DEPTH is the maximum depth of nest dictionaries and */ + /* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */ + /* required. */ + /* */ +#define T1_MAX_DICT_DEPTH 5 + + + /*************************************************************************/ + /* */ + /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ + /* calls during glyph loading. */ + /* */ +#define T1_MAX_SUBRS_CALLS 16 + + + /*************************************************************************/ + /* */ + /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */ + /* minimum of 16 is required. */ + /* */ + /* The Chinese font MingTiEG-Medium (CNS 11643 character set) needs 256. */ + /* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of `t1afm', which is in charge of reading Type 1 AFM */ + /* files into an existing face. Note that if set, the T1 driver will be */ + /* unable to produce kerning distances. */ + /* */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of the Multiple Masters font support in the Type 1 */ + /* driver. */ + /* */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /*************************************************************************/ + /* */ + /* T1_CONFIG_OPTION_OLD_ENGINE controls whether the pre-Adobe Type 1 */ + /* engine gets compiled into FreeType. If defined, it is possible to */ + /* switch between the two engines using the `hinting-engine' property of */ + /* the type1 driver module. */ + /* */ +/* #define T1_CONFIG_OPTION_OLD_ENGINE */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** C F F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Using CFF_CONFIG_OPTION_DARKENING_PARAMETER_{X,Y}{1,2,3,4} it is */ + /* possible to set up the default values of the four control points that */ + /* define the stem darkening behaviour of the (new) CFF engine. For */ + /* more details please read the documentation of the */ + /* `darkening-parameters' property (file `ftdriver.h'), which allows the */ + /* control at run-time. */ + /* */ + /* Do *not* undefine these macros! */ + /* */ +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0 + + + /*************************************************************************/ + /* */ + /* CFF_CONFIG_OPTION_OLD_ENGINE controls whether the pre-Adobe CFF */ + /* engine gets compiled into FreeType. If defined, it is possible to */ + /* switch between the two engines using the `hinting-engine' property of */ + /* the cff driver module. */ + /* */ +/* #define CFF_CONFIG_OPTION_OLD_ENGINE */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** P C F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* There are many PCF fonts just called `Fixed' which look completely */ + /* different, and which have nothing to do with each other. When */ + /* selecting `Fixed' in KDE or Gnome one gets results that appear rather */ + /* random, the style changes often if one changes the size and one */ + /* cannot select some fonts at all. This option makes the PCF module */ + /* prepend the foundry name (plus a space) to the family name. */ + /* */ + /* We also check whether we have `wide' characters; all put together, we */ + /* get family names like `Sony Fixed' or `Misc Fixed Wide'. */ + /* */ + /* If this option is activated, it can be controlled with the */ + /* `no-long-family-names' property of the pcf driver module. */ + /* */ +/* #define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Compile autofit module with CJK (Chinese, Japanese, Korean) script */ + /* support. */ + /* */ +#define AF_CONFIG_OPTION_CJK + + /*************************************************************************/ + /* */ + /* Compile autofit module with fallback Indic script support, covering */ + /* some scripts that the `latin' submodule of the autofit module doesn't */ + /* (yet) handle. */ + /* */ +#define AF_CONFIG_OPTION_INDIC + + /*************************************************************************/ + /* */ + /* Compile autofit module with warp hinting. The idea of the warping */ + /* code is to slightly scale and shift a glyph within a single dimension */ + /* so that as much of its segments are aligned (more or less) on the */ + /* grid. To find out the optimal scaling and shifting value, various */ + /* parameter combinations are tried and scored. */ + /* */ + /* This experimental option is active only if the rendering mode is */ + /* FT_RENDER_MODE_LIGHT; you can switch warping on and off with the */ + /* `warping' property of the auto-hinter (see file `ftdriver.h' for more */ + /* information; by default it is switched off). */ + /* */ +#define AF_CONFIG_OPTION_USE_WARPER + + /*************************************************************************/ + /* */ + /* Use TrueType-like size metrics for `light' auto-hinting. */ + /* */ + /* It is strongly recommended to avoid this option, which exists only to */ + /* help some legacy applications retain its appearance and behaviour */ + /* with respect to auto-hinted TrueType fonts. */ + /* */ + /* The very reason this option exists at all are GNU/Linux distributions */ + /* like Fedora that did not un-patch the following change (which was */ + /* present in FreeType between versions 2.4.6 and 2.7.1, inclusive). */ + /* */ + /* 2011-07-16 Steven Chu */ + /* */ + /* [truetype] Fix metrics on size request for scalable fonts. */ + /* */ + /* This problematic commit is now reverted (more or less). */ + /* */ +/* #define AF_CONFIG_OPTION_TT_SIZE_METRICS */ + + /* */ + + + /* + * This macro is obsolete. Support has been removed in FreeType + * version 2.5. + */ +/* #define FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* + * This macro is defined if native TrueType hinting is requested by the + * definitions above. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 1 +#define TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY +#endif + +#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 2 +#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#endif +#endif +#endif + + + /* + * Check CFF darkening parameters. The checks are the same as in function + * `cff_property_set' in file `cffdrivr.c'. + */ +#if CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 > 500 +#error "Invalid CFF darkening parameters!" +#endif + +FT_END_HEADER + + +#endif /* FTOPTION_H_ */ + + +/* END */ diff --git a/ports/freetype/patch-ftstdlib.h b/ports/freetype/patch-ftstdlib.h new file mode 100644 index 0000000..f0aa2ff --- /dev/null +++ b/ports/freetype/patch-ftstdlib.h @@ -0,0 +1,183 @@ +/***************************************************************************/ +/* */ +/* ftstdlib.h */ +/* */ +/* ANSI-specific library and header configuration file (specification */ +/* only). */ +/* */ +/* Copyright 2002-2018 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to group all #includes to the ANSI C library that */ + /* FreeType normally requires. It also defines macros to rename the */ + /* standard functions within the FreeType source code. */ + /* */ + /* Load a file which defines FTSTDLIB_H_ before this one to override it. */ + /* */ + /*************************************************************************/ + + +#ifndef FTSTDLIB_H_ +#define FTSTDLIB_H_ + +#ifndef IncludedEssenceAPIHeader +#define ES_CRT +#define ES_API +#define ES_FORWARD(x) x +#define ES_DIRECT_API +#define ES_EXTERN_FORWARD extern +#include +#endif + +#include + +#define ft_ptrdiff_t ptrdiff_t + + + /**********************************************************************/ + /* */ + /* integer limits */ + /* */ + /* UINT_MAX and ULONG_MAX are used to automatically compute the size */ + /* of `int' and `long' in bytes at compile-time. So far, this works */ + /* for all platforms the library has been tested on. */ + /* */ + /* Note that on the extremely rare platforms that do not provide */ + /* integer types that are _exactly_ 16 and 32 bits wide (e.g. some */ + /* old Crays where `int' is 36 bits), we do not make any guarantee */ + /* about the correct behaviour of FT2 with all fonts. */ + /* */ + /* In these case, `ftconfig.h' will refuse to compile anyway with a */ + /* message like `couldn't find 32-bit type' or something similar. */ + /* */ + /**********************************************************************/ + + +#include + +#define FT_CHAR_BIT CHAR_BIT +#define FT_USHORT_MAX USHRT_MAX +#define FT_INT_MAX INT_MAX +#define FT_INT_MIN INT_MIN +#define FT_UINT_MAX UINT_MAX +#define FT_LONG_MIN LONG_MIN +#define FT_LONG_MAX LONG_MAX +#define FT_ULONG_MAX ULONG_MAX + + + /**********************************************************************/ + /* */ + /* character and string processing */ + /* */ + /**********************************************************************/ + + +// #include + +#define ft_memchr EsCRTmemchr +#define ft_memcmp EsCRTmemcmp +#define ft_memcpy EsCRTmemcpy +#define ft_memmove EsCRTmemmove +#define ft_memset EsCRTmemset +#define ft_strcat EsCRTstrcat +#define ft_strcmp EsCRTstrcmp +#define ft_strcpy EsCRTstrcpy +#define ft_strlen EsCRTstrlen +#define ft_strncmp EsCRTstrncmp +#define ft_strncpy EsCRTstrncpy +#define ft_strrchr EsCRTstrrchr +#define ft_strstr EsCRTstrstr + + + /**********************************************************************/ + /* */ + /* file handling */ + /* */ + /**********************************************************************/ + + +// #include + +#define FT_FILE FILE +#define ft_fclose fclose +#define ft_fopen fopen +#define ft_fread fread +#define ft_fseek fseek +#define ft_ftell ftell +#define ft_sprintf sprintf + + + /**********************************************************************/ + /* */ + /* sorting */ + /* */ + /**********************************************************************/ + + +// #include + +#define ft_qsort EsCRTqsort + + + /**********************************************************************/ + /* */ + /* memory allocation */ + /* */ + /**********************************************************************/ + + +#define ft_scalloc EsCRTcalloc +#define ft_sfree EsCRTfree +#define ft_smalloc EsCRTmalloc +#define ft_srealloc EsCRTrealloc + + + /**********************************************************************/ + /* */ + /* miscellaneous */ + /* */ + /**********************************************************************/ + + +#define ft_strtol EsCRTstrtol +#define ft_getenv EsCRTgetenv + + + /**********************************************************************/ + /* */ + /* execution control */ + /* */ + /**********************************************************************/ + + +// #include + +#define ft_jmp_buf EsCRTjmp_buf /* note: this cannot be a typedef since */ + /* jmp_buf is defined as a macro */ + /* on certain platforms */ + +#define ft_longjmp EsCRTlongjmp +#define ft_setjmp( b ) EsCRTsetjmp( *(ft_jmp_buf*) &(b) ) /* same thing here */ + + + /* the following is only used for debugging purposes, i.e., if */ + /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE are defined */ + +#include + + +#endif /* FTSTDLIB_H_ */ + + +/* END */ diff --git a/ports/freetype/patch-modules.cfg b/ports/freetype/patch-modules.cfg new file mode 100644 index 0000000..b9b0531 --- /dev/null +++ b/ports/freetype/patch-modules.cfg @@ -0,0 +1,270 @@ +# modules.cfg +# +# Copyright 2005-2018 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. +# +# +# In case you compile the FreeType library with GNU make or makepp, this +# file controls which components are built into the library. Otherwise, +# please read this file for information on the various modules and its +# dependencies, then follow the instructions in the file `docs/INSTALL.ANY'. +# +# To deactivate a module, simply comment out the corresponding line. To +# activate a module, remove the comment character. +# +# Note that many modules and components are further controlled with macros +# in the file `include/freetype/config/ftoption.h'. + + +#### +#### font modules -- at least one is required +#### +#### The order given here (from top to down) is the order used for testing +#### font formats in the compiled library. +#### + +# TrueType font driver. +# +# This driver needs the `sfnt' module. +FONT_MODULES += truetype + +# PostScript Type 1 font driver. +# +# This driver needs the `psaux', `pshinter', and `psnames' modules. +# No FT_CONFIG_OPTION_PIC support. +FONT_MODULES += type1 + +# CFF/OpenType font driver. +# +# This driver needs the `sfnt', `psaux', `pshinter', and `psnames' modules. +FONT_MODULES += cff + +# Type 1 CID-keyed font driver. +# +# This driver needs the `psaux', `pshinter', and `psnames' modules. +# No FT_CONFIG_OPTION_PIC support. +# FONT_MODULES += cid + +# PFR/TrueDoc font driver. See optional extension ftpfr.c below also. +# No FT_CONFIG_OPTION_PIC support. +# FONT_MODULES += pfr + +# PostScript Type 42 font driver. +# +# This driver needs the `truetype' and `psaux' modules. +# No FT_CONFIG_OPTION_PIC support. +FONT_MODULES += type42 + +# Windows FONT/FNT font driver. See optional extension ftwinfnt.c below +# also. +# No FT_CONFIG_OPTION_PIC support. +# FONT_MODULES += winfonts + +# PCF font driver. +# No FT_CONFIG_OPTION_PIC support. +# FONT_MODULES += pcf + +# BDF font driver. See optional extension ftbdf.c below also. +# No FT_CONFIG_OPTION_PIC support. +# FONT_MODULES += bdf + +# SFNT files support. If used without `truetype' or `cff', it supports +# bitmap-only fonts within an SFNT wrapper. +# +# This driver needs the `psnames' module. +FONT_MODULES += sfnt + + +#### +#### hinting modules +#### + +# FreeType's auto hinter. +HINTING_MODULES += autofit + +# PostScript hinter. +HINTING_MODULES += pshinter + +# The TrueType hinting engine doesn't have a module of its own but is +# controlled in file include/freetype/config/ftoption.h +# (TT_CONFIG_OPTION_BYTECODE_INTERPRETER and friends). + + +#### +#### raster modules -- at least one is required for vector font formats +#### + +# Monochrome rasterizer. +RASTER_MODULES += raster + +# Anti-aliasing rasterizer. +RASTER_MODULES += smooth + + +#### +#### auxiliary modules +#### + +# FreeType's cache sub-system (quite stable but still in beta -- this means +# that its public API is subject to change if necessary). See +# include/freetype/ftcache.h. Needs ftglyph.c. +# No FT_CONFIG_OPTION_PIC support. +# AUX_MODULES += cache + +# TrueType GX/AAT table validation. Needs ftgxval.c below. +# +# No FT_CONFIG_OPTION_PIC support. +AUX_MODULES += gxvalid + +# Support for streams compressed with gzip (files with suffix .gz). +# +# See include/freetype/ftgzip.h for the API. +# No FT_CONFIG_OPTION_PIC support. +# AUX_MODULES += gzip + +# Support for streams compressed with LZW (files with suffix .Z). +# +# See include/freetype/ftlzw.h for the API. +# No FT_CONFIG_OPTION_PIC support. +# AUX_MODULES += lzw + +# Support for streams compressed with bzip2 (files with suffix .bz2). +# +# See include/freetype/ftbzip2.h for the API. +# No FT_CONFIG_OPTION_PIC support. +# AUX_MODULES += bzip2 + +# OpenType table validation. Needs ftotval.c below. +# +# No FT_CONFIG_OPTION_PIC support. +# AUX_MODULES += otvalid + +# Auxiliary PostScript driver component to share common code. +# +# This module depends on `psnames'. +# No FT_CONFIG_OPTION_PIC support. +AUX_MODULES += psaux + +# Support for PostScript glyph names. +# +# This module can be controlled in ftconfig.h +# (FT_CONFIG_OPTION_POSTSCRIPT_NAMES). +AUX_MODULES += psnames + + +#### +#### base module extensions +#### + +# Exact bounding box calculation. +# +# See include/freetype/ftbbox.h for the API. +BASE_EXTENSIONS += ftbbox.c + +# Access BDF-specific strings. Needs BDF font driver. +# +# See include/freetype/ftbdf.h for the API. +BASE_EXTENSIONS += ftbdf.c + +# Utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp bitmaps into +# 8bpp format, and for emboldening of bitmap glyphs. +# +# See include/freetype/ftbitmap.h for the API. +BASE_EXTENSIONS += ftbitmap.c + +# Access CID font information. +# +# See include/freetype/ftcid.h for the API. +BASE_EXTENSIONS += ftcid.c + +# Support functions for font formats. +# +# See include/freetype/ftfntfmt.h for the API. +BASE_EXTENSIONS += ftfntfmt.c + +# Access FSType information. Needs fttype1.c. +# +# See include/freetype/freetype.h for the API. +BASE_EXTENSIONS += ftfstype.c + +# Support for GASP table queries. +# +# See include/freetype/ftgasp.h for the API. +BASE_EXTENSIONS += ftgasp.c + +# Convenience functions to handle glyphs. Needs ftbitmap.c. +# +# See include/freetype/ftglyph.h for the API. +BASE_EXTENSIONS += ftglyph.c + +# Interface for gxvalid module. +# +# See include/freetype/ftgxval.h for the API. +BASE_EXTENSIONS += ftgxval.c + +# Support for LCD color filtering of subpixel bitmaps. +# +# See include/freetype/ftlcdfil.h for the API. +BASE_EXTENSIONS += ftlcdfil.c + +# Multiple Master font interface. +# +# See include/freetype/ftmm.h for the API. +BASE_EXTENSIONS += ftmm.c + +# Interface for otvalid module. +# +# See include/freetype/ftotval.h for the API. +BASE_EXTENSIONS += ftotval.c + +# Support for FT_Face_CheckTrueTypePatents. +# +# See include/freetype/freetype.h for the API. +BASE_EXTENSIONS += ftpatent.c + +# Interface for accessing PFR-specific data. Needs PFR font driver. +# +# See include/freetype/ftpfr.h for the API. +BASE_EXTENSIONS += ftpfr.c + +# Path stroker. Needs ftglyph.c. +# +# See include/freetype/ftstroke.h for the API. +BASE_EXTENSIONS += ftstroke.c + +# Support for synthetic emboldening and slanting of fonts. Needs ftbitmap.c. +# +# See include/freetype/ftsynth.h for the API. +BASE_EXTENSIONS += ftsynth.c + +# Interface to access data specific to PostScript Type 1 and Type 2 (CFF) +# fonts. +# +# See include/freetype/t1tables.h for the API. +# BASE_EXTENSIONS += fttype1.c + +# Interface for accessing data specific to Windows FNT files. Needs winfnt +# driver. +# +# See include/freetype/ftwinfnt.h for the API. +# BASE_EXTENSIONS += ftwinfnt.c + +#### +#### The components `ftsystem.c' (for memory allocation and stream I/O +#### management) and `ftdebug.c' (for emitting debug messages to the user) +#### are controlled with the following variables. +#### +#### ftsystem.c: $(FTSYS_SRC) +#### ftdebug.c: $(FTDEBUG_SRC) +#### +#### Please refer to docs/CUSTOMIZE for details. +#### + + +# EOF diff --git a/ports/gcc/changes/binutils_bfd_config.bfd b/ports/gcc/changes/binutils_bfd_config.bfd new file mode 100644 index 0000000..a9f5d42 --- /dev/null +++ b/ports/gcc/changes/binutils_bfd_config.bfd @@ -0,0 +1,1479 @@ +# config.bfd +# +# Copyright (C) 2012-2021 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING3. If not see +# . +# +# Convert a canonical host type into a BFD host type. +# Set shell variable targ to canonical target name, and run +# using ``. config.bfd''. +# Sets the following shell variables: +# targ_defvec Default vector for this target +# targ_selvecs Vectors to build for this target +# targ64_selvecs Vectors to build if --enable-64-bit-bfd is given +# or if host is 64 bit. +# targ_archs Architectures for this target +# targ_cflags $(CFLAGS) for this target (FIXME: pretty bogus) +# targ_underscore Whether underscores are used: yes or no + +# Part of this file is processed by targmatch.sed to generate the +# targmatch.h file. The #ifdef and #endif lines that appear below are +# copied directly into targmatch.h. + +# The binutils c++filt program wants to know whether underscores are +# stripped or not. That is why we set targ_underscore. c++filt uses +# this information to choose a default. This information is +# duplicated in the symbol_leading_char field of the BFD target +# vector, but c++filt does not deal with object files and is not +# linked against libbfd.a. It is not terribly important that c++filt +# get this right; it is just convenient. + +targ_defvec= +targ_selvecs= +targ64_selvecs= +targ_cflags= +targ_underscore=no + +# Catch obsolete configurations. +case $targ in + openrisc-*-* | or32-*-*) + echo "*** Configuration $targ is obsolete." >&2 + echo "*** Use or1k-*-elf or or1k-*-linux as the target instead" >&2 + exit 1 + ;; + arm*-*-symbianelf* | \ + ia64*-*-* | \ + null) + if test "x$enable_obsolete" != xyes; then + echo "*** Configuration $targ is obsolete." >&2 + echo "*** Specify --enable-obsolete to build it anyway." >&2 + echo "*** Support will be REMOVED in the next major release of BINUTILS," >&2 + echo "*** unless a maintainer comes forward." >&2 + exit 1 + fi;; +esac + +case $targ in + *-*-netbsdelf* | i[3-7]86-*-netbsd*-gnu* | i[3-7]86-*-knetbsd*-gnu | \ + mips*-*-irix5* | mips*-*-irix6*) + # Not obsolete + ;; + *-adobe-* | \ + *-go32-rtems* | \ + *-sony-* | \ + *-tandem-* | \ + *-*-ieee* | \ + *-*-netware* | \ + *-*-rtemsaout* | \ + *-*-rtemscoff* | \ + a29k-* | \ + arm*-*-aout | \ + arm-*-coff | \ + arm-*-netbsd* | \ + arm-*-openbsd* | \ + arm-*-oabi | \ + arm-*-riscix* | \ + arm-epoc-pe* | \ + c30-*-*aout* | tic30-*-*aout* | \ + cr16c-*-* | \ + h8300*-*-coff | \ + h8500*-*-coff | \ + hppa*-*-rtems* | \ + i[3-7]86-*-unixware* | \ + i[3-7]86-*-dgux* | \ + i[3-7]86-*-chorus* | \ + i[3-7]86-*-sysv* | \ + i[3-7]86-*-isc* | \ + i[3-7]86-*-sco* | \ + i[3-7]86-*-coff | \ + i[3-7]86-*-aix* | \ + i[3-7]86-sequent-bsd* | \ + i[3-7]86-*-freebsdaout* | i[3-7]86-*-freebsd[12].* | i[3-7]86-*-freebsd[12] | \ + i[3-7]86-*-netbsdaout* | i[3-7]86-*-netbsd* | \ + i[3-7]86-*-openbsd[0-2].* | i[3-7]86-*-openbsd3.[0-3] | \ + i[3-7]86-*-linux*aout* | \ + i[3-7]86-*-mach* | i[3-7]86-*-osf1mk* | \ + i[3-7]86-*-os9k | \ + i[3-7]86-none-* | \ + i[3-7]86-*-aout* | i[3-7]86*-*-vsta* | \ + i370-* | \ + i860-*-* | \ + i960-*-* | \ + m68*-*-*bsd* | \ + m68*-*-aout* | \ + m68*-*-coff* | \ + m68*-*-hpux* | \ + m68*-*-linux*aout* | \ + m68*-*-lynxos* | \ + m68*-*-os68k* | \ + m68*-*-psos* | \ + m68*-*-sunos* | \ + m68*-*-sysv* | \ + m68*-*-vsta* | \ + m68*-*-vxworks* | \ + m68*-apollo-* | \ + m68*-apple-aux* | \ + m68*-bull-sysv* | \ + m68*-ericsson-* | \ + m68*-motorola-sysv* | \ + m68*-netx-* | \ + m88*-*-* | \ + maxq-*-coff | \ + mips*-*-bsd* | \ + mips*-*-ecoff* | \ + mips*-*-lnews* | \ + mips*-*-mach3* | \ + mips*-*-pe* | \ + mips*-*-riscos* | \ + mips*-*-sysv* | \ + mips*-big-* | \ + mips*-dec-* | \ + mips*-sgi-* | \ + mips*el-*-rtems* | \ + powerpc-*-lynxos* | powerpc-*-windiss* | \ + powerpcle-*-pe | powerpcle-*-winnt* | powerpcle-*-cygwin* | \ + sh*-*-symbianelf* | sh5*-*-* | sh64*-*-* | \ + sparc*-*-*aout* | \ + sparc*-*-chorus* | \ + sparc*-*-coff* | \ + sparc-*-lynxos* | \ + sparc-*-openbsd[0-2].* | sparc-*-openbsd3.[0-1] | \ + tahoe-*-* | \ + vax-*-bsd* | vax-*-ultrix* | vax-*-vms* | \ + w65-*-* | \ + we32k-*-* | \ + xc16x-*-* | \ + null) + echo "*** Configuration $targ is obsolete." >&2 + echo "*** Support has been REMOVED." >&2 + exit 1 + ;; +esac + +targ_cpu=`echo $targ | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +case "${targ_cpu}" in +aarch64*) targ_archs="bfd_aarch64_arch bfd_arm_arch";; +alpha*) targ_archs=bfd_alpha_arch ;; +am33_2.0*) targ_archs=bfd_mn10300_arch ;; +arc*) targ_archs=bfd_arc_arch ;; +arm*) targ_archs=bfd_arm_arch ;; +bfin*) targ_archs=bfd_bfin_arch ;; +c30*) targ_archs=bfd_tic30_arch ;; +c4x*) targ_archs=bfd_tic4x_arch ;; +c54x*) targ_archs=bfd_tic54x_arch ;; +cr16*) targ_archs=bfd_cr16_arch ;; +crisv32) targ_archs=bfd_cris_arch ;; +crx*) targ_archs=bfd_crx_arch ;; +csky*) targ_archs=bfd_csky_arch ;; +dlx*) targ_archs=bfd_dlx_arch ;; +fido*) targ_archs=bfd_m68k_arch ;; +hppa*) targ_archs=bfd_hppa_arch ;; +i[3-7]86) targ_archs=bfd_i386_arch ;; +ia16) targ_archs=bfd_i386_arch ;; +lm32) targ_archs=bfd_lm32_arch ;; +m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; +m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; +m68*) targ_archs=bfd_m68k_arch ;; +s12z*) targ_archs=bfd_s12z_arch ;; +microblaze*) targ_archs=bfd_microblaze_arch ;; +mips*) targ_archs=bfd_mips_arch ;; +nds32*) targ_archs=bfd_nds32_arch ;; +nfp) targ_archs=bfd_nfp_arch ;; +nios2*) targ_archs=bfd_nios2_arch ;; +or1k*|or1knd*) targ_archs=bfd_or1k_arch ;; +pdp11*) targ_archs=bfd_pdp11_arch ;; +pj*) targ_archs="bfd_pj_arch bfd_i386_arch";; +powerpc*) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; +pru*) targ_archs=bfd_pru_arch ;; +riscv*) targ_archs=bfd_riscv_arch ;; +rs6000) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; +s390*) targ_archs=bfd_s390_arch ;; +sh*) targ_archs=bfd_sh_arch ;; +sparc*) targ_archs=bfd_sparc_arch ;; +spu*) targ_archs=bfd_spu_arch ;; +tilegx*) targ_archs=bfd_tilegx_arch ;; +tilepro*) targ_archs=bfd_tilepro_arch ;; +v850*) targ_archs="bfd_v850_arch bfd_v850_rh850_arch" ;; +visium*) targ_archs=bfd_visium_arch ;; +wasm32) targ_archs=bfd_wasm32_arch ;; +x86_64*) targ_archs=bfd_i386_arch ;; +xtensa*) targ_archs=bfd_xtensa_arch ;; +xgate) targ_archs=bfd_xgate_arch ;; +z80*|r800|z180|gbz80|ez80*) targ_archs=bfd_z80_arch ;; +z8k*) targ_archs=bfd_z8k_arch ;; +*) targ_archs=bfd_${targ_cpu}_arch ;; +esac + + +# WHEN ADDING ENTRIES TO THIS MATRIX: +# Make sure that the left side always has two dashes. Otherwise you +# can get spurious matches. Even for unambiguous cases, do this as a +# convention, else the table becomes a real mess to understand and maintain. + +case "${targ}" in +# START OF targmatch.h +#ifdef BFD64 + aarch64-*-darwin*) + targ_defvec=aarch64_mach_o_vec + targ_selvecs="arm_mach_o_vec mach_o_le_vec mach_o_be_vec mach_o_fat_vec" + targ_archs="$targ_archs bfd_i386_arch bfd_powerpc_arch bfd_rs6000_arch" + want64=true + ;; + aarch64-*-elf | aarch64-*-rtems*) + targ_defvec=aarch64_elf64_le_vec + targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec" + want64=true + ;; + aarch64_be-*-elf) + targ_defvec=aarch64_elf64_be_vec + targ_selvecs="aarch64_elf64_le_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_be_vec arm_elf32_le_vec" + want64=true + ;; + aarch64-*-freebsd*) + targ_defvec=aarch64_elf64_le_vec + targ_selvecs="aarch64_elf64_be_vec arm_elf32_le_vec arm_elf32_be_vec" + want64=true + ;; + aarch64-*-fuchsia*) + targ_defvec=aarch64_elf64_le_vec + targ_selvecs="aarch64_elf64_be_vec arm_elf32_le_vec arm_elf32_be_vec" + want64=true + ;; + aarch64-*-cloudabi*) + targ_defvec=aarch64_elf64_le_cloudabi_vec + targ_selvecs=aarch64_elf64_be_cloudabi_vec + want64=true + ;; + aarch64-*-linux* | aarch64-*-netbsd*) + targ_defvec=aarch64_elf64_le_vec + targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec" + want64=true + ;; + aarch64_be-*-linux* | aarch64_be-*-netbsd*) + targ_defvec=aarch64_elf64_be_vec + targ_selvecs="aarch64_elf64_le_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_be_vec arm_elf32_le_vec" + want64=true + ;; + alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) + targ_defvec=alpha_elf64_fbsd_vec + targ_selvecs="alpha_elf64_vec alpha_ecoff_le_vec" + want64=true + # FreeBSD <= 4.0 supports only the old nonstandard way of ABI labelling. + case "${targ}" in + alpha*-*-freebsd3* | alpha*-*-freebsd4 | alpha*-*-freebsd4.0*) + targ_cflags=-DOLD_FREEBSD_ABI_LABEL ;; + esac + ;; + alpha*-*-netbsd* | alpha*-*-openbsd*) + targ_defvec=alpha_elf64_vec + targ_selvecs=alpha_ecoff_le_vec + want64=true + ;; + alpha*-*-linux*ecoff*) + targ_defvec=alpha_ecoff_le_vec + targ_selvecs=alpha_elf64_vec + want64=true + ;; + alpha*-*-linux-* | alpha*-*-elf*) + targ_defvec=alpha_elf64_vec + targ_selvecs=alpha_ecoff_le_vec + want64=true + ;; + alpha*-*-*vms*) + targ_defvec=alpha_vms_vec + targ_selvecs=alpha_vms_lib_txt_vec + want64=true + ;; + alpha*-*-*) + targ_defvec=alpha_ecoff_le_vec + want64=true + ;; + ia64*-*-freebsd* | ia64*-*-netbsd* | ia64*-*-linux-* | ia64*-*-elf* | ia64*-*-kfreebsd*-gnu) + targ_defvec=ia64_elf64_le_vec + targ_selvecs="ia64_elf64_be_vec ia64_pei_vec" + want64=true + ;; + ia64*-*-hpux*) + targ_defvec=ia64_elf32_hpux_be_vec + targ_selvecs="ia64_elf64_hpux_be_vec" + want64=true + ;; + ia64*-*-*vms*) + targ_defvec=ia64_elf64_vms_vec + targ_selvecs=alpha_vms_lib_txt_vec + want64=true + ;; +#endif /* BFD64 */ + + am33_2.0-*-linux*) + targ_defvec=am33_elf32_linux_vec + ;; + + arc*eb-*-elf* | arc*eb-*-linux*) + targ_defvec=arc_elf32_be_vec + targ_selvecs=arc_elf32_le_vec + ;; + + arc*-*-elf* | arc*-*-linux*) + targ_defvec=arc_elf32_le_vec + targ_selvecs=arc_elf32_be_vec + ;; + + arm-*-darwin*) + targ_defvec=arm_mach_o_vec + targ_selvecs="mach_o_le_vec mach_o_be_vec mach_o_fat_vec" + targ_archs="$targ_archs bfd_i386_arch bfd_powerpc_arch bfd_rs6000_arch" + ;; + arm-*-fuchsia*) + targ_defvec=arm_elf32_le_vec + targ_selvecs="arm_elf32_be_vec" + ;; + arm-*-nacl*) + targ_defvec=arm_elf32_nacl_le_vec + targ_selvecs="arm_elf32_nacl_be_vec" + ;; + armeb-*-nacl*) + targ_defvec=arm_elf32_nacl_be_vec + targ_selvecs="arm_elf32_nacl_le_vec" + ;; + armeb-*-netbsdelf*) + targ_defvec=arm_elf32_be_vec + targ_selvecs="arm_elf32_le_vec" + ;; + arm-*-netbsdelf*) + targ_defvec=arm_elf32_le_vec + targ_selvecs="arm_elf32_be_vec" + ;; + arm-*-nto* | nto*arm*) + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec + targ_cflags=-D__QNXTARGET__ + ;; + arm-wince-pe | arm-*-wince | arm*-*-mingw32ce* | arm*-*-cegcc*) + targ_defvec=arm_pe_wince_le_vec + targ_selvecs="arm_pe_wince_le_vec arm_pe_wince_be_vec arm_pei_wince_le_vec arm_pei_wince_be_vec" + targ_underscore=no + targ_cflags="-DARM_WINCE -DARM_COFF_BUGFIX" + ;; + arm-*-pe*) + targ_defvec=arm_pe_le_vec + targ_selvecs="arm_pe_le_vec arm_pe_be_vec arm_pei_le_vec arm_pei_be_vec" + targ_underscore=yes + ;; + arm-*-phoenix*) + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec + ;; + armeb-*-elf | arm*b-*-freebsd* | arm*b-*-linux-* | armeb-*-eabi*) + targ_defvec=arm_elf32_be_vec + targ_selvecs=arm_elf32_le_vec + ;; + arm-*-kaos*) + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec + ;; + arm-*-elf | arm*-*-freebsd* | arm*-*-linux-* | arm*-*-conix* | \ + arm*-*-uclinux* | arm-*-kfreebsd*-gnu | \ + arm*-*-eabi* | arm-*-rtems* | arm*-*-uclinuxfdpiceabi) + targ_defvec=arm_elf32_le_vec + targ_selvecs="arm_elf32_fdpic_le_vec arm_elf32_be_vec arm_elf32_fdpic_be_vec" + ;; + arm*-*-vxworks | arm*-*-windiss) + targ_defvec=arm_elf32_vxworks_le_vec + targ_selvecs=arm_elf32_vxworks_be_vec + ;; + arm*-*-symbianelf*) + targ_defvec=arm_elf32_symbian_le_vec + targ_selvecs=arm_elf32_symbian_be_vec + ;; + arm9e-*-elf) + targ_defvec=arm_elf32_le_vec + targ_selvecs=arm_elf32_be_vec + ;; + + avr-*-*) + targ_defvec=avr_elf32_vec + ;; + + bfin-*-*) + targ_defvec=bfin_elf32_vec + targ_selvecs=bfin_elf32_fdpic_vec + targ_underscore=yes + ;; + + c30-*-*coff* | tic30-*-*coff*) + targ_defvec=tic30_coff_vec + ;; + + c4x-*-*coff* | tic4x-*-*coff*) + targ_defvec=tic4x_coff1_vec + targ_selvecs="tic4x_coff1_beh_vec tic4x_coff2_vec tic4x_coff2_beh_vec tic4x_coff0_vec tic4x_coff0_beh_vec" + targ_underscore=yes + ;; + + c54x*-*-*coff* | tic54x-*-*coff*) + targ_defvec=tic54x_coff1_vec + targ_selvecs="tic54x_coff1_beh_vec tic54x_coff2_vec tic54x_coff2_beh_vec tic54x_coff0_vec tic54x_coff0_beh_vec" + targ_underscore=yes + ;; + + cr16-*-elf* | cr16*-*-uclinux*) + targ_defvec=cr16_elf32_vec + targ_underscore=yes + ;; + +#ifdef BFD64 + cris-*-* | crisv32-*-*) + targ_defvec=cris_aout_vec + targ_selvecs="cris_elf32_us_vec cris_elf32_vec" + case "${targ}" in + *-*-linux*) ;; + *) targ_underscore=yes ;; + esac + want64=true + ;; +#endif + + crx-*-elf*) + targ_defvec=crx_elf32_vec + targ_underscore=yes + ;; + + csky-*-elf* | csky-*-linux* ) + targ_defvec=csky_elf32_le_vec + targ_selvecs="csky_elf32_be_vec csky_elf32_le_vec" + ;; + + d10v-*-*) + targ_defvec=d10v_elf32_vec + ;; + + dlx-*-elf*) + targ_defvec=dlx_elf32_be_vec + targ_selvecs="dlx_elf32_be_vec" + ;; + + d30v-*-*) + targ_defvec=d30v_elf32_vec + ;; + +#ifdef BFD64 + bpf-*-none) + targ_defvec=bpf_elf64_le_vec + targ_selvecs=bpf_elf64_be_vec + targ_underscore=yes + ;; +#endif + + epiphany-*-*) + targ_defvec=epiphany_elf32_vec + targ_underscore=yes + ;; + + fido-*-elf* ) + targ_defvec=m68k_elf32_vec + ;; + + fr30-*-elf) + targ_defvec=fr30_elf32_vec + ;; + + frv-*-elf) + targ_defvec=frv_elf32_vec + targ_selvecs=frv_elf32_fdpic_vec + ;; + + frv-*-*linux*) + targ_defvec=frv_elf32_fdpic_vec + targ_selvecs=frv_elf32_vec + ;; + + moxie-*-elf | moxie-*-rtems* | moxie-*-uclinux) + targ_defvec=moxie_elf32_be_vec + targ_selvecs=moxie_elf32_le_vec + ;; + + moxie-*-moxiebox*) + targ_defvec=moxie_elf32_le_vec + ;; + + h8300*-*-elf | h8300*-*-rtems*) + targ_defvec=h8300_elf32_vec + targ_underscore=yes + ;; + + h8300*-*-linux*) + targ_defvec=h8300_elf32_linux_vec + ;; + +#ifdef BFD64 + hppa*64*-*-linux-*) + targ_defvec=hppa_elf64_linux_vec + targ_selvecs=hppa_elf64_vec + want64=true + ;; + hppa*64*-*-hpux11*) + targ_defvec=hppa_elf64_vec + targ_selvecs=hppa_elf64_linux_vec + targ_cflags=-DHPUX_LARGE_AR_IDS + want64=true + ;; +#endif + + hppa*-*-linux-*) + targ_defvec=hppa_elf32_linux_vec + targ_selvecs=hppa_elf32_vec + ;; + hppa*-*-netbsd*) + targ_defvec=hppa_elf32_nbsd_vec + targ_selvecs="hppa_elf32_vec hppa_elf32_linux_vec" + ;; + hppa*-*-*elf* | hppa*-*-lites* | hppa*-*-sysv4* | hppa*-*-openbsd*) + targ_defvec=hppa_elf32_vec + targ_selvecs=hppa_elf32_linux_vec + ;; + + hppa*-*-bsd*) + targ_defvec=hppa_som_vec + targ_selvecs=hppa_elf32_vec + ;; + hppa*-*-hpux* | hppa*-*-hiux* | hppa*-*-mpeix*) + targ_defvec=hppa_som_vec + ;; + hppa*-*-osf*) + targ_defvec=hppa_som_vec + targ_selvecs=hppa_elf32_vec + ;; + + i[3-7]86-*-elf* | i[3-7]86-*-rtems*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_vec" + ;; + i[3-7]86-*-solaris2*) + targ_defvec=i386_elf32_sol2_vec + targ_selvecs="iamcu_elf32_vec i386_coff_vec i386_pei_vec" + targ64_selvecs="x86_64_elf64_sol2_vec l1om_elf64_vec k1om_elf64_vec x86_64_pe_vec x86_64_pei_vec" + want64=true + ;; +#ifdef BFD64 + x86_64-*-solaris2*) + targ_defvec=i386_elf32_sol2_vec + targ_selvecs="x86_64_elf64_sol2_vec l1om_elf64_vec k1om_elf64_vec iamcu_elf32_vec i386_coff_vec i386_pei_vec x86_64_pe_vec x86_64_pei_vec" + want64=true + ;; +#endif + i[3-7]86-*-nto*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_vec" + ;; + i[3-7]86-*-aros*) + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec + ;; + i[3-7]86-*-dicos*) + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec + targ64_selvecs="x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec" + ;; + *-*-msdosdjgpp* | *-*-go32* ) + targ_defvec=i386_coff_go32_vec + targ_selvecs="i386_coff_go32stubbed_vec i386_aout_vec" + ;; + i[3-7]86-*-darwin* | i[3-7]86-*-macos10* | i[3-7]86-*-rhapsody*) + targ_defvec=i386_mach_o_vec + targ_selvecs="mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" + targ64_selvecs=x86_64_mach_o_vec + targ_archs="$targ_archs bfd_powerpc_arch bfd_rs6000_arch" + ;; + i[3-7]86-*-bsd*) + targ_defvec=i386_aout_bsd_vec + targ_underscore=yes + ;; + i[3-7]86-*-dragonfly*) + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec + targ64_selvecs="x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec" + ;; + i[3-7]86-*-freebsd* | i[3-7]86-*-kfreebsd*-gnu) + targ_defvec=i386_elf32_fbsd_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec i386_pei_vec i386_coff_vec" + targ64_selvecs="x86_64_elf64_fbsd_vec x86_64_elf64_vec x86_64_pe_vec x86_64_pei_vec l1om_elf64_vec l1om_elf64_fbsd_vec k1om_elf64_vec k1om_elf64_fbsd_vec" + # FreeBSD <= 4.0 supports only the old nonstandard way of ABI labelling. + case "${targ}" in + i[3-7]86-*-freebsd3* | i[3-7]86-*-freebsd4 | i[3-7]86-*-freebsd4.0*) + targ_cflags=-DOLD_FREEBSD_ABI_LABEL ;; + esac + ;; + i[3-7]86-*-netbsdelf* | i[3-7]86-*-netbsd*-gnu* | i[3-7]86-*-knetbsd*-gnu) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec" + targ64_selvecs="x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec" + ;; + i[3-7]86-*-netbsdpe*) + targ_defvec=i386_pe_vec + targ_selvecs="i386_pe_vec i386_pei_vec i386_elf32_vec iamcu_elf32_vec" + ;; + i[3-7]86-*-openbsd*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec" + ;; + i[3-7]86-*-linux-*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_pei_vec" + targ64_selvecs="x86_64_elf64_vec x86_64_elf32_vec x86_64_pe_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" + ;; + i[3-7]86-*-redox*) + targ_defvec=i386_elf32_vec + targ_selvecs= + targ64_selvecs=x86_64_elf64_vec + ;; +#ifdef BFD64 + x86_64-*-cloudabi*) + targ_defvec=x86_64_elf64_cloudabi_vec + want64=true + ;; + x86_64-*-darwin*) + targ_defvec=x86_64_mach_o_vec + targ_selvecs="i386_mach_o_vec mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" + targ_archs="$targ_archs bfd_powerpc_arch bfd_rs6000_arch" + want64=true + ;; + x86_64-*-dicos*) + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec l1om_elf64_vec k1om_elf64_vec" + want64=true + ;; + x86_64-*-elf* | x86_64-*-rtems* | x86_64-*-fuchsia | x86_64-*-essence) + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec x86_64_elf32_vec l1om_elf64_vec k1om_elf64_vec" + case "${targ}" in + x86_64-*-rtems*) + targ_selvecs="${targ_selvecs} x86_64_pe_vec x86_64_pei_vec" + esac + want64=true + ;; + x86_64-*-dragonfly*) + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec l1om_elf64_vec k1om_elf64_vec" + want64=true + ;; + x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) + targ_defvec=x86_64_elf64_fbsd_vec + targ_selvecs="i386_elf32_fbsd_vec iamcu_elf32_vec i386_coff_vec i386_pei_vec x86_64_pe_vec x86_64_pei_vec i386_elf32_vec x86_64_elf64_vec l1om_elf64_vec l1om_elf64_fbsd_vec k1om_elf64_vec k1om_elf64_fbsd_vec" + want64=true + ;; + x86_64-*-netbsd* | x86_64-*-openbsd*) + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec i386_coff_vec i386_pei_vec x86_64_pe_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" + want64=true + ;; + x86_64-*-linux-*) + targ_defvec=x86_64_elf64_vec + targ_selvecs="i386_elf32_vec iamcu_elf32_vec x86_64_elf32_vec i386_pei_vec x86_64_pe_vec x86_64_pei_vec l1om_elf64_vec k1om_elf64_vec" + want64=true + ;; + x86_64-*-mingw* | x86_64-*-pe | x86_64-*-pep | x86_64-*-cygwin) + targ_defvec=x86_64_pe_vec + targ_selvecs="x86_64_pe_vec x86_64_pei_vec x86_64_pe_big_vec x86_64_elf64_vec l1om_elf64_vec k1om_elf64_vec i386_pe_vec i386_pei_vec i386_elf32_vec iamcu_elf32_vec" + want64=true + targ_underscore=no + ;; + x86_64-*-rdos*) + targ_defvec=x86_64_elf64_vec + want64=true + ;; + x86_64-*-redox*) + targ_defvec=x86_64_elf64_vec + targ_selvecs=i386_elf32_vec + want64=true + ;; +#endif + i[3-7]86-*-lynxos*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_lynx_vec i386_aout_lynx_vec" + ;; + i[3-7]86-*-gnu*) + targ_defvec=i386_elf32_vec + targ_selvecs=iamcu_elf32_vec + ;; + i[3-7]86-*-msdos*) + targ_defvec=i386_aout_vec + targ_selvecs=i386_msdos_vec + ;; + i[3-7]86-*-moss*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_msdos_vec i386_aout_vec" + ;; + i[3-7]86-*-beospe*) + targ_defvec=i386_pe_vec + targ_selvecs="i386_pe_vec i386_pei_vec" + ;; + i[3-7]86-*-beoself* | i[3-7]86-*-beos*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_pe_vec i386_pei_vec" + ;; + i[3-7]86-*-interix*) + targ_defvec=i386_pei_vec + targ_selvecs="i386_pe_vec" + # FIXME: This should eventually be checked at runtime. + targ_cflags=-DSTRICT_PE_FORMAT + ;; + i[3-7]86-*-rdos*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_coff_vec" + ;; + i[3-7]86-*-mingw32* | i[3-7]86-*-cygwin* | i[3-7]86-*-winnt | i[3-7]86-*-pe) + targ_defvec=i386_pe_vec + targ_selvecs="i386_pe_vec i386_pe_big_vec i386_pei_vec i386_elf32_vec iamcu_elf32_vec" + targ_underscore=yes + ;; + i[3-7]86-*-vxworks*) + targ_defvec=i386_elf32_vxworks_vec + targ_underscore=yes + ;; + + ia16-*-elf) + targ_defvec=i386_elf32_vec + targ_selvecs="i386_msdos_vec i386_aout_vec" + ;; + + ip2k-*-elf) + targ_defvec=ip2k_elf32_vec + targ_underscore=yes + ;; + + iq2000-*-elf) + targ_defvec=iq2000_elf32_vec + ;; + + lm32-*-elf | lm32-*-rtems*) + targ_defvec=lm32_elf32_vec + targ_selvecs=lm32_elf32_fdpic_vec + ;; + + lm32-*-*linux*) + targ_defvec=lm32_elf32_fdpic_vec + targ_selvecs=lm32_elf32_vec + ;; + + m32c-*-elf | m32c-*-rtems*) + targ_defvec=m32c_elf32_vec + targ_underscore=yes + ;; + + m32r*le-*-linux*) + targ_defvec=m32r_elf32_linux_le_vec + targ_selvecs="m32r_elf32_linux_vec m32r_elf32_linux_le_vec" + ;; + m32r*-*-linux*) + targ_defvec=m32r_elf32_linux_vec + targ_selvecs="m32r_elf32_linux_vec m32r_elf32_linux_le_vec" + ;; + m32r*le-*-*) + targ_defvec=m32r_elf32_le_vec + targ_selvecs="m32r_elf32_vec m32r_elf32_le_vec" + ;; + m32r-*-*) + targ_defvec=m32r_elf32_vec + ;; + + m68hc11-*-* | m6811-*-*) + targ_defvec=m68hc11_elf32_vec + targ_selvecs="m68hc11_elf32_vec m68hc12_elf32_vec" + ;; + m68hc12-*-* | m6812-*-*) + targ_defvec=m68hc12_elf32_vec + targ_selvecs="m68hc11_elf32_vec m68hc12_elf32_vec" + ;; + + m68*-*-*) + targ_defvec=m68k_elf32_vec + ;; + + s12z-*-*) + targ_defvec=s12z_elf32_vec + ;; + mcore-*-elf) + targ_defvec=mcore_elf32_be_vec + targ_selvecs="mcore_elf32_be_vec mcore_elf32_le_vec" + ;; + mcore-*-pe) + targ_defvec=mcore_pe_be_vec + targ_selvecs="mcore_pe_be_vec mcore_pe_le_vec mcore_pei_be_vec mcore_pei_le_vec" + ;; + + mep-*-elf) + targ_defvec=mep_elf32_vec + targ_selvecs=mep_elf32_le_vec + ;; + + metag-*-*) + targ_defvec=metag_elf32_vec + targ_underscore=yes + ;; + + microblazeel*-*) + targ_defvec=microblaze_elf32_le_vec + targ_selvecs=microblaze_elf32_vec + ;; + + microblaze*-*) + targ_defvec=microblaze_elf32_vec + targ_selvecs=microblaze_elf32_le_vec + ;; + +#ifdef BFD64 + mips*el-*-netbsd*) + targ_defvec=mips_elf32_trad_le_vec + targ_selvecs="mips_elf32_trad_be_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec mips_ecoff_le_vec mips_ecoff_be_vec" + ;; + mips*-*-netbsd*) + targ_defvec=mips_elf32_trad_be_vec + targ_selvecs="mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec mips_ecoff_be_vec mips_ecoff_le_vec" + ;; + mips*-*-irix6*) + targ_defvec=mips_elf32_n_be_vec + targ_selvecs="mips_elf32_n_le_vec mips_elf32_be_vec mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" + ;; + mips64*-ps2-elf*) + targ_defvec=mips_elf32_n_le_vec + targ_selvecs="mips_elf32_n_le_vec mips_elf32_n_be_vec mips_elf32_be_vec mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" + ;; + mips*-ps2-elf*) + targ_defvec=mips_elf32_le_vec + targ_selvecs="mips_elf32_be_vec mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" + ;; + mips*-*-irix5*) + targ_defvec=mips_elf32_be_vec + targ_selvecs="mips_elf32_le_vec mips_ecoff_be_vec mips_ecoff_le_vec" + ;; + mips*el-*-vxworks*) + targ_defvec=mips_elf32_vxworks_le_vec + targ_selvecs="mips_elf32_le_vec mips_elf32_vxworks_be_vec mips_elf32_be_vec mips_elf64_be_vec mips_elf64_le_vec" + ;; + mips*-*-vxworks*) + targ_defvec=mips_elf32_vxworks_be_vec + targ_selvecs="mips_elf32_be_vec mips_elf32_vxworks_le_vec mips_elf32_be_vec mips_elf64_be_vec mips_elf64_le_vec" + ;; + mips*el-sde-elf*) + targ_defvec=mips_elf32_trad_le_vec + targ_selvecs="mips_elf32_trad_be_vec mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec" + ;; + mips*-sde-elf* | mips*-mti-elf* | mips*-img-elf*) + targ_defvec=mips_elf32_trad_be_vec + targ_selvecs="mips_elf32_trad_le_vec mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec" + ;; + mips*el-*-elf* | mips*-*-chorus*) + targ_defvec=mips_elf32_le_vec + targ_selvecs="mips_elf32_be_vec mips_elf64_be_vec mips_elf64_le_vec" + ;; + mips*-*-elf* | mips*-*-rtems* | mips*-*-windiss | mips*-*-none) + targ_defvec=mips_elf32_be_vec + targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec" + ;; + mips64*-*-openbsd*) + targ_defvec=mips_elf64_trad_be_vec + targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec" + ;; + mips*el-*-openbsd*) + targ_defvec=mips_elf32_le_vec + targ_selvecs="mips_elf32_be_vec mips_elf64_be_vec mips_elf64_le_vec mips_ecoff_le_vec mips_ecoff_be_vec" + ;; + mips*-*-openbsd*) + targ_defvec=mips_elf32_be_vec + targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec mips_ecoff_be_vec mips_ecoff_le_vec" + ;; + mips64*el-*-linux*) + targ_defvec=mips_elf32_ntrad_le_vec + targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec mips_elf64_trad_be_vec" + ;; + mips64*-*-linux*) + targ_defvec=mips_elf32_ntrad_be_vec + targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec" + ;; + mips*el-*-linux*) + targ_defvec=mips_elf32_trad_le_vec + targ_selvecs="mips_elf32_trad_be_vec mips_ecoff_le_vec mips_ecoff_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_le_vec mips_elf32_ntrad_be_vec mips_elf64_trad_be_vec" + ;; + mips*-*-linux*) + targ_defvec=mips_elf32_trad_be_vec + targ_selvecs="mips_elf32_trad_le_vec mips_ecoff_be_vec mips_ecoff_le_vec mips_elf32_ntrad_be_vec mips_elf64_trad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_le_vec" + ;; + mips64*el-*-freebsd* | mips64*el-*-kfreebsd*-gnu) + # FreeBSD vectors + targ_defvec=mips_elf32_ntradfbsd_le_vec + targ_selvecs="mips_elf32_ntradfbsd_be_vec mips_elf32_tradfbsd_le_vec mips_elf32_tradfbsd_be_vec mips_elf64_tradfbsd_le_vec mips_elf64_tradfbsd_be_vec" + # Generic vectors + targ_selvecs="${targ_selvecs} mips_elf32_ntrad_le_vec mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec mips_elf64_trad_be_vec" + ;; + mips64*-*-freebsd* | mips64*-*-kfreebsd*-gnu) + # FreeBSD vectors + targ_defvec=mips_elf32_ntradfbsd_be_vec + targ_selvecs="mips_elf32_ntradfbsd_le_vec mips_elf32_tradfbsd_be_vec mips_elf32_tradfbsd_le_vec mips_elf64_tradfbsd_be_vec mips_elf64_tradfbsd_le_vec" + # Generic vectors + targ_selvecs="${targ_selvecs} mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec" + ;; + mips*el-*-freebsd* | mips*el-*-kfreebsd*-gnu) + # FreeBSD vectors + targ_defvec=mips_elf32_tradfbsd_le_vec + targ_selvecs="mips_elf32_tradfbsd_be_vec mips_elf32_ntradfbsd_le_vec mips_elf64_tradfbsd_le_vec mips_elf32_ntradfbsd_be_vec mips_elf64_tradfbsd_be_vec" + # Generic vectors + targ_selvecs="${targ_selvecs} mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_le_vec mips_elf32_ntrad_be_vec mips_elf64_trad_be_vec" + ;; + mips*-*-freebsd* | mips*-*-kfreebsd*-gnu) + # FreeBSD vectors + targ_defvec=mips_elf32_tradfbsd_be_vec + targ_selvecs="mips_elf32_tradfbsd_le_vec mips_elf32_ntradfbsd_be_vec mips_elf64_tradfbsd_be_vec mips_elf32_ntradfbsd_le_vec mips_elf64_tradfbsd_le_vec" + # Generic vectors + targ_selvecs="${targ_selvecs} mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf32_ntrad_be_vec mips_elf64_trad_be_vec mips_elf32_ntrad_le_vec mips_elf64_trad_le_vec" + ;; + mmix-*-*) + targ_defvec=mmix_elf64_vec + targ_selvecs=mmix_mmo_vec + want64=true + ;; +#endif + mn10200-*-*) + targ_defvec=mn10200_elf32_vec + targ_underscore=yes + ;; + + mn10300-*-*) + targ_defvec=mn10300_elf32_vec + targ_underscore=yes + ;; + + mt-*-elf) + targ_defvec=mt_elf32_vec + ;; + + msp430-*-*) + targ_defvec=msp430_elf32_vec + targ_selvecs=msp430_elf32_ti_vec + ;; + + nds32*le-*-linux*) + targ_defvec=nds32_elf32_linux_le_vec + targ_selvecs=nds32_elf32_linux_be_vec + ;; + + nds32*be-*-linux*) + targ_defvec=nds32_elf32_linux_be_vec + targ_selvecs=nds32_elf32_linux_le_vec + ;; + + nds32*le-*-*) + targ_defvec=nds32_elf32_le_vec + targ_selvecs=nds32_elf32_be_vec + ;; + + nds32*be-*-*) + targ_defvec=nds32_elf32_be_vec + targ_selvecs=nds32_elf32_le_vec + ;; + +#ifdef BFD64 + nfp-*-*) + targ_defvec=nfp_elf64_vec + ;; +#endif + + ns32k-pc532-mach* | ns32k-pc532-ux*) + targ_defvec=ns32k_aout_pc532mach_vec + targ_underscore=yes + ;; + ns32k-*-netbsd* | ns32k-*-lites* | ns32k-*-openbsd*) + targ_defvec=ns32k_aout_pc532nbsd_vec + targ_underscore=yes + ;; + + nios2eb-*-*) + targ_defvec=nios2_elf32_be_vec + targ_selvecs=nios2_elf32_le_vec + ;; + + nios2el-*-*) + targ_defvec=nios2_elf32_le_vec + targ_selvecs=nios2_elf32_be_vec + ;; + + nios2-*-*) + targ_defvec=nios2_elf32_le_vec + targ_selvecs=nios2_elf32_be_vec + ;; + + or1k-*-elf | or1k-*-linux* | or1k-*-rtems*) + targ_defvec=or1k_elf32_vec + ;; + + or1knd-*-elf | or1knd-*-linux* | or1knd-*-rtems*) + targ_defvec=or1k_elf32_vec + ;; + + pdp11-*-*) + targ_defvec=pdp11_aout_vec + targ_underscore=yes + ;; + + pj-*-*) + targ_defvec=pj_elf32_vec + targ_selvecs="pj_elf32_vec pj_elf32_le_vec" + ;; + + pjl-*-*) + targ_defvec=pj_elf32_le_vec + targ_selvecs="pj_elf32_le_vec pj_elf32_vec i386_elf32_vec iamcu_elf32_vec" + ;; + + powerpc-*-aix5.[01] | rs6000-*-aix5.[01]) + targ_defvec=rs6000_xcoff_vec + targ_selvecs="rs6000_xcoff64_aix_vec" + want64=true + ;; +#ifdef BFD64 + powerpc64-*-aix5.[01]) + targ_defvec=rs6000_xcoff64_aix_vec + targ_selvecs="rs6000_xcoff_vec" + want64=true + ;; +#endif + powerpc-*-aix[5-9]* | rs6000-*-aix[5-9]*) + targ_cflags=-DAIX_WEAK_SUPPORT + targ_defvec=rs6000_xcoff_vec + targ_selvecs="rs6000_xcoff64_aix_vec" + want64=true + ;; +#ifdef BFD64 + powerpc64-*-aix[5-9]*) + targ_cflags=-DAIX_WEAK_SUPPORT + targ_defvec=rs6000_xcoff64_aix_vec + targ_selvecs="rs6000_xcoff_vec" + want64=true + ;; +#endif + + powerpc-*-aix* | powerpc-*-beos* | rs6000-*-*) + targ_defvec=rs6000_xcoff_vec + targ64_selvecs=rs6000_xcoff64_vec + case "${targ}" in + *-*-aix4.[3456789]* | *-*-aix[56789]*) + want64=true;; + *) + targ_cflags=-DSMALL_ARCHIVE;; + esac + ;; +#ifdef BFD64 + powerpc64-*-aix*) + targ_defvec=rs6000_xcoff64_vec + targ_selvecs=rs6000_xcoff_vec + want64=true + ;; + powerpc64-*-freebsd*) + targ_defvec=powerpc_elf64_fbsd_vec + targ_selvecs="powerpc_elf64_vec powerpc_elf32_vec powerpc_elf32_fbsd_vec powerpc_elf32_le_vec rs6000_xcoff_vec rs6000_xcoff64_vec rs6000_xcoff64_aix_vec" + want64=true + ;; + powerpc64le-*-freebsd*) + targ_defvec=powerpc_elf64_fbsd_le_vec + targ_selvecs="powerpc_elf64_vec powerpc_elf32_vec powerpc_elf32_fbsd_vec powerpc_elf32_le_vec rs6000_xcoff_vec rs6000_xcoff64_vec rs6000_xcoff64_aix_vec" + want64=true + ;; + powerpc64-*-elf* | powerpc-*-elf64* | powerpc64-*-linux* | \ + powerpc64-*-*bsd*) + targ_defvec=powerpc_elf64_vec + targ_selvecs="powerpc_elf64_le_vec powerpc_elf32_vec powerpc_elf32_le_vec rs6000_xcoff_vec rs6000_xcoff64_vec rs6000_xcoff64_aix_vec" + want64=true + ;; + powerpc64le-*-elf* | powerpcle-*-elf64* | powerpc64le-*-linux* | \ + powerpc64le-*-*bsd*) + targ_defvec=powerpc_elf64_le_vec + targ_selvecs="powerpc_elf64_vec powerpc_elf32_le_vec powerpc_elf32_vec rs6000_xcoff_vec rs6000_xcoff64_vec rs6000_xcoff64_aix_vec" + want64=true + ;; +#endif + powerpc-*-*freebsd*) + targ_defvec=powerpc_elf32_fbsd_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_vec powerpc_elf32_le_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec powerpc_elf64_fbsd_vec" + ;; + powerpc-*-*bsd* | powerpc-*-elf* | powerpc-*-sysv4* | powerpc-*-eabi* | \ + powerpc-*-solaris2* | powerpc-*-linux-* | powerpc-*-rtems* | \ + powerpc-*-chorus*) + targ_defvec=powerpc_elf32_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_le_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec" + ;; + powerpc-*-kaos*) + targ_defvec=powerpc_elf32_vec + targ_selvecs="powerpc_elf32_le_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec" + ;; + powerpc-*-darwin* | powerpc-*-macos10* | powerpc-*-rhapsody*) + targ_defvec=mach_o_be_vec + targ_selvecs="mach_o_be_vec mach_o_le_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" + targ_archs="$targ_archs bfd_i386_arch" + ;; + powerpc-*-macos*) + targ_defvec=powerpc_xcoff_vec + ;; + powerpc-*-lynxos*) + targ_defvec=powerpc_elf32_vec + targ_selvecs="rs6000_xcoff_vec" + targ_cflags=-DSMALL_ARCHIVE + ;; + powerpc-*-nto*) + targ_defvec=powerpc_elf32_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_le_vec powerpc_boot_vec" + ;; + powerpc-*-vxworks* | powerpc-*-windiss*) + targ_defvec=powerpc_elf32_vxworks_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_vec powerpc_elf32_le_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec" + ;; + powerpcle-*-nto*) + targ_defvec=powerpc_elf32_le_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_vec powerpc_boot_vec" + ;; + powerpcle-*-elf* | powerpcle-*-sysv4* | powerpcle-*-eabi* | \ + powerpcle-*-solaris2* | powerpcle-*-linux-* | powerpcle-*-vxworks*) + targ_defvec=powerpc_elf32_le_vec + targ_selvecs="rs6000_xcoff_vec powerpc_elf32_vec powerpc_boot_vec" + targ64_selvecs="powerpc_elf64_vec powerpc_elf64_le_vec" + ;; + + pru-*-*) + targ_defvec=pru_elf32_vec + ;; + +#ifdef BFD64 + riscvbe-*-* | riscv32be*-*-*) + targ_defvec=riscv_elf32_be_vec + targ_selvecs="riscv_elf32_vec riscv_elf64_vec riscv_elf32_be_vec riscv_elf64_be_vec" + want64=true + ;; + riscv-*-* | riscv32*-*-*) + targ_defvec=riscv_elf32_vec + targ_selvecs="riscv_elf32_vec riscv_elf64_vec riscv_elf32_be_vec riscv_elf64_be_vec" + want64=true + ;; + riscv64be*-*-*) + targ_defvec=riscv_elf64_be_vec + targ_selvecs="riscv_elf32_vec riscv_elf64_vec riscv_elf32_be_vec riscv_elf64_be_vec" + want64=true + ;; + riscv64*-*-*) + targ_defvec=riscv_elf64_vec + targ_selvecs="riscv_elf32_vec riscv_elf64_vec riscv_elf32_be_vec riscv_elf64_be_vec" + want64=true + ;; +#endif + + rl78-*-elf) + targ_defvec=rl78_elf32_vec + targ_underscore=yes + ;; + + rx-*-elf) + targ_defvec=rx_elf32_le_vec + targ_selvecs="rx_elf32_be_vec rx_elf32_le_vec rx_elf32_be_ns_vec" + targ_underscore=yes + ;; + rx-*-linux*) + targ_defvec=rx_elf32_linux_le_vec + targ_selvecs="rx_elf32_linux_le_vec" + ;; + + s390-*-linux*) + targ_defvec=s390_elf32_vec + targ64_selvecs=s390_elf64_vec + want64=true + ;; +#ifdef BFD64 + s390x-*-linux*) + targ_defvec=s390_elf64_vec + targ_selvecs=s390_elf32_vec + want64=true + ;; + s390x-*-tpf*) + targ_defvec=s390_elf64_vec + want64=true + ;; + + score*-*-elf*) + targ_defvec=score_elf32_be_vec + targ_selvecs=score_elf32_le_vec + ;; +#endif /* BFD64 */ + + sh*eb-*-linux*) + targ_defvec=sh_elf32_linux_be_vec + targ_selvecs=sh_elf32_linux_vec + targ_selvecs="${targ_selvecs} sh_elf32_fdpic_le_vec sh_elf32_fdpic_be_vec" + ;; + sh*-*-linux*) + targ_defvec=sh_elf32_linux_vec + targ_selvecs=sh_elf32_linux_be_vec + targ_selvecs="${targ_selvecs} sh_elf32_fdpic_le_vec sh_elf32_fdpic_be_vec" + ;; + + sh-*-uclinux* | sh[12]-*-uclinux*) + targ_defvec=sh_elf32_vec + targ_selvecs="sh_elf32_le_vec sh_elf32_linux_be_vec sh_elf32_linux_vec sh_elf32_fdpic_le_vec sh_elf32_fdpic_be_vec" + ;; + + sh*l*-*-netbsdelf*) + targ_defvec=sh_elf32_nbsd_le_vec + targ_selvecs="sh_elf32_nbsd_vec sh_coff_vec sh_coff_le_vec" + ;; + sh*-*-netbsdelf*) + targ_defvec=sh_elf32_nbsd_vec + targ_selvecs="sh_elf32_nbsd_le_vec sh_coff_vec sh_coff_le_vec" + ;; + + shl*-*-elf* | sh[1234]l*-*-elf* | sh3el*-*-elf* | shl*-*-kaos*) + targ_defvec=sh_elf32_le_vec + targ_selvecs="sh_elf32_vec sh_coff_le_vec sh_coff_vec sh_coff_small_le_vec sh_coff_small_vec" + targ_underscore=yes + ;; + + sh-*-elf* | sh[1234]*-elf* | sh-*-rtems* | sh-*-kaos*) + targ_defvec=sh_elf32_vec + targ_selvecs="sh_elf32_le_vec sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec" + targ_underscore=yes + ;; + + sh-*-nto*) + targ_defvec=sh_elf32_vec + targ_selvecs="sh_elf32_le_vec sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec" + targ_underscore=yes + ;; + sh*-*-openbsd*) + targ_defvec=sh_elf32_nbsd_le_vec + targ_selvecs="sh_elf32_nbsd_vec sh_coff_vec sh_coff_le_vec" + ;; + sh-*-pe) + targ_defvec=sh_pe_le_vec + targ_selvecs="sh_pe_le_vec sh_pei_le_vec" + targ_underscore=yes + ;; + sh-*-vxworks) + targ_defvec=sh_elf32_vxworks_vec + targ_selvecs="sh_elf32_vxworks_le_vec" + # FIXME None of the following are actually used on this target, but + # they're necessary for coff-sh.c (which is unconditionally used) to be + # compiled correctly. + targ_selvecs="$targ_selvecs sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec" + targ_underscore=yes + ;; + sh-*-*) + targ_defvec=sh_coff_vec + targ_selvecs="sh_coff_vec sh_coff_le_vec sh_coff_small_vec sh_coff_small_le_vec" + targ_underscore=yes + ;; + + sparc-*-solaris2.[0-6] | sparc-*-solaris2.[0-6].*) + targ_defvec=sparc_elf32_sol2_vec + targ_selvecs=sparc_elf32_vec + ;; +#ifdef BFD64 + sparc-*-solaris2* | sparcv9-*-solaris2* | sparc64-*-solaris2*) + targ_defvec=sparc_elf32_sol2_vec + targ_selvecs="sparc_elf64_sol2_vec sparc_elf32_vec sparc_elf64_vec" + want64=true + ;; + sparc64-*-freebsd* | sparc64-*-kfreebsd*-gnu) + targ_defvec=sparc_elf64_fbsd_vec + targ_selvecs="sparc_elf64_vec sparc_elf32_vec" + ;; + sparc64*-*-*) + targ_defvec=sparc_elf64_vec + targ_selvecs="sparc_elf32_vec" + want64=true + ;; +#endif + sparc-*-linux-* | sparcv*-*-linux-*) + targ_defvec=sparc_elf32_vec + targ_selvecs="sparc_elf64_vec" + ;; + sparc-*-vxworks*) + targ_defvec=sparc_elf32_vxworks_vec + targ_selvecs="sparc_elf32_vec" + ;; + sparc*-*-*) + targ_defvec=sparc_elf32_vec + ;; + + spu-*-elf) + targ_defvec=spu_elf32_vec + want64=true + ;; + + tic6x-*-elf) + targ_defvec=tic6x_elf32_c6000_le_vec + targ_selvecs="tic6x_elf32_c6000_be_vec tic6x_elf32_le_vec tic6x_elf32_be_vec" + ;; + + tic6x-*-uclinux) + targ_defvec=tic6x_elf32_linux_le_vec + targ_selvecs="tic6x_elf32_linux_be_vec tic6x_elf32_le_vec tic6x_elf32_be_vec" + ;; + +#ifdef BFD64 + tilegx-*-*) + targ_defvec=tilegx_elf64_le_vec + targ_selvecs="tilegx_elf64_be_vec tilegx_elf32_be_vec tilegx_elf32_le_vec" + ;; + tilegxbe-*-*) + targ_defvec=tilegx_elf64_be_vec + targ_selvecs="tilegx_elf64_le_vec tilegx_elf32_be_vec tilegx_elf32_le_vec" + ;; +#endif + + tilepro-*-*) + targ_defvec=tilepro_elf32_vec + ;; + + ft32*-*-*) + targ_defvec=ft32_elf32_vec + ;; + + v850*-*-*) + targ_defvec=v850_elf32_vec + targ_selvecs="v800_elf32_vec" + targ_underscore=yes + ;; + + vax-*-netbsdelf*) + targ_defvec=vax_elf32_vec + targ_selvecs="vax_aout_nbsd_vec vax_aout_1knbsd_vec" + ;; + + vax-*-netbsdaout* | vax-*-netbsd*) + targ_defvec=vax_aout_nbsd_vec + targ_selvecs="vax_elf32_vec vax_aout_1knbsd_vec" + targ_underscore=yes + ;; + + vax-*-openbsd*) + targ_defvec=vax_aout_nbsd_vec + targ_underscore=yes + ;; + + vax-*-linux-*) + targ_defvec=vax_elf32_vec + ;; + + visium-*-elf) + targ_defvec=visium_elf32_vec + ;; + + wasm32-*-*) + targ_defvec=wasm32_elf32_vec + targ_selvecs="wasm_vec" + ;; + + xc16x-*-elf) + targ_defvec=xc16x_elf32_vec + ;; + + xgate-*-*) + targ_defvec=xgate_elf32_vec + targ_selvecs="xgate_elf32_vec" + ;; + + xstormy16-*-elf) + targ_defvec=xstormy16_elf32_vec + ;; + + xtensa*-*-*) + targ_defvec=xtensa_elf32_le_vec + targ_selvecs=xtensa_elf32_be_vec + ;; + + z80-*-coff) + targ_defvec=z80_coff_vec + targ_underscore=no + ;; + + z80-*-elf) + targ_defvec=z80_elf32_vec + targ_underscore=no + ;; + + z8k*-*-*) + targ_defvec=z8k_coff_vec + targ_underscore=yes + ;; + +# END OF targmatch.h + bpf-*-*) + echo "*** Configuration $targ is not fully supported." >&2 + echo "*** Use bpf or bpf-*-none as the target instead." >&2 + exit 1 + ;; + + *) + echo 1>&2 "*** BFD does not support target ${targ}." + echo 1>&2 "*** Look in bfd/config.bfd for supported targets." + exit 1 + ;; +esac + +# All MIPS ELF targets need a 64-bit bfd_vma. +case "${targ_defvec} ${targ_selvecs}" in + *mips_elf*) + want64=true + ;; +esac + +case "${host64}${want64}" in + *true*) + targ_selvecs="${targ_selvecs} ${targ64_selvecs}" + ;; +esac + +# If we support any ELF target, then automatically add support for the +# generic ELF targets. This permits an objdump with some ELF support +# to be used on an arbitrary ELF file for anything other than +# relocation information. +case "${targ_defvec} ${targ_selvecs}" in + *elf64* | *mips_elf32_n*) + targ_selvecs="${targ_selvecs} elf64_le_vec elf64_be_vec elf32_le_vec elf32_be_vec" + ;; + *elf32*) + targ_selvecs="${targ_selvecs} elf32_le_vec elf32_be_vec" + ;; +esac + +# If we support Intel MCU target, then add support for bfd_iamcu_arch. +case "${targ_defvec} ${targ_selvecs}" in + *iamcu_elf32*) + targ_archs="$targ_archs bfd_iamcu_arch" + ;; +esac + +# If we support Intel L1OM target, then add support for bfd_l1om_arch. +case "${targ_defvec} ${targ_selvecs}" in + *l1om_elf64*) + targ_archs="$targ_archs bfd_l1om_arch" + ;; +esac + +# If we support Intel K1OM target, then add support for bfd_k1om_arch. +case "${targ_defvec} ${targ_selvecs}" in + *k1om_elf64*) + targ_archs="$targ_archs bfd_k1om_arch" + ;; +esac diff --git a/ports/gcc/changes/binutils_config.sub b/ports/gcc/changes/binutils_config.sub new file mode 100755 index 0000000..e0b6363 --- /dev/null +++ b/ports/gcc/changes/binutils_config.sub @@ -0,0 +1,1855 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2021 Free Software Foundation, Inc. + +timestamp='2021-01-07' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=$(echo "$0" | sed -e 's,.*/,,') + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2021 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Split fields of configuration type +# shellcheck disable=SC2162 +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines +case $basic_machine in + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + basic_os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + basic_os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + basic_os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv32 + ;; + i*86v4*) + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv4 + ;; + i*86v) + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv + ;; + i*86sol2) + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $basic_os in + irix*) + ;; + *) + basic_os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) + ;; + ns2*) + basic_os=nextstep2 + ;; + *) + basic_os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + basic_os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=$(echo "$basic_machine" | sed 's/-.*//') + ;; + + *-*) + # shellcheck disable=SC2162 + IFS="-" read cpu vendor <&2 + exit 1 + ;; + esac + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $vendor in + digital*) + vendor=dec + ;; + commodore*) + vendor=cbm + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if test x$basic_os != x +then + +# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|') + ;; + os2-emx) + kernel=os2 + os=$(echo $basic_os | sed -e 's|os2-emx|emx|') + ;; + nto-qnx*) + kernel=nto + os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|') + ;; + *-*) + # shellcheck disable=SC2162 + IFS="-" read kernel os <&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) + vendor=acorn + ;; + *-sunos*) + vendor=sun + ;; + *-cnk* | *-aix*) + vendor=ibm + ;; + *-beos*) + vendor=be + ;; + *-hpux*) + vendor=hp + ;; + *-mpeix*) + vendor=hp + ;; + *-hiux*) + vendor=hitachi + ;; + *-unos*) + vendor=crds + ;; + *-dgux*) + vendor=dg + ;; + *-luna*) + vendor=omron + ;; + *-genix*) + vendor=ns + ;; + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) + vendor=ibm + ;; + s390-* | s390x-*) + vendor=ibm + ;; + *-ptx*) + vendor=sequent + ;; + *-tpf*) + vendor=ibm + ;; + *-vxsim* | *-vxworks* | *-windiss*) + vendor=wrs + ;; + *-aux*) + vendor=apple + ;; + *-hms*) + vendor=hitachi + ;; + *-mpw* | *-macos*) + vendor=apple + ;; + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) + vendor=atari + ;; + *-vos*) + vendor=stratus + ;; + esac + ;; +esac + +echo "$cpu-$vendor-${kernel:+$kernel-}$os" +exit + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/ports/gcc/changes/binutils_gas_configure.tgt b/ports/gcc/changes/binutils_gas_configure.tgt new file mode 100644 index 0000000..ee94eca --- /dev/null +++ b/ports/gcc/changes/binutils_gas_configure.tgt @@ -0,0 +1,460 @@ +# gas target specific configuration file. This is a -*- sh -*- file. +# +# Copyright (C) 2012-2021 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING3. If not see +# . +# + +# This is invoked by configure. Putting it in a separate shell file +# lets us skip running autoconf when modifying target specific +# information. + +# Input shell variables: +# targ a configuration target name, such as i686-pc-linux-gnu. + +# Output shell variables: +# cpu_type canonical gas cpu type; identifies the config/tc-* files +# fmt output format; identifies the config/obj-* files +# em emulation; identifies the config/te-* files + +# Optional output shell variables; these are not always set: +# arch the default architecture; sets DEFAULT_ARCH on some systems +# endian "big" or "little"; used on bi-endian systems + +cpu_type= +fmt= +em=generic +bfd_gas=no +arch= +endian= + +eval `echo $targ | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/cpu=\1 vendor=\2 os=\3/'` + +# Check for architecture variants. Set cpu_type and, optionally, +# endian and arch. +# Note: This table is alpha-sorted, please try to keep it that way. +case ${cpu} in + aarch64) cpu_type=aarch64 endian=little arch=aarch64;; + aarch64_be) cpu_type=aarch64 endian=big arch=aarch64;; + alpha*) cpu_type=alpha ;; + am33_2.0) cpu_type=mn10300 endian=little ;; + arc*eb) cpu_type=arc endian=big ;; + arm*be|arm*b) cpu_type=arm endian=big ;; + arm*) cpu_type=arm endian=little ;; + bfin*) cpu_type=bfin endian=little ;; + c4x*) cpu_type=tic4x ;; + cr16*) cpu_type=cr16 endian=little ;; + crisv32) cpu_type=cris arch=crisv32 ;; + crx*) cpu_type=crx endian=little ;; + epiphany*) cpu_type=epiphany endian=little ;; + fido) cpu_type=m68k ;; + hppa*) cpu_type=hppa ;; + i[3-7]86) cpu_type=i386 arch=i386;; + ia16) cpu_type=i386 arch=i386;; + ia64) cpu_type=ia64 ;; + ip2k) cpu_type=ip2k endian=big ;; + iq2000) cpu_type=iq2000 endian=big ;; + lm32) cpu_type=lm32 ;; + m32c) cpu_type=m32c endian=little ;; + m32r) cpu_type=m32r endian=big ;; + m32rle) cpu_type=m32r endian=little ;; + m5200) cpu_type=m68k ;; + m68008) cpu_type=m68k ;; + m680[012346]0) cpu_type=m68k ;; + m6811|m6812|m68hc12) cpu_type=m68hc11 ;; + m683??) cpu_type=m68k ;; + s12z) cpu_type=s12z ;; + mep) cpu_type=mep endian=little ;; + microblazeel*) cpu_type=microblaze endian=little;; + microblaze*) cpu_type=microblaze endian=big;; + mips*el) cpu_type=mips endian=little ;; + mips*) cpu_type=mips endian=big ;; + mt) cpu_type=mt endian=big ;; + nds32be) cpu_type=nds32 endian=big ;; + nds32le) cpu_type=nds32 endian=little ;; + or1k* | or1knd*) cpu_type=or1k endian=big ;; + pjl*) cpu_type=pj endian=little ;; + pj*) cpu_type=pj endian=big ;; + powerpc*le*) cpu_type=ppc endian=little ;; + powerpc*) cpu_type=ppc endian=big ;; + riscv64be*) cpu_type=riscv endian=big arch=riscv64 ;; + riscv64*) cpu_type=riscv endian=little arch=riscv64 ;; + riscv32be*|riscvbe*) cpu_type=riscv endian=big arch=riscv32 ;; + riscv32* | riscv*) cpu_type=riscv endian=little arch=riscv32 ;; + rs6000*) cpu_type=ppc ;; + rl78*) cpu_type=rl78 ;; + rx) cpu_type=rx ;; + s390x*) cpu_type=s390 arch=s390x ;; + s390*) cpu_type=s390 arch=s390 ;; + score*l) cpu_type=score endian=little ;; + score*) cpu_type=score endian=big ;; + sh*le) cpu_type=sh endian=little ;; + sh*) cpu_type=sh endian=big ;; + sparc64* | sparcv9*) cpu_type=sparc arch=v9-64 ;; + sparc86x*) cpu_type=sparc arch=sparc86x ;; + sparclet*) cpu_type=sparc arch=sparclet ;; + sparclite*) cpu_type=sparc arch=sparclite ;; + sparc*) cpu_type=sparc arch=sparclite ;; # ??? See tc-sparc.c. + tilegx*be) cpu_type=tilegx endian=big ;; + tilegx*) cpu_type=tilegx endian=little ;; + v850*) cpu_type=v850 ;; + visium) cpu_type=visium endian=big ;; + wasm32) cpu_type=wasm32 endian=little ;; + x86_64*) cpu_type=i386 arch=x86_64;; + xgate) cpu_type=xgate ;; + xtensa*) cpu_type=xtensa arch=xtensa ;; + *) cpu_type=${cpu} ;; +esac + + +# Assign object format. Set fmt, em, and bfd_gas. +generic_target=${cpu_type}-$vendor-$os +# Note: This table is alpha-sorted, please try to keep it that way. +case ${generic_target} in + aarch64*-*-elf*) fmt=elf;; + aarch64*-*-fuchsia*) fmt=elf;; + aarch64*-*-linux*) fmt=elf em=linux + case ${cpu}-${os} in + aarch64*-linux-gnu_ilp32) arch=aarch64:32 ;; + esac ;; + aarch64*-*-netbsd*) fmt=elf em=nbsd;; + + alpha-*-*vms*) fmt=evax ;; + alpha-*-osf*) fmt=ecoff ;; + alpha-*-linux*ecoff*) fmt=ecoff ;; + alpha-*-linux-*) fmt=elf em=linux ;; + alpha-*-netbsd* | alpha-*-openbsd*) fmt=elf em=nbsd ;; + + arc-*-elf*) fmt=elf ;; + arc*-*-linux*) fmt=elf bfd_gas=yes ;; + + arm-*-phoenix*) fmt=elf ;; + arm-*-elf) fmt=elf ;; + arm-*-eabi* | arm-*-rtems*) fmt=elf em=armeabi ;; + arm-*-symbianelf*) fmt=elf em=symbian ;; + arm-*-kaos*) fmt=elf ;; + arm-*-conix*) fmt=elf ;; + arm-*-freebsd[89].* | armeb-*-freebsd[89].*) + fmt=elf em=freebsd ;; + arm-*-freebsd* | armeb-*-freebsd*) fmt=elf em=armfbsdeabi ;; + arm*-*-freebsd*) fmt=elf em=armfbsdvfp ;; + arm-*-linux-*eabi*) fmt=elf em=armlinuxeabi ;; + arm-*-linux-*) fmt=elf em=linux ;; + arm-*-uclinux*eabi*) fmt=elf em=armlinuxeabi ;; + arm-*-uclinux*) fmt=elf em=linux ;; + arm-*-nacl*) fmt=elf em=nacl ;; + arm-*-netbsdelf*) fmt=elf em=nbsd ;; + arm-*-nto*) fmt=elf ;; + arm-wince-pe | arm-*-wince | arm*-*-mingw32ce* | arm*-*-cegcc*) + fmt=coff em=wince-pe ;; + arm-*-pe) fmt=coff em=pe ;; + arm-*-fuchsia*) fmt=elf ;; + + avr-*-*) fmt=elf bfd_gas=yes ;; + + bfin-*-linux-uclibc) fmt=fdpicelf em=linux ;; + bfin-*-uclinux*) fmt=elf em=linux ;; + bfin-*elf) fmt=elf ;; + + cr16-*-elf*) fmt=elf ;; + + cris-*-linux-* | crisv32-*-linux-*) + fmt=multi em=linux ;; + cris-*-* | crisv32-*-*) fmt=multi ;; + + crx-*-elf*) fmt=elf ;; + + csky-*-elf*abiv1) fmt=elf em=csky_abiv1 ;; + csky-*-elf*) fmt=elf em=csky_abiv2 ;; + csky-*-linux*abiv1) fmt=elf em=csky_abiv1_linux ;; + csky-*-linux*) fmt=elf em=csky_abiv2_linux ;; + + d10v-*-*) fmt=elf ;; + d30v-*-*) fmt=elf ;; + dlx-*-*) fmt=elf ;; + + bpf-*-*) fmt=elf ;; + epiphany-*-*) fmt=elf ;; + + fr30-*-*) fmt=elf ;; + frv-*-*linux*) fmt=elf em=linux;; + frv-*-*) fmt=elf ;; + + ft32-*-*) fmt=elf ;; + + hppa-*-linux*) + case ${cpu} in + hppa*64*) fmt=elf em=hppalinux64 ;; + hppa*) fmt=elf em=linux ;; + esac ;; + hppa-*-*elf*) fmt=elf em=hppa ;; + hppa-*-lites*) fmt=elf em=hppa ;; + hppa-*-netbsd*) fmt=elf em=nbsd ;; + hppa-*-openbsd*) fmt=elf em=hppa ;; + hppa-*-osf*) fmt=som em=hppa ;; + hppa-*-hpux11*) + case ${cpu} in + hppa*64*) fmt=elf em=hppa64 ;; + hppa*) fmt=som em=hppa ;; + esac ;; + hppa-*-hpux*) fmt=som em=hppa ;; + hppa-*-mpeix*) fmt=som em=hppa ;; + hppa-*-bsd*) fmt=som em=hppa ;; + hppa-*-hiux*) fmt=som em=hppa ;; + + h8300-*-elf) fmt=elf ;; + h8300-*-linux*) fmt=elf em=linux ;; + + i386-*-beospe*) fmt=coff em=pe ;; + i386-*-beos*) fmt=elf ;; + i386-*-elfiamcu) fmt=elf arch=iamcu ;; + i386-*-elf*) fmt=elf ;; + i386-*-essence*) fmt=elf ;; + i386-*-fuchsia*) fmt=elf ;; + i386-*-bsd*) fmt=aout em=386bsd ;; + i386-*-netbsdpe*) fmt=coff em=pe ;; + i386-*-netbsd*-gnu* | \ + i386-*-knetbsd*-gnu | \ + i386-*-netbsd* | \ + i386-*-openbsd*) fmt=elf em=nbsd ;; + i386-*-linux-*) fmt=elf em=linux + case ${cpu}-${os} in + x86_64*-linux-gnux32) arch=x86_64:32 ;; + esac ;; + i386-*-lynxos*) fmt=elf em=lynx ;; + i386-*-redox*) fmt=elf ;; + i386-*-solaris*) fmt=elf em=solaris ;; + i386-*-freebsd* \ + | i386-*-kfreebsd*-gnu) fmt=elf em=freebsd ;; + i386-*-msdosdjgpp* \ + | i386-*-go32*) fmt=coff em=go32 ;; + i386-*-gnu*) fmt=elf em=gnu ;; + i386-*-msdos*) fmt=aout ;; + i386-*-moss*) fmt=elf ;; + i386-*-pe) fmt=coff em=pe ;; + i386-*-cygwin*) + case ${cpu} in + x86_64*) fmt=coff em=pep ;; + i*) fmt=coff em=pe ;; + esac ;; + i386-*-interix*) fmt=coff em=interix ;; + i386-*-mingw*) + case ${cpu} in + x86_64*) fmt=coff em=pep ;; + i*) fmt=coff em=pe ;; + esac ;; + i386-*-nto-qnx*) fmt=elf ;; + i386-*-*nt*) fmt=coff em=pe ;; + i386-*-rdos*) fmt=elf ;; + i386-*-darwin*) fmt=macho ;; + + ia16-*-elf*) fmt=elf ;; + + ia64-*-elf*) fmt=elf ;; + ia64-*-*vms*) fmt=elf em=vms ;; + ia64-*-aix*) fmt=elf em=ia64aix ;; + ia64-*-linux-*) fmt=elf em=linux ;; + ia64-*-hpux*) fmt=elf em=hpux ;; + ia64-*-netbsd*) fmt=elf em=nbsd ;; + + ip2k-*-*) fmt=elf ;; + + iq2000-*-elf) fmt=elf ;; + + lm32-*-*) fmt=elf ;; + + m32c-*-elf) fmt=elf ;; + + m32r-*-elf*) fmt=elf ;; + m32r-*-linux*) fmt=elf em=linux;; + + m68hc11-*-* | m6811-*-*) fmt=elf ;; + m68hc12-*-* | m6812-*-*) fmt=elf ;; + + m68k-*-elf*) fmt=elf ;; + m68k-*-sysv4*) fmt=elf em=svr4 ;; + m68k-*-linux-*) fmt=elf em=linux ;; + m68k-*-uclinux*) fmt=elf em=uclinux ;; + m68k-*-gnu*) fmt=elf ;; + m68k-*-netbsdelf*) fmt=elf em=nbsd ;; + + s12z-*-*) fmt=elf ;; + + mep-*-elf) fmt=elf ;; + + metag-*-elf) fmt=elf ;; + metag-*-linux*) fmt=elf em=linux ;; + + mcore-*-elf) fmt=elf ;; + mcore-*-pe) fmt=coff em=pe bfd_gas=yes ;; + + microblaze-*-*) fmt=elf ;; + + mips-*-irix6*) fmt=elf em=irix ;; + mips-*-irix5*) fmt=elf em=irix ;; + mips*-*-linux*) fmt=elf em=tmips ;; + mips*-*-freebsd* | mips*-*-kfreebsd*-gnu) + fmt=elf em=freebsd ;; + mips-*-sysv4* | mips-*-gnu*) fmt=elf em=tmips ;; + mips*-sde-elf* | mips*-mti-elf* | mips*-img-elf*) + fmt=elf em=tmips ;; + mips-*-elf*) fmt=elf ;; + mips-*-netbsd*) fmt=elf em=tmips ;; + mips-*-openbsd*) fmt=elf em=tmips ;; + mips-*-windiss) fmt=elf ;; + + mmix-*-*) fmt=elf ;; + + mn10200-*-*) fmt=elf ;; + + # cpu_type for am33_2.0 is set to mn10300 + mn10300-*-linux*) fmt=elf em=linux ;; + mn10300-*-*) fmt=elf ;; + + moxie-*-uclinux) fmt=elf em=linux ;; + moxie-*-moxiebox*) fmt=elf endian=little ;; + moxie-*-*) fmt=elf ;; + + mt-*-elf) fmt=elf bfd_gas=yes ;; + + msp430-*-*) fmt=elf ;; + + nds32-*-elf*) fmt=elf ;; + nds32-*-linux*) fmt=elf em=linux ;; + + nios2*-linux*) fmt=elf em=linux ;; + + ns32k-pc532-mach*) fmt=aout em=pc532mach ;; + ns32k-pc532-ux*) fmt=aout em=pc532mach ;; + ns32k-pc532-lites*) fmt=aout em=nbsd532 ;; + ns32k-*-*n*bsd*) fmt=aout em=nbsd532 ;; + + or1k*-*-elf | or1k*-*-rtems*) fmt=elf endian=big ;; + or1k*-*-linux*) fmt=elf em=linux endian=big ;; + + pj*) fmt=elf ;; + + ppc-*-aix5.[01]) fmt=coff em=aix5 ;; + ppc-*-aix[5-9].*) fmt=coff em=aix5 ;; + ppc-*-aix*) fmt=coff em=aix ;; + ppc-*-beos*) fmt=coff ;; + ppc-*-*n*bsd* | ppc-*-elf*) fmt=elf ;; + ppc-*-eabi* | ppc-*-sysv4*) fmt=elf ;; + ppc-*-linux-*) fmt=elf em=linux ;; + ppc-*-solaris*) fmt=elf em=solaris ;; + ppc-*-macos*) fmt=coff em=macos ;; + ppc-*-nto*) fmt=elf ;; + ppc-*-kaos*) fmt=elf ;; + + pru-*-*) fmt=elf ;; + + riscv*-*-*) fmt=elf ;; + + rx-*-linux*) fmt=elf em=linux ;; + + s390-*-linux-*) fmt=elf em=linux ;; + s390-*-tpf*) fmt=elf ;; + + score-*-elf) fmt=elf ;; + + sh*-*-linux*) fmt=elf em=linux + case ${cpu} in + sh*eb) endian=big ;; + *) endian=little ;; + esac ;; + sh*-*-netbsdelf*) fmt=elf em=nbsd + case ${cpu} in + sh*l*) endian=little ;; + *) endian=big ;; + esac ;; + sh-*-elf*) fmt=elf ;; + sh-*-uclinux* | sh[12]-*-uclinux*) fmt=elf em=uclinux ;; + sh-*-coff*) fmt=coff ;; + sh-*-nto*) fmt=elf ;; + sh-*-pe*) fmt=coff em=pe endian=little ;; + sh-*-kaos*) fmt=elf ;; + shle*-*-kaos*) fmt=elf ;; + + sparc-*-linux-*) fmt=elf em=linux ;; + sparc-*-solaris*) fmt=elf em=solaris ;; + sparc-*-freebsd*) fmt=elf em=freebsd ;; + sparc-*-*bsd*) fmt=elf em=nbsd ;; + + spu-*-elf) fmt=elf ;; + + tic30-*-*coff*) fmt=coff bfd_gas=yes ;; + tic4x-*-* | c4x-*-*) fmt=coff bfd_gas=yes ;; + tic54x-*-* | c54x*-*-*) fmt=coff bfd_gas=yes need_libm=yes;; + tic6x-*-*) fmt=elf ;; + + tilepro-*-* | tilegx*-*-*) fmt=elf ;; + + v850*-*-*) fmt=elf ;; + + vax-*-netbsdelf*) fmt=elf em=nbsd ;; + vax-*-linux-*) fmt=elf em=linux ;; + + visium-*-elf) fmt=elf ;; + + wasm32-*-*) fmt=elf ;; + + xstormy16-*-*) fmt=elf ;; + + xgate-*-*) fmt=elf ;; + + xtensa*-*-*) fmt=elf ;; + + z80-*-coff) fmt=coff ;; + + z8k-*-coff | z8k-*-sim) fmt=coff ;; + + *-*-aout | *-*-scout) fmt=aout ;; + *-*-cloudabi*) fmt=elf em=cloudabi ;; + *-*-dragonfly*) fmt=elf em=dragonfly ;; + *-*-freebsd* | *-*-kfreebsd*-gnu) fmt=elf em=freebsd ;; + *-*-generic) fmt=generic ;; + *-*-xray | *-*-hms) fmt=coff ;; + *-*-sim) fmt=coff ;; + *-*-elf | *-*-rtems* | *-*-sysv4*) fmt=elf ;; + *-*-solaris*) fmt=elf em=solaris ;; + *-*-aros*) fmt=elf em=linux ;; + *-*-vxworks* | *-*-windiss) fmt=elf em=vxworks ;; +esac + +case ${cpu_type} in + aarch64 | alpha | arm | csky | i386 | ia64 | microblaze | mips | ns32k | \ + or1k | or1knd | pdp11 | ppc | riscv | sh | sparc | z80 | z8k) + bfd_gas=yes + ;; +esac +case ${fmt} in + elf | ecoff | fdpicelf | multi | som) + bfd_gas=yes + ;; +esac + +if test $bfd_gas != yes; then + echo This target is no longer supported in gas + exit 1 +fi + +case ${cpu_type}-${fmt}-${os} in +i386-elf-linux*) + # Default to compress DWARF debug sections for Linux/x86. + if test ${ac_default_compressed_debug_sections} = unset; then + ac_default_compressed_debug_sections=yes + fi + ;; +esac diff --git a/ports/gcc/changes/binutils_ld_configure.tgt b/ports/gcc/changes/binutils_ld_configure.tgt new file mode 100644 index 0000000..8f34c80 --- /dev/null +++ b/ports/gcc/changes/binutils_ld_configure.tgt @@ -0,0 +1,1130 @@ +# configure.tgt +# +# Copyright (C) 2013-2021 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING3. If not see +# . + +# This is the linker target specific file. This is invoked by the +# autoconf generated configure script. Putting it in a separate shell +# file lets us skip running autoconf when modifying target specific +# information. + +# This file switches on the shell variable ${targ}, and sets the +# following shell variables: +# targ_emul name of linker emulation to use +# targ_extra_emuls additional linker emulations to provide +# targ_extra_libpath additional linker emulations using LIB_PATH +# targ_extra_ofiles additional host-compiled objects needed by the emulation +# targ64_extra_emuls additional linker emulations to provide if +# --enable-64-bit-bfd is given or if host is 64 bit. +# targ64_extra_libpath additional linker emulations using LIB_PATH if +# --enable-64-bit-bfd is given or if host is 64 bit. +# NATIVE_LIB_DIRS library directories to search on this host +# (if we are a native or sysrooted linker) + +targ_extra_emuls= +targ_extra_libpath= +targ_extra_ofiles="ldelf.o ldelfgen.o" +targ64_extra_emuls= +targ64_extra_libpath= + +# Please try to keep this table more or less in alphabetic order - it +# makes it much easier to lookup a specific archictecture. +case "${targ}" in +aarch64_be-*-elf) targ_emul=aarch64elfb + targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b armelfb armelf" + ;; +aarch64-*-elf | aarch64-*-rtems*) + targ_emul=aarch64elf + targ_extra_emuls="aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb" + ;; +aarch64-*-cloudabi*) targ_emul=aarch64cloudabi + targ_extra_emuls=aarch64cloudabib + ;; +aarch64-*-freebsd*) targ_emul=aarch64fbsd + targ_extra_emuls="aarch64fbsdb aarch64elf" + ;; +aarch64-*-fuchsia*) targ_emul=aarch64elf + targ_extra_emuls="aarch64elfb armelf armelfb" + ;; +aarch64_be-*-linux-gnu_ilp32) + targ_emul=aarch64linux32b + targ_extra_libpath="aarch64linuxb aarch64linux aarch64linux32 armelfb_linux_eabi armelf_linux_eabi" + targ_extra_emuls="aarch64elfb aarch64elf aarch64elf32 aarch64elf32b armelfb armelf $targ_extra_libpath" + ;; +aarch64-*-linux-gnu_ilp32) + targ_emul=aarch64linux32 + targ_extra_libpath="aarch64linux aarch64linuxb aarch64linux32b armelfb_linux_eabi armelf_linux_eabi" + targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb $targ_extra_libpath" + ;; +aarch64_be-*-linux*) targ_emul=aarch64linuxb + targ_extra_libpath="aarch64linux aarch64linux32 aarch64linux32b armelfb_linux_eabi armelf_linux_eabi" + targ_extra_emuls="aarch64elfb aarch64elf aarch64elf32 aarch64elf32b armelfb armelf $targ_extra_libpath" + ;; +aarch64-*-linux*) targ_emul=aarch64linux + targ_extra_libpath="aarch64linuxb aarch64linux32 aarch64linux32b armelfb_linux_eabi armelf_linux_eabi" + targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb $targ_extra_libpath" + ;; +alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) + targ_emul=elf64alpha_fbsd + targ_extra_emuls="elf64alpha alpha" + tdir_alpha=`echo ${targ_alias} | sed -e 's/freebsd/freebsdecoff/'` + ;; +alpha*-*-linux*ecoff*) targ_emul=alpha + targ_extra_emuls=elf64alpha + tdir_elf64alpha=`echo ${targ_alias} | sed -e 's/ecoff//'` + ;; +alpha*-*-linux-*) targ_emul=elf64alpha + targ_extra_emuls=alpha + tdir_alpha=`echo ${targ_alias} | sed -e 's/linux\(-gnu\)*/linux\1ecoff/'` + ;; +alpha*-*-osf*) targ_emul=alpha + targ_extra_ofiles= + ;; +alpha*-*-gnu*) targ_emul=elf64alpha + ;; +alpha*-*-netbsd*) targ_emul=elf64alpha_nbsd + ;; +alpha*-*-openbsd*) targ_emul=elf64alpha + ;; +alpha*-*-*vms*) targ_emul=alphavms + targ_extra_ofiles= + ;; +am33_2.0-*-linux*) targ_emul=elf32am33lin # mn10300 variant + ;; +arc*-*-elf*) targ_emul=arcelf + targ_extra_emuls="arclinux arclinux_nps arcv2elf arcv2elfx" + ;; +arc*-*-linux*) case "${with_cpu}" in + nps400) targ_emul=arclinux_nps + targ_extra_emuls=arclinux + ;; + *) targ_emul=arclinux + targ_extra_emuls=arclinux_nps + ;; + esac + targ_extra_emuls="${targ_extra_emuls} arcelf arcv2elf arcv2elfx" + ;; +arm*-*-cegcc*) targ_emul=arm_wince_pe + targ_extra_ofiles="deffilep.o pe-dll.o" + LIB_PATH='${tooldir}/lib/w32api' + ;; +arm-wince-pe | arm-*-wince | arm*-*-mingw32ce*) + targ_emul=arm_wince_pe + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +arm-*-pe) targ_emul=armpe + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +arm*b-*-freebsd*) targ_emul=armelfb_fbsd + targ_extra_emuls="armelf_fbsd armelf" + ;; +arm*-*-freebsd* | arm-*-kfreebsd*-gnu) + targ_emul=armelf_fbsd + targ_extra_emuls="armelfb_fbsd armelf" + ;; +armeb-*-netbsdelf*) targ_emul=armelfb_nbsd; + targ_extra_emuls="armelf_nbsd armelf" + ;; +arm-*-netbsdelf*) targ_emul=armelf_nbsd; + targ_extra_emuls="armelfb_nbsd armelf" + ;; +arm-*-nto*) targ_emul=armnto + ;; +arm-*-phoenix*) targ_emul=armelf + ;; +armeb-*-elf | armeb-*-eabi*) + targ_emul=armelfb + ;; +arm-*-elf | arm*-*-eabi* | arm-*-rtems*) + targ_emul=armelf + ;; +arm*-*-symbianelf*) targ_emul=armsymbian;; +arm-*-kaos*) targ_emul=armelf + ;; +arm9e-*-elf) targ_emul=armelf + ;; +arm*b-*-linux-*eabi*) targ_emul=armelfb_linux_eabi + targ_extra_emuls=armelf_linux_eabi + targ_extra_libpath=$targ_extra_emuls + ;; +arm*b-*-linux-*) targ_emul=armelfb_linux + targ_extra_emuls="armelfb armelf armelf_linux" + targ_extra_libpath="armelf_linux" + ;; +arm*-*-linux-*eabi*) targ_emul=armelf_linux_eabi + targ_extra_emuls="armelfb_linux_eabi" + targ_extra_libpath=$targ_extra_emuls + ;; +arm*-*-uclinuxfdpiceabi) + targ_emul=armelf_linux_eabi + targ_extra_emuls="armelfb_linux_eabi armelf_linux_fdpiceabi armelfb_linux_fdpiceabi" + targ_extra_libpath=$targ_extra_emuls + ;; +arm*-*-linux-*) targ_emul=armelf_linux + targ_extra_emuls="armelf armelfb armelfb_linux" + targ_extra_libpath="armelfb_linux" + ;; +arm*b-*-nacl*) targ_emul=armelfb_nacl + targ_extra_emuls="armelf_nacl" + targ_extra_libpath=$targ_extra_emuls + ;; +arm*-*-nacl*) targ_emul=armelf_nacl + targ_extra_emuls="armelfb_nacl" + targ_extra_libpath=$targ_extra_emuls + ;; +arm*-*-uclinux*eabi*) targ_emul=armelf_linux_eabi + targ_extra_emuls=armelfb_linux_eabi + targ_extra_libpath=$targ_extra_emuls + ;; +arm*-*-uclinux*) targ_emul=armelf_linux + targ_extra_emuls="armelf armelfb armelfb_linux" + targ_extra_libpath="armelfb_linux" + ;; +arm-*-vxworks) targ_emul=armelf_vxworks + ;; +arm*-*-conix*) targ_emul=armelf + ;; +arm*-*-fuchsia*) targ_emul=armelf_fuchsia + targ_extra_emuls="armelfb_fuchsia armelf armelfb" + ;; +avr-*-*) targ_emul=avr2 + targ_extra_emuls="avr1 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega1 avrxmega2 avrxmega3 avrxmega4 avrxmega5 avrxmega6 avrxmega7 avrtiny" + ;; +bfin-*-elf | bfin-*-rtems*) + targ_emul=elf32bfin + targ_extra_emuls="elf32bfinfd" + targ_extra_libpath=$targ_extra_emuls + ;; +bfin-*-uclinux*) targ_emul=elf32bfin; + targ_extra_emuls="elf32bfinfd" + targ_extra_libpath=$targ_extra_emuls + ;; +bfin-*-linux-uclibc*) targ_emul=elf32bfinfd; + targ_extra_emuls="elf32bfin" + targ_extra_libpath=$targ_extra_emuls + ;; +bpf-*-*) targ_emul=elf64bpf + ;; +cr16-*-elf*) targ_emul=elf32cr16 + ;; +cris-*-*aout*) targ_emul=crisaout + targ_extra_emuls="criself crislinux" + targ_extra_libpath=$targ_extra_emuls + ;; +cris-*-linux-* | crisv32-*-linux-*) + targ_emul=crislinux + ;; +cris-*-* | crisv32-*-*) targ_emul=criself + targ_extra_emuls="crisaout crislinux" + targ_extra_libpath=$targ_extra_emuls + ;; +crx-*-elf*) targ_emul=elf32crx + ;; + +csky-*-elf*) targ_emul=cskyelf + ;; +csky-*-linux*) targ_emul=cskyelf_linux + ;; + +d10v-*-*) targ_emul=d10velf + ;; +d30v-*-*ext*) targ_emul=d30v_e + targ_extra_emuls="d30velf d30v_o" + targ_extra_ofiles=ldelfgen.o + ;; +d30v-*-*onchip*) targ_emul=d30v_o + targ_extra_emuls="d30velf d30v_e" + targ_extra_ofiles=ldelfgen.o + ;; +d30v-*-*) targ_emul=d30velf + targ_extra_emuls="d30v_e d30v_o" + targ_extra_ofiles=ldelfgen.o + ;; +dlx-*-elf*) targ_emul=elf32_dlx + targ_extra_ofiles=ldelfgen.o + ;; +epiphany-*-*) targ_emul=elf32epiphany + targ_extra_emuls="elf32epiphany_4x4" + ;; +fido*-*-elf*) targ_emul=m68kelf + ;; +fr30-*-*) targ_emul=elf32fr30 + targ_extra_ofiles=ldelfgen.o + ;; +frv-*-*linux*) targ_emul=elf32frvfd + ;; +frv-*-*) targ_emul=elf32frv + targ_extra_emuls="elf32frvfd" + ;; +ft32-*-*) targ_emul=elf32ft32 + targ_extra_ofiles=ldelfgen.o + ;; +h8300-*-elf* | h8300-*-rtems*) + targ_emul=h8300elf; + targ_extra_emuls="h8300helf h8300self h8300hnelf h8300snelf h8300sxelf h8300sxnelf" + ;; +h8300-*-linux*) + targ_emul=h8300elf_linux; + targ_extra_emuls="h8300helf_linux h8300self_linux h8300sxelf_linux" + ;; +hppa*64*-*-linux-*) targ_emul=hppa64linux + ;; +hppa*64*-hpux*) targ_emul=elf64hppa + ;; +hppa*-*-linux-*) targ_emul=hppalinux + ;; +hppa*-*-*elf*) targ_emul=hppaelf + ;; +hppa*-*-lites*) targ_emul=hppaelf + ;; +hppa*-*-netbsd*) targ_emul=hppanbsd + ;; +hppa*-*-openbsd*) targ_emul=hppaobsd + ;; +i[3-7]86-*-nto-qnx*) targ_emul=i386nto + ;; +i[3-7]86-*-go32) targ_emul=i386go32 + targ_extra_ofiles= + ;; +i[3-7]86-*-msdosdjgpp*) targ_emul=i386go32 + targ_extra_ofiles= + ;; +i[3-7]86-*-lynxos*) targ_emul=i386lynx + ;; +i[3-7]86-*-aros*) targ_emul=elf_i386 + targ_extra_emuls=elf_iamcu + ;; +i[3-7]86-*-rdos*) targ_emul=elf_i386 + targ_extra_emuls=elf_iamcu + ;; +i[3-7]86-*-bsd) targ_emul=i386bsd + targ_extra_ofiles= + ;; +i[3-7]86-*-bsd386) targ_emul=i386bsd + targ_extra_ofiles= + ;; +i[3-7]86-*-bsdi*) targ_emul=i386bsd + targ_extra_ofiles= + ;; +i[3-7]86-*-linux-*) targ_emul=elf_i386 + targ_extra_emuls="elf_iamcu" + targ64_extra_emuls="elf_x86_64 elf32_x86_64 elf_l1om elf_k1om" + targ64_extra_libpath="elf_x86_64 elf32_x86_64" + ;; +i[3-7]86-*-redox*) targ_emul=elf_i386 + targ_extra_emuls=elf_x86_64 + ;; +i[3-7]86-*-sysv[45]*) targ_emul=elf_i386 + targ_extra_emuls=elf_iamcu + ;; +i[3-7]86-*-solaris2*) targ_emul=elf_i386_sol2 + targ_extra_emuls="elf_i386_ldso elf_i386 elf_iamcu elf_x86_64_sol2 elf_x86_64 elf_l1om elf_k1om" + targ_extra_libpath=$targ_extra_emuls + ;; +i[3-7]86-*-unixware) targ_emul=elf_i386 + targ_extra_emuls=elf_iamcu + ;; +i[3-7]86-*-solaris*) targ_emul=elf_i386_ldso + targ_extra_emuls="elf_i386" + targ_extra_libpath=$targ_extra_emuls + ;; +i[3-7]86-*-netbsdelf* | \ +i[3-7]86-*-netbsd*-gnu* | \ +i[3-7]86-*-knetbsd*-gnu | \ +i[3-7]86-*-openbsd*) + targ_emul=elf_i386 + targ_extra_emuls="elf_iamcu" + ;; +i[3-7]86-*-netbsdpe*) targ_emul=i386pe + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +i[3-7]86-*-elfiamcu) targ_emul=elf_iamcu + targ_extra_emuls=elf_i386 + ;; +i[3-7]86-*-elf* | i[3-7]86-*-rtems*) + targ_emul=elf_i386 + targ_extra_emuls=elf_iamcu + ;; +i[3-7]86-*-dragonfly*) targ_emul=elf_i386 + targ_extra_emuls="elf_iamcu i386bsd" + ;; +i[3-7]86-*-freebsd* | i[3-7]86-*-kfreebsd*-gnu) + targ_emul=elf_i386_fbsd + targ_extra_emuls="elf_i386 elf_iamcu i386bsd" + ;; +i[3-7]86-*-gnu*) targ_emul=elf_i386 + targ_extra_emuls=elf_iamcu + ;; +i[3-7]86-*-msdos*) targ_emul=i386msdos + targ_extra_emuls=i386aout + targ_extra_ofiles= + ;; +i[3-7]86-*-moss*) targ_emul=i386moss + targ_extra_emuls=i386msdos + ;; +i[3-7]86-*-winnt*) targ_emul=i386pe ; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +i[3-7]86-*-pe) targ_emul=i386pe ; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +i[3-7]86-*-cygwin*) targ_emul=i386pe ; + targ_extra_ofiles="deffilep.o pe-dll.o" ; + test "$targ" != "$host" && LIB_PATH='${tooldir}/lib/w32api' + ;; +i[3-7]86-*-mingw32*) targ_emul=i386pe ; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +i[3-7]86-*-interix*) targ_emul=i386pe_posix; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +i[3-7]86-*-beospe*) targ_emul=i386beos + targ_extra_ofiles= + ;; +i[3-7]86-*-beos*) targ_emul=elf_i386_be + ;; +i[3-7]86-*-vxworks*) targ_emul=elf_i386_vxworks + ;; +i[3-7]86-*-chaos) targ_emul=elf_i386_chaos + ;; +ia16-*-elf*) targ_emul=elf_i386 + targ_extra_emuls=i386msdos + ;; +ia64-*-elf*) targ_emul=elf64_ia64 + ;; +ia64-*-freebsd* | ia64-*-kfreebsd*-gnu) + targ_emul=elf64_ia64_fbsd + targ_extra_emuls="elf64_ia64" + ;; +ia64-*-netbsd*) targ_emul=elf64_ia64 + ;; +ia64-*-linux*) targ_emul=elf64_ia64 + ;; +ia64-*-*vms*) targ_emul=elf64_ia64_vms + targ_extra_ofiles=ldelfgen.o + ;; +ia64-*-aix*) targ_emul=elf64_aix + ;; +ip2k-*-elf) targ_emul=elf32ip2k + ;; +iq2000-*-elf) targ_emul=elf32iq2000 + targ_extra_emuls="elf32iq10" + targ_extra_ofiles=ldelfgen.o + ;; +lm32-*-*linux*) targ_emul=elf32lm32fd + ;; +lm32-*-*) targ_emul=elf32lm32 + targ_extra_emuls="elf32lm32fd" + ;; +m32c-*-elf | m32c-*-rtems*) + targ_emul=elf32m32c + ;; +m32r*le-*-elf*) targ_emul=m32rlelf + ;; +m32r*-*-elf* | m32r*-*-rtems*) + targ_emul=m32relf + ;; +m32r*le-*-linux-*) targ_emul=m32rlelf_linux + ;; +m32r*-*-linux-*) targ_emul=m32relf_linux + ;; +m68hc11-*-*|m6811-*-*) targ_emul=m68hc11elf + targ_extra_emuls="m68hc11elfb m68hc12elf m68hc12elfb" + ;; +m68hc12-*-*|m6812-*-*) targ_emul=m68hc12elf + targ_extra_emuls="m68hc12elfb m68hc11elf m68hc11elfb" + ;; +m68*-*-netbsdelf*) targ_emul=m68kelfnbsd + ;; +m68*-*-*) targ_emul=m68kelf + ;; +mcore-*-pe) targ_emul=mcorepe ; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +mcore-*-elf) targ_emul=elf32mcore + ;; +mep-*-elf) targ_emul=elf32mep + ;; +metag-*-*) targ_emul=elf32metag + ;; +microblazeel*-linux*) targ_emul="elf32mbel_linux" + targ_extra_emuls="elf32mb_linux" + ;; +microblaze*-linux*) targ_emul="elf32mb_linux" + targ_extra_emuls="elf32mbel_linux" + ;; +microblazeel*) targ_emul=elf32microblazeel + targ_extra_emuls=elf32microblaze + ;; +microblaze*) targ_emul=elf32microblaze + targ_extra_emuls=elf32microblazeel + ;; +mips*-sgi-irix5*) targ_emul=elf32bsmip + ;; +mips*-sgi-irix6*) targ_emul=elf32bmipn32 + targ_extra_emuls="elf32bsmip elf64bmip" + targ_extra_libpath=$targ_extra_emuls + ;; +mips*el-*-netbsd*) targ_emul=elf32ltsmip + targ_extra_emuls="elf32btsmip elf64ltsmip elf64btsmip" + ;; +mips*-*-netbsd*) targ_emul=elf32btsmip + targ_extra_emuls="elf32ltsmip elf64btsmip elf64ltsmip" + ;; +mips64el-*-openbsd*) targ_emul=elf64ltsmip + targ_extra_emuls=elf64btsmip + ;; +mips64-*-openbsd*) targ_emul=elf64btsmip + targ_extra_emuls=elf64ltsmip + ;; +mips*vr4300el-*-elf*) targ_emul=elf32l4300 + ;; +mips*vr4300-*-elf*) targ_emul=elf32b4300 + ;; +mips*vr4100el-*-elf*) targ_emul=elf32l4300 + ;; +mips*vr4100-*-elf*) targ_emul=elf32b4300 + ;; +mips*vr5000el-*-elf*) targ_emul=elf32l4300 + ;; +mips*vr5000-*-elf*) targ_emul=elf32b4300 + ;; +mips*el-sde-elf* | mips*el-mti-elf* | mips*el-img-elf*) + targ_emul=elf32ltsmip + targ_extra_emuls="elf32btsmip elf32ltsmipn32 elf64ltsmip elf32btsmipn32 elf64btsmip" + ;; +mips*-sde-elf* | mips*-mti-elf* | mips*-img-elf*) + targ_emul=elf32btsmip + targ_extra_emuls="elf32ltsmip elf32btsmipn32 elf64btsmip elf32ltsmipn32 elf64ltsmip" + ;; +mips64*el-ps2-elf*) targ_emul=elf32lr5900n32 + targ_extra_emuls="elf32lr5900" + targ_extra_libpath=$targ_extra_emuls + ;; +mips*el-ps2-elf*) targ_emul=elf32lr5900 + targ_extra_emuls="elf32lr5900n32" + targ_extra_libpath=$targ_extra_emuls + ;; +mips*el-*-elf*) targ_emul=elf32elmip + ;; +mips*-*-elf* | mips*-*-rtems*) + targ_emul=elf32ebmip + ;; +mips*el-*-vxworks*) targ_emul=elf32elmipvxworks + targ_extra_emuls="elf32ebmipvxworks" + ;; +mips*-*-vxworks*) targ_emul=elf32ebmipvxworks + targ_extra_emuls="elf32elmipvxworks" + ;; +mips*-*-windiss) targ_emul=elf32mipswindiss + ;; +mips64*el-*-linux-*) targ_emul=elf32ltsmipn32 + targ_extra_emuls="elf32btsmipn32 elf32ltsmip elf32btsmip elf64ltsmip elf64btsmip" + targ_extra_libpath=$targ_extra_emuls + ;; +mips64*-*-linux-*) targ_emul=elf32btsmipn32 + targ_extra_emuls="elf32ltsmipn32 elf32btsmip elf32ltsmip elf64btsmip elf64ltsmip" + targ_extra_libpath=$targ_extra_emuls + ;; +mips*el-*-linux-*) targ_emul=elf32ltsmip + targ_extra_emuls="elf32btsmip elf32ltsmipn32 elf64ltsmip elf32btsmipn32 elf64btsmip" + targ_extra_libpath=$targ_extra_emuls + ;; +mips*-*-linux-*) targ_emul=elf32btsmip + targ_extra_emuls="elf32ltsmip elf32btsmipn32 elf64btsmip elf32ltsmipn32 elf64ltsmip" + targ_extra_libpath=$targ_extra_emuls + ;; +mips64*el-*-freebsd* | mips64*el-*-kfreebsd*-gnu) + targ_emul=elf32ltsmipn32_fbsd + targ_extra_emuls="elf32ltsmip elf32btsmip elf32ltsmipn32 elf32btsmipn32 elf64ltsmip elf64btsmip elf32ltsmip_fbsd elf32btsmip_fbsd elf32btsmipn32_fbsd elf64ltsmip_fbsd elf64btsmip_fbsd" + targ_extra_libpath=$targ_extra_emuls + ;; +mips64*-*-freebsd* | mips64*-*-kfreebsd*-gnu) + targ_emul=elf32btsmipn32_fbsd + targ_extra_emuls="elf32ltsmip elf32btsmip elf32ltsmipn32 elf32btsmipn32 elf64ltsmip elf64btsmip elf32ltsmip_fbsd elf32btsmip_fbsd elf32ltsmipn32_fbsd elf64ltsmip_fbsd elf64btsmip_fbsd" + targ_extra_libpath=$targ_extra_emuls + ;; +mips*el-*-freebsd* | mips*el-*-kfreebsd*-gnu) + targ_emul=elf32ltsmip_fbsd + targ_extra_emuls="elf32ltsmip elf32btsmip elf32ltsmipn32 elf32btsmipn32 elf64ltsmip elf64btsmip elf32ltsmipn32_fbsd elf32btsmip_fbsd elf32btsmipn32_fbsd elf64ltsmip_fbsd elf64btsmip_fbsd" + targ_extra_libpath=$targ_extra_emuls + ;; +mips*-*-freebsd* | mips*-*-kfreebsd*-gnu) + targ_emul=elf32btsmip_fbsd + targ_extra_emuls="elf32ltsmip elf32btsmip elf32ltsmipn32 elf32btsmipn32 elf64ltsmip elf64btsmip elf32ltsmip_fbsd elf32btsmipn32_fbsd elf32ltsmipn32_fbsd elf64ltsmip_fbsd elf64btsmip_fbsd" + targ_extra_libpath=$targ_extra_emuls + ;; +mips*-*-sysv4*) targ_emul=elf32btsmip + ;; +mmix-*-*) targ_emul=mmo + targ_extra_emuls=elf64mmix + ;; +mn10200-*-*) targ_emul=mn10200 + targ_extra_ofiles=ldelfgen.o + ;; +mn10300-*-*) targ_emul=mn10300 + ;; +moxie-*-moxiebox*) targ_emul=moxiebox + targ_extra_ofiles=ldelfgen.o + ;; +moxie-*-*) targ_emul=elf32moxie + ;; +msp430-*-*) targ_emul=msp430elf + targ_extra_emuls="msp430X" + targ_extra_ofiles=ldelfgen.o + ;; +mt-*elf) targ_emul=elf32mt + targ_extra_ofiles=ldelfgen.o + ;; +nds32*le-*-elf*) targ_emul=nds32elf + targ_extra_emuls="nds32elf16m nds32belf nds32belf16m" + ;; +nds32*be-*-elf*) targ_emul=nds32belf + targ_extra_emuls="nds32elf nds32elf16m nds32belf16m" + ;; +nds32*le-*-linux-gnu*) targ_emul=nds32elf_linux + ;; +nds32*be-*-linux-gnu*) targ_emul=nds32belf_linux + ;; +nios2*-*-linux*) targ_emul=nios2linux + ;; +nios2*-*-*) targ_emul=nios2elf + ;; +ns32k-pc532-mach* | ns32k-pc532-ux*) targ_emul=pc532macha + targ_extra_ofiles= + ;; +ns32k-*-netbsd* | ns32k-pc532-lites*) targ_emul=ns32knbsd + targ_extra_ofiles= + ;; +or1k-*-elf | or1knd-*-elf | or1k-*-rtems* | or1knd-*-rtems*) + targ_emul=elf32or1k + ;; +or1k-*-linux* | or1knd-*-linux*) targ_emul=elf32or1k_linux + ;; +pdp11-*-*) targ_emul=pdp11 + targ_extra_ofiles= + ;; +pjl*-*-*) targ_emul=pjlelf + targ_extra_emuls="elf_i386 elf_iamcu" + ;; +pj*-*-*) targ_emul=pjelf + targ_extra_ofiles=ldelfgen.o + ;; +powerpc-*-freebsd* | powerpc-*-kfreebsd*-gnu) + targ_emul=elf32ppc_fbsd + targ_extra_emuls="elf32ppc elf32ppcsim" + targ_extra_libpath=elf32ppc; + tdir_elf32ppcsim=`echo ${targ_alias} | sed -e 's/ppc/ppcsim/'` + ;; +powerpc64-*-freebsd*) + targ_emul=elf64ppc_fbsd + targ_extra_emuls="elf64ppc elf32ppc_fbsd elf32ppc" + targ_extra_libpath="elf32ppc_fbsd elf32ppc" + tdir_elf32ppc=`echo "${targ_alias}" | sed -e 's/64//'` + tdir_elf32ppc_fbsd=$tdir_elf32ppc + ;; +powerpc64le-*-freebsd*) + targ_emul=elf64lppc_fbsd + targ_extra_emuls="elf64lppc" + ;; +powerpc-*-vxworks*) + targ_emul=elf32ppcvxworks + targ_extra_emuls="elf32ppc elf32ppclinux elf32ppcsim" + ;; +powerpc*-*-elf* | powerpc*-*-eabi* | powerpc*-*-sysv* \ + | powerpc*-*-linux* | powerpc*-*-netbsd* | powerpc*-*-openbsd* \ + | powerpc*-*-rtems* \ + | powerpc*-*-solaris* | powerpc*-*-kaos* | powerpc*-*-vxworks*) + case "${targ}" in + powerpc64*) + targ_emul=elf64ppc + targ_extra_emuls="elf32ppc elf32ppclinux elf32ppcsim" + targ_extra_libpath="elf32ppc elf32ppclinux" ;; + *linux*) + targ_emul=elf32ppclinux + targ_extra_emuls="elf32ppc elf32ppcsim" + targ_extra_libpath=elf32ppc + targ64_extra_emuls=elf64ppc + targ64_extra_libpath=elf64ppc ;; + *) + targ_emul=elf32ppc + targ_extra_emuls="elf32ppclinux elf32ppcsim" + targ_extra_libpath=elf32ppclinux + targ64_extra_emuls=elf64ppc + targ64_extra_libpath=elf64ppc ;; + esac + td=tdir_elf32ppc + td64=tdir_elf64ppc + s=s/ppc/lppc/g + case "${targ}" in + powerpcle-* | powerpc64le-*) + for z in td td64 targ_emul targ_extra_emuls \ + targ_extra_libpath targ64_extra_emuls \ + targ64_extra_libpath + do + eval ${z}=\"\`echo \$${z} \| sed -e $s\`\" + done + s=s/lppc/ppc/g ;; + esac + # Why oh why did we set tooldir based on target_alias + # rather than on target? + eval tdir_${targ_emul}="${targ_alias}" + cpu=`echo "${targ_alias}" | sed -e 's/-.*//'` + rest=`echo "${targ_alias}" | sed -e 's/^[^-]*//'` + le=le + case "${cpu}" in + *little) le=little + esac + ta32=`echo "${cpu}" | sed -e s/64//`"${rest}" + ta64=`echo "${cpu}" | sed -e 's/64//;s/$/64/;s/'${le}'64$/64'${le}'/;s/be64$/64be/'`"${rest}" + eval test -n \"\$${td}\" || eval ${td}="${ta32}" + eval test -n \"\$${td}linux\" || eval ${td}linux="${ta32}" + eval test -n \"\$${td}sim\" || eval ${td}sim="${ta32}" + eval test -n \"\$${td64}\" || eval ${td64}="${ta64}" + # Now provide the other endian + for z in targ_extra_emuls targ_extra_libpath + do + eval ${z}=\"\$${z} \`echo ${targ_emul} \$${z} \| sed -e $s\`\" + done + for z in targ64_extra_emuls targ64_extra_libpath + do + eval ${z}=\"\$${z} \`echo \$${z} \| sed -e $s\`\" + done + td=`echo "${td}" | sed -e $s` + td64=`echo "${td64}" | sed -e $s` + case "${targ}" in + powerpcle-* | powerpc64le-*) + cpu=`echo "${cpu}" | sed -e s/${le}\$//` ;; + *) + cpu=`echo "${cpu}" | sed -e s/be\$//`${le} ;; + esac + ta32=`echo "${cpu}" | sed -e s/64//`"${rest}" + ta64=`echo "${cpu}" | sed -e 's/64//;s/$/64/;s/'${le}'64$/64'${le}/`"${rest}" + eval test -n \"\$${td}\" || eval ${td}="${ta32}" + eval test -n \"\$${td}linux\" || eval ${td}linux="${ta32}" + eval test -n \"\$${td}sim\" || eval ${td}sim="${ta32}" + eval test -n \"\$${td64}\" || eval ${td64}="${ta64}" + ;; +powerpc-*-nto*) targ_emul=elf32ppcnto + ;; +powerpcle-*-nto*) targ_emul=elf32lppcnto + ;; +powerpc-*-macos*) targ_emul=ppcmacos + targ_extra_ofiles= + ;; +powerpc-*-aix[5-9]*) targ_emul=aix5ppc + targ_extra_ofiles= + ;; +powerpc-*-aix*) targ_emul=aixppc + targ_extra_ofiles= + ;; +powerpc-*-beos*) targ_emul=aixppc + targ_extra_ofiles= + ;; +powerpc-*-windiss*) targ_emul=elf32ppcwindiss + ;; +pru*-*-*) targ_emul=pruelf + ;; +riscv32be*-*-linux*) targ_emul=elf32briscv + targ_extra_emuls="elf32briscv_ilp32f elf32briscv_ilp32 elf64briscv elf64briscv_lp64f elf64briscv_lp64 elf32lriscv elf32lriscv_ilp32f elf32lriscv_ilp32 elf64lriscv elf64lriscv_lp64f elf64lriscv_lp64" + targ_extra_libpath=$targ_extra_emuls + ;; +riscv32*-*-linux*) targ_emul=elf32lriscv + targ_extra_emuls="elf32lriscv_ilp32f elf32lriscv_ilp32 elf64lriscv elf64lriscv_lp64f elf64lriscv_lp64 elf32briscv elf32briscv_ilp32f elf32briscv_ilp32 elf64briscv elf64briscv_lp64f elf64briscv_lp64" + targ_extra_libpath=$targ_extra_emuls + ;; +riscvbe-*-* | riscv32be*-*-*) + targ_emul=elf32briscv + targ_extra_emuls="elf64briscv elf32lriscv elf64lriscv" + targ_extra_libpath=$targ_extra_emuls + ;; +riscv-*-* | riscv32*-*-*) + targ_emul=elf32lriscv + targ_extra_emuls="elf64lriscv elf32briscv elf64briscv" + targ_extra_libpath=$targ_extra_emuls + ;; +riscv64be*-*-linux*) targ_emul=elf64briscv + targ_extra_emuls="elf64briscv_lp64f elf64briscv_lp64 elf32briscv elf32briscv_ilp32f elf32briscv_ilp32 elf64lriscv elf64lriscv_lp64f elf64lriscv_lp64 elf32lriscv elf32lriscv_ilp32f elf32lriscv_ilp32" + targ_extra_libpath=$targ_extra_emuls + ;; +riscv64*-*-linux*) targ_emul=elf64lriscv + targ_extra_emuls="elf64lriscv_lp64f elf64lriscv_lp64 elf32lriscv elf32lriscv_ilp32f elf32lriscv_ilp32 elf64briscv elf64briscv_lp64f elf64briscv_lp64 elf32briscv elf32briscv_ilp32f elf32briscv_ilp32" + targ_extra_libpath=$targ_extra_emuls + ;; +riscv64be*-*-*) targ_emul=elf64briscv + targ_extra_emuls="elf32briscv elf64lriscv elf32lriscv" + targ_extra_libpath=$targ_extra_emuls + ;; +riscv64*-*-*) targ_emul=elf64lriscv + targ_extra_emuls="elf32lriscv elf64briscv elf32briscv" + targ_extra_libpath=$targ_extra_emuls + ;; +rs6000-*-aix[5-9]*) targ_emul=aix5rs6 + targ_extra_ofiles= + ;; +rs6000-*-aix*) targ_emul=aixrs6 + targ_extra_ofiles= + ;; +rl78-*-*) targ_emul=elf32rl78 + ;; +rx-*-linux*) targ_emul=elf32rx_linux + ;; +rx-*-*) targ_emul=elf32rx + ;; +s12z-*-*) targ_emul=m9s12zelf + targ_extra_ofiles=ldelfgen.o + ;; +s390x-*-linux*) targ_emul=elf64_s390 + targ_extra_emuls=elf_s390 + targ_extra_libpath=$targ_extra_emuls + tdir_elf_s390=`echo ${targ_alias} | sed -e 's/s390x/s390/'` + ;; +s390x-*-tpf*) targ_emul=elf64_s390 + tdir_elf_s390=`echo ${targ_alias} | sed -e 's/s390x/s390/'` + ;; +s390-*-linux*) targ_emul=elf_s390 + targ64_extra_emuls=elf64_s390 + targ64_extra_libpath=elf64_s390 + tdir_elf64_s390=`echo ${targ_alias} | sed -e 's/s390/s390x/'` + ;; +score-*-elf) targ_emul=score7_elf + targ_extra_emuls=score3_elf + ;; +sh-*-linux*) targ_emul=shlelf_linux + targ_extra_emuls="shelf_linux shlelf_fd shelf_fd" + targ_extra_libpath=shelf_linux + ;; +sh*eb-*-linux*) targ_emul=shelf_linux + targ_extra_emuls="shelf_fd" + ;; +sh*-*-linux*) targ_emul=shlelf_linux + targ_extra_emuls="shlelf_fd" + ;; +sh*l*-*-netbsdelf*) targ_emul=shlelf_nbsd + targ_extra_emuls=shelf_nbsd + ;; +sh*-*-netbsdelf*) targ_emul=shelf_nbsd + targ_extra_emuls=shlelf_nbsd + ;; +shle*-*-elf* | sh[1234]*le*-*-elf | shle*-*-kaos*) + targ_emul=shlelf + targ_extra_emuls="shelf shl sh" + ;; +sh-*-elf* | sh[1234]*-*-elf | sh-*-rtems* | sh-*-kaos*) + targ_emul=shelf + targ_extra_emuls="shlelf sh shl" + ;; +sh-*-uclinux* | sh[12]-*-uclinux*) + targ_emul=shelf_uclinux + targ_extra_emuls="shelf shlelf sh shl shelf_fd shlelf_fd" + ;; +sh-*-vxworks) targ_emul=shelf_vxworks + targ_extra_emuls=shlelf_vxworks + ;; +sh-*-nto*) targ_emul=shelf_nto + targ_extra_emuls=shlelf_nto + ;; +sh-*-pe) targ_emul=shpe ; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +sh-*-*) targ_emul=sh; + targ_extra_emuls=shl + targ_extra_ofiles= + ;; +sparc64-*-freebsd* | sparcv9-*-freebsd* | sparc64-*-kfreebsd*-gnu | sparcv9-*-kfreebsd*-gnu) + targ_emul=elf64_sparc_fbsd + targ_extra_emuls="elf64_sparc elf32_sparc" + targ_extra_libpath=$targ_extra_emuls + tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` + ;; +sparc64-*-linux-*) targ_emul=elf64_sparc + targ_extra_emuls="elf32_sparc" + targ_extra_libpath=elf32_sparc + tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` + ;; +sparc64-*-*bsd*) targ_emul=elf64_sparc + targ_extra_emuls="elf32_sparc" + ;; +sparc64-*-solaris2* | sparcv9-*-solaris2*) + targ_emul=elf64_sparc_sol2 + targ_extra_emuls="elf64_sparc elf32_sparc_sol2 elf32_sparc" + targ_extra_libpath=$targ_extra_emuls + tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` + ;; +sparc64-*-*) targ_emul=elf64_sparc + ;; +sparc*-*-linux-*) targ_emul=elf32_sparc + targ_extra_emuls="elf64_sparc" + targ_extra_libpath=elf64_sparc + tdir_elf64_sparc=`echo ${targ_alias} | sed -e 's/32//'` + ;; +sparc-*-solaris2.[0-6] | sparc-*-solaris2.[0-6].*) + targ_emul=elf32_sparc_sol2 + targ_extra_emuls=elf32_sparc + ;; +sparc-*-solaris2*) targ_emul=elf32_sparc_sol2 + targ_extra_emuls="elf32_sparc elf64_sparc_sol2 elf64_sparc" + targ_extra_libpath=$targ_extra_emuls + tdir_elf64_sparc=`echo ${targ_alias} | sed -e 's/32//'` + ;; +sparc*-*-vxworks*) targ_emul=elf32_sparc_vxworks + ;; +sparc*-*-*) targ_emul=elf32_sparc + ;; +spu-*-elf*) targ_emul=elf32_spu + ;; +tic30-*-*coff*) targ_emul=tic30coff + targ_extra_ofiles= + ;; +tic4x-*-* | c4x-*-*) targ_emul=tic4xcoff + targ_extra_emuls="tic3xcoff tic3xcoff_onchip" + targ_extra_ofiles= + ;; +tic54x-*-* | c54x*-*-*) targ_emul=tic54xcoff + targ_extra_ofiles= + ;; +tic6x-*-elf) targ_emul=elf32_tic6x_elf_le + targ_extra_emuls="elf32_tic6x_elf_be elf32_tic6x_le elf32_tic6x_be" + targ_extra_libpath=$targ_extra_emuls + ;; +tic6x-*-uclinux) targ_emul=elf32_tic6x_linux_le + targ_extra_emuls="elf32_tic6x_linux_be elf32_tic6x_le elf32_tic6x_be" + targ_extra_libpath=$targ_extra_emuls + ;; +tilegx-*-*) targ_emul=elf64tilegx + targ_extra_emuls="elf64tilegx_be elf32tilegx elf32tilegx_be" + targ_extra_libpath=$targ_extra_emuls + ;; +tilegxbe-*-*) targ_emul=elf64tilegx_be + targ_extra_emuls="elf64tilegx elf32tilegx elf32tilegx_be" + targ_extra_libpath=$targ_extra_emuls + ;; +tilepro-*-*) targ_emul=elf32tilepro + ;; +v850*-*-*) targ_emul=v850_rh850 + targ_extra_emuls=v850 + ;; +vax-*-netbsdelf*) targ_emul=elf32vax + targ_extra_emuls=vaxnbsd + ;; +vax-*-netbsdaout* | vax-*-netbsd*) + targ_emul=vaxnbsd + targ_extra_emuls=elf32vax + ;; +vax-*-linux-*) targ_emul=elf32vax + ;; +visium-*-elf) targ_emul=elf32visium + ;; +x86_64-*-rdos*) targ_emul=elf64rdos + ;; +x86_64-*-cloudabi*) targ_emul=elf_x86_64_cloudabi + ;; +x86_64-*-linux-gnux32) targ_emul=elf32_x86_64 + targ_extra_emuls="elf_x86_64 elf_i386 elf_iamcu elf_l1om elf_k1om" + targ_extra_libpath="elf_i386 elf_iamcu elf_x86_64 elf_l1om elf_k1om" + tdir_elf_iamcu=`echo ${targ_alias} | sed -e 's/x86_64/i386/' -e 's/-linux-gnux32/-linux-gnu/'` + tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/' -e 's/-linux-gnux32/-linux-gnu/'` + ;; +x86_64-*-linux-*) targ_emul=elf_x86_64 + targ_extra_emuls="elf32_x86_64 elf_i386 elf_iamcu elf_l1om elf_k1om" + targ_extra_libpath="elf_i386 elf32_x86_64 elf_l1om elf_k1om" + tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` + ;; +x86_64-*-redox*) targ_emul=elf_x86_64 + targ_extra_emuls=elf_i386 + ;; +x86_64-*-solaris2*) targ_emul=elf_x86_64_sol2 + targ_extra_emuls="elf_x86_64 elf_i386_sol2 elf_i386_ldso elf_i386 elf_iamcu elf_l1om elf_k1om" + targ_extra_libpath=$targ_extra_emuls + tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` + ;; +x86_64-*-netbsd* | x86_64-*-openbsd*) + targ_emul=elf_x86_64 + targ_extra_emuls="elf_i386 elf_iamcu elf_l1om elf_k1om" + tdir_elf_iamcu=`echo ${targ_alias} | \ + sed -e 's/x86_64/i386/'` + case "${tdir_elf_iamcu}" in + *-netbsdelf*) ;; + *) tdir_elf_iamcu=`echo ${tdir_elf_iamcu} | \ + sed -e 's/netbsd/netbsdelf/'`;; + esac + tdir_elf_i386=`echo ${targ_alias} | \ + sed -e 's/x86_64/i386/'` + case "${tdir_elf_i386}" in + *-netbsdelf*) ;; + *) tdir_elf_i386=`echo ${tdir_elf_i386} | \ + sed -e 's/netbsd/netbsdelf/'`;; + esac + ;; +x86_64-*-elf* | x86_64-*-rtems* | x86_64-*-fuchsia* | x86_64-*-essence*) + targ_emul=elf_x86_64 + targ_extra_emuls="elf_i386 elf_iamcu elf32_x86_64 elf_l1om elf_k1om" + targ_extra_libpath="elf_i386 elf_iamcu elf32_x86_64 elf_l1om elf_k1om" + tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` + ;; +x86_64-*-dragonfly*) targ_emul=elf_x86_64 + targ_extra_emuls="elf_i386 elf_iamcu elf_l1om elf_k1om" + ;; +x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) + targ_emul=elf_x86_64_fbsd + targ_extra_emuls="elf_i386_fbsd elf_x86_64 elf_i386 elf_iamcu elf_l1om elf_l1om_fbsd elf_k1om elf_k1om_fbsd" + targ_extra_libpath="elf_i386_fbsd" + tdir_elf_i386_fbsd=`echo ${targ_alias} \ + | sed -e 's/x86_64/i386/'` + tdir_elf_iamcu=`echo ${targ_alias} \ + | sed -e 's/x86_64/i386/'` + tdir_elf_i386=`echo ${targ_alias} \ + | sed -e 's/x86_64/i386/'` + ;; +x86_64-*-pe | x86_64-*-pep) targ_emul=i386pep ; + targ_extra_emuls=i386pe ; + targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" + ;; +x86_64-*-cygwin) targ_emul=i386pep ; + targ_extra_emuls=i386pe + targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" + test "$targ" != "$host" && LIB_PATH='${tooldir}/lib/w32api' + ;; +x86_64-*-mingw*) targ_emul=i386pep ; + targ_extra_emuls=i386pe + targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" + ;; +xc16x-*-elf) targ_emul=elf32xc16x + targ_extra_emuls="elf32xc16xl elf32xc16xs" + ;; +xgate-*-*) targ_emul=xgateelf + targ_extra_ofiles=ldelfgen.o + ;; +xstormy16-*-*) targ_emul=elf32xstormy16 + ;; +xtensa*-*-*) targ_emul=elf32xtensa + ;; +z80-*-elf*) targ_emul=elf32z80 + targ_extra_ofiles="ldelf.o ldelfgen.o" + ;; +z80-*-coff) targ_emul=z80 + targ_extra_ofiles= + ;; +z8k-*-coff) targ_emul=z8002 + targ_extra_emuls=z8001 + targ_extra_ofiles= + ;; +*-*-ieee*) targ_emul=vanilla + targ_extra_ofiles= + ;; +*) + echo 2>&1 "*** ld does not support target ${targ}" + echo 2>&1 "*** see ld/configure.tgt for supported targets" + exit 1 + +esac + +NATIVE_LIB_DIRS='/usr/local/lib /lib /usr/lib' +case "${target}" in + +*-*-dragonfly*) + NATIVE_LIB_DIRS='/lib /usr/lib /usr/pkg/lib /usr/local/lib' + ;; + +*-*-essence*) + NATIVE_LIB_DIRS='/Applications/POSIX/lib' + ;; + +*-*-freebsd*) + NATIVE_LIB_DIRS='/lib /usr/lib /usr/local/lib' + ;; + +hppa*64*-*-hpux11*) + NATIVE_LIB_DIRS=/usr/lib/pa20_64 + ;; + +i[3-7]86-*-sysv4*) + NATIVE_LIB_DIRS='/usr/local/lib /usr/ccs/lib /lib /usr/lib' + ;; + +i[3-7]86-*-solaris*) + NATIVE_LIB_DIRS='/usr/local/lib /usr/ccs/lib /lib /usr/lib' + ;; + +i[3-7]86-pc-interix*) + NATIVE_LIB_DIRS='/usr/local/lib $$INTERIX_ROOT/usr/lib /lib /usr/lib' + ;; + +ia64-*-aix*) + NATIVE_LIB_DIRS='/usr/local/lib /usr/lib/ia64l64 /lib /usr/lib' + ;; + +sparc*-*-solaris2*) + NATIVE_LIB_DIRS='/usr/local/lib /usr/ccs/lib /lib /usr/lib' + ;; + +spu-*-elf*) + # This allows one to build a pair of PPU/SPU toolchains with common sysroot. + NATIVE_LIB_DIRS='/lib' + ;; + +i[03-9x]86-*-cygwin* | x86_64-*-cygwin*) + NATIVE_LIB_DIRS='/usr/lib /usr/lib/w32api' + ;; + +*-*-linux*) + ;; + +*-*-netbsd*) + ;; + +alpha*-*-*) + NATIVE_LIB_DIRS='/usr/local/lib /usr/ccs/lib /lib /usr/lib' + ;; + +esac + +case "${target}" in +frv-*-* | hppa*-*-* | ia64-*-* | mips*-*-*) + # Don't enable -z relro by default since many relro tests fail on these + # targets: + # FAIL: strip -z relro (relro1) + # FAIL: strip -z relro -shared (relro1) + # FAIL: objcopy -z relro (relro1) + # FAIL: objcopy -z relro -shared (relro1) + # FAIL: objcopy -z relro (tdata1) + # FAIL: objcopy -shared -z relro (tdata1) + # FAIL: objcopy -z relro (tdata2) + # FAIL: objcopy -shared -z relro (tdata2) + # FAIL: objcopy -z relro (tdata3) + # FAIL: objcopy -shared -z relro (tdata3) + # FAIL: objcopy -shared -z relro (tbss1) + # FAIL: objcopy -shared -z relro (tbss2) + # FAIL: objcopy -shared -z relro (tbss3) + ;; +*-*-linux*) + if test ${ac_default_ld_z_relro} = unset; then + ac_default_ld_z_relro=1 + fi + ;; +esac + +# Enable -z separate-code and --warn-textrel by default for Linux/x86. +case "${target}" in +i[3-7]86-*-linux-* | x86_64-*-linux-*) + if test ${ac_default_ld_z_separate_code} = unset; then + ac_default_ld_z_separate_code=1 + fi + if test ${ac_default_ld_textrel_check} = unset; then + ac_default_ld_textrel_check=yes + fi + ;; +esac diff --git a/ports/gcc/changes/gcc_config.sub b/ports/gcc/changes/gcc_config.sub new file mode 100755 index 0000000..fcd22cb --- /dev/null +++ b/ports/gcc/changes/gcc_config.sub @@ -0,0 +1,1860 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2021 Free Software Foundation, Inc. + +timestamp='2021-01-08' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=$(echo "$0" | sed -e 's,.*/,,') + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2021 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Split fields of configuration type +# shellcheck disable=SC2162 +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines +case $basic_machine in + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + basic_os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + basic_os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + basic_os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv32 + ;; + i*86v4*) + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv4 + ;; + i*86v) + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv + ;; + i*86sol2) + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $basic_os in + irix*) + ;; + *) + basic_os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) + ;; + ns2*) + basic_os=nextstep2 + ;; + *) + basic_os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + basic_os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=$(echo "$basic_machine" | sed 's/-.*//') + ;; + + *-*) + # shellcheck disable=SC2162 + IFS="-" read cpu vendor <&2 + exit 1 + ;; + esac + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $vendor in + digital*) + vendor=dec + ;; + commodore*) + vendor=cbm + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if test x$basic_os != x +then + +# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|') + ;; + os2-emx) + kernel=os2 + os=$(echo $basic_os | sed -e 's|os2-emx|emx|') + ;; + nto-qnx*) + kernel=nto + os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|') + ;; + *-*) + # shellcheck disable=SC2162 + IFS="-" read kernel os <&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) + vendor=acorn + ;; + *-sunos*) + vendor=sun + ;; + *-cnk* | *-aix*) + vendor=ibm + ;; + *-beos*) + vendor=be + ;; + *-hpux*) + vendor=hp + ;; + *-mpeix*) + vendor=hp + ;; + *-hiux*) + vendor=hitachi + ;; + *-unos*) + vendor=crds + ;; + *-dgux*) + vendor=dg + ;; + *-luna*) + vendor=omron + ;; + *-genix*) + vendor=ns + ;; + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) + vendor=ibm + ;; + s390-* | s390x-*) + vendor=ibm + ;; + *-ptx*) + vendor=sequent + ;; + *-tpf*) + vendor=ibm + ;; + *-vxsim* | *-vxworks* | *-windiss*) + vendor=wrs + ;; + *-aux*) + vendor=apple + ;; + *-hms*) + vendor=hitachi + ;; + *-mpw* | *-macos*) + vendor=apple + ;; + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) + vendor=atari + ;; + *-vos*) + vendor=stratus + ;; + esac + ;; +esac + +echo "$cpu-$vendor-${kernel:+$kernel-}$os" +exit + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/ports/gcc/changes/gcc_fixincludes_mkfixinc.sh b/ports/gcc/changes/gcc_fixincludes_mkfixinc.sh new file mode 100755 index 0000000..6ba0ba6 --- /dev/null +++ b/ports/gcc/changes/gcc_fixincludes_mkfixinc.sh @@ -0,0 +1,33 @@ +#! /bin/sh + +if [ $# -ne 1 ] +then + echo "Usage: $0 " + exit 1 +fi + +machine=$1 +target=fixinc.sh + +# Check for special fix rules for particular targets +case $machine in + i?86-*-cygwin* | \ + i?86-*-mingw32* | \ + x86_64-*-mingw32* | \ + powerpc-*-eabisim* | \ + powerpc-*-eabi* | \ + powerpc-*-rtems* | \ + powerpcle-*-eabisim* | \ + powerpcle-*-eabi* | \ + *-essence* | \ + *-musl* ) + # IF there is no include fixing, + # THEN create a no-op fixer and exit + (echo "#! /bin/sh" ; echo "exit 0" ) > ${target} + ;; + + *) + cat < ${srcdir}/fixinc.in > ${target} || exit 1 + ;; +esac +chmod 755 ${target} diff --git a/ports/gcc/changes/gcc_gcc_config.gcc b/ports/gcc/changes/gcc_gcc_config.gcc new file mode 100644 index 0000000..148e537 --- /dev/null +++ b/ports/gcc/changes/gcc_gcc_config.gcc @@ -0,0 +1,5493 @@ +# GCC target-specific configuration file. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. + +#This file is part of GCC. + +#GCC is free software; you can redistribute it and/or modify it under +#the terms of the GNU General Public License as published by the Free +#Software Foundation; either version 3, or (at your option) any later +#version. + +#GCC is distributed in the hope that it will be useful, but WITHOUT +#ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +#for more details. + +#You should have received a copy of the GNU General Public License +#along with GCC; see the file COPYING3. If not see +#. + +# This is the GCC target-specific configuration file +# where a configuration type is mapped to different system-specific +# definitions and files. This is invoked by the autoconf-generated +# configure script. Putting it in a separate shell file lets us skip +# running autoconf when modifying target-specific information. + +# When you change the cases in the OS or target switches, consider +# updating ../libgcc/config.host also. + +# This file switches on the shell variable ${target}, and also uses the +# following shell variables: +# +# with_* Various variables as set by configure. +# +# enable_threads Either the name, yes or no depending on whether +# threads support was requested. +# +# default_use_cxa_atexit +# The default value for the $enable___cxa_atexit +# variable. enable___cxa_atexit needs to be set to +# "yes" for the correct operation of C++ destructors +# but it relies upon the presence of a non-standard C +# library function called __cxa_atexit. +# Since not all C libraries provide __cxa_atexit the +# default value of $default_use_cxa_atexit is set to +# "no" except for targets which are known to be OK. +# +# default_gnu_indirect_function +# The default value for the $enable_gnu_indirect_function +# variable. enable_gnu_indirect_function relies +# upon the presence of a non-standard gnu ifunc support +# in the assembler, linker and dynamic linker. +# Since not all libraries provide the dynamic linking +# support, the default value of +# $default_gnu_indirect_function is set to +# "no" except for targets which are known to be OK. +# +# gas_flag Either yes or no depending on whether GNU as was +# requested. +# +# gnu_ld_flag Either yes or no depending on whether GNU ld was +# requested. + +# This file sets the following shell variables for use by the +# autoconf-generated configure script: +# +# cpu_type The name of the cpu, if different from the first +# chunk of the canonical target name. +# +# tm_defines List of target macros to define for all compilations. +# +# tm_file A list of target macro files, if different from +# "$cpu_type/$cpu_type.h". Usually it's constructed +# per target in a way like this: +# tm_file="${tm_file} dbxelf.h elfos.h ${cpu_type.h}/elf.h" +# Note that the preferred order is: +# - specific target header "${cpu_type}/${cpu_type.h}" +# - generic headers like dbxelf.h elfos.h, etc. +# - specializing target headers like ${cpu_type.h}/elf.h +# This helps to keep OS specific stuff out of the CPU +# defining header ${cpu_type}/${cpu_type.h}. +# +# It is possible to include automatically-generated +# build-directory files by prefixing them with "./". +# All other files should relative to $srcdir/config. +# +# tm_p_file Location of file with declarations for functions +# in $out_file. +# +# tm_d_file A list of headers with definitions of target hook +# macros for the D compiler. +# +# out_file The name of the machine description C support +# file, if different from "$cpu_type/$cpu_type.c". +# +# common_out_file The name of the source file for code shared between +# the compiler proper and the driver. +# +# md_file The name of the machine-description file, if +# different from "$cpu_type/$cpu_type.md". +# +# tmake_file A list of machine-description-specific +# makefile-fragments, if different from +# "$cpu_type/t-$cpu_type". +# +# extra_modes The name of the file containing a list of extra +# machine modes, if necessary and different from +# "$cpu_type/$cpu_type-modes.def". +# +# extra_objs List of extra objects that should be linked into +# the compiler proper (cc1, cc1obj, cc1plus) +# depending on target. +# +# extra_gcc_objs List of extra objects that should be linked into +# the compiler driver (gcc) depending on target. +# +# extra_headers List of used header files from the directory +# config/${cpu_type}. +# +# user_headers_inc_next_pre +# List of header file names of internal gcc header +# files, which should be prefixed by an include_next. +# user_headers_inc_next_post +# List of header file names of internal gcc header +# files, which should be postfixed by an include_next. +# use_gcc_tgmath If set, add tgmath.h to the list of used header +# files. +# +# use_gcc_stdint If "wrap", install a version of stdint.h that +# wraps the system's copy for hosted compilations; +# if "provide", provide a version of systems without +# such a system header; otherwise "none", do not +# provide such a header at all. +# +# extra_programs List of extra executables compiled for this target +# machine, used when linking. +# +# extra_options List of target-dependent .opt files. +# +# c_target_objs List of extra target-dependent objects that be +# linked into the C compiler only. +# +# cxx_target_objs List of extra target-dependent objects that be +# linked into the C++ compiler only. +# +# d_target_objs List of extra target-dependent objects that be +# linked into the D compiler only. +# +# fortran_target_objs List of extra target-dependent objects that be +# linked into the fortran compiler only. +# +# target_gtfiles List of extra source files with type information. +# +# xm_defines List of macros to define when compiling for the +# target machine. +# +# xm_file List of files to include when compiling for the +# target machine. +# +# use_collect2 Set to yes or no, depending on whether collect2 +# will be used. +# +# target_cpu_default Set to override the default target model. +# +# gdb_needs_out_file_path +# Set to yes if gdb needs a dir command with +# `dirname $out_file`. +# +# thread_file Set to control which thread package to use. +# +# gas Set to yes or no depending on whether the target +# system normally uses GNU as. +# +# configure_default_options +# Set to an initializer for configure_default_options +# in configargs.h, based on --with-cpu et cetera. +# +# native_system_header_dir +# Where system header files are found for this +# target. This defaults to /usr/include. If +# the --with-sysroot configure option or the +# --sysroot command line option is used this +# will be relative to the sysroot. +# target_type_format_char +# The default character to be used for formatting +# the attribute in a +# .type symbol_name, ${t_t_f_c} +# directive. + +# The following variables are used in each case-construct to build up the +# outgoing variables: +# +# gnu_ld Set to yes or no depending on whether the target +# system normally uses GNU ld. +# +# target_has_targetcm Set to yes or no depending on whether the target +# has its own definition of targetcm. +# +# target_has_targetm_common Set to yes or no depending on whether the +# target has its own definition of targetm_common. +# +# target_has_targetdm Set to yes or no depending on whether the target +# has its own definition of targetdm. + +out_file= +common_out_file= +tmake_file= +extra_headers= +user_headers_inc_next_pre= +user_headers_inc_next_post= +use_gcc_tgmath=yes +use_gcc_stdint=none +extra_programs= +extra_objs= +extra_gcc_objs= +extra_options= +c_target_objs= +cxx_target_objs= +d_target_objs= +fortran_target_objs= +target_has_targetcm=no +target_has_targetm_common=yes +target_has_targetdm=no +tm_defines= +xm_defines= +# Set this to force installation and use of collect2. +use_collect2= +# Set this to override the default target model. +target_cpu_default= +# Set this if gdb needs a dir command with `dirname $out_file` +gdb_needs_out_file_path= +# Set this to control which thread package will be used. +thread_file= +# Reinitialize these from the flag values every loop pass, since some +# configure entries modify them. +gas="$gas_flag" +gnu_ld="$gnu_ld_flag" +default_use_cxa_atexit=no +default_gnu_indirect_function=no +target_gtfiles= +need_64bit_isa= +native_system_header_dir=/usr/include +target_type_format_char='@' + +# Don't carry these over build->host->target. Please. +xm_file= +md_file= + +# Obsolete configurations. +case ${target} in + tile*-*-* \ + ) + if test "x$enable_obsolete" != xyes; then + echo "*** Configuration ${target} is obsolete." >&2 + echo "*** Specify --enable-obsolete to build it anyway." >&2 + echo "*** Support will be REMOVED in the next major release of GCC," >&2 + echo "*** unless a maintainer comes forward." >&2 + exit 1 + fi;; +esac + +# Unsupported targets list. Do not put an entry in this list unless +# it would otherwise be caught by a more permissive pattern. The list +# should be in alphabetical order. +case ${target} in + # Avoid special cases that are not obsolete + arm*-*-*eabi* \ + ) + ;; + arm*-wince-pe* \ + | arm*-*-ecos-elf \ + | arm*-*-elf \ + | arm*-*-linux* \ + | arm*-*-uclinux* \ + | cris-*-linux* \ + | crisv32-*-* \ + | i[34567]86-go32-* \ + | i[34567]86-*-go32* \ + | m68k-*-uclinuxoldabi* \ + | mips64orion*-*-rtems* \ + | pdp11-*-bsd \ + | powerpc*-*-linux*paired* \ + | powerpc*-*-*spe* \ + | sparc-hal-solaris2* \ + | spu*-*-* \ + | thumb-*-* \ + | *-*-freebsd[12] | *-*-freebsd[1234].* \ + | *-*-freebsd*aout* \ + | *-*-linux*aout* \ + | *-*-linux*coff* \ + | *-*-linux*libc1* \ + | *-*-linux*oldld* \ + | *-*-rtemsaout* \ + | *-*-rtemscoff* \ + | *-*-solaris2 \ + | *-*-solaris2.[0-9] \ + | *-*-solaris2.[0-9].* \ + | *-*-solaris2.10* \ + | *-*-sysv* \ + | vax-*-vms* \ + ) + echo "*** Configuration ${target} not supported" 1>&2 + exit 1 + ;; +esac + +# Set default cpu_type, tm_file, tm_p_file and xm_file so it can be +# updated in each machine entry. Also set default extra_headers for some +# machines. +tm_p_file= +cpu_type=`echo ${target} | sed 's/-.*$//'` +cpu_is_64bit= +case ${target} in +m32c*-*-*) + cpu_type=m32c + tmake_file=m32c/t-m32c + target_has_targetm_common=no + ;; +aarch64*-*-*) + cpu_type=aarch64 + extra_headers="arm_fp16.h arm_neon.h arm_bf16.h arm_acle.h arm_sve.h" + c_target_objs="aarch64-c.o" + cxx_target_objs="aarch64-c.o" + d_target_objs="aarch64-d.o" + extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch64-bti-insert.o aarch64-cc-fusion.o" + target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c \$(srcdir)/config/aarch64/aarch64-sve-builtins.h \$(srcdir)/config/aarch64/aarch64-sve-builtins.cc" + target_has_targetm_common=yes + ;; +alpha*-*-*) + cpu_type=alpha + extra_options="${extra_options} g.opt" + ;; +amdgcn*) + cpu_type=gcn + use_gcc_stdint=wrap + ;; +am33_2.0-*-linux*) + cpu_type=mn10300 + ;; +arc*-*-*) + cpu_type=arc + c_target_objs="arc-c.o" + cxx_target_objs="arc-c.o" + extra_options="${extra_options} arc/arc-tables.opt g.opt" + extra_headers="arc-simd.h" + ;; +arm*-*-*) + cpu_type=arm + extra_objs="arm-builtins.o aarch-common.o" + extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h arm_cmse.h arm_bf16.h arm_mve_types.h arm_mve.h arm_cde.h" + target_type_format_char='%' + c_target_objs="arm-c.o" + cxx_target_objs="arm-c.o" + d_target_objs="arm-d.o" + extra_options="${extra_options} arm/arm-tables.opt" + target_gtfiles="\$(srcdir)/config/arm/arm-builtins.c" + ;; +avr-*-*) + cpu_type=avr + c_target_objs="avr-c.o" + cxx_target_objs="avr-c.o" + ;; +bfin*-*) + cpu_type=bfin + ;; +bpf-*-*) + cpu_type=bpf + ;; +frv*) cpu_type=frv + extra_options="${extra_options} g.opt" + ;; +ft32*) cpu_type=ft32 + target_has_targetm_common=no + ;; +moxie*) cpu_type=moxie + target_has_targetm_common=no + ;; +fido-*-*) + cpu_type=m68k + extra_headers=math-68881.h + extra_options="${extra_options} m68k/m68k-tables.opt" + ;; +i[34567]86-*-*) + cpu_type=i386 + c_target_objs="i386-c.o" + cxx_target_objs="i386-c.o" + d_target_objs="i386-d.o" + extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o i386-options.o i386-builtins.o i386-expand.o i386-features.o" + target_gtfiles="\$(srcdir)/config/i386/i386-builtins.c \$(srcdir)/config/i386/i386-expand.c \$(srcdir)/config/i386/i386-options.c" + extra_options="${extra_options} fused-madd.opt" + extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h + pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h + nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h + immintrin.h x86intrin.h avxintrin.h xopintrin.h + ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h + lzcntintrin.h bmiintrin.h bmi2intrin.h tbmintrin.h + avx2intrin.h avx512fintrin.h fmaintrin.h f16cintrin.h + rtmintrin.h xtestintrin.h rdseedintrin.h prfchwintrin.h + adxintrin.h fxsrintrin.h xsaveintrin.h xsaveoptintrin.h + avx512cdintrin.h avx512erintrin.h avx512pfintrin.h + shaintrin.h clflushoptintrin.h xsavecintrin.h + xsavesintrin.h avx512dqintrin.h avx512bwintrin.h + avx512vlintrin.h avx512vlbwintrin.h avx512vldqintrin.h + avx512ifmaintrin.h avx512ifmavlintrin.h avx512vbmiintrin.h + avx512vbmivlintrin.h avx5124fmapsintrin.h avx5124vnniwintrin.h + avx512vpopcntdqintrin.h clwbintrin.h mwaitxintrin.h + clzerointrin.h pkuintrin.h sgxintrin.h cetintrin.h + gfniintrin.h cet.h avx512vbmi2intrin.h + avx512vbmi2vlintrin.h avx512vnniintrin.h + avx512vnnivlintrin.h vaesintrin.h vpclmulqdqintrin.h + avx512vpopcntdqvlintrin.h avx512bitalgintrin.h + pconfigintrin.h wbnoinvdintrin.h movdirintrin.h + waitpkgintrin.h cldemoteintrin.h avx512bf16vlintrin.h + avx512bf16intrin.h enqcmdintrin.h serializeintrin.h + avx512vp2intersectintrin.h avx512vp2intersectvlintrin.h + tsxldtrkintrin.h amxtileintrin.h amxint8intrin.h + amxbf16intrin.h x86gprintrin.h uintrintrin.h + hresetintrin.h keylockerintrin.h avxvnniintrin.h" + ;; +x86_64-*-*) + cpu_type=i386 + c_target_objs="i386-c.o" + cxx_target_objs="i386-c.o" + d_target_objs="i386-d.o" + extra_options="${extra_options} fused-madd.opt" + extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o i386-options.o i386-builtins.o i386-expand.o i386-features.o" + target_gtfiles="\$(srcdir)/config/i386/i386-builtins.c \$(srcdir)/config/i386/i386-expand.c \$(srcdir)/config/i386/i386-options.c" + extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h + pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h + nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h + immintrin.h x86intrin.h avxintrin.h xopintrin.h + ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h + lzcntintrin.h bmiintrin.h bmi2intrin.h tbmintrin.h + avx2intrin.h avx512fintrin.h fmaintrin.h f16cintrin.h + rtmintrin.h xtestintrin.h rdseedintrin.h prfchwintrin.h + adxintrin.h fxsrintrin.h xsaveintrin.h xsaveoptintrin.h + avx512cdintrin.h avx512erintrin.h avx512pfintrin.h + shaintrin.h clflushoptintrin.h xsavecintrin.h + xsavesintrin.h avx512dqintrin.h avx512bwintrin.h + avx512vlintrin.h avx512vlbwintrin.h avx512vldqintrin.h + avx512ifmaintrin.h avx512ifmavlintrin.h avx512vbmiintrin.h + avx512vbmivlintrin.h avx5124fmapsintrin.h avx5124vnniwintrin.h + avx512vpopcntdqintrin.h clwbintrin.h mwaitxintrin.h + clzerointrin.h pkuintrin.h sgxintrin.h cetintrin.h + gfniintrin.h cet.h avx512vbmi2intrin.h + avx512vbmi2vlintrin.h avx512vnniintrin.h + avx512vnnivlintrin.h vaesintrin.h vpclmulqdqintrin.h + avx512vpopcntdqvlintrin.h avx512bitalgintrin.h + pconfigintrin.h wbnoinvdintrin.h movdirintrin.h + waitpkgintrin.h cldemoteintrin.h avx512bf16vlintrin.h + avx512bf16intrin.h enqcmdintrin.h serializeintrin.h + avx512vp2intersectintrin.h avx512vp2intersectvlintrin.h + tsxldtrkintrin.h amxtileintrin.h amxint8intrin.h + amxbf16intrin.h x86gprintrin.h uintrintrin.h + hresetintrin.h keylockerintrin.h avxvnniintrin.h" + ;; +ia64-*-*) + extra_headers=ia64intrin.h + extra_options="${extra_options} g.opt fused-madd.opt" + ;; +hppa*-*-*) + cpu_type=pa + ;; +lm32*) + extra_options="${extra_options} g.opt" + ;; +m32r*-*-*) + cpu_type=m32r + extra_options="${extra_options} g.opt" + ;; +m68k-*-*) + extra_headers=math-68881.h + extra_options="${extra_options} m68k/m68k-tables.opt" + ;; +microblaze*-*-*) + cpu_type=microblaze + extra_options="${extra_options} g.opt" + ;; +mips*-*-*) + cpu_type=mips + d_target_objs="mips-d.o" + extra_headers="loongson.h loongson-mmiintrin.h msa.h" + extra_objs="frame-header-opt.o" + extra_options="${extra_options} g.opt fused-madd.opt mips/mips-tables.opt" + ;; +nds32*) + cpu_type=nds32 + extra_headers="nds32_intrinsic.h nds32_isr.h nds32_init.inc" + case ${target} in + nds32*-*-linux*) + extra_options="${extra_options} nds32/nds32-linux.opt" + ;; + nds32*-*-elf*) + extra_options="${extra_options} nds32/nds32-elf.opt" + ;; + *) + ;; + esac + extra_objs="nds32-cost.o nds32-intrinsic.o nds32-isr.o nds32-md-auxiliary.o nds32-pipelines-auxiliary.o nds32-predicates.o nds32-memory-manipulation.o nds32-fp-as-gp.o nds32-relax-opt.o nds32-utils.o" + ;; +nios2-*-*) + cpu_type=nios2 + extra_options="${extra_options} g.opt" + ;; +nvptx-*-*) + cpu_type=nvptx + ;; +or1k*-*-*) + cpu_type=or1k + ;; +powerpc*-*-*) + cpu_type=rs6000 + extra_objs="rs6000-string.o rs6000-p8swap.o rs6000-logue.o" + extra_objs="${extra_objs} rs6000-call.o rs6000-pcrel-opt.o" + extra_headers="ppc-asm.h altivec.h htmintrin.h htmxlintrin.h" + extra_headers="${extra_headers} bmi2intrin.h bmiintrin.h" + extra_headers="${extra_headers} xmmintrin.h mm_malloc.h emmintrin.h" + extra_headers="${extra_headers} mmintrin.h x86intrin.h" + extra_headers="${extra_headers} pmmintrin.h tmmintrin.h smmintrin.h" + extra_headers="${extra_headers} ppu_intrinsics.h spu2vmx.h vec_types.h si2vmx.h" + extra_headers="${extra_headers} amo.h" + case x$with_cpu in + xpowerpc64|xdefault64|x6[23]0|x970|xG5|xpower[3456789]|xpower10|xpower6x|xrs64a|xcell|xa2|xe500mc64|xe5500|xe6500) + cpu_is_64bit=yes + ;; + esac + extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt" + target_gtfiles="$target_gtfiles \$(srcdir)/config/rs6000/rs6000-logue.c \$(srcdir)/config/rs6000/rs6000-call.c" + target_gtfiles="$target_gtfiles \$(srcdir)/config/rs6000/rs6000-pcrel-opt.c" + ;; +pru-*-*) + cpu_type=pru + ;; +riscv*) + cpu_type=riscv + extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o" + d_target_objs="riscv-d.o" + ;; +rs6000*-*-*) + extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt" + extra_objs="rs6000-string.o rs6000-p8swap.o rs6000-logue.o" + extra_objs="${extra_objs} rs6000-call.o rs6000-pcrel-opt.o" + target_gtfiles="$target_gtfiles \$(srcdir)/config/rs6000/rs6000-logue.c \$(srcdir)/config/rs6000/rs6000-call.c" + target_gtfiles="$target_gtfiles \$(srcdir)/config/rs6000/rs6000-pcrel-opt.c" + ;; +sparc*-*-*) + cpu_type=sparc + c_target_objs="sparc-c.o" + cxx_target_objs="sparc-c.o" + d_target_objs="sparc-d.o" + extra_headers="visintrin.h" + ;; +s390*-*-*) + cpu_type=s390 + d_target_objs="s390-d.o" + extra_options="${extra_options} fused-madd.opt" + extra_headers="s390intrin.h htmintrin.h htmxlintrin.h vecintrin.h" + ;; +# Note the 'l'; we need to be able to match e.g. "shle" or "shl". +sh[123456789lbe]*-*-* | sh-*-*) + cpu_type=sh + extra_options="${extra_options} fused-madd.opt" + extra_objs="${extra_objs} sh_treg_combine.o sh-mem.o sh_optimize_sett_clrt.o" + ;; +v850*-*-*) + cpu_type=v850 + ;; +tic6x-*-*) + cpu_type=c6x + extra_headers="c6x_intrinsics.h" + extra_options="${extra_options} c6x/c6x-tables.opt" + ;; +xtensa*-*-*) + extra_options="${extra_options} fused-madd.opt" + ;; +tilegx*-*-*) + cpu_type=tilegx + ;; +tilepro*-*-*) + cpu_type=tilepro + ;; +esac + +tm_file=${cpu_type}/${cpu_type}.h +tm_d_file=${cpu_type}/${cpu_type}.h +if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-protos.h +then + tm_p_file=${cpu_type}/${cpu_type}-protos.h + tm_d_file="${tm_d_file} ${cpu_type}/${cpu_type}-protos.h" +fi + +extra_modes= +if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-modes.def +then + extra_modes=${cpu_type}/${cpu_type}-modes.def +fi +if test -f ${srcdir}/config/${cpu_type}/${cpu_type}.opt +then + extra_options="${extra_options} ${cpu_type}/${cpu_type}.opt" +fi + +case ${target} in +aarch64*-*-*) + tm_p_file="${tm_p_file} arm/aarch-common-protos.h" + case ${with_abi} in + "") + if test "x$with_multilib_list" = xilp32; then + tm_file="aarch64/biarchilp32.h ${tm_file}" + else + tm_file="aarch64/biarchlp64.h ${tm_file}" + fi + ;; + ilp32) + tm_file="aarch64/biarchilp32.h ${tm_file}" + ;; + lp64) + tm_file="aarch64/biarchlp64.h ${tm_file}" + ;; + *) + echo "Unknown ABI used in --with-abi=$with_abi" + exit 1 + esac + ;; +i[34567]86-*-*) + if test "x$with_abi" != x; then + echo "This target does not support --with-abi." + exit 1 + fi + ;; +x86_64-*-*) + case ${with_abi} in + "") + if test "x$with_multilib_list" = xmx32; then + tm_file="i386/biarchx32.h ${tm_file}" + else + tm_file="i386/biarch64.h ${tm_file}" + fi + ;; + 64 | m64) + tm_file="i386/biarch64.h ${tm_file}" + ;; + x32 | mx32) + tm_file="i386/biarchx32.h ${tm_file}" + ;; + *) + echo "Unknown ABI used in --with-abi=$with_abi" + exit 1 + esac + ;; +arm*-*-*) + tm_p_file="arm/arm-flags.h ${tm_p_file} arm/aarch-common-protos.h" + ;; +esac + +# On a.out targets, we need to use collect2. +case ${target} in +*-*-*aout*) + use_collect2=yes + ;; +esac + +# Common C libraries. +tm_defines="$tm_defines LIBC_GLIBC=1 LIBC_UCLIBC=2 LIBC_BIONIC=3 LIBC_MUSL=4" + +# 32-bit x86 processors supported by --with-arch=. Each processor +# MUST be separated by exactly one space. +x86_archs="athlon athlon-4 athlon-fx athlon-mp athlon-tbird \ +athlon-xp k6 k6-2 k6-3 geode c3 c3-2 winchip-c6 winchip2 i386 i486 \ +i586 i686 pentium pentium-m pentium-mmx pentium2 pentium3 pentium3m \ +pentium4 pentium4m pentiumpro prescott lakemont samuel-2 nehemiah \ +c7 esther" + +# 64-bit x86 processors supported by --with-arch=. Each processor +# MUST be separated by exactly one space. +x86_64_archs="amdfam10 athlon64 athlon64-sse3 barcelona bdver1 bdver2 \ +bdver3 bdver4 znver1 znver2 znver3 btver1 btver2 k8 k8-sse3 opteron \ +opteron-sse3 nocona core2 corei7 corei7-avx core-avx-i core-avx2 atom \ +slm nehalem westmere sandybridge ivybridge haswell broadwell bonnell \ +silvermont knl knm skylake-avx512 cannonlake icelake-client icelake-server \ +skylake goldmont goldmont-plus tremont cascadelake tigerlake cooperlake \ +sapphirerapids alderlake rocketlake eden-x2 nano nano-1000 nano-2000 nano-3000 \ +nano-x2 eden-x4 nano-x4 x86-64 x86-64-v2 x86-64-v3 x86-64-v4 native" + +# Additional x86 processors supported by --with-cpu=. Each processor +# MUST be separated by exactly one space. +x86_cpus="generic intel" + +# Common parts for widely ported systems. +case ${target} in +*-*-darwin*) + tmake_file="t-darwin " + tm_file="${tm_file} darwin.h" + darwin_os=`echo ${target} | sed 's/.*darwin\([0-9.]*\).*$/\1/'` + darwin_maj=`expr "$darwin_os" : '\([0-9]*\).*'` + macos_min=`expr "$darwin_os" : '[0-9]*\.\([0-9]*\).*'` + macos_maj=10 + if test x"${macos_min}" = x; then + macos_min=0 + fi + def_ld64=85.2 + case ${target} in + # Darwin 4 to 19 correspond to macOS 10.0 to 10.15 + *-*-darwin[4-9]* | *-*-darwin1[0-9]*) + macos_min=`expr $darwin_maj - 4` + ;; + *-*-darwin20*) + # Darwin 20 corresponds to macOS 11. + macos_maj=11 + def_ld64=609.0 + ;; + *-*-darwin) + case ${cpu_type} in + aarch64) macos_maj=11 ;; + x86_64) macos_min=6 ;; + *) macos_min=5 ;; + esac + case ${host} in + *-*-darwin*) tm_defines="$tm_defines DARWIN_USE_KERNEL_VERS" ;; + *) + # If configuring a cross-compiler then we will have set some + # default above, but it is probably not what was intended. + echo "Warning: Using ${target} is only suitable for Darwin hosts" 1>&2 + echo "configure with an explicit target version" 1>&2 + ;; + esac + ;; + *) + echo "Error: configuring for an unreleased macOS version ${target}" 1>&2 + exit 1 + ;; + esac + tm_defines="$tm_defines DEF_MIN_OSX_VERSION=\\\"${macos_maj}.${macos_min}\\\"" + tm_defines="$tm_defines DEF_LD64=\\\"${def_ld64}\\\"" + tm_file="${tm_file} ${cpu_type}/darwin.h" + tm_p_file="${tm_p_file} darwin-protos.h" + target_gtfiles="$target_gtfiles \$(srcdir)/config/darwin.c" + extra_options="${extra_options} darwin.opt" + c_target_objs="${c_target_objs} darwin-c.o" + cxx_target_objs="${cxx_target_objs} darwin-c.o" + d_target_objs="${d_target_objs} darwin-d.o" + fortran_target_objs="darwin-f.o" + target_has_targetcm=yes + target_has_targetdm=yes + extra_objs="${extra_objs} darwin.o" + extra_gcc_objs="darwin-driver.o" + default_use_cxa_atexit=yes + use_gcc_stdint=wrap + case ${enable_threads} in + "" | yes | posix) thread_file='posix' ;; + esac + ;; +*-*-dragonfly*) + gas=yes + gnu_ld=yes + tmake_file="t-slibgcc" + case ${enable_threads} in + "" | yes | posix) + thread_file='posix' + ;; + no | single) + # Let these non-posix thread selections fall through if requested + ;; + *) + echo 'Unknown thread configuration for DragonFly BSD' + exit 1 + ;; + esac + extra_options="$extra_options rpath.opt dragonfly.opt" + default_use_cxa_atexit=yes + use_gcc_stdint=wrap + d_target_objs="${d_target_objs} dragonfly-d.o" + tmake_file="${tmake_file} t-dragonfly" + target_has_targetdm=yes + ;; +*-*-freebsd*) + # This is the generic ELF configuration of FreeBSD. Later + # machine-specific sections may refine and add to this + # configuration. + # + # Due to tm_file entry ordering issues that vary between cpu + # architectures, we only define fbsd_tm_file to allow the + # machine-specific section to dictate the final order of all + # entries of tm_file with the minor exception that components + # of the tm_file set here will always be of the form: + # + # freebsd.h [freebsd-.h ...] freebsd-spec.h freebsd.h + # + # The machine-specific section should not tamper with this + # ordering but may order all other entries of tm_file as it + # pleases around the provided core setting. + gas=yes + gnu_ld=yes + fbsd_major=`echo ${target} | sed -e 's/.*freebsd//g' | sed -e 's/\..*//g'` + if test "$fbsd_major" = ""; then + echo "Specify the major version number of the targeted FreeBSD release" + echo "like this: --target=amd64-unknown-freebsd10.1" + exit 1 + fi + tm_defines="${tm_defines} FBSD_MAJOR=${fbsd_major}" + tmake_file="t-slibgcc" + case ${enable_threads} in + no) + fbsd_tm_file="${fbsd_tm_file} freebsd-nthr.h" + ;; + "" | yes | posix) + thread_file='posix' + ;; + *) + echo 'Unknown thread configuration for FreeBSD' + exit 1 + ;; + esac + fbsd_tm_file="${fbsd_tm_file} freebsd-spec.h freebsd.h freebsd-stdint.h" + extra_options="$extra_options rpath.opt freebsd.opt" + case ${target} in + *-*-freebsd[345].*) + :;; + *) + default_use_cxa_atexit=yes;; + esac + use_gcc_stdint=wrap + d_target_objs="${d_target_objs} freebsd-d.o" + tmake_file="${tmake_file} t-freebsd" + target_has_targetdm=yes + ;; +*-*-fuchsia*) + native_system_header_dir=/include + ;; +*-*-essence*) + gas=yes + gnu_ld=yes + native_system_header_dir=/Applications/POSIX/include + ;; +*-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu | *-*-uclinuxfdpiceabi) + extra_options="$extra_options gnu-user.opt" + gas=yes + gnu_ld=yes + case ${enable_threads} in + "" | yes | posix) thread_file='posix' ;; + esac + tmake_file="t-slibgcc" + case $target in + *-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-kopensolaris*-gnu) + :;; + *-*-gnu*) + native_system_header_dir=/include + ;; + esac + # Linux C libraries selection switch: glibc / uclibc / bionic. + # uclibc and bionic aren't usable for GNU/Hurd and neither for GNU/k*BSD. + case $target in + *linux*) + tm_p_file="${tm_p_file} linux-protos.h" + tmake_file="${tmake_file} t-linux" + extra_objs="${extra_objs} linux.o" + extra_options="${extra_options} linux.opt" + ;; + esac + case $target in + *-*-*android*) + tm_defines="$tm_defines DEFAULT_LIBC=LIBC_BIONIC" + ;; + *-*-*uclibc* | *-*-uclinuxfdpiceabi) + tm_defines="$tm_defines DEFAULT_LIBC=LIBC_UCLIBC" + ;; + *-*-*musl*) + tm_defines="$tm_defines DEFAULT_LIBC=LIBC_MUSL" + ;; + *) + tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC" + ;; + esac + # Assume that glibc or uClibc or Bionic are being used and so __cxa_atexit + # is provided. + default_use_cxa_atexit=yes + use_gcc_tgmath=no + use_gcc_stdint=wrap + # Enable compilation for Android by default for *android* targets. + case $target in + *-*-*android*) + tm_defines="$tm_defines ANDROID_DEFAULT=1" + ;; + *) + tm_defines="$tm_defines ANDROID_DEFAULT=0" + ;; + esac + c_target_objs="${c_target_objs} glibc-c.o" + cxx_target_objs="${cxx_target_objs} glibc-c.o" + d_target_objs="${d_target_objs} glibc-d.o" + tmake_file="${tmake_file} t-glibc" + target_has_targetcm=yes + target_has_targetdm=yes + ;; +*-*-netbsd*) + tm_p_file="${tm_p_file} netbsd-protos.h" + tmake_file="t-netbsd t-slibgcc" + extra_objs="${extra_objs} netbsd.o" + d_target_objs="${d_target_objs} netbsd-d.o" + gas=yes + gnu_ld=yes + use_gcc_stdint=wrap + case ${enable_threads} in + "" | yes | posix) thread_file='posix' ;; + esac + nbsd_tm_file="netbsd.h netbsd-stdint.h netbsd-elf.h" + default_use_cxa_atexit=yes + target_has_targetdm=yes + case ${target} in + arm*-* | i[34567]86-* | powerpc*-* | sparc*-* | x86_64-*) + default_gnu_indirect_function=yes + ;; + esac + ;; +*-*-openbsd*) + tmake_file="t-openbsd" + case ${enable_threads} in + yes) + thread_file='posix' + ;; + esac + case ${target} in + *-*-openbsd4.[3-9]|*-*-openbsd[5-9]*) + default_use_cxa_atexit=yes + ;; + esac + d_target_objs="${d_target_objs} openbsd-d.o" + target_has_targetdm=yes + ;; +*-*-phoenix*) + gas=yes + gnu_ld=yes + default_use_cxa_atexit=yes + ;; +*-*-rtems*) + case ${enable_threads} in + "" | yes | rtems) thread_file='rtems' ;; + posix) thread_file='posix' ;; + no) ;; + *) + echo 'Unknown thread configuration for RTEMS' + exit 1 + ;; + esac + tmake_file="${tmake_file} t-rtems" + extra_options="${extra_options} rtems.opt" + default_use_cxa_atexit=yes + use_gcc_stdint=wrap + ;; +*-*-uclinux*) + extra_options="$extra_options gnu-user.opt" + use_gcc_stdint=wrap + case ${enable_threads} in + "" | yes | posix) thread_file='posix' ;; + esac + tm_defines="$tm_defines DEFAULT_LIBC=LIBC_UCLIBC SINGLE_LIBC" + ;; +*-*-rdos*) + use_gcc_stdint=wrap + ;; +*-*-solaris2*) + # i?86-*-solaris2* needs to insert headers between cpu default and + # Solaris 2 specific ones. + sol2_tm_file_head="dbxelf.h elfos.h ${cpu_type}/sysv4.h" + sol2_tm_file_tail="${cpu_type}/sol2.h sol2.h" + sol2_tm_file="${sol2_tm_file_head} ${sol2_tm_file_tail}" + case ${target} in + *-*-solaris2.1[1-9]*) + # __cxa_atexit was introduced in Solaris 11.4. + default_use_cxa_atexit=yes + ;; + esac + use_gcc_stdint=wrap + if test x$gnu_ld = xyes; then + tm_file="usegld.h ${tm_file}" + fi + if test x$gas = xyes; then + tm_file="usegas.h ${tm_file}" + fi + tm_p_file="${tm_p_file} sol2-protos.h" + tmake_file="${tmake_file} t-sol2 t-slibgcc" + c_target_objs="${c_target_objs} sol2-c.o" + cxx_target_objs="${cxx_target_objs} sol2-c.o sol2-cxx.o" + d_target_objs="${d_target_objs} sol2-d.o" + extra_objs="${extra_objs} sol2.o sol2-stubs.o" + extra_options="${extra_options} sol2.opt" + case ${enable_threads}:${have_pthread_h}:${have_thread_h} in + "":yes:* | yes:yes:* ) + thread_file=posix + ;; + esac + target_has_targetdm=yes + ;; +*-*-*vms*) + extra_options="${extra_options} vms/vms.opt" + xmake_file=vms/x-vms + tmake_file="vms/t-vms t-slibgcc" + extra_objs="vms.o" + target_gtfiles="$target_gtfiles \$(srcdir)/config/vms/vms.c" + tm_p_file="${tm_p_file} vms/vms-protos.h" + xm_file="vms/xm-vms.h" + c_target_objs="vms-c.o" + cxx_target_objs="vms-c.o" + fortran_target_objs="vms-f.o" + use_gcc_stdint=provide + tm_file="${tm_file} vms/vms-stdint.h" + if test x$gnu_ld != xyes; then + # Build wrappers for native case. + extra_programs="ld\$(exeext) ar\$(exeext)" + tmake_file="$tmake_file vms/t-vmsnative" + fi + ;; +*-*-vxworks*) + tmake_file=t-vxworks + xm_defines=POSIX + + extra_options="${extra_options} vxworks.opt" + extra_objs="$extra_objs vxworks.o" + + c_target_objs="${c_target_objs} vxworks-c.o" + cxx_target_objs="${cxx_target_objs} vxworks-c.o" + extra_headers="${extra_headers} ../vxworks/vxworks-predef.h" + target_has_targetcm="yes" + + # This private header exposes a consistent interface for checks on + # the VxWorks version our runtime header files need to perform, based on + # what the system headers adverstise: + + extra_headers="${extra_headers} ../vxworks/_vxworks-versions.h" + + # Starting from VxWorks 7, the system comes with a Dinkumware + # environment which requires the inclusion of "yvals.h" before other + # system headers. We provide wrapped versions of a few headers to + # accomodate such constraints: + + extra_headers="${extra_headers} ../vxworks/_yvals.h" + extra_headers="${extra_headers} ../vxworks/_yvals-wrapper.h" + + extra_headers="${extra_headers} ../vxworks/math.h ../vxworks/complex.h" + extra_headers="${extra_headers} ../vxworks/inttypes.h ../vxworks/setjmp.h" + + # We provide stdint.h ... + + tm_file="${tm_file} vxworks-stdint.h" + + # .. only through the yvals conditional wrapping mentioned above + # to abide by the VxWorks 7 expectations. The final copy is performed + # explicitly by a t-vxworks Makefile rule. + + use_gcc_stdint=none + extra_headers="${extra_headers} ../../ginclude/stdint-gcc.h" + + case ${enable_threads} in + no) ;; + "" | yes | vxworks) thread_file='vxworks' ;; + *) echo 'Unknown thread configuration for VxWorks'; exit 1 ;; + esac + + # A few common macro definitions conveying general characteristics + # of the configuration at hand. Note that by VxWorks 7, we mean the + # the SR6xx major update or beyond in vendor parlance: + + case $target in + *-*-vxworks7*) + tm_defines="$tm_defines TARGET_VXWORKS7=1" + ;; + esac + case $target in + *64-*-vxworks*) + tm_defines="$tm_defines TARGET_VXWORKS64=1" + ;; + esac + + # Then a few build configuration controls for VxWorks 7, which + # has specificities on top of which we aim to provide more complete + # C++ support: + + case $target in + *-*-vxworks7*) + # VxWorks 7 always has init/fini_array support and it is simpler to + # just leverage this, sticking to what the system toolchain does: + gcc_cv_initfini_array=yes + ;; + esac + ;; +*-*-elf|arc*-*-elf*) + # Assume that newlib is being used and so __cxa_atexit is provided. + default_use_cxa_atexit=yes + use_gcc_stdint=wrap + ;; +esac + +case ${target} in +aarch64*-*-elf | aarch64*-*-fuchsia* | aarch64*-*-rtems*) + tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h" + tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-errata.h aarch64/aarch64-elf-raw.h" + tmake_file="${tmake_file} aarch64/t-aarch64" + case $target in + aarch64-*-elf*) + use_gcc_stdint=wrap + ;; + aarch64-*-fuchsia*) + tm_file="${tm_file} fuchsia.h" + ;; + aarch64-*-rtems*) + tm_file="${tm_file} aarch64/rtems.h rtems.h" + ;; + esac + case $target in + aarch64_be-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + aarch64_multilibs="${with_multilib_list}" + if test "$aarch64_multilibs" = "default"; then + aarch64_multilibs="lp64,ilp32" + fi + aarch64_multilibs=`echo $aarch64_multilibs | sed -e 's/,/ /g'` + for aarch64_multilib in ${aarch64_multilibs}; do + case ${aarch64_multilib} in + ilp32 | lp64 ) + TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG},${aarch64_multilib}" + ;; + *) + echo "--with-multilib-list=${aarch64_multilib} not supported." + exit 1 + esac + done + TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's/^,//'` + ;; +aarch64*-*-freebsd*) + tm_file="${tm_file} dbxelf.h elfos.h ${fbsd_tm_file}" + tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-errata.h aarch64/aarch64-freebsd.h" + tmake_file="${tmake_file} aarch64/t-aarch64 aarch64/t-aarch64-freebsd" + tm_defines="${tm_defines} TARGET_DEFAULT_ASYNC_UNWIND_TABLES=1" + ;; +aarch64*-*-netbsd*) + tm_file="${tm_file} dbxelf.h elfos.h ${nbsd_tm_file}" + tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-errata.h aarch64/aarch64-netbsd.h" + tmake_file="${tmake_file} aarch64/t-aarch64 aarch64/t-aarch64-netbsd" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + ;; +aarch64*-*-linux*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h" + tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-errata.h aarch64/aarch64-linux.h" + tmake_file="${tmake_file} aarch64/t-aarch64 aarch64/t-aarch64-linux" + tm_defines="${tm_defines} TARGET_DEFAULT_ASYNC_UNWIND_TABLES=1" + case $target in + aarch64_be-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + aarch64_multilibs="${with_multilib_list}" + if test "$aarch64_multilibs" = "default"; then + # TODO: turn on ILP32 multilib build after its support is mature. + # aarch64_multilibs="lp64,ilp32" + aarch64_multilibs="lp64" + fi + aarch64_multilibs=`echo $aarch64_multilibs | sed -e 's/,/ /g'` + for aarch64_multilib in ${aarch64_multilibs}; do + case ${aarch64_multilib} in + ilp32 | lp64 ) + TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG},${aarch64_multilib}" + ;; + *) + echo "--with-multilib-list=${aarch64_multilib} not supported." + exit 1 + esac + done + TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's/^,//'` + ;; +aarch64*-wrs-vxworks*) + tm_file="${tm_file} elfos.h aarch64/aarch64-elf.h" + tm_file="${tm_file} vx-common.h vxworks.h aarch64/aarch64-vxworks.h" + tmake_file="${tmake_file} aarch64/t-aarch64 aarch64/t-aarch64-vxworks" + ;; +alpha*-*-linux*) + tm_file="elfos.h ${tm_file} alpha/elf.h alpha/linux.h alpha/linux-elf.h glibc-stdint.h" + tmake_file="${tmake_file} alpha/t-linux alpha/t-alpha" + extra_options="${extra_options} alpha/elf.opt" + ;; +alpha*-*-netbsd*) + tm_file="elfos.h ${tm_file} ${nbsd_tm_file} alpha/elf.h alpha/netbsd.h" + tmake_file="${tmake_file} alpha/t-alpha" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt \ + alpha/elf.opt" + ;; +alpha*-*-openbsd*) + tm_defines="${tm_defines} OBSD_HAS_DECLARE_FUNCTION_NAME OBSD_HAS_DECLARE_FUNCTION_SIZE OBSD_HAS_DECLARE_OBJECT" + tm_file="elfos.h alpha/alpha.h alpha/elf.h openbsd.h openbsd-stdint.h alpha/openbsd.h openbsd-libpthread.h" + tmake_file="${tmake_file} alpha/t-alpha" + extra_options="${extra_options} openbsd.opt alpha/elf.opt" + # default x-alpha is only appropriate for dec-osf. + ;; +alpha*-dec-*vms*) + tm_file="${tm_file} vms/vms.h alpha/vms.h" + tmake_file="${tmake_file} alpha/t-vms alpha/t-alpha" + ;; +arc*-*-elf*) + tm_file="arc/arc-arch.h dbxelf.h elfos.h newlib-stdint.h arc/elf.h ${tm_file}" + tmake_file="arc/t-multilib arc/t-arc" + extra_gcc_objs="driver-arc.o" + if test "x$with_cpu" != x; then + tm_defines="${tm_defines} TARGET_CPU_BUILD=PROCESSOR_$with_cpu" + fi + if test x${with_endian} = x; then + case ${target} in + arc*be-*-* | arc*eb-*-*) with_endian=big ;; + *) with_endian=little ;; + esac + fi + case ${with_endian} in + big|little) ;; + *) echo "with_endian=${with_endian} not supported."; exit 1 ;; + esac + case ${with_endian} in + big*) tm_file="arc/big.h ${tm_file}" + esac + ;; +arc*-*-linux*) + tm_file="arc/arc-arch.h dbxelf.h elfos.h gnu-user.h linux.h linux-android.h glibc-stdint.h arc/linux.h ${tm_file}" + tmake_file="${tmake_file} arc/t-multilib-linux arc/t-arc" + extra_gcc_objs="driver-arc.o" + if test "x$with_cpu" != x; then + tm_defines="${tm_defines} TARGET_CPU_BUILD=PROCESSOR_$with_cpu" + fi + if test x${with_endian} = x; then + case ${target} in + arc*be-*-* | arc*eb-*-*) with_endian=big ;; + *) with_endian=little ;; + esac + fi + case ${with_endian} in + big|little) ;; + *) echo "with_endian=${with_endian} not supported."; exit 1 ;; + esac + case ${with_endian} in + big*) tm_file="arc/big.h ${tm_file}" + esac + # Force .init_array support. The configure script cannot always + # automatically detect that GAS supports it, yet we require it. + gcc_cv_initfini_array=yes + ;; +arm-wrs-vxworks7*) + # We only support VxWorks 7 now on ARM, post SR600. Pre SR600 + # VxWorks 7 was transitory and major versions prior to 7 were based + # on long deprecated ABI, not supported at all any more regardless + # of VxWorks. + extra_options="${extra_options} arm/vxworks.opt" + tmake_file="${tmake_file} arm/t-arm arm/t-vxworks arm/t-bpabi" + tm_file="elfos.h arm/elf.h arm/bpabi.h arm/aout.h ${tm_file}" + tm_file="${tm_file} vx-common.h vxworks.h arm/vxworks.h" + target_cpu_cname="generic-armv7-a" + need_64bit_hwint=yes + ;; +arm*-*-freebsd*) # ARM FreeBSD EABI + tm_file="dbxelf.h elfos.h ${fbsd_tm_file} arm/elf.h" + case $target in + arm*b-*-freebsd*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + tmake_file="${tmake_file} arm/t-arm arm/t-bpabi" + tm_file="${tm_file} arm/bpabi.h arm/freebsd.h arm/aout.h arm/arm.h" + case $target in + armv6*-*-freebsd*) + target_cpu_cname="arm1176jzf-s" + if test $fbsd_major -ge 11; then + tm_defines="${tm_defines} TARGET_FREEBSD_ARM_HARD_FLOAT=1" + fi + ;; + armv7*-*-freebsd*) + target_cpu_cname="generic-armv7-a" + tm_defines="${tm_defines} TARGET_FREEBSD_ARM_HARD_FLOAT=1" + ;; + *) + target_cpu_cname="arm9" + ;; + esac + with_tls=${with_tls:-gnu} + ;; +arm*-*-netbsdelf*) + target_cpu_cname="strongarm" + tmake_file="${tmake_file} arm/t-arm" + tm_file="dbxelf.h elfos.h ${nbsd_tm_file} arm/elf.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + case ${target} in + arm*eb-*) tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" ;; + esac + case ${target} in + arm*-*-netbsdelf-*eabi*) + tm_file="$tm_file arm/bpabi.h arm/netbsd-elf.h arm/netbsd-eabi.h" + tmake_file="$tmake_file arm/t-bpabi arm/t-netbsdeabi" + ;; + *) + tm_file="$tm_file arm/netbsd-elf.h" + tmake_file="$tmake_file arm/t-netbsd" + ;; + esac + tm_file="${tm_file} arm/aout.h arm/arm.h" + case ${target} in + arm*-*-netbsdelf-*eabihf*) + # Hard-float requires at least Arm v5te + target_cpu_cname="arm10e" + tm_defines="${tm_defines} TARGET_DEFAULT_FLOAT_ABI=ARM_FLOAT_ABI_HARD" + ;; + esac + case ${target} in + armv6*) target_cpu_cname="arm1176jzf-s";; + armv7*) target_cpu_cname="generic-armv7-a";; + esac + ;; +arm*-*-linux-* | arm*-*-uclinuxfdpiceabi) + tm_file="dbxelf.h elfos.h gnu-user.h linux.h linux-android.h glibc-stdint.h arm/elf.h arm/linux-gas.h arm/linux-elf.h" + extra_options="${extra_options} linux-android.opt" + case $target in + arm*b-*-linux*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + tmake_file="${tmake_file} arm/t-arm arm/t-arm-elf arm/t-bpabi arm/t-linux-eabi" + tm_file="$tm_file arm/bpabi.h arm/linux-eabi.h arm/aout.h arm/arm.h" + case $target in + arm*-*-uclinuxfdpiceabi) + tm_file="$tm_file arm/uclinuxfdpiceabi.h" + ;; + esac + # Generation of floating-point instructions requires at least ARMv5te. + if [ "$with_float" = "hard" -o "$with_float" = "softfp" ] ; then + target_cpu_cname="arm10e" + else + target_cpu_cname="arm10tdmi" + fi + # Define multilib configuration for arm-linux-androideabi. + case ${target} in + *-androideabi) + tmake_file="$tmake_file arm/t-linux-androideabi" + ;; + esac + # The EABI requires the use of __cxa_atexit. + default_use_cxa_atexit=yes + with_tls=${with_tls:-gnu} + ;; +arm*-*-uclinux*eabi*) # ARM ucLinux + tm_file="dbxelf.h elfos.h arm/unknown-elf.h arm/elf.h arm/linux-gas.h arm/uclinux-elf.h glibc-stdint.h" + tmake_file="${tmake_file} arm/t-arm arm/t-arm-elf arm/t-bpabi" + tm_file="$tm_file arm/bpabi.h arm/uclinux-eabi.h arm/aout.h arm/arm.h" + target_cpu_cname="arm7tdmi" + # The EABI requires the use of __cxa_atexit. + default_use_cxa_atexit=yes + ;; +arm*-*-phoenix*) + tm_file="elfos.h arm/unknown-elf.h arm/elf.h arm/bpabi.h" + tm_file="${tm_file} newlib-stdint.h phoenix.h" + tm_file="${tm_file} arm/aout.h arm/arm.h" + tmake_file="${tmake_file} arm/t-arm arm/t-bpabi arm/t-phoenix" + target_cpu_cname="arm7tdmi" + ;; +arm*-*-eabi* | arm*-*-symbianelf* | arm*-*-rtems* | arm*-*-fuchsia*) + case ${target} in + arm*eb-*-eabi*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + esac + default_use_cxa_atexit=yes + tm_file="dbxelf.h elfos.h arm/unknown-elf.h arm/elf.h arm/bpabi.h" + tmake_file="${tmake_file} arm/t-arm arm/t-arm-elf" + target_cpu_cname="arm7tdmi" + case ${target} in + arm*-*-eabi*) + tm_file="$tm_file newlib-stdint.h" + tmake_file="${tmake_file} arm/t-bpabi" + use_gcc_stdint=wrap + ;; + arm*-*-fuchsia*) + tm_file="${tm_file} fuchsia.h arm/fuchsia-elf.h glibc-stdint.h" + tmake_file="${tmake_file} arm/t-bpabi arm/t-fuchsia" + target_cpu_cname="generic-armv7-a" + ;; + arm*-*-rtems*) + tm_file="${tm_file} arm/rtems.h rtems.h newlib-stdint.h" + tmake_file="${tmake_file} arm/t-bpabi arm/t-rtems" + ;; + arm*-*-symbianelf*) + tm_file="${tm_file} arm/symbian.h" + # We do not include t-bpabi for Symbian OS because the system + # provides its own implementation of the BPABI functions. + tmake_file="${tmake_file} arm/t-symbian" + target_cpu_cname="arm10tdmi" + ;; + esac + tm_file="${tm_file} arm/aout.h arm/arm.h" + ;; +avr-*-*) + tm_file="elfos.h avr/elf.h avr/avr-arch.h avr/avr.h avr/specs.h dbxelf.h avr/avr-stdint.h" + if test x${with_avrlibc} != xno; then + tm_file="${tm_file} ${cpu_type}/avrlibc.h" + tm_defines="${tm_defines} WITH_AVRLIBC" + fi + # Work out avr_double_comparison which is 2 or 3 and is used in + # target hook FLOAT_LIB_COMPARE_RETURNS_BOOL to determine whether + # DFmode comparisons return 3-state or 2-state results. + case y${with_double_comparison} in + y | ytristate) + avr_double_comparison=3 + ;; + ybool | ylibf7) + avr_double_comparison=2 + ;; + *) + echo "Error: --with-double-comparison= can only be used with: 'tristate', 'bool', 'libf7'" 1>&2 + exit 1 + ;; + esac + case "y${with_libf7}" in + yno) + # avr_double_comparison as set above. + ;; + ylibgcc) + avr_double_comparison=2 + tm_defines="${tm_defines} WITH_LIBF7_LIBGCC" + ;; + y | yyes | ymath-symbols) + avr_double_comparison=2 + tm_defines="${tm_defines} WITH_LIBF7_LIBGCC" + tm_defines="${tm_defines} WITH_LIBF7_MATH" + tm_defines="${tm_defines} WITH_LIBF7_MATH_SYMBOLS" + ;; + ymath) + avr_double_comparison=2 + tm_defines="${tm_defines} WITH_LIBF7_LIBGCC" + tm_defines="${tm_defines} WITH_LIBF7_MATH" + ;; + *) + echo "Error: --with-libf7=${with_libf7} but can only be used with: 'libgcc', 'math', 'math-symbols', 'yes', 'no'" 1>&2 + exit 1 + ;; + esac + tm_defines="${tm_defines} WITH_DOUBLE_COMPARISON=${avr_double_comparison}" + case y${with_double} in + y32) + avr_double=32 + tm_defines="${tm_defines} HAVE_DOUBLE32" + ;; + y64) + avr_double=64 + tm_defines="${tm_defines} HAVE_DOUBLE64" + ;; + y64,32) + avr_double=64 + avr_double_multilib=1 + tm_defines="${tm_defines} HAVE_DOUBLE32" + tm_defines="${tm_defines} HAVE_DOUBLE64" + tm_defines="${tm_defines} HAVE_DOUBLE_MULTILIB" + ;; + y | y32,64) + avr_double=32 + avr_double_multilib=1 + tm_defines="${tm_defines} HAVE_DOUBLE32" + tm_defines="${tm_defines} HAVE_DOUBLE64" + tm_defines="${tm_defines} HAVE_DOUBLE_MULTILIB" + ;; + *) + echo "Error: --with-double= can only be used with: '32', '32,64', '64,32', '64'" 1>&2 + exit 1 + ;; + esac + case y${with_long_double} in + y32) + avr_long_double=32 + tm_defines="${tm_defines} HAVE_LONG_DOUBLE32" + ;; + y64) + avr_long_double=64 + tm_defines="${tm_defines} HAVE_LONG_DOUBLE64" + ;; + y | y64,32) + avr_long_double=64 + avr_long_double_multilib=1 + tm_defines="${tm_defines} HAVE_LONG_DOUBLE32" + tm_defines="${tm_defines} HAVE_LONG_DOUBLE64" + tm_defines="${tm_defines} HAVE_LONG_DOUBLE_MULTILIB" + ;; + y32,64) + avr_long_double=32 + avr_long_double_multilib=1 + tm_defines="${tm_defines} HAVE_LONG_DOUBLE32" + tm_defines="${tm_defines} HAVE_LONG_DOUBLE64" + tm_defines="${tm_defines} HAVE_LONG_DOUBLE_MULTILIB" + ;; + ydouble) + avr_long_double=${avr_double} + tm_defines="${tm_defines} HAVE_LONG_DOUBLE_IS_DOUBLE" + if test y${avr_double_multilib} = y1; then + tm_defines="${tm_defines} HAVE_LONG_DOUBLE32" + tm_defines="${tm_defines} HAVE_LONG_DOUBLE64" + else + tm_defines="${tm_defines} HAVE_LONG_DOUBLE${avr_long_double}" + fi + ;; + *) + echo "Error: --with-long_double= can only be used with: '32', '32,64', '64,32', '64', 'double'" 1>&2 + exit 1 + ;; + esac + if test ${avr_long_double}x${avr_long_double_multilib}y${avr_double_multilib}z = 32xy1z; then + if test y${with_long_double} != ydouble; then + echo "Error: --with-double=${with_double} requests a multilib for double, but long double is always 32 bits wide due to --with-long-double=${with_long_double}" 1>&2 + exit 1 + fi + fi + if test ${avr_double}x${avr_long_double_multilib}y${avr_double_multilib}z = 64x1yz; then + echo "Error: --with-long-double=${with_long_double} requests a multilib for long double, but double is always 64 bits wide due to --with-double=64" 1>&2 + exit 1 + fi + if test y${avr_double}${avr_long_double} = y6432; then + echo "Error: double default of 64 bits from --with-double=${with_double} conflicts with default of 32 bits for long double from --with-long-double=${with_long_double}" 1>&2 + exit 1 + fi + tm_defines="${tm_defines} WITH_DOUBLE${avr_double}" + tm_defines="${tm_defines} WITH_LONG_DOUBLE${avr_long_double}" + tmake_file="${tmake_file} avr/t-avr avr/t-multilib" + use_gcc_stdint=wrap + extra_gcc_objs="driver-avr.o avr-devices.o" + extra_objs="avr-devices.o avr-log.o" + ;; +bfin*-elf*) + tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h bfin/elf.h" + tmake_file=bfin/t-bfin-elf + use_collect2=no + ;; +bfin*-uclinux*) + tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h gnu-user.h linux.h glibc-stdint.h bfin/uclinux.h" + tmake_file=bfin/t-bfin-uclinux + use_collect2=no + ;; +bfin*-linux-uclibc*) + tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h gnu-user.h linux.h glibc-stdint.h bfin/linux.h ./linux-sysroot-suffix.h" + tmake_file="${tmake_file} bfin/t-bfin-linux" + use_collect2=no + ;; +bfin*-rtems*) + tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h bfin/rtems.h rtems.h newlib-stdint.h" + tmake_file="${tmake_file} bfin/t-rtems" + ;; +bfin*-*) + tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h bfin/elf.h" + use_collect2=no + use_gcc_stdint=wrap + ;; +bpf-*-*) + tm_file="elfos.h ${tm_file}" + tmake_file="${tmake_file} bpf/t-bpf" + use_collect2=no + extra_headers="bpf-helpers.h" + use_gcc_stdint=provide + ;; +cr16-*-elf) + tm_file="elfos.h ${tm_file} newlib-stdint.h" + tmake_file="${tmake_file} cr16/t-cr16 " + use_collect2=no + ;; +cris-*-elf | cris-*-none) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + tmake_file="cris/t-cris cris/t-elfmulti" + gas=yes + extra_options="${extra_options} cris/elf.opt" + use_gcc_stdint=wrap + ;; +csky-*-*) + if test x${with_endian} != x; then + case ${with_endian} in + big|little) ;; + *) + echo "with_endian=${with_endian} not supported." + exit 1 + ;; + esac + fi + if test x${with_float} != x; then + case ${with_float} in + soft | hard) ;; + *) echo + "Unknown floating point type used in --with-float=$with_float" + exit 1 + ;; + esac + fi + tm_file="csky/csky.h" + md_file="csky/csky.md" + out_file="csky/csky.c" + tm_p_file="${tm_p_file} csky/csky-protos.h" + extra_options="${extra_options} csky/csky_tables.opt" + + if test x${enable_tpf_debug} = xyes; then + tm_defines="${tm_defines} ENABLE_TPF_DEBUG" + fi + + case ${target} in + csky-*-elf*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file} csky/csky-elf.h" + tmake_file="csky/t-csky csky/t-csky-elf" + default_use_cxa_atexit=no + use_gcc_stdint=wrap + ;; + csky-*-linux*) + tm_file="dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h ${tm_file} csky/csky-linux-elf.h" + tmake_file="${tmake_file} csky/t-csky csky/t-csky-linux" + + if test "x${enable_multilib}" = xyes ; then + tm_file="$tm_file ./sysroot-suffix.h" + tmake_file="${tmake_file} csky/t-sysroot-suffix" + fi + + case ${target} in + csky-*-linux-gnu*) + tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC" + # Force .init_array support. The configure script cannot always + # automatically detect that GAS supports it, yet we require it. + gcc_cv_initfini_array=yes + ;; + csky-*-linux-uclibc*) + tm_defines="$tm_defines DEFAULT_LIBC=LIBC_UCLIBC" + default_use_cxa_atexit=no + ;; + *) + echo "Unknown target $target" + exit 1 + ;; + esac + ;; + *) + echo "Unknown target $target" + exit 1 + ;; + esac + ;; +epiphany-*-elf | epiphany-*-rtems*) + tm_file="${tm_file} dbxelf.h elfos.h" + tmake_file="${tmake_file} epiphany/t-epiphany" + case ${target} in + epiphany-*-rtems*) + tm_file="${tm_file} epiphany/rtems.h rtems.h newlib-stdint.h" + ;; + *) + tm_file="${tm_file} newlib-stdint.h" + ;; + esac + extra_options="${extra_options} fused-madd.opt" + extra_objs="${extra_objs} mode-switch-use.o resolve-sw-modes.o" + tm_defines="${tm_defines} EPIPHANY_STACK_OFFSET=${with_stack_offset:-8}" + extra_headers="epiphany_intrinsics.h" + ;; +fr30-*-elf) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + ;; +frv-*-elf) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + tmake_file=frv/t-frv + ;; +frv-*-*linux*) + tm_file="dbxelf.h elfos.h ${tm_file} \ + gnu-user.h linux.h glibc-stdint.h frv/linux.h" + tmake_file="${tmake_file} frv/t-frv frv/t-linux" + ;; +ft32-*-elf) + gas=yes + gnu_ld=yes + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + tmake_file="${tmake_file} ft32/t-ft32" + ;; +amdgcn-*-amdhsa) + tm_file="elfos.h gcn/gcn-hsa.h gcn/gcn.h newlib-stdint.h" + tmake_file="gcn/t-gcn-hsa" + native_system_header_dir=/include + extra_modes=gcn/gcn-modes.def + extra_objs="${extra_objs} gcn-tree.o" + extra_gcc_objs="driver-gcn.o" + case "$host" in + x86_64*-*-linux-gnu ) + if test "$ac_cv_search_dlopen" != no; then + extra_programs="${extra_programs} gcn-run\$(exeext)" + fi + ;; + esac + if test x$enable_as_accelerator = xyes; then + extra_programs="${extra_programs} mkoffload\$(exeext)" + tm_file="${tm_file} gcn/offload.h" + fi + # Force .init_array support. + gcc_cv_initfini_array=yes + thread_file=gcn + ;; +moxie-*-elf) + gas=yes + gnu_ld=yes + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + tmake_file="${tmake_file} moxie/t-moxie" + ;; +moxie-*-uclinux*) + gas=yes + gnu_ld=yes + tm_file="dbxelf.h elfos.h ${tm_file} gnu-user.h linux.h glibc-stdint.h moxie/uclinux.h" + tmake_file="${tmake_file} moxie/t-moxie" + ;; +moxie-*-rtems*) + tmake_file="${tmake_file} moxie/t-moxie" + tm_file="moxie/moxie.h dbxelf.h elfos.h moxie/rtems.h rtems.h newlib-stdint.h" + ;; +moxie-*-moxiebox*) + gas=yes + gnu_ld=yes + tm_file="${tm_file} dbxelf.h elfos.h moxie/moxiebox.h newlib-stdint.h" + tmake_file="${tmake_file} moxie/t-moxiebox" + ;; +h8300-*-elf*) + tmake_file="h8300/t-h8300" + tm_file="h8300/h8300.h dbxelf.h elfos.h newlib-stdint.h h8300/elf.h" + ;; +h8300-*-linux*) + tmake_file="${tmake_file} h8300/t-h8300 h8300/t-linux" + tm_file="h8300/h8300.h dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h h8300/linux.h" + ;; +hppa*64*-*-linux*) + target_cpu_default="MASK_PA_11|MASK_PA_20" + tm_file="pa/pa64-start.h ${tm_file} dbxelf.h elfos.h gnu-user.h linux.h \ + glibc-stdint.h pa/pa-linux.h pa/pa64-regs.h pa/pa-64.h \ + pa/pa64-linux.h" + tmake_file="${tmake_file} pa/t-pa pa/t-linux" + d_target_objs="${d_target_objs} pa-d.o" + gas=yes gnu_ld=yes + ;; +hppa*-*-linux*) + target_cpu_default="MASK_PA_11|MASK_NO_SPACE_REGS|MASK_CALLER_COPIES" + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h pa/pa-linux.h \ + pa/pa32-regs.h pa/pa32-linux.h" + tmake_file="${tmake_file} pa/t-pa pa/t-linux" + d_target_objs="${d_target_objs} pa-d.o" + ;; +hppa*-*-openbsd*) + target_cpu_default="MASK_PA_11" + tm_file="${tm_file} dbxelf.h elfos.h openbsd.h openbsd-stdint.h openbsd-libpthread.h \ + pa/pa-openbsd.h pa/pa32-regs.h pa/pa32-openbsd.h" + extra_options="${extra_options} openbsd.opt" + tmake_file="pa/t-pa" + d_target_objs="${d_target_objs} pa-d.o" + gas=yes + gnu_ld=yes + ;; +hppa*-*-netbsd*) + target_cpu_default="MASK_PA_11|MASK_NO_SPACE_REGS" + tm_file="${tm_file} dbxelf.h elfos.h ${nbsd_tm_file} \ + pa/pa-netbsd.h pa/pa32-regs.h pa/pa32-netbsd.h" + tmake_file="${tmake_file}" + tm_defines="${tm_defines} CHAR_FAST8=1 SHORT_FAST16=1" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + ;; +hppa[12]*-*-hpux10*) + case ${target} in + hppa1.1-*-* | hppa2*-*-*) + target_cpu_default="MASK_PA_11" + ;; + esac + tm_file="${tm_file} pa/pa32-regs.h dbxelf.h pa/som.h \ + pa/pa-hpux.h pa/pa-hpux10.h" + extra_options="${extra_options} pa/pa-hpux.opt pa/pa-hpux10.opt" + case ${target} in + *-*-hpux10.[1-9]*) + tm_file="${tm_file} pa/pa-hpux1010.h" + extra_options="${extra_options} pa/pa-hpux1010.opt" + ;; + esac + use_gcc_stdint=provide + tm_file="${tm_file} hpux-stdint.h" + tmake_file="pa/t-pa t-slibgcc" + d_target_objs="${d_target_objs} pa-d.o" + case ${enable_threads} in + "") + if test x$have_pthread_h = xyes ; then + tmake_file="${tmake_file} pa/t-dce-thr" + fi + ;; + yes | dce) + tmake_file="${tmake_file} pa/t-dce-thr" + ;; + esac + use_collect2=yes + gas=yes + if test "x$with_dwarf2" != x; then + echo "Warning: dwarf2 debug format is not supported for this target, --with-dwarf2 ignored" 1>&2 + dwarf2=no + fi + ;; +hppa*64*-*-hpux11*) + target_cpu_default="MASK_PA_11|MASK_PA_20" + if test x$gnu_ld = xyes + then + target_cpu_default="${target_cpu_default}|MASK_GNU_LD" + fi + tm_file="pa/pa64-start.h ${tm_file} dbxelf.h elfos.h \ + pa/pa64-regs.h pa/pa-hpux.h pa/pa-hpux1010.h \ + pa/pa-hpux11.h" + case ${target} in + *-*-hpux11.[12]*) + tm_file="${tm_file} pa/pa-hpux1111.h pa/pa-64.h pa/pa64-hpux.h" + extra_options="${extra_options} pa/pa-hpux1111.opt" + ;; + *-*-hpux11.[3-9]*) + tm_file="${tm_file} pa/pa-hpux1131.h pa/pa-64.h pa/pa64-hpux.h" + extra_options="${extra_options} pa/pa-hpux1131.opt" + ;; + *) + tm_file="${tm_file} pa/pa-64.h pa/pa64-hpux.h" + ;; + esac + extra_options="${extra_options} pa/pa-hpux.opt \ + pa/pa-hpux1010.opt pa/pa64-hpux.opt hpux11.opt" + tmake_file="pa/t-pa t-slibgcc" + d_target_objs="${d_target_objs} pa-d.o" + case x${enable_threads} in + x | xyes | xposix ) + thread_file=posix + ;; + esac + gas=yes + case ${target} in + *-*-hpux11.[01]*) + use_gcc_stdint=provide + tm_file="${tm_file} hpux-stdint.h" + ;; + *-*-hpux11.[23]*) + use_gcc_stdint=wrap + tm_file="${tm_file} hpux-stdint.h" + ;; + esac + ;; +hppa[12]*-*-hpux11*) + case ${target} in + hppa1.1-*-* | hppa2*-*-*) + target_cpu_default="MASK_PA_11" + ;; + esac + tm_file="${tm_file} pa/pa32-regs.h dbxelf.h pa/som.h \ + pa/pa-hpux.h pa/pa-hpux1010.h pa/pa-hpux11.h" + extra_options="${extra_options} pa/pa-hpux.opt pa/pa-hpux1010.opt \ + hpux11.opt" + case ${target} in + *-*-hpux11.[12]*) + tm_file="${tm_file} pa/pa-hpux1111.h" + extra_options="${extra_options} pa/pa-hpux1111.opt" + ;; + *-*-hpux11.[3-9]*) + tm_file="${tm_file} pa/pa-hpux1131.h" + extra_options="${extra_options} pa/pa-hpux1131.opt" + ;; + esac + tmake_file="pa/t-pa t-slibgcc" + d_target_objs="${d_target_objs} pa-d.o" + case x${enable_threads} in + x | xyes | xposix ) + thread_file=posix + ;; + esac + use_collect2=yes + gas=yes + case ${target} in + *-*-hpux11.[01]*) + use_gcc_stdint=provide + tm_file="${tm_file} hpux-stdint.h" + ;; + *-*-hpux11.[23]*) + use_gcc_stdint=wrap + tm_file="${tm_file} hpux-stdint.h" + ;; + esac + if test "x$with_dwarf2" != x; then + echo "Warning: dwarf2 debug format is not supported for this target, --with-dwarf2 ignored" 1>&2 + dwarf2=no + fi + ;; +i[34567]86-*-darwin1[89]*) + echo "Error: 32bit target is not supported after Darwin17" 1>&2 + ;; +i[34567]86-*-darwin*) + need_64bit_isa=yes + # Baseline choice for a machine that allows m64 support. + with_cpu=${with_cpu:-core2} + tmake_file="${tmake_file} ${cpu_type}/t-darwin32-biarch t-slibgcc" + tm_file="${tm_file} ${cpu_type}/darwin32-biarch.h" + ;; +x86_64-*-darwin1[89]* | x86_64-*-darwin2[01]*) + # Only 64b from now + with_cpu=${with_cpu:-core2} + tmake_file="${tmake_file} t-slibgcc" + ;; +x86_64-*-darwin*) + with_cpu=${with_cpu:-core2} + tmake_file="${tmake_file} ${cpu_type}/t-darwin64-biarch t-slibgcc" + tm_file="${tm_file} ${cpu_type}/darwin64-biarch.h" + ;; +i[34567]86-*-elfiamcu) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/iamcu.h" + ;; +i[34567]86-*-elf*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h" + ;; +x86_64-*-elf*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h" + ;; +x86_64-*-rtems*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h i386/rtemself.h rtems.h" + ;; +i[34567]86-*-rdos*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/rdos.h" + ;; +x86_64-*-rdos*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h i386/rdos.h i386/rdos64.h" + tmake_file="i386/t-i386elf t-svr4" + ;; +i[34567]86-*-dragonfly*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h dragonfly.h dragonfly-stdint.h i386/dragonfly.h" + tmake_file="${tmake_file} i386/t-crtstuff" + ;; +x86_64-*-dragonfly*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h dragonfly.h dragonfly-stdint.h i386/x86-64.h i386/dragonfly.h" + tmake_file="${tmake_file} i386/t-crtstuff" + ;; +i[34567]86-*-freebsd*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h ${fbsd_tm_file} i386/freebsd.h" + ;; +x86_64-*-freebsd*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h ${fbsd_tm_file} i386/x86-64.h i386/freebsd.h i386/freebsd64.h" + ;; +i[34567]86-*-netbsdelf*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h ${nbsd_tm_file} i386/netbsd-elf.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + ;; +x86_64-*-netbsd*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h ${nbsd_tm_file} i386/x86-64.h i386/netbsd64.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + ;; +i[34567]86-*-openbsd*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h" + tm_file="${tm_file} openbsd.h openbsd-stdint.h openbsd-libpthread.h i386/openbsdelf.h" + extra_options="${extra_options} openbsd.opt" + gas=yes + gnu_ld=yes + ;; +x86_64-*-openbsd*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h" + tm_file="${tm_file} openbsd.h openbsd-stdint.h openbsd-libpthread.h i386/x86-64.h i386/openbsdelf.h" + extra_options="${extra_options} openbsd.opt" + gas=yes + gnu_ld=yes + ;; +i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-gnu* | i[34567]86-*-kopensolaris*-gnu) + # Intel 80386's running GNU/* + # with ELF format using glibc 2 + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h gnu-user.h glibc-stdint.h" + case ${target} in + i[34567]86-*-linux*) + tm_file="${tm_file} linux.h linux-android.h" + extra_options="${extra_options} linux-android.opt" + if test x$enable_targets = xall; then + tm_file="${tm_file} i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h i386/linux-common.h i386/linux64.h" + tm_defines="${tm_defines} TARGET_BI_ARCH=1" + tmake_file="${tmake_file} i386/t-linux64" + x86_multilibs="${with_multilib_list}" + if test "$x86_multilibs" = "default"; then + x86_multilibs="m64,m32" + fi + x86_multilibs=`echo $x86_multilibs | sed -e 's/,/ /g'` + for x86_multilib in ${x86_multilibs}; do + case ${x86_multilib} in + m32 | m64 | mx32) + TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG},${x86_multilib}" + ;; + *) + echo "--with-multilib-list=${x86_with_multilib} not supported." + exit 1 + esac + done + TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's/^,//'` + need_64bit_isa=yes + if test x$with_cpu = x; then + if test x$with_cpu_64 = x; then + with_cpu_64=generic + fi + else + case " $x86_cpus $x86_archs $x86_64_archs " in + *" $with_cpu "*) + ;; + *) + echo "Unsupported CPU used in --with-cpu=$with_cpu, supported values:" 1>&2 + echo "$x86_cpus $x86_archs $x86_64_archs " 1>&2 + exit 1 + ;; + esac + fi + else + tm_file="${tm_file} i386/gnu-user-common.h i386/gnu-user.h i386/linux-common.h i386/linux.h" + fi + ;; + i[34567]86-*-kfreebsd*-gnu) + tm_file="${tm_file} i386/gnu-user-common.h i386/gnu-user.h kfreebsd-gnu.h i386/kfreebsd-gnu.h" + ;; + i[34567]86-*-kopensolaris*-gnu) + tm_file="${tm_file} i386/gnu-user-common.h i386/gnu-user.h kopensolaris-gnu.h i386/kopensolaris-gnu.h" + ;; + i[34567]86-*-gnu*) + tm_file="$tm_file i386/gnu-user-common.h i386/gnu-user.h gnu.h i386/gnu.h" + ;; + esac + ;; +x86_64-*-linux* | x86_64-*-kfreebsd*-gnu) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h gnu-user.h glibc-stdint.h \ + i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h" + case ${target} in + x86_64-*-linux*) + tm_file="${tm_file} linux.h linux-android.h i386/linux-common.h i386/linux64.h" + extra_options="${extra_options} linux-android.opt" + ;; + x86_64-*-kfreebsd*-gnu) + tm_file="${tm_file} kfreebsd-gnu.h i386/kfreebsd-gnu64.h" + ;; + esac + tmake_file="${tmake_file} i386/t-linux64" + x86_multilibs="${with_multilib_list}" + if test "$x86_multilibs" = "default"; then + case ${with_abi} in + x32 | mx32) + x86_multilibs="mx32" + ;; + *) + x86_multilibs="m64,m32" + ;; + esac + fi + x86_multilibs=`echo $x86_multilibs | sed -e 's/,/ /g'` + for x86_multilib in ${x86_multilibs}; do + case ${x86_multilib} in + m32 | m64 | mx32) + TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG},${x86_multilib}" + ;; + *) + echo "--with-multilib-list=${x86_with_multilib} not supported." + exit 1 + esac + done + TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's/^,//'` + ;; +i[34567]86-pc-msdosdjgpp*) + xm_file=i386/xm-djgpp.h + tm_file="dbxcoff.h ${tm_file} i386/unix.h i386/bsd.h i386/gas.h i386/djgpp.h i386/djgpp-stdint.h" + native_system_header_dir=/dev/env/DJDIR/include + extra_options="${extra_options} i386/djgpp.opt" + gnu_ld=yes + gas=yes + use_gcc_stdint=wrap + ;; +i[34567]86-*-lynxos*) + xm_defines=POSIX + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/lynx.h lynx.h" + tmake_file="${tmake_file} t-lynx" + extra_options="${extra_options} lynx.opt" + thread_file=lynx + gnu_ld=yes + gas=yes + ;; +i[34567]86-*-nto-qnx*) + tm_file="${tm_file} i386/att.h dbxelf.h tm-dwarf2.h elfos.h i386/unix.h i386/nto.h" + extra_options="${extra_options} i386/nto.opt" + gnu_ld=yes + gas=yes + ;; +i[34567]86-*-rtems*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h i386/rtemself.h rtems.h newlib-stdint.h" + tmake_file="${tmake_file} i386/t-rtems" + ;; +i[34567]86-*-solaris2* | x86_64-*-solaris2*) + # Set default arch_32 to pentium4, tune_32 to generic like the other + # i386 targets, although config.guess defaults to i386-pc-solaris2*. + with_arch_32=${with_arch_32:-pentium4} + with_tune_32=${with_tune_32:-generic} + tm_file="${tm_file} i386/unix.h i386/att.h ${sol2_tm_file_head} i386/x86-64.h ${sol2_tm_file_tail}" + tm_defines="${tm_defines} TARGET_BI_ARCH=1" + tmake_file="$tmake_file i386/t-sol2" + need_64bit_isa=yes + if test x$with_cpu = x; then + if test x$with_cpu_64 = x; then + with_cpu_64=generic + fi + else + case " $x86_cpus $x86_archs $x86_64_archs " in + *" $with_cpu "*) + ;; + *) + echo "Unsupported CPU used in --with-cpu=$with_cpu, supported values:" 1>&2 + echo "$x86_cpus $x86_archs $x86_64_archs" 1>&2 + exit 1 + ;; + esac + fi + ;; +i[4567]86-wrs-vxworks*|x86_64-wrs-vxworks7*) + tm_file="${tm_file} i386/unix.h i386/att.h elfos.h" + case ${target} in + x86_64-*) + need_64bit_isa=yes + tm_file="${tm_file} i386/x86-64.h" + ;; + esac + tm_file="${tm_file} vx-common.h" + case ${target} in + *-vxworksae*) + tm_file="${tm_file} vxworksae.h i386/vxworks.h i386/vxworksae.h" + tmake_file="${tmake_file} i386/t-vxworks i386/t-vxworksae" + ;; + *) + tm_file="${tm_file} vxworks.h i386/vxworks.h" + tmake_file="${tmake_file} i386/t-vxworks" + ;; + esac + ;; +i[34567]86-*-cygwin*) + tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h dbxcoff.h i386/cygming.h i386/cygwin.h i386/cygwin-stdint.h" + xm_file=i386/xm-cygwin.h + tmake_file="${tmake_file} i386/t-cygming t-slibgcc" + target_gtfiles="$target_gtfiles \$(srcdir)/config/i386/winnt.c" + extra_options="${extra_options} i386/cygming.opt i386/cygwin.opt" + extra_objs="${extra_objs} winnt.o winnt-stubs.o" + c_target_objs="${c_target_objs} msformat-c.o" + cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o" + d_target_objs="${d_target_objs} winnt-d.o" + target_has_targetdm="yes" + if test x$enable_threads = xyes; then + thread_file='posix' + fi + default_use_cxa_atexit=yes + use_gcc_stdint=wrap + ;; +x86_64-*-cygwin*) + need_64bit_isa=yes + tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h dbxcoff.h i386/cygming.h i386/cygwin.h i386/cygwin-w64.h i386/cygwin-stdint.h" + xm_file=i386/xm-cygwin.h + tmake_file="${tmake_file} i386/t-cygming t-slibgcc i386/t-cygwin-w64" + target_gtfiles="$target_gtfiles \$(srcdir)/config/i386/winnt.c" + extra_options="${extra_options} i386/cygming.opt i386/cygwin.opt" + extra_objs="${extra_objs} winnt.o winnt-stubs.o" + c_target_objs="${c_target_objs} msformat-c.o" + cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o" + d_target_objs="${d_target_objs} winnt-d.o" + target_has_targetdm="yes" + if test x$enable_threads = xyes; then + thread_file='posix' + fi + default_use_cxa_atexit=yes + use_gcc_stdint=wrap + tm_defines="${tm_defines} TARGET_CYGWIN64=1" + ;; +i[34567]86-*-mingw* | x86_64-*-mingw*) + tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h dbxcoff.h i386/cygming.h" + xm_file=i386/xm-mingw32.h + c_target_objs="${c_target_objs} winnt-c.o" + cxx_target_objs="${cxx_target_objs} winnt-c.o" + d_target_objs="${d_target_objs} winnt-d.o" + target_has_targetcm="yes" + target_has_targetdm="yes" + case ${target} in + x86_64-*-* | *-w64-*) + need_64bit_isa=yes + ;; + *) + ;; + esac + if test x$enable_threads = xposix ; then + tm_file="${tm_file} i386/mingw-pthread.h" + fi + tm_file="${tm_file} i386/mingw32.h" + # This makes the logic if mingw's or the w64 feature set has to be used + case ${target} in + *-w64-*) + user_headers_inc_next_post="${user_headers_inc_next_post} float.h" + user_headers_inc_next_pre="${user_headers_inc_next_pre} stddef.h stdarg.h" + tm_file="${tm_file} i386/mingw-w64.h" + if test x$enable_targets = xall; then + tm_defines="${tm_defines} TARGET_BI_ARCH=1" + if test x$with_cpu = x; then + if test x$with_cpu_64 = x; then + with_cpu_64=generic + fi + else + case " $x86_cpus $x86_archs $x86_64_archs " in + *" $with_cpu "*) + ;; + *) + echo "Unsupported CPU used in --with-cpu=$with_cpu, supported values:" 1>&2 + echo "$x86_cpus $x86_archs $x86_64_archs" 1>&2 + exit 1 + ;; + esac + fi + fi + ;; + *) + ;; + esac + tm_file="${tm_file} i386/mingw-stdint.h" + tmake_file="${tmake_file} t-winnt i386/t-cygming t-slibgcc" + case ${target} in + x86_64-w64-*) + tmake_file="${tmake_file} i386/t-mingw-w64" + ;; + i[34567]86-w64-*) + tmake_file="${tmake_file} i386/t-mingw-w32" + ;; + esac + native_system_header_dir=/mingw/include + target_gtfiles="$target_gtfiles \$(srcdir)/config/i386/winnt.c" + extra_options="${extra_options} i386/cygming.opt i386/mingw.opt" + case ${target} in + *-w64-*) + extra_options="${extra_options} i386/mingw-w64.opt" + ;; + *) + ;; + esac + extra_objs="${extra_objs} winnt.o winnt-stubs.o" + c_target_objs="${c_target_objs} msformat-c.o" + cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o" + gas=yes + gnu_ld=yes + default_use_cxa_atexit=yes + use_gcc_stdint=wrap + case ${enable_threads} in + "" | yes | win32) + thread_file='win32' + ;; + posix) + thread_file='posix' + ;; + esac + case ${target} in + *mingw32crt*) + tm_file="${tm_file} i386/crtdll.h" + ;; + *mingw32msv* | *mingw*) + ;; + esac + ;; +x86_64-*-essence*) + tmake_file="${tmake_file} i386/t-x86_64-essence" + tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h essence.h" + ;; +x86_64-*-fuchsia*) + tmake_file="${tmake_file} i386/t-x86_64-elf" + tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h fuchsia.h" + ;; +ia64*-*-elf*) + tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h ia64/sysv4.h ia64/elf.h" + tmake_file="ia64/t-ia64" + target_cpu_default="0" + if test x$gas = xyes + then + target_cpu_default="${target_cpu_default}|MASK_GNU_AS" + fi + if test x$gnu_ld = xyes + then + target_cpu_default="${target_cpu_default}|MASK_GNU_LD" + fi + ;; +ia64*-*-freebsd*) + tm_file="${tm_file} dbxelf.h elfos.h ${fbsd_tm_file} ia64/sysv4.h ia64/freebsd.h" + target_cpu_default="MASK_GNU_AS|MASK_GNU_LD" + tmake_file="${tmake_file} ia64/t-ia64" + ;; +ia64*-*-linux*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h ia64/sysv4.h ia64/linux.h" + tmake_file="${tmake_file} ia64/t-ia64 ia64/t-linux t-libunwind" + target_cpu_default="MASK_GNU_AS|MASK_GNU_LD" + ;; +ia64*-*-hpux*) + tm_file="${tm_file} dbxelf.h elfos.h ia64/sysv4.h ia64/hpux.h" + tmake_file="ia64/t-ia64 ia64/t-hpux t-slibgcc" + target_cpu_default="MASK_GNU_AS" + case x$enable_threads in + x | xyes | xposix ) + thread_file=posix + ;; + esac + use_collect2=no + c_target_objs="ia64-c.o" + cxx_target_objs="ia64-c.o" + extra_options="${extra_options} ia64/ilp32.opt hpux11.opt" + use_gcc_stdint=wrap + tm_file="${tm_file} hpux-stdint.h" + case ${target} in + *-*-hpux11.3*) + tm_file="${tm_file} ia64/hpux-unix2003.h" + ;; + esac + ;; +ia64-hp-*vms*) + tm_file="${tm_file} elfos.h ia64/sysv4.h vms/vms.h ia64/vms.h" + tmake_file="${tmake_file} ia64/t-ia64" + target_cpu_default="0" + if test x$gas = xyes + then + target_cpu_default="${target_cpu_default}|MASK_GNU_AS" + fi + extra_options="${extra_options} ia64/vms.opt" + ;; +iq2000*-*-elf*) + tm_file="elfos.h newlib-stdint.h iq2000/iq2000.h" + out_file=iq2000/iq2000.c + md_file=iq2000/iq2000.md + ;; +lm32-*-elf*) + tm_file="dbxelf.h elfos.h ${tm_file} newlib-stdint.h" + tmake_file="${tmake_file} lm32/t-lm32" + ;; +lm32-*-rtems*) + tm_file="dbxelf.h elfos.h ${tm_file} lm32/rtems.h rtems.h newlib-stdint.h" + tmake_file="${tmake_file} lm32/t-lm32" + tmake_file="${tmake_file} lm32/t-rtems" + ;; +lm32-*-uclinux*) + tm_file="dbxelf.h elfos.h ${tm_file} gnu-user.h linux.h lm32/uclinux-elf.h" + tmake_file="${tmake_file} lm32/t-lm32" + ;; +m32r-*-elf*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + ;; +m32rle-*-elf*) + tm_file="dbxelf.h elfos.h newlib-stdint.h m32r/little.h ${tm_file}" + ;; +m32r-*-linux*) + tm_file="dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h ${tm_file} m32r/linux.h" + tmake_file="${tmake_file} m32r/t-linux t-slibgcc" + gnu_ld=yes + if test x$enable_threads = xyes; then + thread_file='posix' + fi + ;; +m32rle-*-linux*) + tm_file="dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h m32r/little.h ${tm_file} m32r/linux.h" + tmake_file="${tmake_file} m32r/t-linux t-slibgcc" + gnu_ld=yes + if test x$enable_threads = xyes; then + thread_file='posix' + fi + ;; +m68k-*-elf* | fido-*-elf*) + case ${target} in + fido-*-elf*) + # Check that $with_cpu makes sense. + case $with_cpu in + "" | "fidoa") + ;; + *) + echo "Cannot accept --with-cpu=$with_cpu" + exit 1 + ;; + esac + with_cpu=fidoa + ;; + *) + default_m68k_cpu=68020 + default_cf_cpu=5206 + ;; + esac + tm_file="${tm_file} m68k/m68k-none.h m68k/m68kelf.h dbxelf.h elfos.h newlib-stdint.h m68k/m68kemb.h m68k/m68020-elf.h" + tm_defines="${tm_defines} MOTOROLA=1" + tmake_file="m68k/t-floatlib m68k/t-m68kbare m68k/t-m68kelf" + # Add multilibs for targets other than fido. + case ${target} in + fido-*-elf*) + ;; + *) + tmake_file="$tmake_file m68k/t-mlibs" + ;; + esac + ;; +m68k*-*-netbsdelf*) + default_m68k_cpu=68020 + default_cf_cpu=5475 + tm_file="${tm_file} dbxelf.h elfos.h ${nbsd_tm_file} m68k/netbsd-elf.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + tm_defines="${tm_defines} MOTOROLA=1 CHAR_FAST8=1 SHORT_FAST16=1" + ;; +m68k*-*-openbsd*) + default_m68k_cpu=68020 + default_cf_cpu=5475 + # needed to unconfuse gdb + tm_defines="${tm_defines} OBSD_OLD_GAS" + tm_file="${tm_file} openbsd.h openbsd-stdint.h openbsd-libpthread.h m68k/openbsd.h" + extra_options="${extra_options} openbsd.opt" + tmake_file="t-openbsd m68k/t-openbsd" + # we need collect2 until our bug is fixed... + use_collect2=yes + ;; +m68k-*-uclinux*) # Motorola m68k/ColdFire running uClinux + # with uClibc, using the new GNU/Linux-style + # ABI. + default_m68k_cpu=68020 + default_cf_cpu=5206 + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h flat.h m68k/linux.h m68k/uclinux.h ./sysroot-suffix.h" + extra_options="${extra_options} m68k/uclinux.opt" + tm_defines="${tm_defines} MOTOROLA=1" + tmake_file="m68k/t-floatlib m68k/t-uclinux m68k/t-mlibs" + ;; +m68k-*-linux*) # Motorola m68k's running GNU/Linux + # with ELF format using glibc 2 + # aka the GNU/Linux C library 6. + default_m68k_cpu=68020 + default_cf_cpu=5475 + with_arch=${with_arch:-m68k} + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h m68k/linux.h ./sysroot-suffix.h" + extra_options="${extra_options} m68k/ieee.opt" + tm_defines="${tm_defines} MOTOROLA=1" + tmake_file="${tmake_file} m68k/t-floatlib m68k/t-linux m68k/t-mlibs" + ;; +m68k-*-rtems*) + default_m68k_cpu=68020 + default_cf_cpu=5206 + tmake_file="${tmake_file} m68k/t-floatlib m68k/t-m68kbare m68k/t-crtstuff m68k/t-rtems m68k/t-mlibs" + tm_file="${tm_file} m68k/m68k-none.h m68k/m68kelf.h dbxelf.h elfos.h m68k/m68kemb.h m68k/m68020-elf.h m68k/rtemself.h rtems.h newlib-stdint.h" + tm_defines="${tm_defines} MOTOROLA=1" + ;; +mcore-*-elf) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file} mcore/mcore-elf.h" + tmake_file=mcore/t-mcore + inhibit_libc=true + ;; +microblaze*-linux*) + case $target in + microblazeel-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=0" + ;; + microblaze-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=4321" + ;; + esac + tm_file="${tm_file} dbxelf.h gnu-user.h linux.h microblaze/linux.h" + tm_file="${tm_file} glibc-stdint.h" + c_target_objs="${c_target_objs} microblaze-c.o" + cxx_target_objs="${cxx_target_objs} microblaze-c.o" + tmake_file="${tmake_file} microblaze/t-microblaze" + tmake_file="${tmake_file} microblaze/t-microblaze-linux" + ;; +microblaze*-*-rtems*) + case $target in + microblazeel-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=0" + ;; + microblaze-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=4321" + ;; + esac + tm_file="${tm_file} dbxelf.h" + tm_file="${tm_file} microblaze/rtems.h rtems.h newlib-stdint.h" + c_target_objs="${c_target_objs} microblaze-c.o" + cxx_target_objs="${cxx_target_objs} microblaze-c.o" + tmake_file="${tmake_file} microblaze/t-microblaze" + tmake_file="${tmake_file} microblaze/t-rtems" + ;; +microblaze*-*-elf) + case $target in + microblazeel-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=0" + ;; + microblaze-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=4321" + ;; + esac + tm_file="${tm_file} dbxelf.h newlib-stdint.h" + c_target_objs="${c_target_objs} microblaze-c.o" + cxx_target_objs="${cxx_target_objs} microblaze-c.o" + tmake_file="${tmake_file} microblaze/t-microblaze" + ;; +riscv*-*-linux*) + tm_file="elfos.h gnu-user.h linux.h glibc-stdint.h ${tm_file} riscv/linux.h" + case "x${enable_multilib}" in + xno) ;; + xyes) tmake_file="${tmake_file} riscv/t-linux-multilib" ;; + *) echo "Unknown value for enable_multilib"; exit 1 + esac + tmake_file="${tmake_file} riscv/t-riscv riscv/t-linux" + gnu_ld=yes + gas=yes + case $target in + riscv32be-*|riscv64be-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + # Force .init_array support. The configure script cannot always + # automatically detect that GAS supports it, yet we require it. + gcc_cv_initfini_array=yes + ;; +riscv*-*-elf* | riscv*-*-rtems*) + tm_file="elfos.h newlib-stdint.h ${tm_file} riscv/elf.h" + case ${target} in + *-*-rtems*) + tm_file="${tm_file} riscv/rtems.h rtems.h" + tmake_file="${tmake_file} riscv/t-rtems" + ;; + *) + if test "x${with_multilib_generator}" == xdefault; then + case "x${enable_multilib}" in + xno) ;; + xyes) tmake_file="${tmake_file} riscv/t-elf-multilib" ;; + *) echo "Unknown value for enable_multilib"; exit 1 + esac + fi + esac + tmake_file="${tmake_file} riscv/t-riscv" + gnu_ld=yes + gas=yes + case $target in + riscv32be-*|riscv64be-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + # Force .init_array support. The configure script cannot always + # automatically detect that GAS supports it, yet we require it. + gcc_cv_initfini_array=yes + ;; +riscv*-*-freebsd*) + tm_file="${tm_file} elfos.h ${fbsd_tm_file} riscv/freebsd.h" + tmake_file="${tmake_file} riscv/t-riscv" + gnu_ld=yes + gas=yes + case $target in + riscv32be-*|riscv64be-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + # Force .init_array support. The configure script cannot always + # automatically detect that GAS supports it, yet we require it. + gcc_cv_initfini_array=yes + ;; +mips*-*-netbsd*) # NetBSD/mips, either endian. + target_cpu_default="MASK_ABICALLS" + tm_file="elfos.h ${tm_file} mips/elf.h ${nbsd_tm_file} mips/netbsd.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + ;; +mips*-img-linux*) + tm_file="dbxelf.h elfos.h gnu-user.h linux.h linux-android.h glibc-stdint.h ${tm_file} mips/gnu-user.h mips/linux.h mips/linux-common.h mips/mti-linux.h" + extra_options="${extra_options} linux-android.opt" + tmake_file="${tmake_file} mips/t-img-linux" + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=37 MIPS_ABI_DEFAULT=ABI_32" + with_arch_32="mips32r6" + with_arch_64="mips64r6" + gnu_ld=yes + gas=yes + ;; +mips*-mti-linux*) + tm_file="dbxelf.h elfos.h gnu-user.h linux.h linux-android.h glibc-stdint.h ${tm_file} mips/gnu-user.h mips/linux.h mips/linux-common.h mips/mti-linux.h" + extra_options="${extra_options} linux-android.opt" + tmake_file="${tmake_file} mips/t-mti-linux" + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=33 MIPS_ABI_DEFAULT=ABI_32" + with_arch_32="mips32r2" + with_arch_64="mips64r2" + gnu_ld=yes + gas=yes + ;; +mips*-*-linux*) # Linux MIPS, either endian. + tm_file="dbxelf.h elfos.h gnu-user.h linux.h linux-android.h glibc-stdint.h ${tm_file} mips/gnu-user.h mips/linux.h mips/linux-common.h" + extra_options="${extra_options} linux-android.opt" + case ${target} in + mipsisa32r6*) + default_mips_arch=mips32r6 + ;; + mipsisa32r2*) + default_mips_arch=mips32r2 + ;; + mipsisa32*) + default_mips_arch=mips32 + ;; + mips64el-st-linux-gnu) + default_mips_abi=n32 + tm_file="${tm_file} mips/st.h" + tmake_file="${tmake_file} mips/t-st" + enable_mips_multilibs="yes" + ;; + mips64octeon*-*-linux*) + default_mips_abi=n32 + tm_defines="${tm_defines} MIPS_CPU_STRING_DEFAULT=\\\"octeon\\\"" + target_cpu_default=MASK_SOFT_FLOAT_ABI + enable_mips_multilibs="yes" + ;; + mipsisa64r6*-*-linux*) + default_mips_abi=n32 + default_mips_arch=mips64r6 + enable_mips_multilibs="yes" + ;; + mipsisa64r2*-*-linux*) + default_mips_abi=n32 + default_mips_arch=mips64r2 + enable_mips_multilibs="yes" + ;; + mips64*-*-linux* | mipsisa64*-*-linux*) + default_mips_abi=n32 + enable_mips_multilibs="yes" + ;; + esac + if test x$enable_targets = xall; then + enable_mips_multilibs="yes" + fi + if test x$enable_mips_multilibs = xyes; then + tmake_file="${tmake_file} mips/t-linux64" + fi + ;; +mips*-mti-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h mips/n32-elf.h mips/sde.h mips/mti-elf.h" + tmake_file="mips/t-mti-elf" + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=33 MIPS_ABI_DEFAULT=ABI_32" + with_arch_32="mips32r2" + with_arch_64="mips64r2" + ;; +mips*-img-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h mips/n32-elf.h mips/sde.h mips/mti-elf.h" + tmake_file="mips/t-img-elf" + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=37 MIPS_ABI_DEFAULT=ABI_32" + with_arch_32="mips32r6" + with_arch_64="mips64r6" + ;; +mips*-sde-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h mips/n32-elf.h mips/sde.h" + tmake_file="mips/t-sde" + extra_options="${extra_options} mips/sde.opt" + case "${with_newlib}" in + yes) + # newlib / libgloss. + ;; + *) + # MIPS toolkit libraries. + tm_file="$tm_file mips/sdemtk.h" + tmake_file="$tmake_file mips/t-sdemtk" + case ${enable_threads} in + "" | yes | mipssde) + thread_file='mipssde' + ;; + esac + ;; + esac + case ${target} in + mipsisa32r6*) + tm_defines="MIPS_ISA_DEFAULT=37 MIPS_ABI_DEFAULT=ABI_32" + ;; + mipsisa32r2*) + tm_defines="MIPS_ISA_DEFAULT=33 MIPS_ABI_DEFAULT=ABI_32" + ;; + mipsisa32*) + tm_defines="MIPS_ISA_DEFAULT=32 MIPS_ABI_DEFAULT=ABI_32" + ;; + mipsisa64r6*) + tm_defines="MIPS_ISA_DEFAULT=69 MIPS_ABI_DEFAULT=ABI_N32" + ;; + mipsisa64r2*) + tm_defines="MIPS_ISA_DEFAULT=65 MIPS_ABI_DEFAULT=ABI_N32" + ;; + mipsisa64*) + tm_defines="MIPS_ISA_DEFAULT=64 MIPS_ABI_DEFAULT=ABI_N32" + ;; + esac + ;; +mipsisa32-*-elf* | mipsisa32el-*-elf* | \ +mipsisa32r2-*-elf* | mipsisa32r2el-*-elf* | \ +mipsisa32r6-*-elf* | mipsisa32r6el-*-elf* | \ +mipsisa64-*-elf* | mipsisa64el-*-elf* | \ +mipsisa64r2-*-elf* | mipsisa64r2el-*-elf* | \ +mipsisa64r6-*-elf* | mipsisa64r6el-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h" + tmake_file="mips/t-isa3264" + case ${target} in + mipsisa32r6*) + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=37" + ;; + mipsisa32r2*) + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=33" + ;; + mipsisa32*) + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=32" + ;; + mipsisa64r6*) + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=69" + ;; + mipsisa64r2*) + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=65" + ;; + mipsisa64*) + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=64" + ;; + esac + case ${target} in + mipsisa32*-*-elfoabi*) + tm_defines="${tm_defines} MIPS_ABI_DEFAULT=ABI_32" + tm_file="${tm_file} mips/elfoabi.h" + ;; + mipsisa64*-*-elfoabi*) + tm_defines="${tm_defines} MIPS_ABI_DEFAULT=ABI_O64" + tm_file="${tm_file} mips/elfoabi.h" + ;; + *-*-elf*) + tm_defines="${tm_defines} MIPS_ABI_DEFAULT=ABI_EABI" + ;; + esac + ;; +mipsisa64sr71k-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h" + tmake_file=mips/t-sr71k + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=64 MIPS_CPU_STRING_DEFAULT=\\\"sr71000\\\" MIPS_ABI_DEFAULT=ABI_EABI" + ;; +mipsisa64sb1-*-elf* | mipsisa64sb1el-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h" + tmake_file="mips/t-elf mips/t-sb1" + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=64 MIPS_CPU_STRING_DEFAULT=\\\"sb1\\\" MIPS_ABI_DEFAULT=ABI_O64" + ;; +mips-*-elf* | mipsel-*-elf* | mipsr5900-*-elf* | mipsr5900el-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h" + tmake_file="mips/t-elf" + ;; +mips64r5900-*-elf* | mips64r5900el-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h mips/n32-elf.h" + tmake_file="mips/t-elf" + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=3 MIPS_ABI_DEFAULT=ABI_N32" + ;; +mips64-*-elf* | mips64el-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h" + tmake_file="mips/t-elf" + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=3 MIPS_ABI_DEFAULT=ABI_O64" + ;; +mips64vr-*-elf* | mips64vrel-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/vr.h mips/elf.h" + tmake_file=mips/t-vr + tm_defines="${tm_defines} MIPS_ABI_DEFAULT=ABI_EABI" + ;; +mips64orion-*-elf* | mips64orionel-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elforion.h mips/elf.h" + tmake_file="mips/t-elf" + tm_defines="${tm_defines} MIPS_ISA_DEFAULT=3 MIPS_ABI_DEFAULT=ABI_O64" + ;; +mips*-*-rtems*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/elf.h mips/rtems.h rtems.h" + tmake_file="${tmake_file} mips/t-elf mips/t-rtems" + ;; +mips-wrs-vxworks) + tm_file="elfos.h ${tm_file} mips/elf.h vx-common.h vxworks.h mips/vxworks.h" + tmake_file="${tmake_file} mips/t-vxworks" + ;; +mipstx39-*-elf* | mipstx39el-*-elf*) + tm_file="elfos.h newlib-stdint.h ${tm_file} mips/r3900.h mips/elf.h" + tmake_file="mips/t-r3900" + ;; +mmix-knuth-mmixware) + tm_file="${tm_file} newlib-stdint.h" + use_gcc_stdint=wrap + ;; +mn10300-*-*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + if test x$stabs = xyes + then + tm_file="${tm_file} dbx.h" + fi + use_collect2=no + use_gcc_stdint=wrap + ;; +msp430-*-*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + c_target_objs="msp430-c.o" + cxx_target_objs="msp430-c.o" + tmake_file="${tmake_file} msp430/t-msp430" + extra_objs="${extra_objs} msp430-devices.o" + extra_gcc_objs="driver-msp430.o msp430-devices.o" + # Enable .init_array unless it has been explicitly disabled. + # The MSP430 EABI mandates the use of .init_array, and the Newlib CRT + # code since mid-2019 expects it. + if test x${disable_initfini_array} != xyes; then + gcc_cv_initfini_array=yes + fi + case ${target} in + msp430-*-elfbare) + # __cxa_atexit increases code size, and we don't need to support + # dynamic shared objects on MSP430, so regular Newlib atexit is a + # fine replacement as it also supports registration of more than 32 + # functions. + default_use_cxa_atexit=no + # This target does not match the generic *-*-elf case above which + # sets use_gcc_stdint=wrap, so explicitly set it here. + use_gcc_stdint=wrap + ;; + esac + ;; +nds32*-*-*) + target_cpu_default="0" + tm_defines="${tm_defines}" + case ${target} in + nds32le*-*-*) + ;; + nds32be-*-*) + target_cpu_default="${target_cpu_default}|MASK_BIG_ENDIAN" + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + case ${target} in + nds32*-*-elf*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file} nds32/elf.h nds32/nds32_intrinsic.h" + tmake_file="nds32/t-nds32 nds32/t-elf" + ;; + nds32*-*-linux*) + tm_file="dbxelf.h elfos.h ${tm_file} gnu-user.h linux.h glibc-stdint.h nds32/linux.h nds32/nds32_intrinsic.h" + tmake_file="${tmake_file} nds32/t-nds32 nds32/t-linux" + gcc_cv_initfini_array=yes + ;; + esac + + # Handle --enable-default-relax setting. + if test x${enable_default_relax} = xyes; then + tm_defines="${tm_defines} TARGET_DEFAULT_RELAX=1" + fi + # Handle --with-ext-dsp + if test x${with_ext_dsp} = xyes; then + tm_defines="${tm_defines} TARGET_DEFAULT_EXT_DSP=1" + fi + ;; +nios2-*-*) + tm_file="elfos.h ${tm_file}" + tmake_file="${tmake_file} nios2/t-nios2" + case ${target} in + nios2-*-linux*) + tm_file="${tm_file} gnu-user.h linux.h glibc-stdint.h nios2/linux.h " + ;; + nios2-*-elf*) + tm_file="${tm_file} newlib-stdint.h nios2/elf.h" + extra_options="${extra_options} nios2/elf.opt" + ;; + nios2-*-rtems*) + tm_file="${tm_file} newlib-stdint.h nios2/rtems.h rtems.h" + tmake_file="${tmake_file} t-rtems nios2/t-rtems" + ;; + esac + ;; +nvptx-*) + tm_file="${tm_file} newlib-stdint.h" + use_gcc_stdint=wrap + tmake_file="nvptx/t-nvptx" + if test x$enable_as_accelerator = xyes; then + extra_programs="${extra_programs} mkoffload\$(exeext)" + tm_file="${tm_file} nvptx/offload.h" + fi + ;; +or1k*-*-*) + tm_file="elfos.h ${tm_file}" + tmake_file="${tmake_file} or1k/t-or1k" + # Force .init_array support. The configure script cannot always + # automatically detect that GAS supports it, yet we require it. + gcc_cv_initfini_array=yes + + # Handle --with-multilib-list=... + or1k_multilibs="${with_multilib_list}" + if test "$or1k_multilibs" = "default"; then + or1k_multilibs="mcmov,msoft-mul,msoft-div" + fi + or1k_multilibs=`echo $or1k_multilibs | sed -e 's/,/ /g'` + for or1k_multilib in ${or1k_multilibs}; do + case ${or1k_multilib} in + mcmov | msext | msfimm | \ + mror | mrori | \ + mhard-float | mdouble-float | munordered-float | msoft-float | \ + mhard-div | mhard-mul | \ + msoft-div | msoft-mul ) + TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG},${or1k_multilib}" + ;; + *) + echo "--with-multilib-list=${with_multilib_list} not supported." + exit 1 + esac + done + TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's/^,//'` + + case ${target} in + or1k*-*-linux*) + tm_file="${tm_file} gnu-user.h linux.h glibc-stdint.h" + tm_file="${tm_file} or1k/linux.h" + ;; + or1k*-*-elf*) + tm_file="${tm_file} newlib-stdint.h or1k/elf.h" + extra_options="${extra_options} or1k/elf.opt" + ;; + or1k*-*-rtems*) + tm_file="${tm_file} newlib-stdint.h or1k/rtems.h rtems.h" + tmake_file="${tmake_file} or1k/t-rtems" + ;; + esac + ;; +pdp11-*-*) + tm_file="${tm_file} newlib-stdint.h" + use_gcc_stdint=wrap + ;; +# port not yet contributed +#powerpc-*-openbsd*) +# tmake_file="${tmake_file} rs6000/t-fprules" +# extra_headers= +# ;; +powerpc-*-darwin*) + extra_options="${extra_options} ${cpu_type}/darwin.opt" + case ${target} in + *-darwin1[0-9]* | *-darwin9*) + tmake_file="${tmake_file} ${cpu_type}/t-darwin32-biarch" + tm_file="${tm_file} ${cpu_type}/darwin32-biarch.h" + ;; + *-darwin8*) + tmake_file="${tmake_file} ${cpu_type}/t-darwin32-biarch" + tm_file="${tm_file} ${cpu_type}/darwin32-biarch.h" + ;; + *-darwin7*) + tm_file="${tm_file} ${cpu_type}/darwin7.h" + ;; + *-darwin[456]*) + # Earlier - ingle arch, with 32b only + # OS X 10.0, the first edition is Darwin4 + ;; + esac + tmake_file="${tmake_file} t-slibgcc" + ;; +powerpc64-*-darwin*) + extra_options="${extra_options} ${cpu_type}/darwin.opt" + tmake_file="${tmake_file} ${cpu_type}/t-darwin64-biarch t-slibgcc" + tm_file="${tm_file} ${cpu_type}/darwin64-biarch.h" + ;; +powerpc*-*-freebsd*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h ${fbsd_tm_file} rs6000/sysv4.h" + extra_options="${extra_options} rs6000/sysv4.opt" + tmake_file="rs6000/t-fprules rs6000/t-ppcos ${tmake_file} rs6000/t-ppccomm" + case ${target} in + powerpc*le-*-*) + tm_file="${tm_file} rs6000/sysv4le.h" ;; + esac + case ${target} in + powerpc64*) + tm_file="${tm_file} rs6000/default64.h rs6000/freebsd64.h" + tmake_file="${tmake_file} rs6000/t-freebsd64" + extra_options="${extra_options} rs6000/linux64.opt" + if test $fbsd_major -ge 13; then + tm_defines="${tm_defines} TARGET_FREEBSD32_SECURE_PLT=1" + fi + ;; + *) + if test $fbsd_major -ge 13; then + tm_file="rs6000/secureplt.h ${tm_file}" + fi + tm_file="${tm_file} rs6000/freebsd.h" + ;; + esac + ;; +powerpc-*-netbsd*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h ${nbsd_tm_file} freebsd-spec.h rs6000/sysv4.h rs6000/netbsd.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + tmake_file="${tmake_file} rs6000/t-netbsd" + extra_options="${extra_options} rs6000/sysv4.opt" + ;; +powerpc-*-eabisimaltivec*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h rs6000/eabi.h rs6000/eabisim.h rs6000/eabialtivec.h" + extra_options="${extra_options} rs6000/sysv4.opt" + tmake_file="rs6000/t-fprules rs6000/t-ppcendian rs6000/t-ppccomm" + use_gcc_stdint=wrap + ;; +powerpc-*-eabisim*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h usegas.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h rs6000/eabi.h rs6000/eabisim.h" + extra_options="${extra_options} rs6000/sysv4.opt" + tmake_file="rs6000/t-fprules rs6000/t-ppcgas rs6000/t-ppccomm" + use_gcc_stdint=wrap + ;; +powerpc-*-elf*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h usegas.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h" + extra_options="${extra_options} rs6000/sysv4.opt" + tmake_file="rs6000/t-fprules rs6000/t-ppcgas rs6000/t-ppccomm" + ;; +powerpc-*-eabialtivec*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h rs6000/eabi.h rs6000/eabialtivec.h" + extra_options="${extra_options} rs6000/sysv4.opt" + tmake_file="rs6000/t-fprules rs6000/t-ppcendian rs6000/t-ppccomm" + use_gcc_stdint=wrap + ;; +powerpc-*-eabi*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h usegas.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h rs6000/eabi.h" + extra_options="${extra_options} rs6000/sysv4.opt" + tmake_file="rs6000/t-fprules rs6000/t-ppcgas rs6000/t-ppccomm" + use_gcc_stdint=wrap + ;; +powerpc-*-rtems*) + tm_file="rs6000/biarch64.h ${tm_file} dbxelf.h elfos.h gnu-user.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h rs6000/rtems.h rtems.h" + extra_options="${extra_options} rs6000/sysv4.opt rs6000/linux64.opt" + tmake_file="${tmake_file} rs6000/t-fprules rs6000/t-rtems rs6000/t-ppccomm" + ;; +powerpc*-*-linux*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h freebsd-spec.h rs6000/sysv4.h" + extra_options="${extra_options} rs6000/sysv4.opt" + tmake_file="${tmake_file} rs6000/t-fprules rs6000/t-ppccomm" + extra_objs="$extra_objs rs6000-linux.o" + case ${target} in + powerpc*le-*-*) + tm_file="${tm_file} rs6000/sysv4le.h" ;; + esac + case ${target}:${with_cpu} in + powerpc64*: | powerpc64*:native) cpu_is_64bit=yes ;; + esac + maybe_biarch=${cpu_is_64bit} + case ${enable_targets} in + *powerpc64*) maybe_biarch=yes ;; + all) maybe_biarch=yes ;; + esac + case ${target}:${enable_targets}:${maybe_biarch} in + powerpc64-* | powerpc-*:*:yes | *:*powerpc64-*:yes | *:all:yes \ + | powerpc64le*:*powerpcle* | powerpc64le*:*powerpc-* \ + | powerpcle-*:*powerpc64le*:yes) + if test x$cpu_is_64bit = xyes; then + tm_file="${tm_file} rs6000/default64.h" + fi + tm_file="rs6000/biarch64.h ${tm_file} rs6000/linux64.h glibc-stdint.h" + tmake_file="$tmake_file rs6000/t-linux64" + case ${target} in + powerpc*le-*-*) + tmake_file="$tmake_file rs6000/t-linux64le" + case ${enable_targets} in + all | *powerpc64-* | *powerpc-*) + tmake_file="$tmake_file rs6000/t-linux64lebe" ;; + esac ;; + *) + case ${enable_targets} in + all | *powerpc64le-* | *powerpcle-*) + tmake_file="$tmake_file rs6000/t-linux64bele" ;; + esac ;; + esac + extra_options="${extra_options} rs6000/linux64.opt" + ;; + powerpc64*) + tm_file="${tm_file} rs6000/default64.h rs6000/linux64.h glibc-stdint.h" + extra_options="${extra_options} rs6000/linux64.opt" + tmake_file="${tmake_file} rs6000/t-linux" + ;; + *) + tm_file="${tm_file} rs6000/linux.h glibc-stdint.h" + tmake_file="${tmake_file} rs6000/t-ppcos rs6000/t-linux" + ;; + esac + case ${target} in + powerpc*-*-linux*ppc476*) + tm_file="${tm_file} rs6000/476.h" + extra_options="${extra_options} rs6000/476.opt" ;; + powerpc*-*-linux*altivec*) + tm_file="${tm_file} rs6000/linuxaltivec.h" ;; + esac + case ${target} in + *-linux*-musl*) + enable_secureplt=yes ;; + esac + if test x${enable_secureplt} = xyes; then + tm_file="rs6000/secureplt.h ${tm_file}" + fi + ;; +powerpc*-wrs-vxworks7r*) + + # Wind River 7 post SR0600 is mostly like Linux so we setup + # our config in a very similar fashion and adjust to a few + # specificities. + + # The system compiler is configured with secureplt by default. + tm_file="${tm_file} rs6000/secureplt.h" + + tm_file="${tm_file} elfos.h gnu-user.h linux.h freebsd-spec.h" + tm_file="${tm_file} rs6000/sysv4.h rs6000/biarch64.h rs6000/default64.h rs6000/linux64.h" + tm_file="${tm_file} vx-common.h vxworks.h rs6000/vxworks.h" + + extra_options="${extra_options} rs6000/sysv4.opt linux.opt rs6000/linux64.opt" + + tmake_file="${tmake_file} t-linux rs6000/t-linux64 rs6000/t-fprules rs6000/t-ppccomm" + tmake_file="${tmake_file} rs6000/t-vxworks" + + tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC" + extra_objs="$extra_objs linux.o rs6000-linux.o" + ;; +powerpc-wrs-vxworks*) + tm_file="${tm_file} elfos.h gnu-user.h freebsd-spec.h rs6000/sysv4.h" + tmake_file="${tmake_file} rs6000/t-fprules rs6000/t-ppccomm rs6000/t-vxworks" + extra_options="${extra_options} rs6000/sysv4.opt" + extra_headers="${extra_headers} ppc-asm.h" + case ${target} in + *-vxworksmils*) + tm_file="${tm_file} vx-common.h vxworksae.h rs6000/vxworks.h rs6000/vxworksmils.h" + tmake_file="${tmake_file} rs6000/t-vxworksmils" + ;; + *-vxworksae*) + tm_file="${tm_file} vx-common.h vxworksae.h rs6000/vxworks.h rs6000/vxworksae.h" + tmake_file="${tmake_file} rs6000/t-vxworksae" + ;; + *-vxworks*) + tm_file="${tm_file} vx-common.h vxworks.h rs6000/vxworks.h" + ;; + esac + ;; +powerpc-*-lynxos*) + xm_defines=POSIX + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h rs6000/sysv4.h rs6000/lynx.h lynx.h" + tmake_file="t-lynx rs6000/t-lynx" + extra_options="${extra_options} rs6000/sysv4.opt lynx.opt" + thread_file=lynx + gnu_ld=yes + gas=yes + ;; +powerpcle-*-elf*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h usegas.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h rs6000/sysv4le.h" + tmake_file="rs6000/t-fprules rs6000/t-ppcgas rs6000/t-ppccomm" + extra_options="${extra_options} rs6000/sysv4.opt" + ;; +powerpcle-*-eabisim*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h usegas.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h rs6000/sysv4le.h rs6000/eabi.h rs6000/eabisim.h" + tmake_file="rs6000/t-fprules rs6000/t-ppcgas rs6000/t-ppccomm" + extra_options="${extra_options} rs6000/sysv4.opt" + use_gcc_stdint=wrap + ;; +powerpcle-*-eabi*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h usegas.h freebsd-spec.h newlib-stdint.h rs6000/sysv4.h rs6000/sysv4le.h rs6000/eabi.h" + tmake_file="rs6000/t-fprules rs6000/t-ppcgas rs6000/t-ppccomm" + extra_options="${extra_options} rs6000/sysv4.opt" + use_gcc_stdint=wrap + ;; +pru*-*-*) + tm_file="elfos.h newlib-stdint.h ${tm_file}" + tmake_file="${tmake_file} pru/t-pru" + extra_objs="pru-pragma.o pru-passes.o" + use_gcc_stdint=wrap + ;; +rs6000-ibm-aix6.* | powerpc-ibm-aix6.*) + tm_file="${tm_file} rs6000/aix.h rs6000/aix61.h rs6000/xcoff.h rs6000/aix-stdint.h" + tmake_file="rs6000/t-aix52 t-slibgcc" + extra_options="${extra_options} rs6000/aix64.opt" + use_collect2=yes + thread_file='aix' + use_gcc_stdint=wrap + default_use_cxa_atexit=yes + ;; +rs6000-ibm-aix7.1.* | powerpc-ibm-aix7.1.*) + tmake_file="rs6000/t-aix52 t-slibgcc" + if test x$cpu_is_64bit = xyes; then + tm_file="${tm_file} rs6000/biarch64.h" + tmake_file="rs6000/t-aix64 t-slibgcc" + fi + tm_file="${tm_file} rs6000/aix.h rs6000/aix71.h rs6000/xcoff.h rs6000/aix-stdint.h" + extra_options="${extra_options} rs6000/aix64.opt" + use_collect2=yes + thread_file='aix' + use_gcc_stdint=wrap + default_use_cxa_atexit=yes + ;; +rs6000-ibm-aix[789].* | powerpc-ibm-aix[789].*) + tmake_file="rs6000/t-aix52 t-slibgcc" + if test x$cpu_is_64bit = xyes; then + tm_file="${tm_file} rs6000/biarch64.h" + tmake_file="rs6000/t-aix64 t-slibgcc" + fi + tm_file="${tm_file} rs6000/aix.h rs6000/aix72.h rs6000/xcoff.h rs6000/aix-stdint.h" + extra_options="${extra_options} rs6000/aix64.opt" + use_collect2=yes + thread_file='aix' + use_gcc_stdint=wrap + default_use_cxa_atexit=yes + ;; +rl78-*-elf*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + target_has_targetm_common=no + c_target_objs="rl78-c.o" + cxx_target_objs="rl78-c.o" + tmake_file="${tmake_file} rl78/t-rl78" + ;; +rx-*-elf*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + tmake_file="${tmake_file} rx/t-rx" + extra_options="${extra_options} rx/elf.opt" + ;; +rx-*-linux*) + tm_file="elfos.h linux.h glibc-stdint.h rx/linux.h ../../libgcc/config/rx/rx-abi.h" + tmake_file="${tmake_file} rx/t-linux" + ;; +s390-*-linux*) + tm_file="s390/s390.h dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h s390/linux.h" + c_target_objs="${c_target_objs} s390-c.o" + cxx_target_objs="${cxx_target_objs} s390-c.o" + if test x$enable_targets = xall; then + tmake_file="${tmake_file} s390/t-linux64" + fi + tmake_file="${tmake_file} s390/t-s390" + ;; +s390x-*-linux*) + tm_file="s390/s390x.h s390/s390.h dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h s390/linux.h" + tm_p_file="linux-protos.h s390/s390-protos.h" + c_target_objs="${c_target_objs} s390-c.o" + cxx_target_objs="${cxx_target_objs} s390-c.o" + md_file=s390/s390.md + extra_modes=s390/s390-modes.def + out_file=s390/s390.c + tmake_file="${tmake_file} s390/t-linux64 s390/t-s390" + ;; +s390x-ibm-tpf*) + tm_file="s390/s390x.h s390/s390.h dbxelf.h elfos.h glibc-stdint.h s390/tpf.h" + tm_p_file=s390/s390-protos.h + c_target_objs="${c_target_objs} s390-c.o" + cxx_target_objs="${cxx_target_objs} s390-c.o" + md_file=s390/s390.md + extra_modes=s390/s390-modes.def + out_file=s390/s390.c + thread_file='tpf' + extra_options="${extra_options} s390/tpf.opt" + tmake_file="${tmake_file} s390/t-s390" + ;; +sh-*-elf* | sh[12346l]*-*-elf* | \ + sh-*-linux* | sh[2346lbe]*-*-linux* | \ + sh-*-netbsdelf* | shl*-*-netbsdelf*) + tmake_file="${tmake_file} sh/t-sh sh/t-elf" + if test x${with_endian} = x; then + case ${target} in + sh[1234]*be-*-* | sh[1234]*eb-*-*) with_endian=big ;; + shbe-*-* | sheb-*-*) with_endian=big,little ;; + sh[1234]l* | sh[34]*-*-linux*) with_endian=little ;; + shl* | sh*-*-linux* | \ + sh-superh-elf) with_endian=little,big ;; + sh[1234]*-*-*) with_endian=big ;; + *) with_endian=big,little ;; + esac + fi + # TM_ENDIAN_CONFIG is used by t-sh to determine multilibs. + # First word : the default endian. + # Second word: the secondary endian (optional). + case ${with_endian} in + big) TM_ENDIAN_CONFIG=mb ;; + little) TM_ENDIAN_CONFIG=ml ;; + big,little) TM_ENDIAN_CONFIG="mb ml" ;; + little,big) TM_ENDIAN_CONFIG="ml mb" ;; + *) echo "with_endian=${with_endian} not supported."; exit 1 ;; + esac + case ${with_endian} in + little*) tm_file="sh/little.h ${tm_file}" ;; + esac + tm_file="${tm_file} dbxelf.h elfos.h sh/elf.h" + case ${target} in + sh*-*-linux*) tmake_file="${tmake_file} sh/t-linux" + if test x$enable_fdpic = xyes; then + tm_defines="$tm_defines FDPIC_DEFAULT=1" + fi + tm_file="${tm_file} gnu-user.h linux.h glibc-stdint.h sh/linux.h" ;; + sh*-*-netbsd*) + tm_file="${tm_file} ${nbsd_tm_file} sh/netbsd-elf.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + + ;; + sh*-superh-elf) if test x$with_libgloss != xno; then + with_libgloss=yes + tm_file="${tm_file} sh/newlib.h" + fi + tm_file="${tm_file} sh/embed-elf.h" + tm_file="${tm_file} sh/superh.h" + extra_options="${extra_options} sh/superh.opt" ;; + *) if test x$with_newlib = xyes \ + && test x$with_libgloss = xyes; then + tm_file="${tm_file} sh/newlib.h" + fi + tm_file="${tm_file} sh/embed-elf.h" ;; + esac + case ${target} in + *-*-netbsd) + ;; + *-*-elf*) + tm_file="${tm_file} newlib-stdint.h" + ;; + esac + # sed el/eb endian suffixes away to avoid confusion with sh[23]e + case `echo ${target} | sed 's/e[lb]-/-/'` in + sh4a_single_only*) sh_cpu_target=sh4a-single-only ;; + sh4a_single*) sh_cpu_target=sh4a-single ;; + sh4a_nofpu*) sh_cpu_target=sh4a-nofpu ;; + sh4al) sh_cpu_target=sh4al ;; + sh4a*) sh_cpu_target=sh4a ;; + sh4_single_only*) sh_cpu_target=sh4-single-only ;; + sh4_single*) sh_cpu_target=sh4-single ;; + sh4_nofpu*) sh_cpu_target=sh4-nofpu ;; + sh4* | sh-superh-*) sh_cpu_target=sh4 ;; + sh3e*) sh_cpu_target=sh3e ;; + sh*-*-netbsd* | sh3*) sh_cpu_target=sh3 ;; + sh2a_single_only*) sh_cpu_target=sh2a-single-only ;; + sh2a_single*) sh_cpu_target=sh2a-single ;; + sh2a_nofpu*) sh_cpu_target=sh2a-nofpu ;; + sh2a*) sh_cpu_target=sh2a ;; + sh2e*) sh_cpu_target=sh2e ;; + sh2*) sh_cpu_target=sh2 ;; + *) sh_cpu_target=sh1 ;; + esac + # did the user say --without-fp ? + if test x$with_fp = xno; then + case ${sh_cpu_target} in + sh4al | sh1) ;; + sh4a* ) sh_cpu_target=sh4a-nofpu ;; + sh4*) sh_cpu_target=sh4-nofpu ;; + sh3*) sh_cpu_target=sh3 ;; + sh2a*) sh_cpu_target=sh2a-nofpu ;; + sh2*) sh_cpu_target=sh2 ;; + *) echo --without-fp not available for $target: ignored + esac + tm_defines="$tm_defines STRICT_NOFPU=1" + fi + sh_cpu_default="`echo $with_cpu|sed s/^m/sh/|tr A-Z_ a-z-`" + case $sh_cpu_default in + sh2a-single-only | sh2a-single | sh2a-nofpu | sh2a | \ + sh4a-single-only | sh4a-single | sh4a-nofpu | sh4a | sh4al | \ + sh4-single-only | sh4-single | sh4-nofpu | sh4 | sh4-300 | \ + sh3e | sh3 | sh2e | sh2 | sh1) ;; + "") sh_cpu_default=${sh_cpu_target} ;; + *) echo "with_cpu=$with_cpu not supported"; exit 1 ;; + esac + sh_multilibs=${with_multilib_list} + if test "$sh_multilibs" = "default" ; then + case ${target} in + sh[1234]*) sh_multilibs=${sh_cpu_target} ;; + sh-superh-*) sh_multilibs=m4,m4-single,m4-single-only,m4-nofpu ;; + sh*-*-linux*) sh_multilibs=m1,m2,m2a,m3e,m4 ;; + sh*-*-netbsd*) sh_multilibs=m3,m3e,m4 ;; + *) sh_multilibs=m1,m2,m2e,m4,m4-single,m4-single-only,m2a,m2a-single ;; + esac + if test x$with_fp = xno; then + sh_multilibs="`echo $sh_multilibs|sed -e s/m4/sh4-nofpu/ -e s/,m4-[^,]*//g -e s/,m[23]e// -e s/m2a,m2a-single/m2a-nofpu/ -e s/m5-..m....,//g`" + fi + fi + target_cpu_default=SELECT_`echo ${sh_cpu_default}|tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_` + tm_defines=${tm_defines}' SH_MULTILIB_CPU_DEFAULT=\"'`echo $sh_cpu_default|sed s/sh/m/`'\"' + tm_defines="$tm_defines SUPPORT_`echo $sh_cpu_default | sed 's/^m/sh/' | tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_`=1" + sh_multilibs=`echo $sh_multilibs | sed -e 's/,/ /g' -e 's/^[Ss][Hh]/m/' -e 's/ [Ss][Hh]/ m/g' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ_ abcdefghijklmnopqrstuvwxyz-` + for sh_multilib in ${sh_multilibs}; do + case ${sh_multilib} in + m1 | m2 | m2e | m3 | m3e | \ + m4 | m4-single | m4-single-only | m4-nofpu | m4-300 |\ + m4a | m4a-single | m4a-single-only | m4a-nofpu | m4al | \ + m2a | m2a-single | m2a-single-only | m2a-nofpu) + # TM_MULTILIB_CONFIG is used by t-sh for the non-endian multilib definition + # It is passed to MULTIILIB_OPTIONS verbatim. + TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG}/${sh_multilib}" + tm_defines="$tm_defines SUPPORT_`echo $sh_multilib | sed 's/^m/sh/' | tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_`=1" + ;; + \!*) # TM_MULTILIB_EXCEPTIONS_CONFIG is used by t-sh + # It is passed the MULTILIB_EXCEPTIONS verbatim. + TM_MULTILIB_EXCEPTIONS_CONFIG="${TM_MULTILIB_EXCEPTIONS_CONFIG} `echo $sh_multilib | sed 's/^!//'`" ;; + *) + echo "with_multilib_list=${sh_multilib} not supported." + exit 1 + ;; + esac + done + TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's:^/::'` + if test x${enable_incomplete_targets} = xyes ; then + tm_defines="$tm_defines SUPPORT_SH1=1 SUPPORT_SH2E=1 SUPPORT_SH4=1 SUPPORT_SH4_SINGLE=1 SUPPORT_SH2A=1 SUPPORT_SH2A_SINGLE=1" + fi + tm_file="$tm_file ./sysroot-suffix.h" + tmake_file="$tmake_file t-sysroot-suffix" + ;; +sh-*-rtems*) + tmake_file="${tmake_file} sh/t-sh sh/t-rtems" + tm_file="${tm_file} dbxelf.h elfos.h sh/elf.h sh/embed-elf.h sh/rtemself.h rtems.h newlib-stdint.h" + ;; +sh-wrs-vxworks) + tmake_file="$tmake_file sh/t-sh sh/t-vxworks" + tm_file="${tm_file} elfos.h sh/elf.h sh/embed-elf.h vx-common.h vxworks.h sh/vxworks.h" + ;; +sparc-*-elf*) + tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h sparc/sysv4.h sparc/sp-elf.h" + case ${target} in + *-leon-*) + tmake_file="sparc/t-sparc sparc/t-leon" + ;; + *-leon[3-9]*) + tmake_file="sparc/t-sparc sparc/t-leon3" + ;; + *) + tmake_file="sparc/t-sparc sparc/t-elf" + ;; + esac + ;; +sparc-*-rtems*) + tm_file="${tm_file} dbxelf.h elfos.h sparc/sysv4.h sparc/sp-elf.h sparc/rtemself.h rtems.h newlib-stdint.h" + tmake_file="${tmake_file} sparc/t-sparc sparc/t-rtems" + ;; +sparc-*-linux*) + tm_file="${tm_file} dbxelf.h elfos.h sparc/sysv4.h gnu-user.h linux.h glibc-stdint.h sparc/tso.h" + extra_options="${extra_options} sparc/long-double-switch.opt" + case ${target} in + *-leon-*) + tmake_file="${tmake_file} sparc/t-sparc sparc/t-leon" + ;; + *-leon[3-9]*) + tmake_file="${tmake_file} sparc/t-sparc sparc/t-leon3" + ;; + *) + tmake_file="${tmake_file} sparc/t-sparc" + ;; + esac + if test x$enable_targets = xall; then + tm_file="sparc/biarch64.h ${tm_file} sparc/linux64.h" + tmake_file="${tmake_file} sparc/t-linux64" + else + tm_file="${tm_file} sparc/linux.h" + tmake_file="${tmake_file} sparc/t-linux" + fi + ;; +sparc-*-netbsdelf*) + tm_file="${tm_file} dbxelf.h elfos.h sparc/sysv4.h ${nbsd_tm_file} sparc/netbsd-elf.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + extra_options="${extra_options} sparc/long-double-switch.opt" + tmake_file="${tmake_file} sparc/t-sparc" + ;; +sparc*-*-solaris2*) + tm_file="sparc/biarch64.h ${tm_file} ${sol2_tm_file} sparc/tso.h" + case ${target} in + sparc64-*-* | sparcv9-*-*) + tm_file="sparc/default64.h ${tm_file}" + ;; + *) + test x$with_cpu != x || with_cpu=v9 + ;; + esac + tmake_file="${tmake_file} sparc/t-sparc sparc/t-sol2" + ;; +sparc-wrs-vxworks) + tm_file="${tm_file} elfos.h sparc/sysv4.h vx-common.h vxworks.h sparc/vxworks.h" + tmake_file="${tmake_file} sparc/t-sparc sparc/t-vxworks" + ;; +sparc64-*-elf*) + tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h sparc/sysv4.h sparc/sp64-elf.h" + extra_options="${extra_options}" + tmake_file="${tmake_file} sparc/t-sparc" + ;; +sparc64-*-rtems*) + tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h sparc/sysv4.h sparc/sp64-elf.h sparc/rtemself.h rtems.h" + extra_options="${extra_options}" + tmake_file="${tmake_file} sparc/t-sparc sparc/t-rtems-64" + ;; +sparc64-*-linux*) + tm_file="sparc/biarch64.h ${tm_file} dbxelf.h elfos.h sparc/sysv4.h gnu-user.h linux.h glibc-stdint.h sparc/default64.h sparc/linux64.h sparc/tso.h" + extra_options="${extra_options} sparc/long-double-switch.opt" + tmake_file="${tmake_file} sparc/t-sparc sparc/t-linux64" + ;; +sparc64-*-freebsd*|ultrasparc-*-freebsd*) + tm_file="${tm_file} ${fbsd_tm_file} dbxelf.h elfos.h sparc/sysv4.h sparc/freebsd.h" + extra_options="${extra_options} sparc/long-double-switch.opt" + case "x$with_cpu" in + xultrasparc) ;; + x) with_cpu=ultrasparc ;; + *) echo "$with_cpu not supported for freebsd target"; exit 1 ;; + esac + tmake_file="${tmake_file} sparc/t-sparc" + ;; +sparc64-*-netbsd*) + tm_file="sparc/biarch64.h ${tm_file}" + tm_file="${tm_file} dbxelf.h elfos.h sparc/sysv4.h ${nbsd_tm_file} sparc/netbsd-elf.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt" + extra_options="${extra_options} sparc/long-double-switch.opt" + tmake_file="${tmake_file} sparc/t-sparc sparc/t-netbsd64" + ;; +sparc64-*-openbsd*) + tm_file="sparc/openbsd1-64.h ${tm_file} dbxelf.h elfos.h sparc/sysv4.h sparc/sp64-elf.h" + tm_file="${tm_file} openbsd.h openbsd-stdint.h openbsd-libpthread.h sparc/openbsd64.h" + extra_options="${extra_options} openbsd.opt" + extra_options="${extra_options}" + gas=yes gnu_ld=yes + with_cpu=ultrasparc + tmake_file="${tmake_file} sparc/t-sparc" + ;; +tic6x-*-elf) + tm_file="elfos.h ${tm_file} c6x/elf-common.h c6x/elf.h" + tm_file="${tm_file} dbxelf.h tm-dwarf2.h newlib-stdint.h" + tmake_file="c6x/t-c6x c6x/t-c6x-elf" + use_collect2=no + ;; +tic6x-*-uclinux) + tm_file="elfos.h ${tm_file} gnu-user.h linux.h c6x/elf-common.h c6x/uclinux-elf.h" + tm_file="${tm_file} dbxelf.h tm-dwarf2.h glibc-stdint.h" + tm_file="${tm_file} ./sysroot-suffix.h" + tmake_file="t-sysroot-suffix t-slibgcc" + tmake_file="${tmake_file} c6x/t-c6x c6x/t-c6x-elf c6x/t-c6x-uclinux" + use_collect2=no + ;; +tilegx*-*-linux*) + tm_file="elfos.h gnu-user.h linux.h glibc-stdint.h tilegx/linux.h ${tm_file}" + tmake_file="${tmake_file} tilegx/t-tilegx" + extra_objs="${extra_objs} mul-tables.o" + c_target_objs="${c_target_objs} tilegx-c.o" + cxx_target_objs="${cxx_target_objs} tilegx-c.o" + extra_headers="feedback.h" + case $target in + tilegxbe-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + ;; +tilepro*-*-linux*) + tm_file="elfos.h gnu-user.h linux.h glibc-stdint.h tilepro/linux.h ${tm_file}" + tmake_file="${tmake_file} tilepro/t-tilepro" + extra_objs="${extra_objs} mul-tables.o" + c_target_objs="${c_target_objs} tilepro-c.o" + cxx_target_objs="${cxx_target_objs} tilepro-c.o" + extra_headers="feedback.h" + ;; +v850-*-rtems*) + target_cpu_default="TARGET_CPU_generic" + tm_file="dbxelf.h elfos.h v850/v850.h" + tm_file="${tm_file} v850/rtems.h rtems.h newlib-stdint.h" + tmake_file="${tmake_file} v850/t-v850" + tmake_file="${tmake_file} v850/t-rtems" + use_collect2=no + c_target_objs="v850-c.o" + cxx_target_objs="v850-c.o" + ;; +v850*-*-*) + case ${target} in + v850e3v5-*-*) + target_cpu_default="TARGET_CPU_v850e3v5" + ;; + v850e2v3-*-*) + target_cpu_default="TARGET_CPU_v850e2v3" + ;; + v850e2-*-*) + target_cpu_default="TARGET_CPU_v850e2" + ;; + v850e1-*-* | v850es-*-*) + target_cpu_default="TARGET_CPU_v850e1" + ;; + v850e-*-*) + target_cpu_default="TARGET_CPU_v850e" + ;; + v850-*-*) + target_cpu_default="TARGET_CPU_generic" + ;; + esac + tm_file="dbxelf.h elfos.h newlib-stdint.h v850/v850.h" + if test x$stabs = xyes + then + tm_file="${tm_file} dbx.h" + fi + use_collect2=no + c_target_objs="v850-c.o" + cxx_target_objs="v850-c.o" + use_gcc_stdint=wrap + ;; +vax-*-linux*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h vax/elf.h vax/linux.h" + extra_options="${extra_options} vax/elf.opt" + ;; +vax-*-netbsdelf*) + tm_file="${tm_file} elfos.h ${nbsd_tm_file} vax/elf.h vax/netbsd-elf.h" + extra_options="${extra_options} netbsd.opt netbsd-elf.opt vax/elf.opt" + tm_defines="${tm_defines} CHAR_FAST8=1 SHORT_FAST16=1" + ;; +vax-*-openbsd*) + tm_file="vax/vax.h vax/openbsd1.h openbsd.h openbsd-stdint.h openbsd-libpthread.h vax/openbsd.h" + extra_options="${extra_options} openbsd.opt" + use_collect2=yes + ;; +visium-*-elf*) + tm_file="dbxelf.h elfos.h ${tm_file} visium/elf.h newlib-stdint.h" + tmake_file="visium/t-visium visium/t-crtstuff" + ;; +xstormy16-*-elf) + # For historical reasons, the target files omit the 'x'. + tm_file="dbxelf.h elfos.h newlib-stdint.h stormy16/stormy16.h" + tm_p_file=stormy16/stormy16-protos.h + tm_d_file="elfos.h stormy16/stormy16.h" + md_file=stormy16/stormy16.md + out_file=stormy16/stormy16.c + extra_options=stormy16/stormy16.opt + tmake_file="stormy16/t-stormy16" + ;; +xtensa*-*-elf*) + tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h xtensa/elf.h" + extra_options="${extra_options} xtensa/elf.opt" + ;; +xtensa*-*-linux*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h xtensa/linux.h" + tmake_file="${tmake_file} xtensa/t-xtensa" + ;; +xtensa*-*-uclinux*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h xtensa/uclinux.h" + tmake_file="${tmake_file} xtensa/t-xtensa" + extra_options="${extra_options} xtensa/uclinux.opt" + ;; +am33_2.0-*-linux*) + tm_file="mn10300/mn10300.h dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h mn10300/linux.h" + gas=yes gnu_ld=yes + use_collect2=no + ;; +m32c-*-rtems*) + tm_file="dbxelf.h elfos.h ${tm_file} m32c/rtems.h rtems.h newlib-stdint.h" + c_target_objs="m32c-pragma.o" + cxx_target_objs="m32c-pragma.o" + ;; +m32c-*-elf*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + c_target_objs="m32c-pragma.o" + cxx_target_objs="m32c-pragma.o" + ;; +*) + echo "*** Configuration ${target} not supported" 1>&2 + exit 1 + ;; +esac + +case ${target} in +i[34567]86-*-linux* | x86_64-*-linux*) + tmake_file="${tmake_file} i386/t-pmm_malloc i386/t-i386" + ;; +i[34567]86-*-* | x86_64-*-*) + tmake_file="${tmake_file} i386/t-gmm_malloc i386/t-i386" + ;; +powerpc*-*-* | rs6000-*-*) + tm_file="${tm_file} ${cpu_type}/option-defaults.h" +esac + +# non-glibc systems +case ${target} in +*-linux-musl*) + tmake_file="${tmake_file} t-musl" + ;; +*-linux-uclibc*) + tmake_file="${tmake_file} t-uclibc" + ;; +esac + +# Assume the existence of indirect function support and allow the use of the +# resolver attribute. +case ${target} in +*-*-linux*android*|*-*-linux*uclibc*|*-*-linux*musl*) + ;; +*-*-kfreebsd*-gnu | *-*-kopensolaris*-gnu) + ;; +*-*-linux* | *-*-gnu*) + case ${target} in + aarch64*-* | arm*-* | i[34567]86-* | powerpc*-* | s390*-* | sparc*-* | x86_64-*) + default_gnu_indirect_function=yes + ;; + esac + ;; +esac + +# Build mkoffload tool +case ${target} in +*-intelmic-* | *-intelmicemul-*) + tmake_file="${tmake_file} i386/t-intelmic" + tm_file="${tm_file} i386/intelmic-offload.h" + ;; +esac + +if [ "$target_has_targetcm" = "no" ]; then + c_target_objs="$c_target_objs default-c.o" + cxx_target_objs="$cxx_target_objs default-c.o" +fi + +if [ "$common_out_file" = "" ]; then + if [ "$target_has_targetm_common" = "yes" ]; then + common_out_file="$cpu_type/$cpu_type-common.c" + else + common_out_file="default-common.c" + fi +fi + +if [ "$target_has_targetdm" = "no" ]; then + d_target_objs="$d_target_objs default-d.o" +fi + +# Support for --with-cpu and related options (and a few unrelated options, +# too). +case ${with_cpu} in + yes | no) + echo "--with-cpu must be passed a value" 1>&2 + exit 1 + ;; +esac + +# Set arch and cpu from ${target} and ${target_noncanonical}. Set cpu +# to generic if there is no processor scheduler model for the target. +arch= +cpu= +arch_without_sse2=no +arch_without_64bit=no +case ${target} in + i386-*-freebsd*) + if test $fbsd_major -ge 6; then + arch=i486 + else + arch=i386 + fi + cpu=generic + arch_without_sse2=yes + arch_without_64bit=yes + ;; + i386-*-netbsd*) + arch=i486 + cpu=generic + arch_without_sse2=yes + arch_without_64bit=yes + ;; + i386-*-*) + arch=i386 + cpu=i386 + arch_without_sse2=yes + arch_without_64bit=yes + ;; + i486-*-*) + arch=i486 + cpu=i486 + arch_without_sse2=yes + arch_without_64bit=yes + ;; + i586-*-*) + arch_without_sse2=yes + arch_without_64bit=yes + case ${target_noncanonical} in + k6_2-*) + arch=k6-2 + cpu=k6-2 + ;; + k6_3-*) + arch=k6-3 + cpu=k6-3 + ;; + k6-*) + arch=k6 + cpu=k6 + ;; + pentium_mmx-*|winchip_c6-*|winchip2-*|c3-*) + arch=pentium-mmx + cpu=pentium-mmx + ;; + *) + arch=pentium + cpu=pentium + ;; + esac + ;; + i686-*-* | i786-*-*) + case ${target_noncanonical} in + znver1-*) + arch=znver1 + cpu=znver1 + ;; + znver2-*) + arch=znver2 + cpu=znver2 + ;; + znver3-*) + arch=znver3 + cpu=znver3 + ;; + bdver4-*) + arch=bdver4 + cpu=bdver4 + ;; + bdver3-*) + arch=bdver3 + cpu=bdver3 + ;; + bdver2-*) + arch=bdver2 + cpu=bdver2 + ;; + bdver1-*) + arch=bdver1 + cpu=bdver1 + ;; + btver1-*) + arch=btver1 + cpu=btver1 + ;; + btver2-*) + arch=btver2 + cpu=btver2 + ;; + amdfam10-*|barcelona-*) + arch=amdfam10 + cpu=amdfam10 + ;; + k8_sse3-*|opteron_sse3-*|athlon64_sse3-*) + arch=k8-sse3 + cpu=k8-sse3 + ;; + k8-*|opteron-*|athlon64-*|athlon_fx-*) + arch=k8 + cpu=k8 + ;; + athlon_xp-*|athlon_mp-*|athlon_4-*) + arch=athlon-4 + cpu=athlon-4 + arch_without_sse2=yes + arch_without_64bit=yes + ;; + athlon_tbird-*|athlon-*) + arch=athlon + cpu=athlon + arch_without_sse2=yes + ;; + geode-*) + arch=geode + cpu=geode + arch_without_sse2=yes + ;; + pentium2-*) + arch=pentium2 + cpu=pentium2 + arch_without_sse2=yes + ;; + pentium3-*|pentium3m-*) + arch=pentium3 + cpu=pentium3 + arch_without_sse2=yes + ;; + pentium4-*|pentium4m-*) + arch=pentium4 + cpu=pentium4 + ;; + prescott-*) + arch=prescott + cpu=prescott + ;; + nocona-*) + arch=nocona + cpu=nocona + ;; + atom-*) + arch=atom + cpu=atom + ;; + slm-*) + arch=slm + cpu=slm + ;; + core2-*) + arch=core2 + cpu=core2 + ;; + corei7-*) + arch=corei7 + cpu=corei7 + ;; + corei7_avx-*) + arch=corei7-avx + cpu=corei7-avx + ;; + pentium_m-*) + arch=pentium-m + cpu=pentium-m + ;; + pentiumpro-*) + arch=pentiumpro + cpu=pentiumpro + arch_without_sse2=yes + ;; + *) + arch=pentiumpro + cpu=generic + arch_without_sse2=yes + arch_without_64bit=yes + ;; + esac + ;; + x86_64-*-*) + case ${target_noncanonical} in + znver1-*) + arch=znver1 + cpu=znver1 + ;; + znver2-*) + arch=znver2 + cpu=znver2 + ;; + znver3-*) + arch=znver3 + cpu=znver3 + ;; + bdver4-*) + arch=bdver4 + cpu=bdver4 + ;; + bdver3-*) + arch=bdver3 + cpu=bdver3 + ;; + bdver2-*) + arch=bdver2 + cpu=bdver2 + ;; + bdver1-*) + arch=bdver1 + cpu=bdver1 + ;; + btver1-*) + arch=btver1 + cpu=btver1 + ;; + btver2-*) + arch=btver2 + cpu=btver2 + ;; + amdfam10-*|barcelona-*) + arch=amdfam10 + cpu=amdfam10 + ;; + k8_sse3-*|opteron_sse3-*|athlon64_sse3-*) + arch=k8-sse3 + cpu=k8-sse3 + ;; + k8-*|opteron-*|athlon_64-*) + arch=k8 + cpu=k8 + ;; + nocona-*) + arch=nocona + cpu=nocona + ;; + atom-*) + arch=atom + cpu=atom + ;; + slm-*) + arch=slm + cpu=slm + ;; + core2-*) + arch=core2 + cpu=core2 + ;; + corei7-*) + arch=corei7 + cpu=corei7 + ;; + *) + arch=x86-64 + cpu=generic + ;; + esac + ;; +esac + +# If there is no $with_cpu option, try to infer one from ${target}. +# This block sets nothing except for with_cpu. +if test x$with_cpu = x ; then + case ${target} in + i[34567]86-*-elfiamcu) + with_cpu=lakemont + ;; + i[34567]86-*-*|x86_64-*-*) + with_cpu=$cpu + ;; + alphaev6[78]*-*-*) + with_cpu=ev67 + ;; + alphaev6*-*-*) + with_cpu=ev6 + ;; + alphapca56*-*-*) + with_cpu=pca56 + ;; + alphaev56*-*-*) + with_cpu=ev56 + ;; + alphaev5*-*-*) + with_cpu=ev5 + ;; + frv-*-*linux* | frv400-*-*linux*) + with_cpu=fr400 + ;; + frv550-*-*linux*) + with_cpu=fr550 + ;; + m68k*-*-*) + case "$with_arch" in + "cf") + with_cpu=${default_cf_cpu} + ;; + "" | "m68k") + with_cpu=m${default_m68k_cpu} + ;; + esac + ;; + sparc*-*-*) + case ${target} in + *-leon-*) + with_cpu=leon + ;; + *-leon[3-9]*) + with_cpu=leon3 + ;; + *-leon[3-9]v7*) + with_cpu=leon3v7 + ;; + *) + with_cpu="`echo ${target} | sed 's/-.*$//'`" + ;; + esac + ;; + visium-*-*) + with_cpu=gr5 + ;; + esac + + # Avoid overriding --with-cpu-32 and --with-cpu-64 values. + case ${target} in + i[34567]86-*-*|x86_64-*-*) + if test x$with_cpu_32 != x || test x$with_cpu_64 != x; then + if test x$with_cpu_32 = x; then + with_cpu_32=$with_cpu + fi + if test x$with_cpu_64 = x; then + with_cpu_64=$with_cpu + fi + with_cpu= + fi + ;; + esac +fi + +# Support for --with-arch and related options (and a few unrelated options, +# too). +case ${with_arch} in + yes | no) + echo "--with-arch must be passed a value" 1>&2 + exit 1 + ;; +esac + +# If there is no $with_arch option, try to infer one from ${target}. +# This block sets nothing except for with_arch. +if test x$with_arch = x ; then + case ${target} in + i[34567]86-*-darwin*|x86_64-*-darwin*) + # Default arch is set via TARGET_SUBTARGET32_ISA_DEFAULT + # and TARGET_SUBTARGET64_ISA_DEFAULT in config/i386/darwin.h. + ;; + i[34567]86-*-elfiamcu) + with_arch=lakemont + ;; + i[34567]86-*-*) + # --with-fpmath sets the default ISA to SSE2, which is the same + # ISA supported by Pentium 4. + if test x$with_fpmath = x || test $arch_without_sse2 = no; then + with_arch=$arch + else + with_arch=pentium4 + fi + ;; + x86_64-*-*) + with_arch=$arch + ;; + mips64r5900-*-* | mips64r5900el-*-* | mipsr5900-*-* | mipsr5900el-*-*) + with_arch=r5900 + ;; + mips*-*-vxworks) + with_arch=mips2 + ;; + esac + + # Avoid overriding --with-arch-32 and --with-arch-64 values. + case ${target} in + i[34567]86-*-darwin*|x86_64-*-darwin*) + # Default arch is set via TARGET_SUBTARGET32_ISA_DEFAULT + # and TARGET_SUBTARGET64_ISA_DEFAULT in config/i386/darwin.h. + ;; + i[34567]86-*-*|x86_64-*-*) + if test x$with_arch_32 != x || test x$with_arch_64 != x; then + if test x$with_arch_32 = x; then + with_arch_32=$with_arch + fi + if test x$with_arch_64 = x; then + if test $arch_without_64bit = yes; then + # Set the default 64bit arch to x86-64 if the default arch + # doesn't support 64bit. + with_arch_64=x86-64 + else + with_arch_64=$with_arch + fi + fi + with_arch= + elif test $arch_without_64bit$need_64bit_isa = yesyes; then + # Set the default 64bit arch to x86-64 if the default arch + # doesn't support 64bit and we need 64bit ISA. + with_arch_32=$with_arch + with_arch_64=x86-64 + with_arch= + fi + ;; + esac +fi + +# Infer a default setting for --with-float. +if test x$with_float = x; then + case ${target} in + mips64r5900-*-* | mips64r5900el-*-* | mipsr5900-*-* | mipsr5900el-*-*) + # The R5900 doesn't support 64-bit float. 32-bit float doesn't + # comply with IEEE 754. + with_float=soft + ;; + esac +fi + +# Infer a default setting for --with-fpu. +if test x$with_fpu = x; then + case ${target} in + mips64r5900-*-* | mips64r5900el-*-* | mipsr5900-*-* | mipsr5900el-*-*) + # The R5900 FPU only supports single precision. + with_fpu=single + ;; + esac +fi + +# Support --with-fpmath. +if test x$with_fpmath != x; then + case ${target} in + i[34567]86-*-* | x86_64-*-*) + case ${with_fpmath} in + avx) + tm_file="${tm_file} i386/avxmath.h" + ;; + sse) + tm_file="${tm_file} i386/ssemath.h" + ;; + *) + echo "Invalid --with-fpmath=$with_fpmath" 1>&2 + exit 1 + ;; + esac + ;; + *) + echo "--with-fpmath isn't supported for $target." 1>&2 + exit 1 + ;; + esac +fi + +# Similarly for --with-schedule. +if test x$with_schedule = x; then + case ${target} in + hppa1*) + # Override default PA8000 scheduling model. + with_schedule=7100LC + ;; + esac +fi + +# Infer a default setting for --with-llsc. +if test x$with_llsc = x; then + case ${target} in + mips*-*-linux*) + # The kernel emulates LL and SC where necessary. + with_llsc=yes + ;; + mips64r5900-*-* | mips64r5900el-*-* | mipsr5900-*-* | mipsr5900el-*-*) + # The R5900 doesn't support LL(D) and SC(D). + with_llsc=no + ;; + esac +fi + +# Validate and mark as valid any --with options supported +# by this target. In order to use a particular --with option +# you must list it in supported_defaults; validating the value +# is optional. This case statement should set nothing besides +# supported_defaults. + +supported_defaults= +case "${target}" in + aarch64*-*-*) + supported_defaults="abi cpu cpu_64 arch arch_64 tune tune_64" + if test x$with_cpu_64 != x && test x$with_cpu = x; then + with_cpu=$with_cpu_64 + fi + if test x$with_arch_64 != x && test x$with_arch = x; then + with_arch=$with_arch_64 + fi + if test x$with_tune_64 != x && test x$with_tune = x; then + with_tune=$with_tune_64 + fi + for which in cpu arch tune; do + eval "val=\$with_$which" + base_val=`echo $val | sed -e 's/\+.*//'` + ext_val=`echo $val | sed -e 's/[a-z0-9.-]\+//'` + + if [ $which = arch ]; then + def=aarch64-arches.def + pattern=AARCH64_ARCH + else + def=aarch64-cores.def + pattern=AARCH64_CORE + fi + + ext_mask=AARCH64_CPU_DEFAULT_FLAGS + + # Find the base CPU or ARCH id in aarch64-cores.def or + # aarch64-arches.def + if [ x"$base_val" = x ] \ + || grep "^$pattern(\"$base_val\"," \ + ${srcdir}/config/aarch64/$def \ + > /dev/null; then + + if [ $which = arch ]; then + base_id=`grep "^$pattern(\"$base_val\"," \ + ${srcdir}/config/aarch64/$def | \ + sed -e 's/^[^,]*,[ ]*//' | \ + sed -e 's/,.*$//'` + # Extract the architecture flags from aarch64-arches.def + ext_mask=`grep "^$pattern(\"$base_val\"," \ + ${srcdir}/config/aarch64/$def | \ + sed -e 's/)$//' | \ + sed -e 's/^.*,//'` + else + base_id=`grep "^$pattern(\"$base_val\"," \ + ${srcdir}/config/aarch64/$def | \ + sed -e 's/^[^,]*,[ ]*//' | \ + sed -e 's/,.*$//'` + fi + + # Disallow extensions in --with-tune=cortex-a53+crc. + if [ $which = tune ] && [ x"$ext_val" != x ]; then + echo "Architecture extensions not supported in --with-$which=$val" 1>&2 + exit 1 + fi + + # Use the pre-processor to strip flatten the options. + # This makes the format less rigid than if we use + # grep and sed directly here. + opt_macro="AARCH64_OPT_EXTENSION(A, B, C, D, E, F)=A, B, C, D, E, F" + options_parsed="`$ac_cv_prog_CPP -D"$opt_macro" -x c \ + ${srcdir}/config/aarch64/aarch64-option-extensions.def`" + + # Match one element inside AARCH64_OPT_EXTENSION, we + # consume anything that's not a ,. + elem="[ ]*\([^,]\+\)[ ]*" + + # Repeat the pattern for the number of entries in the + # AARCH64_OPT_EXTENSION, currently 6 times. + sed_patt="^$elem,$elem,$elem,$elem,$elem,$elem" + + while [ x"$ext_val" != x ] + do + ext_val=`echo $ext_val | sed -e 's/\+//'` + ext=`echo $ext_val | sed -e 's/\+.*//'` + base_ext=`echo $ext | sed -e 's/^no//'` + opt_line=`echo -e "$options_parsed" | \ + grep "^\"$base_ext\""` + + if [ x"$base_ext" = x ] \ + || [[ -n $opt_line ]]; then + + # These regexp extract the elements based on + # their group match index in the regexp. + ext_canon=`echo -e "$opt_line" | \ + sed -e "s/$sed_patt/\2/"` + ext_on=`echo -e "$opt_line" | \ + sed -e "s/$sed_patt/\3/"` + ext_off=`echo -e "$opt_line" | \ + sed -e "s/$sed_patt/\4/"` + + if [ $ext = $base_ext ]; then + # Adding extension + ext_mask="("$ext_mask") | ("$ext_on" | "$ext_canon")" + else + # Removing extension + ext_mask="("$ext_mask") & ~("$ext_off" | "$ext_canon")" + fi + + true + else + echo "Unknown extension used in --with-$which=$val" 1>&2 + exit 1 + fi + ext_val=`echo $ext_val | sed -e 's/[a-z0-9]\+//'` + done + + ext_mask="(("$ext_mask") << 6)" + if [ x"$base_id" != x ]; then + target_cpu_cname="TARGET_CPU_$base_id | $ext_mask" + fi + true + else + # Allow --with-$which=native. + if [ "$val" = native ]; then + true + else + echo "Unknown $which used in --with-$which=$val" 1>&2 + exit 1 + fi + fi + done + ;; + + alpha*-*-*) + supported_defaults="cpu tune" + for which in cpu tune; do + eval "val=\$with_$which" + case "$val" in + "" \ + | ev4 | ev45 | 21064 | ev5 | 21164 | ev56 | 21164a \ + | pca56 | 21164PC | 21164pc | ev6 | 21264 | ev67 \ + | 21264a) + ;; + *) + echo "Unknown CPU used in --with-$which=$val" 1>&2 + exit 1 + ;; + esac + done + ;; + + arc*-*-*) + supported_defaults="cpu" + + if [ x"$with_cpu" = x ] \ + || grep "^ARC_CPU ($with_cpu," \ + ${srcdir}/config/arc/arc-cpus.def \ + > /dev/null; then + # Ok + true + else + echo "Unknown cpu used in --with-cpu=$with_cpu" 1>&2 + exit 1 + fi + ;; + + csky-*-*) + supported_defaults="cpu endian float" + ;; + + arm*-*-*) + supported_defaults="arch cpu float tune fpu abi mode tls" + for which in cpu tune arch; do + # See if it matches a supported value + eval "val=\$with_$which" + if [ x"$val" != x ]; then + cpu=`awk -f ${srcdir}/config/arm/parsecpu.awk \ + -v cmd="chk$which $val" \ + ${srcdir}/config/arm/arm-cpus.in` + if [ "$cpu" = "error" ]; then + echo "Unknown target in --with-$which=$val" 1>&2 + exit 1 + else + new_val=$cpu + eval "target_${which}_cname=$new_val" + echo "For $val real value is $new_val" + fi + fi + done + + case "$with_float" in + "" \ + | soft | hard | softfp) + # OK + ;; + *) + echo "Unknown floating point type used in --with-float=$with_float" 1>&2 + exit 1 + ;; + esac + + # see if --with-fpu matches any of the supported FPUs + if [ x"$with_fpu" != x ] ; then + val=$with_fpu + fpu=`awk -f ${srcdir}/config/arm/parsecpu.awk \ + -v cmd="chkfpu $val" \ + ${srcdir}/config/arm/arm-cpus.in` + if [ "$fpu" = "error" ] + then + echo "Unknown target in --with-fpu=$val" 1>&2 + exit 1 + fi + fi + + case "$with_abi" in + "" \ + | apcs-gnu | atpcs | aapcs | iwmmxt | aapcs-linux ) + #OK + ;; + *) + echo "Unknown ABI used in --with-abi=$with_abi" + exit 1 + ;; + esac + + case "$with_mode" in + "" \ + | arm | thumb ) + #OK + ;; + *) + echo "Unknown mode used in --with-mode=$with_mode" + exit 1 + ;; + esac + + case "$with_tls" in + "" \ + | gnu | gnu2) + # OK + ;; + *) + echo "Unknown TLS method used in --with-tls=$with_tls" 1>&2 + exit 1 + ;; + esac + + if test "x$with_arch" != x && test "x$with_cpu" != x; then + echo "Switch \"--with-arch\" may not be used with switch \"--with-cpu\"" 1>&2 + exit 1 + fi + + if test "x$with_cpu" != x && test "x$with_tune" != x; then + echo "Switch \"--with-tune\" may not be used with switch \"--with-cpu\"" 1>&2 + exit 1 + fi + + # Add extra multilibs + if test "x$with_multilib_list" != x; then + ml= + arm_multilibs=`echo $with_multilib_list | sed -e 's/,/ /g'` + if test "x${arm_multilibs}" != xdefault ; then + for arm_multilib in ${arm_multilibs}; do + case ${arm_multilib} in + aprofile|rmprofile) + tmake_profile_file="arm/t-multilib" + ;; + @*) + ml=`echo "X$arm_multilib" | sed '1s,^X@,,'` + if test -f "${srcdir}/config/arm/${ml}"; then + tmake_file="${tmake_file} arm/${ml}" + else + echo "Error: ${ml} does not exist in ${srcdir}/config/arm" >&2 + exit 1 + fi + ;; + *) + echo "Error: --with-multilib-list=${with_multilib_list} not supported." 1>&2 + exit 1 + ;; + esac + done + fi + + if test "x${tmake_profile_file}" != x ; then + # arm/t-aprofile and arm/t-rmprofile are only + # designed to work without any with-cpu, + # with-arch, with-mode, with-fpu or with-float + # options. + if test "x$with_arch" != x \ + || test "x$with_cpu" != x \ + || test "x$with_float" != x \ + || test "x$with_fpu" != x \ + || test "x$with_mode" != x ; then + echo "Error: You cannot use any of --with-arch/cpu/fpu/float/mode with --with-multilib-list=${with_multilib_list}" 1>&2 + exit 1 + elif test "x$ml" != x ; then + echo "Error: You cannot use builtin multilib profiles along with custom ones" 1>&2 + exit 1 + fi + # But pass the default value for float-abi + # through to the multilib selector + with_float="soft" + tmake_file="${tmake_file} ${tmake_profile_file}" + TM_MULTILIB_CONFIG="$with_multilib_list" + fi + fi + target_cpu_cname=${target_cpu_cname:-arm7tdmi} + with_cpu=${with_cpu:-$target_cpu_cname} + ;; + + fr*-*-*linux*) + supported_defaults=cpu + case "$with_cpu" in + fr400) ;; + fr550) ;; + *) + echo "Unknown cpu used in --with-cpu=$with_cpu" 1>&2 + exit 1 + ;; + esac + ;; + + fido-*-* | m68k*-*-*) + supported_defaults="arch cpu" + case "$with_arch" in + "" | "m68k"| "cf") + m68k_arch_family="$with_arch" + ;; + *) + echo "Invalid --with-arch=$with_arch" 1>&2 + exit 1 + ;; + esac + + # We always have a $with_cpu setting here. + case "$with_cpu" in + "m68000" | "m68010" | "m68020" | "m68030" | "m68040" | "m68060") + m68k_cpu_ident=$with_cpu + ;; + "m68020-40") + m68k_cpu_ident=m68020 + tm_defines="$tm_defines M68K_DEFAULT_TUNE=u68020_40" + ;; + "m68020-60") + m68k_cpu_ident=m68020 + tm_defines="$tm_defines M68K_DEFAULT_TUNE=u68020_60" + ;; + *) + # We need the C identifier rather than the string. + m68k_cpu_ident=`awk -v arg="\"$with_cpu\"" \ + 'BEGIN { FS="[ \t]*[,()][ \t]*" }; \ + $1 == "M68K_DEVICE" && $2 == arg { print $3 }' \ + ${srcdir}/config/m68k/m68k-devices.def` + if [ x"$m68k_cpu_ident" = x ] ; then + echo "Unknown CPU used in --with-cpu=$with_cpu" 1>&2 + exit 1 + fi + with_cpu="mcpu=$with_cpu" + ;; + esac + ;; + + amdgcn-*-*) + supported_defaults="arch tune" + + for which in arch tune; do + eval "val=\$with_$which" + case ${val} in + "" | fiji | gfx900 | gfx906 ) + # OK + ;; + *) + echo "Unknown cpu used in --with-$which=$val." 1>&2 + exit 1 + ;; + esac + done + [ "x$with_arch" = x ] && with_arch=fiji + ;; + + hppa*-*-*) + supported_defaults="arch schedule" + + case "$with_arch" in + "" | 1.0 | 1.1 | 2.0) + # OK + ;; + *) + echo "Unknown architecture used in --with-arch=$with_arch" 1>&2 + exit 1 + ;; + esac + + case "$with_schedule" in + "" | 700 | 7100 | 7100LC | 7200 | 7300 | 8000) + # OK + ;; + *) + echo "Unknown processor used in --with-schedule=$with_schedule." 1>&2 + exit 1 + ;; + esac + ;; + + i[34567]86-*-* | x86_64-*-*) + supported_defaults="abi arch arch_32 arch_64 cpu cpu_32 cpu_64 tune tune_32 tune_64" + for which in arch arch_32 arch_64 cpu cpu_32 cpu_64 tune tune_32 tune_64; do + eval "val=\$with_$which" + case " $x86_archs " in + *" ${val} "*) + case "${target}" in + x86_64-*-*) + case "x$which" in + *_32) + ;; + *) + echo "CPU given in --with-$which=$val doesn't support 64bit mode." 1>&2 + exit 1 + ;; + esac + ;; + esac + # OK + ;; + *) + if test x${val} != x; then + case " $x86_64_archs " in + *" ${val} "*) + # Disallow x86-64-v* for --with-cpu=/--with-tune= + case "x$which$val" in + xcpu*x86-64-v*|xtune*x86-64-v*) + echo "Unknown CPU given in --with-$which=$val." 1>&2 + exit 1 + ;; + *) + ;; + esac + # OK + ;; + *) + # Allow $x86_cpus --with-cpu=/--with-tune= + case "x$which" in + xcpu*|xtune*) + case " $x86_cpus " in + *" ${val} "*) + # OK + ;; + *) + echo "Unknown CPU given in --with-$which=$val." 1>&2 + exit 1 + ;; + esac + ;; + *) + echo "Unknown CPU given in --with-$which=$val." 1>&2 + exit 1 + ;; + esac + ;; + esac + fi + ;; + esac + done + ;; + + riscv*-*-*) + supported_defaults="abi arch tune riscv_attribute isa_spec" + + case "${target}" in + riscv-* | riscv32*) xlen=32 ;; + riscv64*) xlen=64 ;; + *) echo "Unsupported RISC-V target ${target}" 1>&2; exit 1 ;; + esac + + case "${with_isa_spec}" in + ""|default|2.2) + tm_defines="${tm_defines} TARGET_DEFAULT_ISA_SPEC=ISA_SPEC_CLASS_2P2" + ;; + 20191213 | 201912) + tm_defines="${tm_defines} TARGET_DEFAULT_ISA_SPEC=ISA_SPEC_CLASS_20191213" + ;; + 20190608 | 201906) + tm_defines="${tm_defines} TARGET_DEFAULT_ISA_SPEC=ISA_SPEC_CLASS_20190608" + ;; + *) + echo "--with-isa-spec only accept 2.2, 20191213, 201912, 20190608 or 201906" 1>&2 + exit 1 + esac + + case "${with_riscv_attribute}" in + yes) + tm_defines="${tm_defines} TARGET_RISCV_ATTRIBUTE=1" + ;; + no) + tm_defines="${tm_defines} TARGET_RISCV_ATTRIBUTE=0" + ;; + ""|default) + case "${target}" in + riscv*-*-elf*) + tm_defines="${tm_defines} TARGET_RISCV_ATTRIBUTE=1" + ;; + *) + tm_defines="${tm_defines} TARGET_RISCV_ATTRIBUTE=0" + ;; + esac + ;; + *) + echo "--with-riscv-attribute=${with_riscv_attribute} is not supported. The argument must begin with yes, no or default." 1>&2 + exit 1 + ;; + esac + + + # Infer arch from --with-arch, --target, and --with-abi. + case "${with_arch}" in + rv32e* | rv32i* | rv32g* | rv64i* | rv64g*) + # OK. + ;; + "") + # Infer XLEN, but otherwise assume GC. + case "${with_abi}" in + ilp32e) with_arch="rv32e" ;; + ilp32 | ilp32f | ilp32d) with_arch="rv32gc" ;; + lp64 | lp64f | lp64d) with_arch="rv64gc" ;; + *) with_arch="rv${xlen}gc" ;; + esac + ;; + *) + echo "--with-arch=${with_arch} is not supported. The argument must begin with rv32e, rv32i, rv32g, rv64i, or rv64g." 1>&2 + exit 1 + ;; + esac + PYTHON=`which python || which python3 || which python2` + if test "x${PYTHON}" != x; then + with_arch=`${PYTHON} ${srcdir}/config/riscv/arch-canonicalize ${with_arch}` + fi + tm_defines="${tm_defines} TARGET_RISCV_DEFAULT_ARCH=${with_arch}" + + # Make sure --with-abi is valid. If it was not specified, + # pick a default based on the ISA, preferring soft-float + # unless the D extension is present. + case "${with_abi}" in + ilp32 | ilp32e | ilp32f | ilp32d | lp64 | lp64f | lp64d) + ;; + "") + case "${with_arch}" in + rv32*d* | rv32g*) with_abi=ilp32d ;; + rv32e*) with_abi=ilp32e ;; + rv32*) with_abi=ilp32 ;; + rv64*d* | rv64g*) with_abi=lp64d ;; + rv64*) with_abi=lp64 ;; + esac + ;; + *) + echo "--with-abi=${with_abi} is not supported" 1>&2 + exit 1 + ;; + esac + tm_defines="${tm_defines} TARGET_RISCV_DEFAULT_ABI=${with_abi}" + + # Make sure ABI and ISA are compatible. + case "${with_abi},${with_arch}" in + ilp32,rv32* | ilp32e,rv32e* \ + | ilp32f,rv32*f* | ilp32f,rv32g* \ + | ilp32d,rv32*d* | ilp32d,rv32g* \ + | lp64,rv64* \ + | lp64f,rv64*f* | lp64f,rv64g* \ + | lp64d,rv64*d* | lp64d,rv64g*) + ;; + *) + echo "--with-abi=${with_abi} is not supported for ISA ${with_arch}" 1>&2 + exit 1 + ;; + esac + # Handle --with-multilib-generator. + if test "x${with_multilib_generator}" != xdefault; then + if test "x${with_multilib_list}" != xdefault; then + echo "--with-multilib-list= can't used with --with-multilib-generator= at same time" 1>&2 + exit 1 + fi + case "${target}" in + riscv*-*-elf*) + if ${srcdir}/config/riscv/multilib-generator \ + `echo ${with_multilib_generator} | sed 's/;/ /g'`\ + > t-multilib-config; + then + tmake_file="${tmake_file} riscv/t-withmultilib-generator" + else + echo "invalid option for --with-multilib-generator" 1>&2 + exit 1 + fi + ;; + *) + echo "--with-multilib-generator= is not supported for ${target}, only supported for riscv*-*-elf*" 1>&2 + exit 1 + ;; + esac + fi + + # Handle --with-multilib-list. + if test "x${with_multilib_list}" != xdefault; then + tmake_file="${tmake_file} riscv/t-withmultilib" + + case ${with_multilib_list} in + ilp32 | ilp32f | ilp32d \ + | lp64 | lp64f | lp64d ) + TM_MULTILIB_CONFIG="${with_arch},${with_multilib_list}" + ;; + *) + echo "--with-multilib-list=${with_multilib_list} not supported." + exit 1 + esac + fi + ;; + + mips*-*-*) + supported_defaults="abi arch arch_32 arch_64 float fpu nan fp_32 odd_spreg_32 tune tune_32 tune_64 divide llsc mips-plt synci lxc1-sxc1 madd4" + + case ${with_float} in + "" | soft | hard) + # OK + ;; + *) + echo "Unknown floating point type used in --with-float=$with_float" 1>&2 + exit 1 + ;; + esac + + case ${with_fpu} in + "" | single | double) + # OK + ;; + *) + echo "Unknown fpu type used in --with-fpu=$with_fpu" 1>&2 + exit 1 + ;; + esac + + case ${with_nan} in + "" | 2008 | legacy) + # OK + ;; + *) + echo "Unknown NaN encoding used in --with-nan=$with_nan" 1>&2 + exit 1 + ;; + esac + + case ${with_fp_32} in + "" | 32 | xx | 64) + # OK + ;; + *) + echo "Unknown FP mode used in --with-fp-32=$with_fp_32" 1>&2 + exit 1 + ;; + esac + + case ${with_odd_spreg_32} in + yes) + with_odd_spreg_32="odd-spreg" + ;; + no) + with_odd_spreg_32="no-odd-spreg" + ;; + "") + # OK + ;; + *) + echo "Unknown odd-spreg-32 type used in --with-odd-spreg-32=$with_odd_spreg_32" 1>&2 + exit 1 + ;; + esac + + case ${with_abi} in + "" | 32 | o64 | n32 | 64 | eabi) + # OK + ;; + *) + echo "Unknown ABI used in --with-abi=$with_abi" 1>&2 + exit 1 + ;; + esac + + case ${with_divide} in + "" | breaks | traps) + # OK + ;; + *) + echo "Unknown division check type use in --with-divide=$with_divide" 1>&2 + exit 1 + ;; + esac + + case ${with_llsc} in + yes) + with_llsc=llsc + ;; + no) + with_llsc="no-llsc" + ;; + "") + # OK + ;; + *) + echo "Unknown llsc type used in --with-llsc" 1>&2 + exit 1 + ;; + esac + + case ${with_mips_plt} in + yes) + with_mips_plt=plt + ;; + no) + with_mips_plt=no-plt + ;; + "") + ;; + *) + echo "Unknown --with-mips-plt argument: $with_mips_plt" 1>&2 + exit 1 + ;; + esac + + case ${with_synci} in + yes) + with_synci=synci + ;; + no) + with_synci=no-synci + ;; + "") + ;; + *) + echo "Unknown synci type used in --with-synci" 1>&2 + exit 1 + ;; + esac + + case ${with_lxc1_sxc1} in + yes) + with_lxc1_sxc1=lxc1-sxc1 + ;; + no) + with_lxc1_sxc1=no-lxc1-sxc1 + ;; + "") + ;; + *) + echo "Unknown lxc1-sxc1 type used in --with-lxc1-sxc1" 1>&2 + exit 1 + ;; + esac + + case ${with_madd4} in + yes) + with_madd4=madd4 + ;; + no) + with_madd4=no-madd4 + ;; + "") + ;; + *) + echo "Unknown madd4 type used in --with-madd4" 1>&2 + exit 1 + ;; + esac + ;; + + nds32*-*-*) + supported_defaults="arch cpu nds32_lib float fpu_config" + + # process --with-arch + case "${with_arch}" in + "" | v3 ) + tm_defines="${tm_defines} TARGET_ARCH_DEFAULT=0" + ;; + v2 | v2j | v3m) + # OK + tm_defines="${tm_defines} TARGET_ARCH_DEFAULT=0" + ;; + v3f) + tm_defines="${tm_defines} TARGET_ARCH_DEFAULT=1" + ;; + v3s) + tm_defines="${tm_defines} TARGET_ARCH_DEFAULT=2" + + ;; + *) + echo "Cannot accept --with-arch=$with_arch, available values are: v2 v2j v3 v3m v3f v3s" 1>&2 + exit 1 + ;; + esac + + case "${with_cpu}" in + "") + with_cpu=n9 + ;; + n6 | n7 |n8 | e8 | s8 | n9 | n10 | d10 | n12 | n13 | n15) + # OK + ;; + *) + echo "Cannot accept --with-cpu=$with_cpu, available values are: n6 n7 n8 e8 s8 n9 n10 d10 n12 n13 n15" 1>&2 + exit 1 + ;; + esac + + # process --with-nds32-lib + case "${with_nds32_lib}" in + "") + case ${target} in + *-*-*uclibc*) + with_nds32_lib=ulibc + ;; + *-*-linux*) + with_nds32_lib=glibc + ;; + *) + with_nds32_lib=newlib + tm_defines="${tm_defines} TARGET_DEFAULT_CTOR_DTOR=1" + ;; + esac + ;; + newlib) + # OK + tm_defines="${tm_defines} TARGET_DEFAULT_CTOR_DTOR=1" + ;; + mculib) + # OK + # for the arch=v3f or arch=v3s under mculib toolchain, + # we would like to set -fno-math-errno as default + case "${with_arch}" in + v3f | v3s) + tm_defines="${tm_defines} TARGET_DEFAULT_NO_MATH_ERRNO=1" + ;; + esac + ;; + glibc | uclibc) + # OK + ;; + *) + echo "Cannot accept --with-nds32-lib=$with_nds32_lib, available values are: newlib mculib glibc uclibc" 1>&2 + exit 1 + ;; + esac + + # process --with-float + case "${with_float}" in + "" | soft | hard) + # OK + ;; + *) + echo "Cannot accept --with-float=$with_float, available values are: soft hard" 1>&2 + exit 1 + ;; + esac + + # process --with-config-fpu + case "${with_config_fpu}" in + "" | 0 | 1 | 2 | 3) + # OK + ;; + *) + echo "Cannot accept --with-config-fpu=$with_config_fpu, available values from 0 to 7" 1>&2 + exit 1 + ;; + esac + + + ;; + nios2*-*-*) + supported_defaults="arch" + case "$with_arch" in + "" | r1 | r2) + # OK + ;; + *) + echo "Unknown arch used in --with-arch=$with_arch" 1>&2 + exit 1 + ;; + esac + ;; + + powerpc*-*-* | rs6000-*-*) + supported_defaults="abi cpu cpu_32 cpu_64 float tune tune_32 tune_64 advance_toolchain" + + for which in cpu cpu_32 cpu_64 tune tune_32 tune_64; do + eval "val=\$with_$which" + case ${val} in + default32 | default64) + case $which in + cpu | tune) + ;; + *) + echo "$val only valid for --with-cpu and --with-tune." 1>&2 + exit 1 + ;; + esac + with_which="with_$which" + eval $with_which= + ;; + 405cr) + tm_defines="${tm_defines} CONFIG_PPC405CR" + eval "with_$which=405" + ;; + "" | common | native \ + | power[3456789] | power10 | power5+ | power6x \ + | powerpc | powerpc64 | powerpc64le \ + | rs64 \ + | 401 | 403 | 405 | 405fp | 440 | 440fp | 464 | 464fp \ + | 476 | 476fp | 505 | 601 | 602 | 603 | 603e | ec603e \ + | 604 | 604e | 620 | 630 | 740 | 750 | 7400 | 7450 \ + | a2 | e300c[23] | 854[08] | e500mc | e500mc64 | e5500 | e6500 \ + | titan | 801 | 821 | 823 | 860 | 970 | G3 | G4 | G5 | cell) + # OK + ;; + *) + echo "Unknown cpu used in --with-$which=$val." 1>&2 + exit 1 + ;; + esac + done + + case "$with_abi" in + "" | elfv1 | elfv2 ) + #OK + ;; + *) + echo "Unknown ABI used in --with-abi=$with_abi" + exit 1 + ;; + esac + + if test "x$with_advance_toolchain" != x; then + if test -d "/opt/$with_advance_toolchain/." -a \ + -d "/opt/$with_advance_toolchain/bin/." -a \ + -d "/opt/$with_advance_toolchain/include/."; then + + tm_file="$tm_file ./advance-toolchain.h" + (at="/opt/$with_advance_toolchain" + echo "/* Use Advance Toolchain $at */" + echo + echo "#undef LINK_OS_EXTRA_SPEC32" + echo "#define LINK_OS_EXTRA_SPEC32" \ + "\"%(link_os_new_dtags)" \ + "-rpath $prefix/lib -rpath $at/lib\"" + echo + echo "#undef LINK_OS_EXTRA_SPEC64" + echo "#define LINK_OS_EXTRA_SPEC64" \ + "\"%(link_os_new_dtags)" \ + "-rpath $prefix/lib64 -rpath $at/lib64\"" + echo + echo "#undef LINK_OS_NEW_DTAGS_SPEC" + echo "#define LINK_OS_NEW_DTAGS_SPEC" \ + "\"--enable-new-dtags\"" + echo + echo "#undef DYNAMIC_LINKER_PREFIX" + echo "#define DYNAMIC_LINKER_PREFIX \"$at\"" + echo + echo "#undef MD_EXEC_PREFIX" + echo "#define MD_EXEC_PREFIX \"$at/bin/\"" + echo + echo "#undef MD_STARTFILE_PREFIX" + echo "#define MD_STARTFILE_PREFIX \"$prefix/lib/\"" + echo + echo "#undef MD_STARTFILE_PREFIX_1" + echo "#define MD_STARTFILE_PREFIX_1 \"$at/lib/\"") \ + > advance-toolchain.h + else + echo "Unknown advance-toolchain $with_advance_toolchain" + exit 1 + fi + fi + + # Set up the default long double format if the user changed it. + if test x$with_long_double_format = xieee; then + tm_defines="${tm_defines} TARGET_IEEEQUAD_DEFAULT=1" + + elif test x$with_long_double_format = xibm; then + tm_defines="${tm_defines} TARGET_IEEEQUAD_DEFAULT=0" + fi + ;; + + s390*-*-*) + supported_defaults="arch mode tune" + + for which in arch tune; do + eval "val=\$with_$which" + case ${val} in + "" | native | z900 | z990 | z9-109 | z9-ec | z10 | z196 | zEC12 | z13 | z14 | z15 | arch5 | arch6 | arch7 | arch8 | arch9 | arch10 | arch11 | arch12 | arch13 | arch14 ) + # OK + ;; + *) + echo "Unknown cpu used in --with-$which=$val." 1>&2 + exit 1 + ;; + esac + done + + case ${with_mode} in + "" | esa | zarch) + # OK + ;; + *) + echo "Unknown architecture mode used in --with-mode=$with_mode." 1>&2 + exit 1 + ;; + esac + ;; + + sh[123456ble]*-*-* | sh-*-*) + supported_defaults="cpu" + case "`echo $with_cpu | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ_ abcdefghijklmnopqrstuvwxyz- | sed s/sh/m/`" in + "" | m1 | m2 | m2e | m3 | m3e | m4 | m4-single | m4-single-only | m4-nofpu ) + # OK + ;; + m2a | m2a-single | m2a-single-only | m2a-nofpu) + ;; + m4a | m4a-single | m4a-single-only | m4a-nofpu | m4al) + ;; + *) + echo "Unknown CPU used in --with-cpu=$with_cpu, known values:" 1>&2 + echo "m1 m2 m2e m3 m3e m4 m4-single m4-single-only m4-nofpu" 1>&2 + echo "m4a m4a-single m4a-single-only m4a-nofpu m4al" 1>&2 + echo "m2a m2a-single m2a-single-only m2a-nofpu" 1>&2 + exit 1 + ;; + esac + ;; + sparc*-*-*) + supported_defaults="cpu cpu_32 cpu_64 float tune tune_32 tune_64" + + for which in cpu cpu_32 cpu_64 tune tune_32 tune_64; do + eval "val=\$with_$which" + case ${val} in + "" | sparc | sparcv9 | sparc64 \ + | v7 | cypress \ + | v8 | supersparc | hypersparc | leon | leon3 | leon3v7 \ + | sparclite | f930 | f934 | sparclite86x \ + | sparclet | tsc701 \ + | v9 | ultrasparc | ultrasparc3 | niagara | niagara2 \ + | niagara3 | niagara4 | niagara7 | m8) + # OK + ;; + *) + echo "Unknown cpu used in --with-$which=$val" 1>&2 + exit 1 + ;; + esac + done + + case ${with_float} in + "" | soft | hard) + # OK + ;; + *) + echo "Unknown floating point type used in --with-float=$with_float" 1>&2 + exit 1 + ;; + esac + ;; + + tic6x-*-*) + supported_defaults="arch" + + case ${with_arch} in + "" | c62x | c64x | c64x+ | c67x | c67x+ | c674x) + # OK + ;; + *) + echo "Unknown arch used in --with-arch=$with_arch." 1>&2 + exit 1 + ;; + esac + ;; + + v850*-*-*) + supported_defaults=cpu + case ${with_cpu} in + "" | v850e | v850e1 | v850e2 | v850es | v850e2v3 | v850e3v5) + # OK + ;; + *) + echo "Unknown cpu used in --with-cpu=$with_cpu" 1>&2 + exit 1 + ;; + esac + ;; + visium-*-*) + supported_defaults="cpu" + case $with_cpu in + "" | gr5 | gr6) + ;; + *) echo "Unknown cpu used in --with-cpu=$with_cpu" 1>&2 + exit 1 + ;; + esac + ;; +esac + +# Targets for which there is at least one VxWorks port should include +# vxworks-dummy.h to allow safe references to various TARGET_VXWORKS kinds +# of markers from other files in the port, including the vxworks*.h files to +# distinguish VxWorks variants such as VxWorks 7 or 64). + +case ${target} in +arm*-*-* | i[34567]86-*-* | mips*-*-* | powerpc*-*-* | sh*-*-* \ +| sparc*-*-* | x86_64-*-*) + tm_file="vxworks-dummy.h ${tm_file}" + ;; +esac + +# Set some miscellaneous flags for particular targets. +target_cpu_default2= +case ${target} in + aarch64*-*-*) + if test x"$target_cpu_cname" != x + then + target_cpu_default2=$target_cpu_cname + fi + ;; + + arm*-*-*) + if test x$with_cpu = x + then + echo "Don't know the target cpu" 1>&2 + exit 1 + else + target_cpu_default2="\\\"$with_cpu\\\"" + fi + ;; + + hppa*-*-*) + if test x$gas = xyes + then + target_cpu_default2="MASK_GAS" + fi + ;; + + fido*-*-* | m68k*-*-*) + target_cpu_default2=$m68k_cpu_ident + tmake_file="m68k/t-opts $tmake_file" + if [ x"$m68k_arch_family" != x ]; then + tmake_file="m68k/t-$m68k_arch_family $tmake_file" + fi + ;; + + i[34567]86-*-darwin* | x86_64-*-darwin*) + ;; + i[34567]86-*-linux* | x86_64-*-linux*) + extra_objs="${extra_objs} gnu-property.o" + tmake_file="$tmake_file i386/t-linux i386/t-gnu-property" + ;; + i[34567]86-*-kfreebsd*-gnu | x86_64-*-kfreebsd*-gnu) + tmake_file="$tmake_file i386/t-kfreebsd" + ;; + i[34567]86-*-gnu*) + tmake_file="$tmake_file i386/t-gnu" + ;; + i[34567]86-*-msdosdjgpp*) + tmake_file="${tmake_file} i386/t-djgpp" + ;; + i[34567]86-*-solaris2* | x86_64-*-solaris2*) + ;; + i[34567]86-*-cygwin* | x86_64-*-cygwin*) + ;; + i[34567]86-*-mingw* | x86_64-*-mingw*) + ;; + i[34567]86-*-dragonfly* | x86_64-*-dragonfly*) + ;; + i[34567]86-*-freebsd*) + ;; + x86_64-*-freebsd*) + tmake_file="${tmake_file} i386/t-freebsd64" + ;; + ia64*-*-linux*) + ;; + + mips*-*-*) + if test x$gnu_ld = xyes + then + target_cpu_default2="MASK_SPLIT_ADDRESSES" + fi + case ${target} in + mips*el-*-*) + tm_defines="TARGET_ENDIAN_DEFAULT=0 $tm_defines" + ;; + esac + if test x$with_arch != x; then + default_mips_arch=$with_arch + fi + if test x$with_abi != x; then + default_mips_abi=$with_abi + fi + case ${default_mips_arch} in + mips1) tm_defines="$tm_defines MIPS_ISA_DEFAULT=1" ;; + mips2) tm_defines="$tm_defines MIPS_ISA_DEFAULT=2" ;; + mips3) tm_defines="$tm_defines MIPS_ISA_DEFAULT=3" ;; + mips4) tm_defines="$tm_defines MIPS_ISA_DEFAULT=4" ;; + mips32) tm_defines="$tm_defines MIPS_ISA_DEFAULT=32" ;; + mips32r2) tm_defines="$tm_defines MIPS_ISA_DEFAULT=33" ;; + mips32r6) tm_defines="$tm_defines MIPS_ISA_DEFAULT=37" ;; + mips64) tm_defines="$tm_defines MIPS_ISA_DEFAULT=64" ;; + mips64r2) tm_defines="$tm_defines MIPS_ISA_DEFAULT=65" ;; + mips64r6) tm_defines="$tm_defines MIPS_ISA_DEFAULT=69" ;; + esac + case ${default_mips_abi} in + 32) tm_defines="$tm_defines MIPS_ABI_DEFAULT=ABI_32" ;; + o64) tm_defines="$tm_defines MIPS_ABI_DEFAULT=ABI_O64" ;; + n32) tm_defines="$tm_defines MIPS_ABI_DEFAULT=ABI_N32" ;; + 64) tm_defines="$tm_defines MIPS_ABI_DEFAULT=ABI_64" ;; + eabi) tm_defines="$tm_defines MIPS_ABI_DEFAULT=ABI_EABI" ;; + esac + tmake_file="mips/t-mips $tmake_file" + ;; + + powerpc*-*-* | rs6000-*-*) + # FIXME: The PowerPC port uses the value set at compile time, + # although it's only cosmetic. + if test "x$with_cpu" != x + then + target_cpu_default2="\\\"$with_cpu\\\"" + fi + out_file="${cpu_type}/${cpu_type}.c" + c_target_objs="${c_target_objs} ${cpu_type}-c.o" + cxx_target_objs="${cxx_target_objs} ${cpu_type}-c.o" + d_target_objs="${d_target_objs} ${cpu_type}-d.o" + tmake_file="${cpu_type}/t-${cpu_type} ${tmake_file}" + ;; + + sh[123456ble]*-*-* | sh-*-*) + c_target_objs="${c_target_objs} sh-c.o" + cxx_target_objs="${cxx_target_objs} sh-c.o" + ;; + + sparc*-*-*) + # Some standard aliases. + case x$with_cpu in + xsparc) + with_cpu=v7 + ;; + xsparcv9 | xsparc64) + with_cpu=v9 + ;; + esac + + if test x$with_tune = x ; then + case ${target} in + *-leon-*) + with_tune=leon + ;; + *-leon[3-9]*) + with_tune=leon3 + ;; + esac + fi + + # The SPARC port checks this value at compile-time. + target_cpu_default2="TARGET_CPU_$with_cpu" + ;; + + v850*-*-*) + case "x$with_cpu" in + x) + ;; + xv850e | xv850e1 | xv850e2 | xv850e2v3 | xv850e3v5) + target_cpu_default2="TARGET_CPU_$with_cpu" + ;; + xv850es) + target_cpu_default2="TARGET_CPU_v850e1" + ;; + esac + ;; + visium-*-*) + target_cpu_default2="TARGET_CPU_$with_cpu" + ;; +esac + +t= +all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu nan fp_32 odd_spreg_32 divide llsc mips-plt synci tls lxc1-sxc1 madd4" +for option in $all_defaults +do + eval "val=\$with_"`echo $option | sed s/-/_/g` + if test -n "$val"; then + case " $supported_defaults " in + *" $option "*) + ;; + *) + echo "This target does not support --with-$option." 2>&1 + echo "Valid --with options are: $supported_defaults" 2>&1 + exit 1 + ;; + esac + + if test "x$t" = x + then + t="{ \"$option\", \"$val\" }" + else + t="${t}, { \"$option\", \"$val\" }" + fi + fi +done + +if test "x$t" = x +then + configure_default_options="{ { NULL, NULL} }" +else + configure_default_options="{ ${t} }" +fi + +if test "$target_cpu_default2" != "" +then + if test "$target_cpu_default" != "" + then + target_cpu_default="(${target_cpu_default}|${target_cpu_default2})" + else + target_cpu_default=$target_cpu_default2 + fi +fi + +case ${target} in +i[34567]86-*-* | x86_64-*-*) + if test x$enable_as_accelerator = xyes; then + extra_programs="mkoffload\$(exeext)" + fi + ;; +esac diff --git a/ports/gcc/changes/gcc_gcc_config_essence.h b/ports/gcc/changes/gcc_gcc_config_essence.h new file mode 100644 index 0000000..7afee22 --- /dev/null +++ b/ports/gcc/changes/gcc_gcc_config_essence.h @@ -0,0 +1,22 @@ +#undef TARGET_ESSENCE +#define TARGET_ESSENCE 1 +/* Default arguments to ld */ +#undef LIB_SPEC +#define LIB_SPEC " -lc " +#undef LINK_SPEC +#define LINK_SPEC " -z max-page-size=0x1000 " +/* Files that are linked before user code. The %s tells GCC to look for these files in the library directory. */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC " %{!shared: crt1.o%s} crti.o%s crtbegin.o%s crtglue.o%s " +/* Files that are linked after user code. */ +#undef ENDFILE_SPEC +#define ENDFILE_SPEC " crtend.o%s crtn.o%s " +/* Additional predefined macros. */ +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + do { \ + builtin_define ("ARCH_64"); \ + builtin_define ("ARCH_X86_64"); \ + builtin_define ("ARCH_X86_COMMON"); \ + builtin_define ("OS_ESSENCE"); \ + } while(0) diff --git a/ports/gcc/changes/gcc_gcc_config_i386_t-x86_64-essence b/ports/gcc/changes/gcc_gcc_config_i386_t-x86_64-essence new file mode 100644 index 0000000..8223e63 --- /dev/null +++ b/ports/gcc/changes/gcc_gcc_config_i386_t-x86_64-essence @@ -0,0 +1,2 @@ +MULTILIB_OPTIONS += mno-red-zone +MULTILIB_DIRNAMES += no-red-zone diff --git a/ports/gcc/changes/gcc_libgcc_config.host b/ports/gcc/changes/gcc_libgcc_config.host new file mode 100644 index 0000000..86077a0 --- /dev/null +++ b/ports/gcc/changes/gcc_libgcc_config.host @@ -0,0 +1,1584 @@ +# libgcc host-specific configuration file. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. + +#This file is part of GCC. + +#GCC is free software; you can redistribute it and/or modify it under +#the terms of the GNU General Public License as published by the Free +#Software Foundation; either version 3, or (at your option) any later +#version. + +#GCC is distributed in the hope that it will be useful, but WITHOUT +#ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +#FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +#for more details. + +#You should have received a copy of the GNU General Public License +#along with GCC; see the file COPYING3. If not see +#. + +# This is the libgcc host-specific configuration file +# where a configuration type is mapped to different system-specific +# definitions and files. This is invoked by the autoconf-generated +# configure script. Putting it in a separate shell file lets us skip +# running autoconf when modifying host-specific information. + +# This file bears an obvious resemblance to gcc/config.gcc. The cases +# should be kept similar, to ease moving library-specific settings +# from config.gcc to this file. That is also why tmake_file is +# left as tmake_file, rather than hmake_file, even though this library +# switches on ${host}. + +# This file switches on the shell variable ${host}, and also uses the +# following shell variables: +# +# with_* Various variables as set by configure. + +# This file sets the following shell variables for use by the +# autoconf-generated configure script: +# +# asm_hidden_op The assembler pseudo-op to use for hide +# lists for object files implemented in +# assembly (with -fvisibility=hidden for C). +# The default is ".hidden". +# cpu_type The name of the cpu, if different from the first +# chunk of the canonical host name. +# enable_execute_stack The name of a source file implementing +# __enable_execute_stack. +# extra_parts List of extra object files that should be compiled +# for this target machine. This may be overridden +# by setting EXTRA_PARTS in a tmake_file fragment. +# If either is set, EXTRA_PARTS and +# EXTRA_MULTILIB_PARTS inherited from the GCC +# subdirectory will be ignored. +# md_unwind_header The name of a header file defining +# MD_FALLBACK_FRAME_STATE_FOR. +# sfp_machine_header The name of a sfp-machine.h header file for soft-fp. +# Defaults to "$cpu_type/sfp-machine.h" if it exists, +# no-sfp-machine.h otherwise. +# tmake_file A list of machine-description-specific +# makefile fragments. +# tm_defines List of target macros to define for all compilations. +# tm_file A list of target macro files used only for code +# built for the target, not the host. These files +# are relative to $srcdir/config and must not have +# the same names as files in $srcdir/../gcc/config. +# unwind_header The name of the header file declaring the unwind +# runtime interface routines. + +asm_hidden_op=.hidden +enable_execute_stack= +extra_parts= +tmake_file= +tm_file= +tm_define= +md_unwind_header=no-unwind.h +unwind_header=unwind-generic.h + +# Set default cpu_type so it can be updated in each machine entry. +cpu_type=`echo ${host} | sed 's/-.*$//'` +case ${host} in +m32c*-*-*) + cpu_type=m32c + tmake_file=t-fdpbit + ;; +aarch64*-*-*) + cpu_type=aarch64 + ;; +alpha*-*-*) + cpu_type=alpha + ;; +am33_2.0-*-linux*) + cpu_type=mn10300 + ;; +amdgcn*-*-*) + cpu_type=gcn + tmake_file="${tmake_file} t-softfp-sfdf t-softfp" + ;; +arc*-*-*) + cpu_type=arc + ;; +arm*-*-*) + cpu_type=arm + ;; +avr-*-*) + cpu_type=avr + ;; +bfin*-*) + cpu_type=bfin + ;; +bpf-*-*) + cpu_type=bpf + ;; +cr16-*-*) + ;; +csky*-*-*) + cpu_type=csky + ;; +fido-*-*) + cpu_type=m68k + ;; +frv*) cpu_type=frv + ;; +ft32*) cpu_type=ft32 + ;; +moxie*) cpu_type=moxie + ;; +i[34567]86-*-*) + cpu_type=i386 + ;; +x86_64-*-*) + cpu_type=i386 + ;; +ia64-*-*) + ;; +hppa*-*-*) + cpu_type=pa + ;; +lm32*-*-*) + cpu_type=lm32 + ;; +m32r*-*-*) + cpu_type=m32r + ;; +m68k-*-*) + ;; +microblaze*-*-*) + cpu_type=microblaze + ;; +mips*-*-*) + # All MIPS targets provide a full set of FP routines. + cpu_type=mips + tmake_file="mips/t-mips" + if test "${libgcc_cv_mips_hard_float}" = yes; then + tmake_file="${tmake_file} t-hardfp-sfdf t-hardfp" + else + tmake_file="${tmake_file} t-softfp-sfdf" + fi + if test "${ac_cv_sizeof_long_double}" = 16; then + tmake_file="${tmake_file} mips/t-softfp-tf" + fi + if test "${host_address}" = 64; then + tmake_file="${tmake_file} mips/t-mips64" + fi + tmake_file="${tmake_file} t-softfp" + ;; +nds32*-*) + cpu_type=nds32 + ;; +nios2*-*-*) + cpu_type=nios2 + ;; +or1k*-*-*) + cpu_type=or1k + ;; +powerpc*-*-*) + cpu_type=rs6000 + ;; +pru-*-*) + cpu_type=pru + ;; +rs6000*-*-*) + ;; +riscv*-*-*) + cpu_type=riscv + ;; +sparc64*-*-*) + cpu_type=sparc + ;; +sparc*-*-*) + cpu_type=sparc + ;; +s390*-*-*) + cpu_type=s390 + ;; +# Note the 'l'; we need to be able to match e.g. "shle" or "shl". +sh[123456789lbe]*-*-*) + cpu_type=sh + ;; +tilegx*-*-*) + cpu_type=tilegx + ;; +tilepro*-*-*) + cpu_type=tilepro + ;; +v850*-*-*) + cpu_type=v850 + ;; +tic6x-*-*) + cpu_type=c6x + ;; +esac + +# Common parts for widely ported systems. +case ${host} in +*-*-darwin*) + asm_hidden_op=.private_extern + tmake_file="$tmake_file t-darwin ${cpu_type}/t-darwin t-libgcc-pic t-slibgcc-darwin" + extra_parts="crt3.o d10-uwfef.o crttms.o crttme.o" + ;; +*-*-dragonfly*) + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip" + tmake_file="$tmake_file t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver" + extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o" + ;; +*-*-freebsd*) + # This is the generic ELF configuration of FreeBSD. Later + # machine-specific sections may refine and add to this + # configuration. + tmake_file="$tmake_file t-freebsd t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver" + extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o" + case ${target_thread_file} in + posix) + tmake_file="${tmake_file} t-freebsd-thread" + # Before 5.0, FreeBSD can't bind shared libraries to -lc + # when "optionally" threaded via weak pthread_* checks. + case ${host} in + *-*-freebsd[34] | *-*-freebsd[34].*) + tmake_file="${tmake_file} t-slibgcc-nolc-override" + ;; + esac + ;; + esac + ;; +*-*-fuchsia*) + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-fuchsia" + extra_parts="crtbegin.o crtend.o" + ;; +*-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu | *-*-uclinuxfdpiceabi) + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-linux" + extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi + ;; +*-*-lynxos*) + tmake_file="$tmake_file t-lynx $cpu_type/t-crtstuff t-crtstuff-pic t-libgcc-pic" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + ;; +*-*-netbsd*) + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip" + tmake_file="$tmake_file t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver" + tmake_file="$tmake_file t-slibgcc-libgcc" + extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o" + ;; +*-*-openbsd*) + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip" + case ${target_thread_file} in + posix) + tmake_file="$tmake_file t-openbsd-thread" + ;; + esac + ;; +*-*-rtems*) + tmake_file="$tmake_file t-rtems" + extra_parts="crtbegin.o crtend.o" + ;; +*-*-solaris2*) + # Unless linker support and dl_iterate_phdr are present, + # unwind-dw2-fde-dip.c automatically falls back to unwind-dw2-fde.c. + tmake_file="$tmake_file sol2/t-sol2 t-eh-dw2-dip t-crtstuff-pic t-libgcc-pic t-slibgcc t-slibgcc-elf-ver" + if test $with_gnu_ld = yes; then + tmake_file="$tmake_file t-slibgcc-gld" + else + tmake_file="$tmake_file t-slibgcc-sld" + fi + # Add cpu-specific t-sol2 after t-slibgcc-* so it can augment SHLIB_MAPFILES. + tmake_file="$tmake_file $cpu_type/t-sol2" + extra_parts="gmon.o crtbegin.o crtend.o" + if test "${libgcc_cv_solaris_crts}" = yes; then + # Solaris 11.4 provides crt1.o, crti.o, and crtn.o as part of the + # base system. crtp.o and crtpg.o implement the compiler-dependent parts. + extra_parts="$extra_parts crtp.o crtpg.o" + # If the Solaris CRTs are present, both ld and gld will have PIE support. + extra_parts="$extra_parts crtbeginS.o crtendS.o" + else + case ${host} in + i?86-*-solaris2* | x86_64-*-solaris2*) + # Solaris 10+/x86 provides crt1.o, crti.o, crtn.o, and gcrt1.o as + # part of the base system. + ;; + sparc*-*-solaris2*) + # Solaris 10+/SPARC lacks crt1.o and gcrt1.o. + extra_parts="$extra_parts crt1.o gcrt1.o" + ;; + esac + fi + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi + ;; +*-*-uclinux*) + extra_parts="crtbegin.o crtend.o" + ;; +*-*-*vms*) + tmake_file="vms/t-vms" + extra_parts="crt0.o crtbegin.o crtbeginS.o crtend.o crtendS.o" + ;; +*-*-vxworks7*) + tmake_file=t-vxworks7 + ;; +*-*-vxworksae*) + tmake_file=t-vxworksae + ;; +*-*-vxworks*) + tmake_file=t-vxworks + ;; +*-*-elf) + extra_parts="crtbegin.o crtend.o" + ;; +esac + +# Except on ARM where we do not use DWARF, table based EH on VxWorks +# relies on specially crafted crtstuff files +case ${host} in +arm-*-vxworks*) + ;; +*-*-vxworks*) + tmake_file="${tmake_file} t-vxcrtstuff" + ;; +esac + +case ${host} in +*-*-darwin* | *-*-dragonfly* | *-*-freebsd* | *-*-netbsd* | *-*-openbsd* | \ + *-*-solaris2*) + enable_execute_stack=enable-execute-stack-mprotect.c + ;; +i[34567]86-*-mingw* | x86_64-*-mingw*) + enable_execute_stack=config/i386/enable-execute-stack-mingw32.c + ;; +i[34567]86-*-cygwin* | x86_64-*-cygwin*) + enable_execute_stack=config/i386/enable-execute-stack-mingw32.c + ;; +*) + enable_execute_stack=enable-execute-stack-empty.c; + ;; +esac + +case ${host} in +aarch64*-*-elf | aarch64*-*-rtems*) + extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o" + extra_parts="$extra_parts crtfastmath.o" + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" + tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" + md_unwind_header=aarch64/aarch64-unwind.h + ;; +aarch64*-*-freebsd*) + extra_parts="$extra_parts crtfastmath.o" + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" + tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" + md_unwind_header=aarch64/freebsd-unwind.h + ;; +aarch64*-*-netbsd*) + extra_parts="$extra_parts crtfastmath.o" + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" + md_unwind_header=aarch64/aarch64-unwind.h + ;; +aarch64*-*-fuchsia*) + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" + tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp" + ;; +aarch64*-*-linux*) + extra_parts="$extra_parts crtfastmath.o" + md_unwind_header=aarch64/linux-unwind.h + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" + tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" + ;; +aarch64*-*-vxworks7*) + extra_parts="$extra_parts crtfastmath.o" + md_unwind_header=aarch64/aarch64-unwind.h + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" + tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" + ;; +alpha*-*-linux*) + tmake_file="${tmake_file} alpha/t-alpha alpha/t-ieee t-crtfm alpha/t-linux" + extra_parts="$extra_parts crtfastmath.o" + md_unwind_header=alpha/linux-unwind.h + ;; +alpha*-*-freebsd*) + tmake_file="${tmake_file} alpha/t-alpha alpha/t-ieee t-crtfm" + extra_parts="$extra_parts crtbeginT.o crtfastmath.o" + ;; +alpha*-*-netbsd*) + tmake_file="${tmake_file} alpha/t-alpha alpha/t-ieee" + ;; +alpha*-*-openbsd*) + tmake_file="${tmake_file} alpha/t-alpha alpha/t-ieee" + ;; +alpha64-dec-*vms*) + tmake_file="$tmake_file alpha/t-alpha alpha/t-ieee alpha/t-vms t-slibgcc-vms" + extra_parts="$extra_parts vms-dwarf2.o vms-dwarf2eh.o" + md_unwind_header=alpha/vms-unwind.h + ;; +alpha*-dec-*vms*) + tmake_file="$tmake_file alpha/t-alpha alpha/t-ieee alpha/t-vms t-slibgcc-vms" + extra_parts="$extra_parts vms-dwarf2.o vms-dwarf2eh.o" + md_unwind_header=alpha/vms-unwind.h + ;; +amdgcn*-*-amdhsa) + tmake_file="$tmake_file gcn/t-amdgcn" + extra_parts="crt0.o" + ;; +arc*-*-elf*) + tmake_file="arc/t-arc" + extra_parts="crti.o crtn.o crtend.o crtbegin.o crtendS.o crtbeginS.o" + extra_parts="$extra_parts crttls.o" + ;; +arc*-*-linux*) + tmake_file="${tmake_file} t-slibgcc-libgcc t-slibgcc-nolc-override arc/t-arc-uClibc arc/t-arc" + extra_parts="$extra_parts crti.o crtn.o" + extra_parts="$extra_parts crttls.o" + md_unwind_header=arc/linux-unwind.h + ;; +arm-wrs-vxworks7*) + tmake_file="$tmake_file arm/t-arm arm/t-elf arm/t-bpabi arm/t-vxworks7" + tmake_file="$tmake_file t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp" + tm_file="$tm_file arm/bpabi-lib.h" + unwind_header=config/arm/unwind-arm.h + extra_parts="$extra_parts crti.o crtn.o" + ;; +arm*-*-freebsd*) # ARM FreeBSD EABI + tmake_file="${tmake_file} arm/t-arm t-fixedpoint-gnu-prefix arm/t-elf" + tmake_file="${tmake_file} arm/t-bpabi arm/t-freebsd" + tm_file="${tm_file} arm/bpabi-lib.h" + unwind_header=config/arm/unwind-arm.h + tmake_file="${tmake_file} t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp" + ;; +arm*-*-fuchsia*) + tmake_file="${tmake_file} arm/t-arm arm/t-elf arm/t-bpabi" + tmake_file="${tmake_file} arm/tsoftfp t-softfp" + tm_file="${tm_file} arm/bpabi-lib.h" + unwind_header=config/arm/unwind-arm.h + ;; +arm*-*-netbsdelf*) + tmake_file="$tmake_file arm/t-arm" + case ${host} in + arm*-*-netbsdelf-*eabi*) + tmake_file="${tmake_file} arm/t-netbsd-eabi" + unwind_header=config/arm/unwind-arm.h + ;; + *) + tmake_file="${tmake_file} arm/t-netbsd t-slibgcc-gld-nover" + ;; + esac + ;; +arm*-*-linux* | arm*-*-uclinuxfdpiceabi) + tmake_file="${tmake_file} arm/t-arm t-fixedpoint-gnu-prefix t-crtfm" + tmake_file="${tmake_file} arm/t-elf arm/t-bpabi arm/t-linux-eabi t-slibgcc-libgcc" + tm_file="$tm_file arm/bpabi-lib.h" + unwind_header=config/arm/unwind-arm.h + tmake_file="$tmake_file t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp" + extra_parts="$extra_parts crtfastmath.o" + ;; +arm*-*-uclinux*) # ARM ucLinux + tmake_file="${tmake_file} t-fixedpoint-gnu-prefix t-crtfm" + tmake_file="$tmake_file arm/t-arm arm/t-elf t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp" + tmake_file="${tmake_file} arm/t-bpabi" + tm_file="$tm_file arm/bpabi-lib.h" + unwind_header=config/arm/unwind-arm.h + extra_parts="$extra_parts crti.o crtn.o" + ;; +arm*-*-phoenix*) + tmake_file="t-hardfp t-softfp arm/t-arm arm/t-elf arm/t-softfp arm/t-phoenix" + tmake_file="${tmake_file} arm/t-bpabi" + tm_file="$tm_file arm/bpabi-lib.h" + extra_parts="crtbegin.o crtend.o crti.o crtn.o" + unwind_header=config/arm/unwind-arm.h + ;; +arm*-*-eabi* | arm*-*-symbianelf* | arm*-*-rtems*) + tmake_file="${tmake_file} arm/t-arm arm/t-elf t-fixedpoint-gnu-prefix" + tm_file="$tm_file arm/bpabi-lib.h" + case ${host} in + arm*-*-eabi* | arm*-*-rtems*) + tmake_file="${tmake_file} arm/t-bpabi t-crtfm" + extra_parts="crtbegin.o crtend.o crti.o crtn.o" + ;; + arm*-*-symbianelf*) + tmake_file="${tmake_file} arm/t-symbian t-slibgcc-nolc-override" + tm_file="$tm_file arm/symbian-lib.h" + # Symbian OS provides its own startup code. + ;; + esac + tmake_file="$tmake_file t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp" + extra_parts="$extra_parts crtfastmath.o" + unwind_header=config/arm/unwind-arm.h + ;; +avr-*-*) + # Make HImode functions for AVR + tmake_file="${cpu_type}/t-avr t-fpbit" + # Make some DFmode functions from libf7, part of avr-libgcc. + # This must be prior to adding t-avrlibc. + case "y${with_libf7}" in + yno) + # No libf7 support. + ;; + ylibgcc) + tmake_file="$tmake_file ${cpu_type}/libf7/t-libf7" + ;; + ymath) + tmake_file="$tmake_file ${cpu_type}/libf7/t-libf7-math" + tmake_file="$tmake_file ${cpu_type}/libf7/t-libf7" + ;; + ymath-symbols | yyes | y) + tmake_file="$tmake_file ${cpu_type}/libf7/t-libf7-math-symbols" + tmake_file="$tmake_file ${cpu_type}/libf7/t-libf7-math" + tmake_file="$tmake_file ${cpu_type}/libf7/t-libf7" + ;; + *) + echo "Error: --with-libf7=${with_libf7} but can only be used with: 'libgcc', 'math', 'math-symbols', 'yes', 'no'" 1>&2 + exit 1 + ;; + esac + if test x${with_avrlibc} != xno; then + tmake_file="$tmake_file ${cpu_type}/t-avrlibc" + fi + tm_file="$tm_file avr/avr-lib.h" + if test x${with_fixed_point} = xno; then + fixed_point=no + fi + ;; +bfin*-elf*) + tmake_file="bfin/t-bfin bfin/t-crtlibid bfin/t-crtstuff t-libgcc-pic t-fdpbit" + extra_parts="$extra_parts crtbeginS.o crtendS.o crti.o crtn.o crtlibid.o" + ;; +bfin*-uclinux*) + tmake_file="bfin/t-bfin bfin/t-crtlibid bfin/t-crtstuff t-libgcc-pic t-fdpbit" + extra_parts="$extra_parts crtbeginS.o crtendS.o crtlibid.o" + md_unwind_header=bfin/linux-unwind.h + ;; +bfin*-linux-uclibc*) + tmake_file="$tmake_file bfin/t-bfin bfin/t-crtstuff t-libgcc-pic t-fdpbit bfin/t-linux" + # No need to build crtbeginT.o on uClibc systems. Should probably + # be moved to the OS specific section above. + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + md_unwind_header=bfin/linux-unwind.h + ;; +bfin*-rtems*) + tmake_file="$tmake_file bfin/t-bfin t-fdpbit" + extra_parts="$extra_parts crti.o crtn.o" + ;; +bfin*-*) + tmake_file="$tmake_file bfin/t-bfin t-fdpbit" + extra_parts="crtbegin.o crtend.o crti.o crtn.o" + ;; +bpf-*-*) + tmake_file="$tmake_file ${cpu_type}/t-${cpu_type}" + extra_parts="crti.o crtn.o" + ;; +cr16-*-elf) + tmake_file="${tmake_file} cr16/t-cr16 cr16/t-crtlibid t-fdpbit" + extra_parts="$extra_parts crti.o crtn.o crtlibid.o" + ;; +cris-*-elf) + tmake_file="$tmake_file cris/t-cris t-softfp-sfdf t-softfp cris/t-elfmulti" + ;; +csky-*-elf*) + tmake_file="csky/t-csky t-fdpbit" + extra_parts="crtbegin.o crtend.o crti.o crtn.o" + ;; +csky-*-linux*) + tmake_file="$tmake_file csky/t-csky t-slibgcc-libgcc t-fdpbit csky/t-linux-csky" + extra_parts="$extra_parts crti.o crtn.o" + md_unwind_header=csky/linux-unwind.h + ;; +epiphany-*-elf* | epiphany-*-rtems*) + tmake_file="$tmake_file epiphany/t-epiphany t-fdpbit epiphany/t-custom-eqsf" + extra_parts="$extra_parts crti.o crtint.o crtrunc.o crtm1reg-r43.o crtm1reg-r63.o crtn.o" + ;; +fr30-*-elf) + tmake_file="$tmake_file fr30/t-fr30 t-fdpbit" + extra_parts="$extra_parts crti.o crtn.o" + ;; +frv-*-elf) + tmake_file="$tmake_file frv/t-frv t-fdpbit" + tm_file="$tm_file frv/elf-lib.h frv/frv-abi.h" + # Don't use crtbegin.o, crtend.o. + extra_parts="frvbegin.o frvend.o" + ;; +frv-*-*linux*) + tmake_file="$tmake_file frv/t-frv frv/t-linux t-fdpbit" + tm_file="$tm_file frv/elf-lib.h frv/frv-abi.h" + ;; +ft32-*-elf) + tmake_file="ft32/t-ft32 t-softfp-sfdf t-softfp-excl t-softfp" + extra_parts="$extra_parts crti.o crti-hw.o crtn.o" + ;; +h8300-*-elf*) + tmake_file="$tmake_file h8300/t-h8300 t-fpbit" + tm_file="$tm_file h8300/h8300-lib.h" + extra_parts="$extra_parts crti.o crtn.o" + ;; +h8300-*-linux*) + tmake_file="t-linux h8300/t-linux t-softfp-sfdf t-softfp" + tm_file="$tm_file h8300/h8300-lib.h" + ;; +hppa*64*-*-linux*) + tmake_file="$tmake_file pa/t-linux pa/t-linux64" + extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o" + ;; +hppa*-*-linux*) + tmake_file="$tmake_file pa/t-linux t-slibgcc-libgcc" + # Set the libgcc version number + if test x$ac_cv_sjlj_exceptions = xyes; then + tmake_file="$tmake_file pa/t-slibgcc-sjlj-ver" + else + tmake_file="$tmake_file pa/t-slibgcc-dwarf-ver" + fi + extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o" + md_unwind_header=pa/linux-unwind.h + ;; +hppa[12]*-*-hpux10*) + tmake_file="$tmake_file pa/t-hpux pa/t-hpux10 t-libgcc-pic t-slibgcc" + # Set the libgcc version number + if test x$ac_cv_sjlj_exceptions = xyes; then + tmake_file="$tmake_file pa/t-slibgcc-sjlj-ver" + else + tmake_file="$tmake_file pa/t-slibgcc-dwarf-ver" + fi + tmake_file="$tmake_file pa/t-slibgcc-hpux t-slibgcc-hpux" + md_unwind_header=pa/hpux-unwind.h + ;; +hppa*64*-*-hpux11*) + tmake_file="$tmake_file pa/t-hpux pa/t-pa64 pa/t-stublib t-libgcc-pic t-slibgcc" + # Set the libgcc version number + if test x$ac_cv_sjlj_exceptions = xyes; then + tmake_file="$tmake_file pa/t-slibgcc-sjlj-ver" + else + tmake_file="$tmake_file pa/t-slibgcc-dwarf-ver" + fi + tmake_file="$tmake_file pa/t-slibgcc-hpux t-slibgcc-hpux" + tm_file="$tm_file pa/pa64-hpux-lib.h" + extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o \ + libgcc_stub.a" + md_unwind_header=pa/hpux-unwind.h + ;; +hppa[12]*-*-hpux11*) + tmake_file="$tmake_file pa/t-hpux pa/t-stublib t-libgcc-pic t-slibgcc" + # Set the libgcc version number + if test x$ac_cv_sjlj_exceptions = xyes; then + tmake_file="$tmake_file pa/t-slibgcc-sjlj-ver" + else + tmake_file="$tmake_file pa/t-slibgcc-dwarf-ver" + fi + tmake_file="$tmake_file pa/t-slibgcc-hpux t-slibgcc-hpux" + extra_parts="libgcc_stub.a" + md_unwind_header=pa/hpux-unwind.h + ;; +hppa*-*-openbsd*) + tmake_file="$tmake_file pa/t-openbsd" + ;; +hppa*-*-netbsd*) + tmake_file="$tmake_file pa/t-netbsd" + ;; +i[34567]86-*-darwin*) + tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-msabi" + tm_file="$tm_file i386/darwin-lib.h" + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + ;; +x86_64-*-darwin*) + tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-msabi" + tm_file="$tm_file i386/darwin-lib.h" + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + ;; +i[34567]86-*-elfiamcu) + tmake_file="$tmake_file i386/t-crtstuff t-softfp-sfdftf i386/32/t-softfp i386/32/t-iamcu i386/t-softfp t-softfp t-dfprules" + ;; +i[34567]86-*-elf*) + tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic" + ;; +x86_64-*-elf* | x86_64-*-rtems*) + tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic" + case ${host} in + x86_64-*-rtems*) + extra_parts="$extra_parts crti.o crtn.o" + ;; + esac + ;; +x86_64-*-essence*) + extra_parts="$extra_parts crti.o crtbegin.o crtend.o crtn.o" + tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic -t-libgcc-pic" + ;; +x86_64-*-fuchsia*) + tmake_file="$tmake_file t-libgcc-pic" + ;; +i[34567]86-*-dragonfly*) + tmake_file="${tmake_file} i386/t-dragonfly i386/t-crtstuff" + md_unwind_header=i386/dragonfly-unwind.h + ;; +x86_64-*-dragonfly*) + tmake_file="${tmake_file} i386/t-dragonfly i386/t-crtstuff" + md_unwind_header=i386/dragonfly-unwind.h + ;; +i[34567]86-*-freebsd*) + tmake_file="${tmake_file} i386/t-freebsd i386/t-crtstuff" + md_unwind_header=i386/freebsd-unwind.h + ;; +x86_64-*-freebsd*) + tmake_file="${tmake_file} i386/t-freebsd i386/t-crtstuff" + md_unwind_header=i386/freebsd-unwind.h + ;; +i[34567]86-*-netbsdelf*) + tmake_file="${tmake_file} i386/t-crtstuff" + ;; +x86_64-*-netbsd*) + tmake_file="${tmake_file} i386/t-crtstuff" + ;; +i[34567]86-*-openbsd*) + ;; +x86_64-*-openbsd*) + ;; +i[34567]86-*-linux*) + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + tmake_file="${tmake_file} i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" + tm_file="${tm_file} i386/elf-lib.h" + md_unwind_header=i386/linux-unwind.h + ;; +i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-kopensolaris*-gnu) + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + tmake_file="${tmake_file} i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" + tm_file="${tm_file} i386/elf-lib.h" + ;; +i[34567]86-*-gnu*) + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + tmake_file="${tmake_file} i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" + tm_file="${tm_file} i386/elf-lib.h" + md_unwind_header=i386/gnu-unwind.h + ;; +x86_64-*-linux*) + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + tmake_file="${tmake_file} i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" + tm_file="${tm_file} i386/elf-lib.h" + md_unwind_header=i386/linux-unwind.h + ;; +x86_64-*-kfreebsd*-gnu) + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + tmake_file="${tmake_file} i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" + tm_file="${tm_file} i386/elf-lib.h" + ;; +i[34567]86-pc-msdosdjgpp*) + ;; +i[34567]86-*-lynxos*) + ;; +i[34567]86-*-nto-qnx*) + tmake_file="$tmake_file i386/t-nto t-libgcc-pic" + extra_parts=crtbegin.o + ;; +i[34567]86-*-rtems*) + tmake_file="$tmake_file i386/t-crtstuff t-softfp-sfdftf i386/32/t-softfp i386/t-softfp t-softfp" + extra_parts="$extra_parts crti.o crtn.o" + ;; +i[34567]86-*-solaris2* | x86_64-*-solaris2*) + tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-msabi" + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + tm_file="${tm_file} i386/elf-lib.h" + md_unwind_header=i386/sol2-unwind.h + ;; +i[4567]86-wrs-vxworks*|x86_64-wrs-vxworks*) + ;; +i[34567]86-*-cygwin*) + extra_parts="crtbegin.o crtbeginS.o crtend.o crtfastmath.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi + # This has to match the logic for DWARF2_UNWIND_INFO in gcc/config/i386/cygming.h + if test x$ac_cv_sjlj_exceptions = xyes; then + tmake_eh_file="i386/t-sjlj-eh" + else + tmake_eh_file="i386/t-dw2-eh" + fi + # Shared libgcc DLL install dir depends on cross/native build. + if test x${build} = x${host} ; then + tmake_dlldir_file="i386/t-dlldir" + else + tmake_dlldir_file="i386/t-dlldir-x" + fi + tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-cygming i386/t-cygwin t-crtfm i386/t-chkstk t-dfprules" + ;; +x86_64-*-cygwin*) + extra_parts="crtbegin.o crtbeginS.o crtend.o crtfastmath.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi + # This has to match the logic for DWARF2_UNWIND_INFO in gcc/config/i386/cygming.h + if test x$ac_cv_sjlj_exceptions = xyes; then + tmake_eh_file="i386/t-sjlj-eh" + elif test "${host_address}" = 32; then + # biarch -m32 with --disable-sjlj-exceptions + tmake_eh_file="i386/t-dw2-eh" + else + tmake_eh_file="i386/t-seh-eh" + fi + # Shared libgcc DLL install dir depends on cross/native build. + if test x${build} = x${host} ; then + tmake_dlldir_file="i386/t-dlldir" + else + tmake_dlldir_file="i386/t-dlldir-x" + fi + # FIXME - dj - t-chkstk used to be in here, need a 64-bit version of that + tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-cygming i386/t-cygwin t-crtfm t-dfprules i386/t-chkstk" + ;; +i[34567]86-*-mingw*) + extra_parts="crtbegin.o crtend.o crtfastmath.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi + case ${target_thread_file} in + win32) + tmake_file="$tmake_file i386/t-gthr-win32" + ;; + posix) + tmake_file="i386/t-mingw-pthread $tmake_file" + ;; + esac + # This has to match the logic for DWARF2_UNWIND_INFO in gcc/config/i386/cygming.h + if test x$ac_cv_sjlj_exceptions = xyes; then + tmake_eh_file="i386/t-sjlj-eh" + else + tmake_eh_file="i386/t-dw2-eh" + md_unwind_header=i386/w32-unwind.h + fi + # Shared libgcc DLL install dir depends on cross/native build. + if test x${build} = x${host} ; then + tmake_dlldir_file="i386/t-dlldir" + else + tmake_dlldir_file="i386/t-dlldir-x" + fi + tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-cygming i386/t-mingw32 t-crtfm i386/t-chkstk t-dfprules" + ;; +x86_64-*-mingw*) + case ${target_thread_file} in + win32) + tmake_file="$tmake_file i386/t-gthr-win32" + ;; + posix) + tmake_file="i386/t-mingw-pthread $tmake_file" + ;; + esac + # This has to match the logic for DWARF2_UNWIND_INFO in gcc/config/i386/cygming.h + if test x$ac_cv_sjlj_exceptions = xyes; then + tmake_eh_file="i386/t-sjlj-eh" + elif test "${host_address}" = 32; then + # biarch -m32 with --disable-sjlj-exceptions + tmake_eh_file="i386/t-dw2-eh" + md_unwind_header=i386/w32-unwind.h + else + tmake_eh_file="i386/t-seh-eh" + fi + # Shared libgcc DLL install dir depends on cross/native build. + if test x${build} = x${host} ; then + tmake_dlldir_file="i386/t-dlldir" + else + tmake_dlldir_file="i386/t-dlldir-x" + fi + tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-cygming i386/t-mingw32 t-dfprules t-crtfm i386/t-chkstk" + extra_parts="$extra_parts crtbegin.o crtend.o crtfastmath.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi + ;; +ia64*-*-elf*) + extra_parts="$extra_parts crtbeginS.o crtendS.o crtfastmath.o" + tmake_file="ia64/t-ia64 ia64/t-ia64-elf ia64/t-eh-ia64 t-crtfm t-softfp-tf ia64/t-softfp t-softfp ia64/t-softfp-compat" + ;; +ia64*-*-freebsd*) + extra_parts="$extra_parts crtfastmath.o" + tmake_file="$tmake_file ia64/t-ia64 ia64/t-ia64-elf ia64/t-eh-ia64 t-crtfm t-softfp-tf ia64/t-softfp t-softfp ia64/t-softfp-compat" + ;; +ia64*-*-linux*) + # Don't use crtbeginT.o from *-*-linux* default. + extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtfastmath.o" + tmake_file="$tmake_file ia64/t-ia64 ia64/t-ia64-elf t-crtfm t-softfp-tf ia64/t-softfp t-softfp ia64/t-softfp-compat ia64/t-eh-ia64 t-libunwind ia64/t-linux" + if test x$with_system_libunwind != xyes ; then + tmake_file="${tmake_file} t-libunwind-elf ia64/t-linux-libunwind" + fi + md_unwind_header=ia64/linux-unwind.h + ;; +ia64*-*-hpux*) + tmake_file="ia64/t-ia64 ia64/t-ia64-elf ia64/t-hpux t-slibgcc ia64/t-slibgcc-hpux t-slibgcc-hpux" + ;; +ia64-hp-*vms*) + tmake_file="$tmake_file ia64/t-ia64 ia64/t-eh-ia64 ia64/t-vms t-slibgcc-vms t-softfp-tf ia64/t-softfp t-softfp" + extra_parts="$extra_parts crtinitS.o" + md_unwind_header=ia64/vms-unwind.h + ;; +iq2000*-*-elf*) + tmake_file="iq2000/t-iq2000 t-fdpbit" + # Don't use default. + extra_parts= + ;; +lm32-*-elf*) + extra_parts="$extra_parts crti.o crtn.o" + tmake_file="lm32/t-lm32 lm32/t-elf t-softfp-sfdf t-softfp" + ;; +lm32-*-rtems*) + tmake_file="$tmake_file lm32/t-lm32 lm32/t-elf t-softfp-sfdf t-softfp" + extra_parts="$extra_parts crti.o crtn.o" + ;; +lm32-*-uclinux*) + extra_parts="$extra_parts crtbegin.o crtendS.o crtbeginT.o" + tmake_file="lm32/t-lm32 lm32/t-uclinux t-libgcc-pic t-softfp-sfdf t-softfp" + ;; +m32r-*-elf*) + tmake_file="$tmake_file m32r/t-m32r t-fdpbit" + extra_parts="$extra_parts crtinit.o crtfini.o" + ;; +m32rle-*-elf*) + tmake_file=t-fdpbit + ;; +m32r-*-linux*) + tmake_file="$tmake_file m32r/t-linux t-fdpbit" + ;; +m32rle-*-linux*) + tmake_file="$tmake_file m32r/t-linux t-fdpbit" + ;; +m68k-*-elf* | fido-*-elf) + tmake_file="$tmake_file m68k/t-floatlib" + ;; +m68k*-*-netbsdelf*) + ;; +m68k*-*-openbsd*) + ;; +m68k-*-uclinux*) # Motorola m68k/ColdFire running uClinux with uClibc + tmake_file="$tmake_file m68k/t-floatlib m68k/t-linux" + md_unwind_header=m68k/linux-unwind.h + ;; +m68k-*-linux*) # Motorola m68k's running GNU/Linux + # with ELF format using glibc 2 + # aka the GNU/Linux C library 6. + tmake_file="$tmake_file m68k/t-floatlib m68k/t-linux" + # If not configured with setjmp/longjmp exceptions, bump the + # libgcc version number. + if test x$ac_cv_sjlj_exceptions != xyes; then + tmake_file="$tmake_file m68k/t-slibgcc-elf-ver" + fi + md_unwind_header=m68k/linux-unwind.h + ;; +m68k-*-rtems*) + tmake_file="$tmake_file m68k/t-floatlib" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mcore-*-elf) + tmake_file="mcore/t-mcore t-fdpbit" + extra_parts="$extra_parts crti.o crtn.o" + ;; +microblaze*-linux*) + tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit t-slibgcc-libgcc" + ;; +microblaze*-*-elf) + tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit" + extra_parts="$extra_parts crtbeginS.o crtendS.o crtbeginT.o crti.o crtn.o" + ;; +microblaze*-*-rtems*) + tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit" + extra_parts="$extra_parts crtbeginS.o crtendS.o crtbeginT.o crti.o crtn.o" + ;; +mips*-*-netbsd*) # NetBSD/mips, either endian. + ;; +mips*-*-linux*) # Linux MIPS, either endian. + extra_parts="$extra_parts crtfastmath.o" + tmake_file="${tmake_file} t-crtfm" + case ${host} in + mips64r5900* | mipsr5900*) + # The MIPS16 support code uses floating point + # instructions that are not supported on r5900. + ;; + *) + tmake_file="${tmake_file} mips/t-mips16 t-slibgcc-libgcc" + ;; + esac + md_unwind_header=mips/linux-unwind.h + ;; +mips*-sde-elf*) + tmake_file="$tmake_file mips/t-crtstuff mips/t-mips16" + case "${with_newlib}" in + yes) + # newlib / libgloss. + ;; + *) + # MIPS toolkit libraries. + tmake_file="$tmake_file mips/t-sdemtk" + ;; + esac + extra_parts="$extra_parts crti.o crtn.o" + ;; +mipsisa32-*-elf* | mipsisa32el-*-elf* | \ +mipsisa32r2-*-elf* | mipsisa32r2el-*-elf* | \ +mipsisa32r6-*-elf* | mipsisa32r6el-*-elf* | \ +mipsisa64-*-elf* | mipsisa64el-*-elf* | \ +mipsisa64r2-*-elf* | mipsisa64r2el-*-elf* | \ +mipsisa64r6-*-elf* | mipsisa64r6el-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff mips/t-mips16" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mipsisa64sr71k-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff t-fdpbit" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mipsisa64sb1-*-elf* | mipsisa64sb1el-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff mips/t-mips16" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mips-*-elf* | mipsel-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff mips/t-mips16" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mipsr5900-*-elf* | mipsr5900el-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mips64-*-elf* | mips64el-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff mips/t-mips16" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mips64r5900-*-elf* | mips64r5900el-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mips64vr-*-elf* | mips64vrel-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-vr mips/t-crtstuff" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mips64orion-*-elf* | mips64orionel-*-elf*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff mips/t-mips16" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mips*-*-rtems*) + tmake_file="$tmake_file mips/t-elf mips/t-crtstuff mips/t-mips16" + extra_parts="$extra_parts crti.o crtn.o" + ;; +mips-wrs-vxworks) + ;; +mipstx39-*-elf* | mipstx39el-*-elf*) + tmake_file="$tmake_file mips/t-crtstuff mips/t-mips16" + ;; +mmix-knuth-mmixware) + extra_parts="crti.o crtn.o crtbegin.o crtend.o" + tmake_file="${tmake_file} ${cpu_type}/t-${cpu_type}" + ;; +mn10300-*-*) + tmake_file=t-fdpbit + ;; +moxie-*-elf | moxie-*-moxiebox* | moxie-*-uclinux* | moxie-*-rtems*) + tmake_file="$tmake_file moxie/t-moxie t-softfp-sfdf t-softfp-excl t-softfp" + extra_parts="$extra_parts crti.o crtn.o crtbegin.o crtend.o" + ;; +msp430-*-elf*) + tmake_file="$tm_file t-crtstuff t-fdpbit msp430/t-msp430" + extra_parts="crtbegin.o crtend.o crtbegin_no_eh.o crtend_no_eh.o" + extra_parts="$extra_parts libmul_none.a libmul_16.a libmul_32.a libmul_f5.a" + ;; +nds32*-linux*) + # Basic makefile fragment and extra_parts for crt stuff. + # We also append c-isr library implementation. + tmake_file="${tmake_file} t-slibgcc-libgcc" + tmake_file="${tmake_file} nds32/t-nds32-glibc nds32/t-crtstuff t-softfp-sfdf t-softfp" + # The header file of defining MD_FALLBACK_FRAME_STATE_FOR. + md_unwind_header=nds32/linux-unwind.h + # Append library definition makefile fragment according to --with-nds32-lib=X setting. + case "${with_nds32_lib}" in + "" | glibc | uclibc ) + ;; + *) + echo "Cannot accept --with-nds32-lib=$with_nds32_lib, available values are: glibc uclibc" 1>&2 + exit 1 + ;; + esac + ;; +nds32*-elf*) + # Basic makefile fragment and extra_parts for crt stuff. + # We also append c-isr library implementation. + tmake_file="${tmake_file} nds32/t-nds32 nds32/t-nds32-isr" + extra_parts="crtbegin1.o crtend1.o libnds32_isr.a" + # Append library definition makefile fragment according to --with-nds32-lib=X setting. + case "${with_nds32_lib}" in + "" | newlib) + # Append library definition makefile fragment t-nds32-newlib. + # Append 'soft-fp' software floating point make rule fragment provided by gcc. + tmake_file="${tmake_file} nds32/t-nds32-newlib t-softfp-sfdf t-softfp" + ;; + mculib) + # Append library definition makefile fragment t-nds32-mculib. + # The software floating point library is included in mculib. + tmake_file="${tmake_file} nds32/t-nds32-mculib" + ;; + *) + echo "Cannot accept --with-nds32-lib=$with_nds32_lib, available values are: newlib mculib" 1>&2 + exit 1 + ;; + esac + ;; +nios2-*-linux*) + tmake_file="$tmake_file nios2/t-nios2 nios2/t-linux t-libgcc-pic t-eh-dw2-dip t-slibgcc-libgcc" + tm_file="$tm_file nios2/elf-lib.h" + md_unwind_header=nios2/linux-unwind.h + ;; +nios2-*-*) + tmake_file="$tmake_file nios2/t-nios2 t-softfp-sfdf t-softfp-excl t-softfp" + extra_parts="$extra_parts crti.o crtn.o" + ;; +or1k-*-linux*) + tmake_file="$tmake_file or1k/t-or1k" + tmake_file="$tmake_file t-softfp-sfdf t-softfp" + md_unwind_header=or1k/linux-unwind.h + ;; +or1k-*-*) + tmake_file="$tmake_file or1k/t-or1k" + tmake_file="$tmake_file t-softfp-sfdf t-softfp" + ;; +pdp11-*-*) + tmake_file="pdp11/t-pdp11 t-fdpbit" + ;; +powerpc-*-darwin*) + case ${host} in + *-*-darwin9* | *-*-darwin[12][0-9]*) + # libSystem contains unwind information for signal frames since + # Darwin 9. + ;; + *) + md_unwind_header=rs6000/darwin-unwind.h + ;; + esac + tmake_file="$tmake_file rs6000/t-ppc64-fp rs6000/t-ibm-ldouble" + extra_parts="$extra_parts crt2.o crt3_2.o libef_ppc.a dw_ppc.o" + ;; +powerpc64-*-darwin*) + tmake_file="$tmake_file rs6000/t-darwin64 rs6000/t-ibm-ldouble" + extra_parts="$extra_parts crt2.o crt3_2.o libef_ppc.a dw_ppc.o" + ;; +powerpc*-*-freebsd*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff rs6000/t-freebsd t-softfp-sfdf t-softfp-excl t-softfp" + extra_parts="$extra_parts crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + case ${host} in + powerpc64*) + tmake_file="${tmake_file} rs6000/t-freebsd64" + md_unwind_header=rs6000/freebsd-unwind.h + ;; + esac + ;; +powerpc-*-netbsd*) + tmake_file="$tmake_file rs6000/t-netbsd rs6000/t-crtstuff" + ;; +powerpc-*-eabispe*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpc-*-eabisimaltivec*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpc-*-eabisim*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpc-*-elf*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpc-*-eabialtivec*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpc-xilinx-eabi*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpc-*-eabi*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpc-*-rtems*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpc*-*-linux*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff rs6000/t-linux t-dfprules rs6000/t-ppc64-fp t-slibgcc-libgcc" + tmake_file="${tmake_file} t-stack rs6000/t-stack-rs6000" + case $ppc_fp_type in + 64) + ;; + hard) + tmake_file="${tmake_file} t-hardfp-sfdf t-hardfp" + ;; + soft) + tmake_file="${tmake_file} t-softfp-sfdf ${ppc_fp_compat} t-softfp" + ;; + e500v1) + tmake_file="${tmake_file} rs6000/t-e500v1-fp ${ppc_fp_compat} t-softfp t-hardfp" + ;; + e500v2) + tmake_file="${tmake_file} t-hardfp-sfdf rs6000/t-e500v2-fp ${ppc_fp_compat} t-softfp t-hardfp" + ;; + *) + echo "Unknown ppc_fp_type $ppc_fp_type" 1>&2 + exit 1 + ;; + esac + + if test $libgcc_cv_powerpc_float128 = yes; then + tmake_file="${tmake_file} rs6000/t-float128" + fi + + if test $libgcc_cv_powerpc_float128_hw = yes; then + tmake_file="${tmake_file} rs6000/t-float128-hw" + fi + + extra_parts="$extra_parts ecrti.o ecrtn.o ncrti.o ncrtn.o" + md_unwind_header=rs6000/linux-unwind.h + ;; +powerpc*-wrs-vxworks7*) + tmake_file="$tmake_file rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff rs6000/t-linux t-dfprules config/rs6000/t-ppc64-fp t-slibgcc-libgcc" + case $ppc_fp_type in + 64) + ;; + hard) + tmake_file="${tmake_file} t-hardfp-sfdf" + ;; + soft) + tmake_file="${tmake_file} t-softfp-sfdf t-softfp" + ;; + *) + echo "Unknown ppc_fp_type $ppc_fp_type" 1>&2 + exit 1 + ;; + esac + ;; +powerpc-wrs-vxworks*) + tmake_file="$tmake_file rs6000/t-ppccomm rs6000/t-savresfgpr t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o" + ;; +powerpc-*-lynxos*) + tmake_file="$tmake_file rs6000/t-lynx t-fdpbit" + ;; +powerpcle-*-elf*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpcle-*-eabisim*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +powerpcle-*-eabi*) + tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-crtstuff t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o ecrti.o ecrtn.o ncrti.o ncrtn.o" + ;; +pru-*-*) + tmake_file="${tmake_file} t-softfp-sfdf t-softfp-excl t-softfp t-gnu-prefix pru/t-pru" + tm_file="$tm_file pru/pru-abi.h" + ;; +riscv*-*-linux*) + tmake_file="${tmake_file} riscv/t-softfp${host_address} t-softfp riscv/t-elf riscv/t-elf${host_address} t-slibgcc-libgcc" + extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o crtendS.o crtbeginT.o" + md_unwind_header=riscv/linux-unwind.h + ;; +riscv*-*-freebsd*) + tmake_file="${tmake_file} riscv/t-softfp${host_address} t-softfp riscv/t-elf riscv/t-elf${host_address} t-slibgcc-libgcc" + extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o crtendS.o crtbeginT.o" + ;; +riscv*-*-*) + tmake_file="${tmake_file} riscv/t-softfp${host_address} t-softfp riscv/t-elf riscv/t-elf${host_address}" + extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o" + ;; +rs6000-ibm-aix4.[3456789]* | powerpc-ibm-aix4.[3456789]*) + md_unwind_header=rs6000/aix-unwind.h + tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-slibgcc-aix rs6000/t-ibm-ldouble" + ;; +rs6000-ibm-aix5.1.* | powerpc-ibm-aix5.1.*) + md_unwind_header=rs6000/aix-unwind.h + tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-slibgcc-aix rs6000/t-ibm-ldouble" + ;; +rs6000-ibm-aix[56789].* | powerpc-ibm-aix[56789].*) + md_unwind_header=rs6000/aix-unwind.h + tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-slibgcc-aix rs6000/t-ibm-ldouble rs6000/t-aix-cxa" + extra_parts="crtcxa.o crtcxa_s.o crtdbase.o crtcxa_64.o crtcxa_64_s.o crtdbase_64.o" + ;; +rl78-*-elf) + tmake_file="$tm_file t-fdpbit rl78/t-rl78" + ;; +rx-*-elf) + tmake_file="rx/t-rx t-fdpbit" + tm_file="$tm_file rx/rx-abi.h rx/rx-lib.h" + ;; +rx-*-linux*) + tmake_file="rx/t-rx t-fdpbit" + tm_file="$tm_file rx/rx-lib.h" + ;; +s390-*-linux*) + tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux s390/32/t-floattodi t-stack s390/t-stack-s390" + md_unwind_header=s390/linux-unwind.h + ;; +s390x-*-linux*) + tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux t-stack s390/t-stack-s390" + if test "${host_address}" = 32; then + tmake_file="${tmake_file} s390/32/t-floattodi" + fi + md_unwind_header=s390/linux-unwind.h + ;; +s390x-ibm-tpf*) + tmake_file="${tmake_file} s390/t-crtstuff t-libgcc-pic t-eh-dw2-dip s390/t-tpf" + extra_parts="crtbeginS.o crtendS.o" + md_unwind_header=s390/tpf-unwind.h + ;; +sh-*-elf* | sh[12346l]*-*-elf*) + tmake_file="$tmake_file sh/t-sh t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crt1.o crti.o crtn.o crtbeginS.o crtendS.o \ + libic_invalidate_array_4-100.a \ + libic_invalidate_array_4-200.a \ + libic_invalidate_array_4a.a \ + libgcc-Os-4-200.a libgcc-4-300.a" + case ${host} in + sh*-superh-elf) + tmake_file="$tmake_file sh/t-superh" + extra_parts="$extra_parts crt1-mmu.o gcrt1-mmu.o gcrt1.o" + ;; + esac + ;; +sh-*-linux* | sh[2346lbe]*-*-linux*) + tmake_file="${tmake_file} sh/t-sh t-slibgcc-libgcc sh/t-linux t-fdpbit" + md_unwind_header=sh/linux-unwind.h + ;; +sh-*-netbsdelf* | shl*-*-netbsdelf*) + tmake_file="$tmake_file sh/t-sh sh/t-netbsd" + + # NetBSD's C library includes a fast software FP library that + # has support for setting/setting the rounding mode, exception + # mask, etc. Therefore, we don't want to include software FP + # in libgcc. + ;; +sh-*-rtems*) + tmake_file="$tmake_file sh/t-sh t-crtstuff-pic t-fdpbit" + extra_parts="$extra_parts crt1.o crti.o crtn.o crtbeginS.o crtendS.o \ + libic_invalidate_array_4-100.a \ + libic_invalidate_array_4-200.a \ + libic_invalidate_array_4a.a \ + libgcc-Os-4-200.a libgcc-4-300.a" + ;; +sh-wrs-vxworks) + tmake_file="$tmake_file sh/t-sh t-crtstuff-pic t-fdpbit" + ;; +sparc-*-netbsdelf*) + ;; +sparc64-*-openbsd*) + ;; +sparc-*-elf*) + case ${host} in + *-leon[3-9]*) + ;; + *) + tmake_file="sparc/t-softmul" + ;; + esac + tmake_file="${tmake_file} t-fdpbit t-crtfm" + extra_parts="$extra_parts crti.o crtn.o crtfastmath.o" + ;; +sparc-*-linux*) # SPARC's running GNU/Linux, libc6 + tmake_file="${tmake_file} t-crtfm" + if test "${host_address}" = 64; then + tmake_file="$tmake_file sparc/t-linux64" + fi + case ${host} in + *-leon*) + tmake_file="${tmake_file} t-fdpbit" + ;; + *) + tmake_file="${tmake_file} sparc/t-linux" + ;; + esac + case ${host} in + *-leon[3-9]*) + ;; + *) + if test "${host_address}" = 32; then + tmake_file="$tmake_file sparc/t-softmul" + fi + ;; + esac + extra_parts="$extra_parts crtfastmath.o" + md_unwind_header=sparc/linux-unwind.h + ;; +sparc-*-rtems*) + tmake_file="$tmake_file sparc/t-elf sparc/t-softmul t-crtfm t-fdpbit" + extra_parts="$extra_parts crti.o crtn.o crtfastmath.o" + ;; +sparc*-*-solaris2*) + tmake_file="$tmake_file t-crtfm" + extra_parts="$extra_parts crtfastmath.o" + md_unwind_header=sparc/sol2-unwind.h + ;; +sparc64-*-elf*) + tmake_file="${tmake_file} t-crtfm" + extra_parts="$extra_parts crti.o crtn.o crtfastmath.o" + ;; +sparc64-*-rtems*) + tmake_file="$tmake_file t-crtfm" + extra_parts="$extra_parts crti.o crtn.o crtfastmath.o" + ;; +sparc-wrs-vxworks) + ;; +sparc64-*-freebsd*|ultrasparc-*-freebsd*) + tmake_file="$tmake_file t-crtfm" + extra_parts="$extra_parts crtfastmath.o" + ;; +sparc64-*-linux*) # 64-bit SPARC's running GNU/Linux + extra_parts="$extra_parts crtfastmath.o" + tmake_file="${tmake_file} t-crtfm sparc/t-linux" + if test "${host_address}" = 64; then + tmake_file="${tmake_file} sparc/t-linux64" + fi + if test "${host_address}" = 32; then + tmake_file="${tmake_file} sparc/t-softmul" + fi + md_unwind_header=sparc/linux-unwind.h + ;; +sparc64-*-netbsd*) + ;; +tic6x-*-uclinux) + tmake_file="${tmake_file} t-softfp-sfdf t-softfp-excl t-softfp \ + c6x/t-elf c6x/t-uclinux t-crtstuff-pic t-libgcc-pic \ + t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-gnu-prefix" + tm_file="$tm_file c6x/c6x-abi.h" + extra_parts="$extra_parts crtbeginS.o crtendS.o crti.o crtn.o" + unwind_header=config/c6x/unwind-c6x.h + ;; +tic6x-*-elf) + tmake_file="${tmake_file} t-softfp-sfdf t-softfp-excl t-softfp t-gnu-prefix c6x/t-elf" + tm_file="$tm_file c6x/c6x-abi.h" + extra_parts="$extra_parts crtbeginS.o crtendS.o crti.o crtn.o" + unwind_header=config/c6x/unwind-c6x.h + ;; +tilegx*-*-linux*) + if test "${host_address}" = 64; then + tmake_file="${tmake_file} tilegx/t-softfp" + fi + tmake_file="${tmake_file} tilegx/t-crtstuff t-softfp-sfdf t-softfp tilegx/t-tilegx" + md_unwind_header=tilepro/linux-unwind.h + ;; +tilepro*-*-linux*) + tmake_file="${tmake_file} tilepro/t-crtstuff t-softfp-sfdf t-softfp tilepro/t-tilepro t-slibgcc-libgcc" + md_unwind_header=tilepro/linux-unwind.h + ;; +v850*-*-*) + tmake_file="${tmake_file} v850/t-v850 t-fdpbit" + ;; +vax-*-linux*) + tmake_file="$tmake_file vax/t-linux" + ;; +vax-*-netbsdelf*) + ;; +vax-*-openbsd*) + ;; +visium-*-elf*) + extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o" + tmake_file="visium/t-visium t-fdpbit" + ;; +xstormy16-*-elf) + tmake_file="stormy16/t-stormy16 t-fdpbit" + ;; +xtensa*-*-elf*) + tmake_file="$tmake_file xtensa/t-xtensa xtensa/t-elf" + extra_parts="$extra_parts crti.o crtn.o" + ;; +xtensa*-*-linux*) + tmake_file="$tmake_file xtensa/t-xtensa xtensa/t-linux t-slibgcc-libgcc" + md_unwind_header=xtensa/linux-unwind.h + ;; +xtensa*-*-uclinux*) + tmake_file="$tmake_file xtensa/t-xtensa xtensa/t-linux t-slibgcc-libgcc" + md_unwind_header=xtensa/linux-unwind.h + extra_parts="$extra_parts crtbeginS.o crtbeginT.o crtendS.o" + ;; +am33_2.0-*-linux*) + # Don't need crtbeginT.o from *-*-linux* default. + extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o" + tmake_file="$tmake_file t-fdpbit" + ;; +m32c-*-elf*|m32c-*-rtems*) + tmake_file="$tmake_file m32c/t-m32c" + ;; +nvptx-*) + tmake_file="$tmake_file nvptx/t-nvptx" + extra_parts="crt0.o" + ;; +*) + echo "*** Configuration ${host} not supported" 1>&2 + exit 1 + ;; +esac + +case ${host} in +i[34567]86-*-* | x86_64-*-*) + case ${host} in + *-musl*) + tmake_file="${tmake_file} i386/t-cpuinfo-static" + ;; + *) + tmake_file="${tmake_file} i386/t-cpuinfo" + ;; + esac + ;; +esac + +case ${host} in +i[34567]86-*-linux* | x86_64-*-linux* | \ + i[34567]86-*-kfreebsd*-gnu | x86_64-*-kfreebsd*-gnu | \ + i[34567]86-*-gnu*) + tmake_file="${tmake_file} t-tls i386/t-linux i386/t-msabi t-slibgcc-libgcc" + if test "$libgcc_cv_cfi" = "yes"; then + tmake_file="${tmake_file} t-stack i386/t-stack-i386" + fi + ;; +esac + +case ${host} in +i[34567]86-*-elfiamcu | i[34567]86-*-rtems*) + # These use soft-fp for SFmode and DFmode, not just TFmode. + ;; +i[34567]86-*-* | x86_64-*-*) + tmake_file="${tmake_file} t-softfp-tf" + if test "${host_address}" = 32; then + tmake_file="${tmake_file} i386/${host_address}/t-softfp" + fi + tmake_file="${tmake_file} i386/t-softfp t-softfp" + ;; +esac + +case ${host} in +i[34567]86-*-linux* | x86_64-*-linux*) + # Provide backward binary compatibility for 64bit Linux/x86. + if test "${host_address}" = 64; then + tmake_file="${tmake_file} i386/${host_address}/t-softfp-compat" + fi + tm_file="${tm_file} i386/value-unwind.h" + ;; +aarch64*-*-*) + # ILP32 needs an extra header for unwinding + tm_file="${tm_file} aarch64/value-unwind.h" + ;; +esac + +# The vxworks threads implementation relies on a few extra sources, +# which we arrange to add after everything else: + +case ${target_thread_file} in +vxworks) + case ${host} in + *-*-vxworksae) + tmake_file="${tmake_file} t-gthr-vxworksae" + ;; + *-*-vxworks*) + tmake_file="${tmake_file} t-gthr-vxworks" + ;; + esac +esac + +case ${host} in +*-*-musl*) + # The gthr weak references are unsafe with static linking + tmake_file="$tmake_file t-gthr-noweak" + ;; +esac diff --git a/ports/gcc/changes/gcc_libstdc++-v3_configure b/ports/gcc/changes/gcc_libstdc++-v3_configure new file mode 100755 index 0000000..85cf58b --- /dev/null +++ b/ports/gcc/changes/gcc_libstdc++-v3_configure @@ -0,0 +1,81243 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for package-unused version-unused. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='package-unused' +PACKAGE_TARNAME='libstdc++' +PACKAGE_VERSION='version-unused' +PACKAGE_STRING='package-unused version-unused' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="src/shared/hashtable-aux.cc" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +get_gcc_base_ver +WARN_FLAGS +OPTIMIZE_CXXFLAGS +TOPLEVEL_INCLUDES +GLIBCXX_INCLUDES +glibcxx_toolexeclibdir +glibcxx_toolexecdir +gxx_include_dir +glibcxx_prefixdir +EXTRA_CFLAGS +tmake_file +CPU_OPT_BITS_RANDOM +CPU_OPT_EXT_RANDOM +ERROR_CONSTANTS_SRCDIR +OS_INC_SRCDIR +ABI_TWEAKS_SRCDIR +CPU_DEFINES_SRCDIR +ATOMIC_FLAGS +ATOMIC_WORD_SRCDIR +ATOMICITY_SRCDIR +INCLUDE_DIR_NOTPARALLEL_FALSE +INCLUDE_DIR_NOTPARALLEL_TRUE +BUILD_PDF_FALSE +BUILD_PDF_TRUE +PDFLATEX +DBLATEX +BUILD_MAN_FALSE +BUILD_MAN_TRUE +BUILD_HTML_FALSE +BUILD_HTML_TRUE +BUILD_XML_FALSE +BUILD_XML_TRUE +BUILD_EPUB_FALSE +BUILD_EPUB_TRUE +XSL_STYLE_DIR +XMLLINT +XSLTPROC +XMLCATALOG +DOT +DOXYGEN +BUILD_INFO_FALSE +BUILD_INFO_TRUE +ENABLE_FILESYSTEM_TS_FALSE +ENABLE_FILESYSTEM_TS_TRUE +baseline_subdir_switch +baseline_dir +HWCAP_CFLAGS +GLIBCXX_LDBL_ALT128_COMPAT_FALSE +GLIBCXX_LDBL_ALT128_COMPAT_TRUE +GLIBCXX_LDBL_COMPAT_FALSE +GLIBCXX_LDBL_COMPAT_TRUE +LONG_DOUBLE_ALT128_COMPAT_FLAGS +LONG_DOUBLE_128_FLAGS +LONG_DOUBLE_COMPAT_FLAGS +ENABLE_CXX11_ABI_FALSE +ENABLE_CXX11_ABI_TRUE +glibcxx_cxx98_abi +ENABLE_DUAL_ABI_FALSE +ENABLE_DUAL_ABI_TRUE +ENABLE_VISIBILITY_FALSE +ENABLE_VISIBILITY_TRUE +libtool_VERSION +ENABLE_SYMVERS_SUN_FALSE +ENABLE_SYMVERS_SUN_TRUE +ENABLE_SYMVERS_DARWIN_FALSE +ENABLE_SYMVERS_DARWIN_TRUE +ENABLE_SYMVERS_GNU_NAMESPACE_FALSE +ENABLE_SYMVERS_GNU_NAMESPACE_TRUE +ENABLE_SYMVERS_GNU_FALSE +ENABLE_SYMVERS_GNU_TRUE +ENABLE_SYMVERS_FALSE +ENABLE_SYMVERS_TRUE +port_specific_symbol_files +SYMVER_FILE +CXXFILT +LTLIBICONV +LIBICONV +OPT_LDFLAGS +SECTION_LDFLAGS +GLIBCXX_LIBS +ENABLE_VTABLE_VERIFY_FALSE +ENABLE_VTABLE_VERIFY_TRUE +VTV_CYGMIN_FALSE +VTV_CYGMIN_TRUE +VTV_CXXLINKFLAGS +VTV_PCH_CXXFLAGS +VTV_CXXFLAGS +ENABLE_WERROR_FALSE +ENABLE_WERROR_TRUE +ENABLE_PYTHONDIR_FALSE +ENABLE_PYTHONDIR_TRUE +python_mod_dir +ENABLE_EXTERN_TEMPLATE_FALSE +ENABLE_EXTERN_TEMPLATE_TRUE +EXTRA_CXX_FLAGS +GLIBCXX_BUILD_DEBUG_FALSE +GLIBCXX_BUILD_DEBUG_TRUE +DEBUG_FLAGS +GLIBCXX_C_HEADERS_COMPATIBILITY_FALSE +GLIBCXX_C_HEADERS_COMPATIBILITY_TRUE +GLIBCXX_C_HEADERS_C_GLOBAL_FALSE +GLIBCXX_C_HEADERS_C_GLOBAL_TRUE +GLIBCXX_C_HEADERS_C_STD_FALSE +GLIBCXX_C_HEADERS_C_STD_TRUE +GLIBCXX_C_HEADERS_C_FALSE +GLIBCXX_C_HEADERS_C_TRUE +C_INCLUDE_DIR +ALLOCATOR_NAME +ALLOCATOR_H +ENABLE_ALLOCATOR_NEW_FALSE +ENABLE_ALLOCATOR_NEW_TRUE +CLOCALE_INTERNAL_H +CLOCALE_CC +CTIME_CC +CTIME_H +CNUMERIC_CC +CMONEY_CC +CMESSAGES_CC +CCTYPE_CC +CCOLLATE_CC +CCODECVT_CC +CMESSAGES_H +CLOCALE_H +USE_NLS +glibcxx_localedir +glibcxx_POFILES +glibcxx_MOFILES +check_msgfmt +BASIC_FILE_CC +BASIC_FILE_H +CSTDIO_H +SECTION_FLAGS +ENABLE_FLOAT128_FALSE +ENABLE_FLOAT128_TRUE +thread_header +glibcxx_PCHFLAGS +GLIBCXX_BUILD_PCH_FALSE +GLIBCXX_BUILD_PCH_TRUE +GLIBCXX_HOSTED_FALSE +GLIBCXX_HOSTED_TRUE +glibcxx_compiler_shared_flag +glibcxx_compiler_pic_flag +glibcxx_lt_pic_flag +enable_static +enable_shared +lt_host_flags +CXXCPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +OBJDUMP +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +LIBTOOL +EGREP +GREP +CPP +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +RANLIB +AR +AS +LN_S +toplevel_srcdir +toplevel_builddir +glibcxx_srcdir +glibcxx_builddir +ac_ct_CXX +CXXFLAGS +CXX +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +multi_basedir +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_multilib +enable_silent_rules +enable_largefile +with_target_subdir +with_cross_host +with_newlib +enable_maintainer_mode +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +enable_hosted_libstdcxx +enable_libstdcxx_verbose +enable_libstdcxx_pch +with_libstdcxx_lock_policy +enable_cstdio +enable_clocale +enable_nls +enable_libstdcxx_allocator +enable_cheaders_obsolete +enable_cheaders +enable_long_long +enable_wchar_t +enable_c99 +enable_concept_checks +enable_libstdcxx_debug_flags +enable_libstdcxx_debug +enable_cxx_flags +enable_fully_dynamic_string +enable_extern_template +with_python_dir +enable_werror +enable_vtable_verify +enable_libstdcxx_time +enable_tls +enable_rpath +with_libiconv_prefix +with_libiconv_type +with_system_libunwind +enable_linux_futex +enable_symvers +enable_libstdcxx_visibility +enable_libstdcxx_dual_abi +with_default_libstdcxx_abi +enable_libstdcxx_threads +enable_libstdcxx_filesystem_ts +enable_cet +with_gxx_include_dir +enable_version_specific_runtime_libs +with_toolexeclibdir +with_gcc_major_version_only +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP +CXXCPP +CXXFILT' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures package-unused version-unused to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/libstdc++] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of package-unused version-unused:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-multilib build many library versions (default) + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --disable-largefile omit support for large files + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --disable-hosted-libstdcxx + only build freestanding C++ runtime support + --disable-libstdcxx-verbose + disable termination messages to standard error + --enable-libstdcxx-pch build pre-compiled libstdc++ headers + [default=$is_hosted] + --enable-cstdio[=PACKAGE] + use target-specific I/O package [default=stdio] + --enable-clocale[=MODEL] + use MODEL for target locale package [default=auto] + --enable-nls use Native Language Support (default) + --enable-libstdcxx-allocator[=KIND] + use KIND for target std::allocator base + [default=auto] + --enable-cheaders-obsolete + allow use of obsolete "C" headers for g++ + [default=no] + --enable-cheaders[=KIND] + construct "C" headers for g++ [default=$c_model] + --enable-long-long enable template specializations for 'long long' + [default=yes] + --enable-wchar_t enable template specializations for 'wchar_t' + [default=yes] + --enable-c99 turns on ISO/IEC 9899:1999 support [default=yes] + --enable-concept-checks use Boost-derived template checks [default=no] + --enable-libstdcxx-debug-flags=FLAGS + pass compiler FLAGS when building debug library + [default="-gdwarf-4 -g3 -O0 -D_GLIBCXX_ASSERTIONS"] + --enable-libstdcxx-debug + build extra debug library [default=no] + --enable-cxx-flags=FLAGS + pass compiler FLAGS when building library [default=] + --enable-fully-dynamic-string + do not put empty strings in per-process static + memory [default=no] + --enable-extern-template + enable extern template [default=yes] + --enable-werror turns on -Werror [default=no] + --enable-vtable-verify enable vtable verify [default=no] + --enable-libstdcxx-time[=KIND] + use KIND for check type [default=auto] + --enable-tls Use thread-local storage [default=yes] + --disable-rpath do not hardcode runtime library paths + --enable-linux-futex use the Linux futex system call [default=default] + --enable-symvers[=STYLE] + enables symbol versioning of the shared library + [default=yes] + --enable-libstdcxx-visibility + enables visibility safe usage [default=yes] + --enable-libstdcxx-dual-abi + support two versions of std::string [default=yes] + --enable-libstdcxx-threads + enable C++11 threads support [default=auto] + --enable-libstdcxx-filesystem-ts + turns on ISO/IEC TS 18822 support [default=auto] + --enable-cet enable Intel CET in target libraries [default=auto] + --enable-version-specific-runtime-libs + Specify that runtime libraries should be installed + in a compiler-specific directory + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-target-subdir=SUBDIR + configuring in a subdirectory + --with-cross-host=HOST configuring with a cross compiler + --with-newlib assume newlib as a system C library + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-libstdcxx-lock-policy={atomic,mutex,auto} + synchronization policy for shared_ptr reference + counting [default=auto] + --with-python-dir the location to install Python modules. This path is + relative starting from the prefix. + --with-gnu-ld assume the C compiler uses GNU ld default=no + --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib + --without-libiconv-prefix don't search for libiconv in includedir and libdir + --with-libiconv-type=TYPE type of library to search for (auto/static/shared) + --with-system-libunwind use installed libunwind + --with-default-libstdcxx-abi + set the std::string ABI to use by default + --with-gxx-include-dir=DIR + installation directory for include files + --with-toolexeclibdir=DIR + install libraries built with a cross compiler within + DIR + --with-gcc-major-version-only + use only GCC major number in filesystem paths + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + CXXCPP C++ preprocessor + CXXFILT Location of GNU c++filt. Defaults to the first GNU version of + `c++filt', `gc++filt' on PATH. + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +package-unused configure version-unused +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES +# --------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_cxx_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_header_mongrel + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 &5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_func + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_cxx_check_type LINENO TYPE VAR INCLUDES +# --------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_cxx_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_type +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by package-unused $as_me version-unused, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + +ac_config_headers="$ac_config_headers config.h" + + +# This works around the fact that libtool configuration may change LD +# for this particular configuration, but some shells, instead of +# keeping the changes in LD private, export them just because LD is +# exported. Only used at the end of this file. +### am handles this now? ORIGINAL_LD_FOR_MULTILIBS=$LD + +# Find the rest of the source tree framework. +# Default to --enable-multilib +# Check whether --enable-multilib was given. +if test "${enable_multilib+set}" = set; then : + enableval=$enable_multilib; case "$enableval" in + yes) multilib=yes ;; + no) multilib=no ;; + *) as_fn_error $? "bad value $enableval for multilib option" "$LINENO" 5 ;; + esac +else + multilib=yes +fi + + +# We may get other options which we leave undocumented: +# --with-target-subdir, --with-multisrctop, --with-multisubdir +# See config-ml.in if you want the gory details. + +if test "$srcdir" = "."; then + if test "$with_target_subdir" != "."; then + multi_basedir="$srcdir/$with_multisrctop../.." + else + multi_basedir="$srcdir/$with_multisrctop.." + fi +else + multi_basedir="$srcdir/.." +fi + + +# Even if the default multilib is not a cross compilation, +# it may be that some of the other multilibs are. +if test $cross_compiling = no && test $multilib = yes \ + && test "x${with_multisubdir}" != x ; then + cross_compiling=maybe +fi + +ac_config_commands="$ac_config_commands default-1" + + +# Gets build, host, target, *_vendor, *_cpu, *_os, etc. +# +# You will slowly go insane if you do not grok the following fact: when +# building v3 as part of the compiler, the top-level /target/ becomes the +# library's /host/. configure then causes --target to default to --host, +# exactly like any other package using autoconf. Therefore, 'target' and +# 'host' will always be the same. This makes sense both for native and +# cross compilers, just think about it for a little while. :-) +# +# Also, if v3 is being configured as part of a cross compiler, the top-level +# configure script will pass the "real" host as $with_cross_host. +# +# Do not delete or change the following two lines. For why, see +# http://gcc.gnu.org/ml/libstdc++/2003-07/msg00451.html +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +target_alias=${target_alias-$host_alias} + +# Handy for debugging: +#AC_MSG_NOTICE($build / $host / $target / $host_alias / $target_alias); sleep 5 + +if test "$build" != "$host"; then + # We are being configured with some form of cross compiler. + GLIBCXX_IS_NATIVE=false + case "$host","$target" in + # Darwin crosses can use the host system's libraries and headers, + # because of the fat library support. Of course, it must be the + # same version of Darwin on both sides. Allow the user to + # just say --target=foo-darwin without a version number to mean + # "the version on this system". + *-*-darwin*,*-*-darwin*) + hostos=`echo $host | sed 's/.*-darwin/darwin/'` + targetos=`echo $target | sed 's/.*-darwin/darwin/'` + if test $hostos = $targetos -o $targetos = darwin ; then + GLIBCXX_IS_NATIVE=true + fi + ;; + + *) + + ;; + esac +else + GLIBCXX_IS_NATIVE=true +fi + +# Sets up automake. Must come after AC_CANONICAL_SYSTEM. Each of the +# following is magically included in AUTOMAKE_OPTIONS in each Makefile.am. +# 1.x: minimum required version +# no-define: PACKAGE and VERSION will not be #define'd in config.h (a bunch +# of other PACKAGE_* variables will, however, and there's nothing +# we can do about that; they come from AC_INIT). +# foreign: we don't follow the normal rules for GNU packages (no COPYING +# file in the top srcdir, etc, etc), so stop complaining. +# no-dependencies: turns off auto dependency generation (just for now) +# no-dist: we don't want 'dist' and related rules. +# -Wall: turns on all automake warnings... +# -Wno-portability: ...except this one, since GNU make is now required. +am__api_version='1.15' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='libstdc++' + VERSION='version-unused' + + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar pax cpio none' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + + + + +# -fno-builtin must be present here so that a non-conflicting form of +# std::exit can be guessed by AC_PROG_CXX, and used in later tests. + +save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS -fno-builtin" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +printf ("hello world\n"); + ; + return 0; +} +_ACEOF +# FIXME: Cleanup? +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + gcc_no_link=no +else + gcc_no_link=yes +fi +if test x$gcc_no_link = xyes; then + # Setting cross_compile will disable run tests; it will + # also disable AC_CHECK_FILE but that's generally + # correct if we can't link. + cross_compiling=yes + EXEEXT= +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CXXFLAGS="$save_CXXFLAGS" + + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + + +# Runs configure.host, and assorted other critical bits. Sets +# up critical shell variables. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + + + # Keep these sync'd with the list in Makefile.am. The first provides an + # expandable list at autoconf time; the second provides an expandable list + # (i.e., shell variable) at configure time. + + SUBDIRS='include libsupc++ src src/c++98 src/c++11 src/c++17 src/c++20 src/filesystem doc po testsuite python' + + # These need to be absolute paths, yet at the same time need to + # canonicalize only relative paths, because then amd will not unmount + # drives. Thus the use of PWDCMD: set it to 'pawd' or 'amq -w' if using amd. + glibcxx_builddir=`${PWDCMD-pwd}` + case $srcdir in + \\/$* | ?:\\/*) glibcxx_srcdir=${srcdir} ;; + *) glibcxx_srcdir=`cd "$srcdir" && ${PWDCMD-pwd} || echo "$srcdir"` ;; + esac + toplevel_builddir=${glibcxx_builddir}/.. + toplevel_srcdir=${glibcxx_srcdir}/.. + + + + + + # We use these options to decide which functions to include. They are + # set from the top level. + +# Check whether --with-target-subdir was given. +if test "${with_target_subdir+set}" = set; then : + withval=$with_target_subdir; +fi + + + +# Check whether --with-cross-host was given. +if test "${with_cross_host+set}" = set; then : + withval=$with_cross_host; +fi + + + +# Check whether --with-newlib was given. +if test "${with_newlib+set}" = set; then : + withval=$with_newlib; +fi + + + # Will set LN_S to either 'ln -s', 'ln', or 'cp -p' (if linking isn't + # available). Uncomment the next line to force a particular method. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + + #LN_S='cp -p' + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AS+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AS="${ac_tool_prefix}as" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AS=$ac_cv_prog_AS +if test -n "$AS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 +$as_echo "$AS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AS"; then + ac_ct_AS=$AS + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AS+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AS"; then + ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AS="as" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AS=$ac_cv_prog_ac_ct_AS +if test -n "$ac_ct_AS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 +$as_echo "$ac_ct_AS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AS" = x; then + AS="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AS=$ac_ct_AS + fi +else + AS="$ac_cv_prog_AS" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB="ranlib-not-found-in-path-error" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + + # Set up safe default values for all subsequent AM_CONDITIONAL tests + # which are themselves conditionally expanded. + ## (Right now, this only matters for enable_wchar_t, but nothing prevents + ## other macros from doing the same. This should be automated.) -pme + + # Check for C library flavor since GNU/Linux platforms use different + # configuration directories depending on the C library in use. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #if __UCLIBC__ + _using_uclibc + #endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "_using_uclibc" >/dev/null 2>&1; then : + uclibc=yes +else + uclibc=no +fi +rm -f conftest* + + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #if __BIONIC__ + _using_bionic + #endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "_using_bionic" >/dev/null 2>&1; then : + bionic=yes +else + bionic=no +fi +rm -f conftest* + + + # Find platform-specific directories containing configuration info. + # Also possibly modify flags used elsewhere, as needed by the platform. + + . $glibcxx_srcdir/configure.host + { $as_echo "$as_me:${as_lineno-$LINENO}: CPU config directory is $cpu_include_dir" >&5 +$as_echo "$as_me: CPU config directory is $cpu_include_dir" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: OS config directory is $os_include_dir" >&5 +$as_echo "$as_me: OS config directory is $os_include_dir" >&6;} + + + +# Libtool setup. +if test "x${with_newlib}" != "xyes" && test "x${with_avrlibc}" != "xyes"; then + enable_dlopen=yes + + + +fi +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.7a' +macro_revision='1.3134' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`print -r -- -n 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + # Allow for Darwin 4-7 (macOS 10.0-10.3) although these are not expect to + # build without first building modern cctools / linker. + case $host_cpu-$host_os in + *-rhapsody* | *-darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + *-darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + *-darwin*) + # darwin 5.x (macOS 10.1) onwards we only need to adjust when the + # deployment target is forced to an earlier version. + case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host in + UNSET,*-darwin[89]*|UNSET,*-darwin[12][0123456789]*) + ;; + 10.[012][,.]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + *) + ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + + +# Set options + + + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + lt_prog_compiler_pic='-Xcompiler -fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo(void) {} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. + +# uclinux* changes (here and below) have been submitted to the libtool +# project, but have not yet been accepted: they are GCC-local changes +# for the time being. (See +# https://lists.gnu.org/archive/html/libtool-patches/2018-05/msg00000.html) +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu* | uclinuxfdpiceabi) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + essence*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 12133 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +void fnord () __attribute__((visibility("default"))); +#endif + +void fnord () { int i=42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 12239 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +void fnord () __attribute__((visibility("default"))); +#endif + +void fnord () { int i=42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + gnu*) + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + lt_prog_compiler_pic_CXX='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_prog_compiler_pic_CXX" >&6; } + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. + +# uclinux* changes (here and below) have been submitted to the libtool +# project, but have not yet been accepted: they are GCC-local changes +# for the time being. (See +# https://lists.gnu.org/archive/html/libtool-patches/2018-05/msg00000.html) +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu* | uclinuxfdpiceabi) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + + + +case $host in + *-cygwin* | *-mingw*) + # 'host' will be top-level target in the case of a target lib, + # we must compare to with_cross_host to decide if this is a native + # or cross-compiler and select where to install dlls appropriately. + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + lt_host_flags='-no-undefined -bindir "$(toolexeclibdir)"'; + else + lt_host_flags='-no-undefined -bindir "$(bindir)"'; + fi + ;; + *) + lt_host_flags= + ;; +esac + + + + + + +if test "$enable_vtable_verify" = yes; then + predep_objects_CXX="${predep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_start.o" + postdep_objects_CXX="${postdep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_end.o" +fi + + +# libtool variables for C++ shared and position-independent compiles. +# +# Use glibcxx_lt_pic_flag to designate the automake variable +# used to encapsulate the default libtool approach to creating objects +# with position-independent code. Default: -prefer-pic. +# +# Use glibcxx_compiler_shared_flag to designate a compile-time flags for +# creating shared objects. Default: -D_GLIBCXX_SHARED. +# +# Use glibcxx_compiler_pic_flag to designate a compile-time flags for +# creating position-independent objects. This varies with the target +# hardware and operating system, but is often: -DPIC -fPIC. +if test "$enable_shared" = yes; then + glibcxx_lt_pic_flag="-prefer-pic" + glibcxx_compiler_pic_flag="$lt_prog_compiler_pic_CXX" + glibcxx_compiler_shared_flag="-D_GLIBCXX_SHARED" + +else + glibcxx_lt_pic_flag= + glibcxx_compiler_pic_flag= + glibcxx_compiler_shared_flag= +fi + + + + +# Override the libtool's pic_flag and pic_mode. +# Do this step after AM_PROG_LIBTOOL, but before AC_OUTPUT. +# NB: this impacts --with-pic and --without-pic. +lt_prog_compiler_pic_CXX="$glibcxx_compiler_pic_flag $glibcxx_compiler_shared_flag" +pic_mode='default' + +# Eliminate -lstdc++ addition to postdeps for cross compiles. +postdeps_CXX=`echo " $postdeps_CXX " | sed 's, -lstdc++ ,,g'` + +# Possibly disable most of the library. +## TODO: Consider skipping unncessary tests altogether in this case, rather +## than just ignoring the results. Faster /and/ more correct, win win. + + # Check whether --enable-hosted-libstdcxx was given. +if test "${enable_hosted_libstdcxx+set}" = set; then : + enableval=$enable_hosted_libstdcxx; +else + case "$host" in + arm*-*-symbianelf*) + enable_hosted_libstdcxx=no + ;; + *) + enable_hosted_libstdcxx=yes + ;; + esac +fi + + if test "$enable_hosted_libstdcxx" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Only freestanding libraries will be built" >&5 +$as_echo "$as_me: Only freestanding libraries will be built" >&6;} + is_hosted=no + hosted_define=0 + enable_abi_check=no + enable_libstdcxx_pch=no + else + is_hosted=yes + hosted_define=1 + fi + + +cat >>confdefs.h <<_ACEOF +#define _GLIBCXX_HOSTED $hosted_define +_ACEOF + + + +# Enable descriptive messages to standard output on termination. + + # Check whether --enable-libstdcxx-verbose was given. +if test "${enable_libstdcxx_verbose+set}" = set; then : + enableval=$enable_libstdcxx_verbose; +else + enable_libstdcxx_verbose=yes +fi + + if test x"$enable_libstdcxx_verbose" = xyes; then + verbose_define=1 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: verbose termination messages are disabled" >&5 +$as_echo "$as_me: verbose termination messages are disabled" >&6;} + verbose_define=0 + fi + +cat >>confdefs.h <<_ACEOF +#define _GLIBCXX_VERBOSE $verbose_define +_ACEOF + + + +# Enable compiler support that doesn't require linking. + + # Check whether --enable-libstdcxx-pch was given. +if test "${enable_libstdcxx_pch+set}" = set; then : + enableval=$enable_libstdcxx_pch; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable libstdcxx-pch must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_libstdcxx_pch=$is_hosted +fi + + + if test $enable_libstdcxx_pch = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler with PCH support" >&5 +$as_echo_n "checking for compiler with PCH support... " >&6; } +if ${glibcxx_cv_prog_CXX_pch+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -Werror -Winvalid-pch -Wno-deprecated" + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + echo '#include ' > conftest.h + if $CXX $CXXFLAGS $CPPFLAGS -x c++-header conftest.h \ + -o conftest.h.gch 1>&5 2>&1 && + echo '#error "pch failed"' > conftest.h && + echo '#include "conftest.h"' > conftest.cc && + $CXX -c $CXXFLAGS $CPPFLAGS conftest.cc 1>&5 2>&1 ; + then + glibcxx_cv_prog_CXX_pch=yes + else + glibcxx_cv_prog_CXX_pch=no + fi + rm -f conftest* + CXXFLAGS=$ac_save_CXXFLAGS + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_prog_CXX_pch" >&5 +$as_echo "$glibcxx_cv_prog_CXX_pch" >&6; } + enable_libstdcxx_pch=$glibcxx_cv_prog_CXX_pch + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for enabled PCH" >&5 +$as_echo_n "checking for enabled PCH... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libstdcxx_pch" >&5 +$as_echo "$enable_libstdcxx_pch" >&6; } + + + if test $enable_libstdcxx_pch = yes; then + glibcxx_PCHFLAGS="-include bits/stdc++.h" + else + glibcxx_PCHFLAGS="" + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread model used by GCC" >&5 +$as_echo_n "checking for thread model used by GCC... " >&6; } + target_thread_file=`$CXX -v 2>&1 | sed -n 's/^Thread model: //p'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $target_thread_file" >&5 +$as_echo "$target_thread_file" >&6; } + +case $target_thread_file in + aix) thread_header=config/rs6000/gthr-aix.h ;; + dce) thread_header=config/pa/gthr-dce.h ;; + gcn) thread_header=config/gcn/gthr-gcn.h ;; + lynx) thread_header=config/gthr-lynx.h ;; + mipssde) thread_header=config/mips/gthr-mipssde.h ;; + posix) thread_header=gthr-posix.h ;; + rtems) thread_header=config/gthr-rtems.h ;; + single) thread_header=gthr-single.h ;; + tpf) thread_header=config/s390/gthr-tpf.h ;; + vxworks) thread_header=config/gthr-vxworks.h ;; + win32) thread_header=config/i386/gthr-win32.h ;; +esac + + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + old_CXXFLAGS="$CXXFLAGS" + + # Do link tests if possible, instead asm tests, limited to some platforms + # see discussion in PR target/40134, PR libstdc++/40133 and the thread + # starting at http://gcc.gnu.org/ml/gcc-patches/2009-07/msg00322.html + atomic_builtins_link_tests=no + if test x$gcc_no_link != xyes; then + # Can do link tests. Limit to some tested platforms + case "$host" in + *-*-linux* | *-*-uclinux* | *-*-kfreebsd*-gnu | *-*-gnu*) + atomic_builtins_link_tests=yes + ;; + esac + fi + + if test x$atomic_builtins_link_tests = xyes; then + + # Do link tests. + + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic builtins for bool" >&5 +$as_echo_n "checking for atomic builtins for bool... " >&6; } + if ${glibcxx_cv_atomic_bool+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +typedef bool atomic_type; + atomic_type c1; + atomic_type c2; + atomic_type c3(0); + // N.B. __atomic_fetch_add is not supported for bool. + __atomic_compare_exchange_n(&c1, &c2, c3, true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED); + __atomic_test_and_set(&c1, __ATOMIC_RELAXED); + __atomic_load_n(&c1, __ATOMIC_RELAXED); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_atomic_bool=yes +else + glibcxx_cv_atomic_bool=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_atomic_bool" >&5 +$as_echo "$glibcxx_cv_atomic_bool" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic builtins for short" >&5 +$as_echo_n "checking for atomic builtins for short... " >&6; } + if ${glibcxx_cv_atomic_short+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +typedef short atomic_type; + atomic_type c1; + atomic_type c2; + atomic_type c3(0); + __atomic_fetch_add(&c1, c2, __ATOMIC_RELAXED); + __atomic_compare_exchange_n(&c1, &c2, c3, true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED); + __atomic_test_and_set(&c1, __ATOMIC_RELAXED); + __atomic_load_n(&c1, __ATOMIC_RELAXED); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_atomic_short=yes +else + glibcxx_cv_atomic_short=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_atomic_short" >&5 +$as_echo "$glibcxx_cv_atomic_short" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic builtins for int" >&5 +$as_echo_n "checking for atomic builtins for int... " >&6; } + if ${glibcxx_cv_atomic_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +typedef int atomic_type; + atomic_type c1; + atomic_type c2; + atomic_type c3(0); + __atomic_fetch_add(&c1, c2, __ATOMIC_RELAXED); + __atomic_compare_exchange_n(&c1, &c2, c3, true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED); + __atomic_test_and_set(&c1, __ATOMIC_RELAXED); + __atomic_load_n(&c1, __ATOMIC_RELAXED); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_atomic_int=yes +else + glibcxx_cv_atomic_int=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_atomic_int" >&5 +$as_echo "$glibcxx_cv_atomic_int" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic builtins for long long" >&5 +$as_echo_n "checking for atomic builtins for long long... " >&6; } + if ${glibcxx_cv_atomic_long_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +typedef long long atomic_type; + atomic_type c1; + atomic_type c2; + atomic_type c3(0); + __atomic_fetch_add(&c1, c2, __ATOMIC_RELAXED); + __atomic_compare_exchange_n(&c1, &c2, c3, true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED); + __atomic_test_and_set(&c1, __ATOMIC_RELAXED); + __atomic_load_n(&c1, __ATOMIC_RELAXED); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_atomic_long_long=yes +else + glibcxx_cv_atomic_long_long=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_atomic_long_long" >&5 +$as_echo "$glibcxx_cv_atomic_long_long" >&6; } + + else + + # Do asm tests. + + # Compile unoptimized. + CXXFLAGS='-O0 -S' + + # Fake what AC_TRY_COMPILE does. + + cat > conftest.$ac_ext << EOF +#line 15921 "configure" +int main() +{ + typedef bool atomic_type; + atomic_type c1; + atomic_type c2; + atomic_type c3(0); + // N.B. __atomic_fetch_add is not supported for bool. + __atomic_compare_exchange_n(&c1, &c2, c3, true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED); + __atomic_test_and_set(&c1, __ATOMIC_RELAXED); + __atomic_load_n(&c1, __ATOMIC_RELAXED); + + return 0; +} +EOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic builtins for bool" >&5 +$as_echo_n "checking for atomic builtins for bool... " >&6; } + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if grep __atomic_ conftest.s >/dev/null 2>&1 ; then + glibcxx_cv_atomic_bool=no + else + glibcxx_cv_atomic_bool=yes + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_atomic_bool" >&5 +$as_echo "$glibcxx_cv_atomic_bool" >&6; } + rm -f conftest* + + cat > conftest.$ac_ext << EOF +#line 15956 "configure" +int main() +{ + typedef short atomic_type; + atomic_type c1; + atomic_type c2; + atomic_type c3(0); + __atomic_fetch_add(&c1, c2, __ATOMIC_RELAXED); + __atomic_compare_exchange_n(&c1, &c2, c3, true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED); + __atomic_test_and_set(&c1, __ATOMIC_RELAXED); + __atomic_load_n(&c1, __ATOMIC_RELAXED); + + return 0; +} +EOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic builtins for short" >&5 +$as_echo_n "checking for atomic builtins for short... " >&6; } + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if grep __atomic_ conftest.s >/dev/null 2>&1 ; then + glibcxx_cv_atomic_short=no + else + glibcxx_cv_atomic_short=yes + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_atomic_short" >&5 +$as_echo "$glibcxx_cv_atomic_short" >&6; } + rm -f conftest* + + cat > conftest.$ac_ext << EOF +#line 15991 "configure" +int main() +{ + // NB: _Atomic_word not necessarily int. + typedef int atomic_type; + atomic_type c1; + atomic_type c2; + atomic_type c3(0); + __atomic_fetch_add(&c1, c2, __ATOMIC_RELAXED); + __atomic_compare_exchange_n(&c1, &c2, c3, true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED); + __atomic_test_and_set(&c1, __ATOMIC_RELAXED); + __atomic_load_n(&c1, __ATOMIC_RELAXED); + + return 0; +} +EOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic builtins for int" >&5 +$as_echo_n "checking for atomic builtins for int... " >&6; } + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if grep __atomic_ conftest.s >/dev/null 2>&1 ; then + glibcxx_cv_atomic_int=no + else + glibcxx_cv_atomic_int=yes + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_atomic_int" >&5 +$as_echo "$glibcxx_cv_atomic_int" >&6; } + rm -f conftest* + + cat > conftest.$ac_ext << EOF +#line 16027 "configure" +int main() +{ + typedef long long atomic_type; + atomic_type c1; + atomic_type c2; + atomic_type c3(0); + __atomic_fetch_add(&c1, c2, __ATOMIC_RELAXED); + __atomic_compare_exchange_n(&c1, &c2, c3, true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED); + __atomic_test_and_set(&c1, __ATOMIC_RELAXED); + __atomic_load_n(&c1, __ATOMIC_RELAXED); + + return 0; +} +EOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic builtins for long long" >&5 +$as_echo_n "checking for atomic builtins for long long... " >&6; } + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if grep __atomic_ conftest.s >/dev/null 2>&1 ; then + glibcxx_cv_atomic_long_long=no + else + glibcxx_cv_atomic_long_long=yes + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_atomic_long_long" >&5 +$as_echo "$glibcxx_cv_atomic_long_long" >&6; } + rm -f conftest* + + fi + + CXXFLAGS="$old_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + # Set atomicity_dir to builtins if all but the long long test above passes, + # or if the builtins were already chosen (e.g. by configure.host). + if { test "$glibcxx_cv_atomic_bool" = yes \ + && test "$glibcxx_cv_atomic_short" = yes \ + && test "$glibcxx_cv_atomic_int" = yes; } \ + || test "$atomicity_dir" = "cpu/generic/atomicity_builtins"; then + +$as_echo "#define _GLIBCXX_ATOMIC_BUILTINS 1" >>confdefs.h + + atomicity_dir=cpu/generic/atomicity_builtins + fi + + # If still generic, set to mutex. + if test $atomicity_dir = "cpu/generic" ; then + atomicity_dir=cpu/generic/atomicity_mutex + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No native atomic operations are provided for this platform." >&5 +$as_echo "$as_me: WARNING: No native atomic operations are provided for this platform." >&2;} + if test "x$target_thread_file" = xsingle; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: They cannot be faked when thread support is disabled." >&5 +$as_echo "$as_me: WARNING: They cannot be faked when thread support is disabled." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Thread-safety of certain classes is not guaranteed." >&5 +$as_echo "$as_me: WARNING: Thread-safety of certain classes is not guaranteed." >&2;} + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: They will be faked using a mutex." >&5 +$as_echo "$as_me: WARNING: They will be faked using a mutex." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Performance of certain classes will degrade as a result." >&5 +$as_echo "$as_me: WARNING: Performance of certain classes will degrade as a result." >&2;} + fi + fi + + + + + +# Check whether --with-libstdcxx-lock-policy was given. +if test "${with_libstdcxx_lock_policy+set}" = set; then : + withval=$with_libstdcxx_lock_policy; libstdcxx_atomic_lock_policy=$withval +else + libstdcxx_atomic_lock_policy=auto +fi + + + case "$libstdcxx_atomic_lock_policy" in + atomic|mutex|auto) ;; + *) as_fn_error $? "Invalid argument for --with-libstdcxx-lock-policy" "$LINENO" 5 ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lock policy for shared_ptr reference counts" >&5 +$as_echo_n "checking for lock policy for shared_ptr reference counts... " >&6; } + + if test x"$libstdcxx_atomic_lock_policy" = x"auto"; then + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #if ! defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 + # error "No 2-byte compare-and-swap" + #elif ! defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + # error "No 4-byte compare-and-swap" + #endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + libstdcxx_atomic_lock_policy=atomic +else + libstdcxx_atomic_lock_policy=mutex +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + CXXFLAGS="$ac_save_CXXFLAGS" + fi + + if test x"$libstdcxx_atomic_lock_policy" = x"atomic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: atomic" >&5 +$as_echo "atomic" >&6; } + +$as_echo "#define HAVE_ATOMIC_LOCK_POLICY 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: mutex" >&5 +$as_echo "mutex" >&6; } + fi + + + + + # Fake what AC_TRY_COMPILE does, without linking as this is + # unnecessary for this test. + + cat > conftest.$ac_ext << EOF +#line 16180 "configure" +int main() +{ + _Decimal32 d1; + _Decimal64 d2; + _Decimal128 d3; + return 0; +} +EOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO/IEC TR 24733 " >&5 +$as_echo_n "checking for ISO/IEC TR 24733 ... " >&6; } + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + +$as_echo "#define _GLIBCXX_USE_DECIMAL_FLOAT 1" >>confdefs.h + + enable_dfp=yes + else + enable_dfp=no + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_dfp" >&5 +$as_echo "$enable_dfp" >&6; } + rm -f conftest* + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Fake what AC_TRY_COMPILE does, without linking as this is + # unnecessary for this test. + + cat > conftest.$ac_ext << EOF +#line 16222 "configure" +template + struct same + { typedef T2 type; }; + +template + struct same; + +int main() +{ + typename same::type i1; + typename same::type i2; +} +EOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __int128" >&5 +$as_echo_n "checking for __int128... " >&6; } + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + +$as_echo "#define _GLIBCXX_USE_INT128 1" >>confdefs.h + + enable_int128=yes + else + enable_int128=no + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_int128" >&5 +$as_echo "$enable_int128" >&6; } + rm -f conftest* + + cat > conftest.$ac_ext << EOF +#line 16256 "configure" +template + struct same + { typedef T2 type; }; + +template + struct same; + +int main() +{ + typename same::type f1; + typename same::type f2; +} +EOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __float128" >&5 +$as_echo_n "checking for __float128... " >&6; } + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + enable_float128=yes + else + enable_float128=no + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_float128" >&5 +$as_echo "$enable_float128" >&6; } + + rm -f conftest* + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +if test "$enable_float128" = yes; then + port_specific_symbol_files="$port_specific_symbol_files \$(top_srcdir)/config/abi/pre/float128.ver" +fi + +# Checks for compiler support that doesn't require linking. + + # All these tests are for C++; save the language and the compiler flags. + # The CXXFLAGS thing is suspicious, but based on similar bits previously + # found in GLIBCXX_CONFIGURE. + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + + # Check for -ffunction-sections -fdata-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for g++ that supports -ffunction-sections -fdata-sections" >&5 +$as_echo_n "checking for g++ that supports -ffunction-sections -fdata-sections... " >&6; } + CXXFLAGS='-g -Werror -ffunction-sections -fdata-sections' + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo; void bar() { }; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_fdsections=yes +else + ac_fdsections=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" + else + # this is the suspicious part + CXXFLAGS='' + fi + if test x"$ac_fdsections" = x"yes"; then + SECTION_FLAGS='-ffunction-sections -fdata-sections' + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_fdsections" >&5 +$as_echo "$ac_fdsections" >&6; } + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +# Enable all the variable C++ runtime options that don't require linking. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for underlying I/O to use" >&5 +$as_echo_n "checking for underlying I/O to use... " >&6; } + # Check whether --enable-cstdio was given. +if test "${enable_cstdio+set}" = set; then : + enableval=$enable_cstdio; + case "$enableval" in + stdio|stdio_posix|stdio_pure) ;; + *) as_fn_error $? "Unknown argument to enable/disable cstdio" "$LINENO" 5 ;; + esac + +else + enable_cstdio=stdio +fi + + + + # The only available I/O model is based on stdio, via basic_file_stdio. + # The default "stdio" is actually "stdio + POSIX" because it uses fdopen(3) + # to get a file descriptor and then uses read(3) and write(3) with it. + # The "stdio_pure" model doesn't use fdopen and only uses FILE* for I/O. + case ${enable_cstdio} in + stdio*) + CSTDIO_H=config/io/c_io_stdio.h + BASIC_FILE_H=config/io/basic_file_stdio.h + BASIC_FILE_CC=config/io/basic_file_stdio.cc + { $as_echo "$as_me:${as_lineno-$LINENO}: result: stdio" >&5 +$as_echo "stdio" >&6; } + + if test "x$enable_cstdio" = "xstdio_pure" ; then + +$as_echo "#define _GLIBCXX_USE_STDIO_PURE 1" >>confdefs.h + + fi + ;; + esac + + + + + + + # Check whether --enable-clocale was given. +if test "${enable_clocale+set}" = set; then : + enableval=$enable_clocale; + case "$enableval" in + generic|gnu|ieee_1003.1-2001|newlib|yes|no|auto) ;; + *) as_fn_error $? "Unknown argument to enable/disable clocale" "$LINENO" 5 ;; + esac + +else + enable_clocale=auto +fi + + + + # Deal with gettext issues. Default to not using it (=no) until we detect + # support for it later. Let the user turn it off via --e/d, but let that + # default to on for easier handling. + USE_NLS=no + # Check whether --enable-nls was given. +if test "${enable_nls+set}" = set; then : + enableval=$enable_nls; +else + enable_nls=yes +fi + + + # Either a known package, or "auto" + if test $enable_clocale = no || test $enable_clocale = yes; then + enable_clocale=auto + fi + enable_clocale_flag=$enable_clocale + + # Probe for locale model to use if none specified. + # Default to "generic". + if test $enable_clocale_flag = auto; then + case ${target_os} in + linux* | gnu* | kfreebsd*-gnu | knetbsd*-gnu) + enable_clocale_flag=gnu + ;; + darwin*) + enable_clocale_flag=darwin + ;; + dragonfly* | freebsd*) + enable_clocale_flag=dragonfly + ;; + openbsd*) + enable_clocale_flag=newlib + ;; + *) + if test x"$with_newlib" = x"yes"; then + enable_clocale_flag=newlib + else + enable_clocale_flag=generic + fi + ;; + esac + fi + + # Sanity check model, and test for special functionality. + if test $enable_clocale_flag = gnu; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(__UCLIBC__) + _GLIBCXX_ok + #endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "_GLIBCXX_ok" >/dev/null 2>&1; then : + enable_clocale_flag=gnu +else + enable_clocale_flag=generic +fi +rm -f conftest* + + + # Set it to scream when it hurts. + ac_save_CFLAGS="$CFLAGS" + CFLAGS="-Wimplicit-function-declaration -Werror" + + # Use strxfrm_l if available. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _GNU_SOURCE 1 + #include + #include +int +main () +{ +char s[128]; __locale_t loc; strxfrm_l(s, "C", 5, loc); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_STRXFRM_L 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + # Use strerror_l if available. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _GNU_SOURCE 1 + #include + #include +int +main () +{ +__locale_t loc; strerror_l(5, loc); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_STRERROR_L 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + CFLAGS="$ac_save_CFLAGS" + fi + + # Perhaps use strerror_r if available, and strerror_l isn't. + ac_save_CFLAGS="$CFLAGS" + CFLAGS="-Wimplicit-function-declaration -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _GNU_SOURCE 1 + #include + #include +int +main () +{ +char s[128]; strerror_r(5, s, 128); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_STRERROR_R 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$ac_save_CFLAGS" + + # Set configure bits for specified locale package + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C locale to use" >&5 +$as_echo_n "checking for C locale to use... " >&6; } + case ${enable_clocale_flag} in + generic) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: generic" >&5 +$as_echo "generic" >&6; } + + CLOCALE_H=config/locale/generic/c_locale.h + CLOCALE_CC=config/locale/generic/c_locale.cc + CCODECVT_CC=config/locale/generic/codecvt_members.cc + CCOLLATE_CC=config/locale/generic/collate_members.cc + CCTYPE_CC=config/locale/generic/ctype_members.cc + CMESSAGES_H=config/locale/generic/messages_members.h + CMESSAGES_CC=config/locale/generic/messages_members.cc + CMONEY_CC=config/locale/generic/monetary_members.cc + CNUMERIC_CC=config/locale/generic/numeric_members.cc + CTIME_H=config/locale/generic/time_members.h + CTIME_CC=config/locale/generic/time_members.cc + CLOCALE_INTERNAL_H=config/locale/generic/c++locale_internal.h + ;; + darwin) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: darwin" >&5 +$as_echo "darwin" >&6; } + + CLOCALE_H=config/locale/generic/c_locale.h + CLOCALE_CC=config/locale/generic/c_locale.cc + CCODECVT_CC=config/locale/generic/codecvt_members.cc + CCOLLATE_CC=config/locale/generic/collate_members.cc + CCTYPE_CC=config/locale/darwin/ctype_members.cc + CMESSAGES_H=config/locale/generic/messages_members.h + CMESSAGES_CC=config/locale/generic/messages_members.cc + CMONEY_CC=config/locale/generic/monetary_members.cc + CNUMERIC_CC=config/locale/generic/numeric_members.cc + CTIME_H=config/locale/generic/time_members.h + CTIME_CC=config/locale/generic/time_members.cc + CLOCALE_INTERNAL_H=config/locale/generic/c++locale_internal.h + ;; + + dragonfly) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: dragonfly or freebsd" >&5 +$as_echo "dragonfly or freebsd" >&6; } + + CLOCALE_H=config/locale/dragonfly/c_locale.h + CLOCALE_CC=config/locale/dragonfly/c_locale.cc + CCODECVT_CC=config/locale/dragonfly/codecvt_members.cc + CCOLLATE_CC=config/locale/dragonfly/collate_members.cc + CCTYPE_CC=config/locale/dragonfly/ctype_members.cc + CMESSAGES_H=config/locale/generic/messages_members.h + CMESSAGES_CC=config/locale/generic/messages_members.cc + CMONEY_CC=config/locale/dragonfly/monetary_members.cc + CNUMERIC_CC=config/locale/dragonfly/numeric_members.cc + CTIME_H=config/locale/dragonfly/time_members.h + CTIME_CC=config/locale/dragonfly/time_members.cc + CLOCALE_INTERNAL_H=config/locale/generic/c++locale_internal.h + ;; + + gnu) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gnu" >&5 +$as_echo "gnu" >&6; } + + # Declare intention to use gettext, and add support for specific + # languages. + # For some reason, ALL_LINGUAS has to be before AM-GNU-GETTEXT + ALL_LINGUAS="de fr" + + # Don't call AM-GNU-GETTEXT here. Instead, assume glibc. + # Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_check_msgfmt+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$check_msgfmt"; then + ac_cv_prog_check_msgfmt="$check_msgfmt" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_check_msgfmt="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_check_msgfmt" && ac_cv_prog_check_msgfmt="no" +fi +fi +check_msgfmt=$ac_cv_prog_check_msgfmt +if test -n "$check_msgfmt"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $check_msgfmt" >&5 +$as_echo "$check_msgfmt" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test x"$check_msgfmt" = x"yes" && test x"$enable_nls" = x"yes"; then + USE_NLS=yes + fi + # Export the build objects. + for ling in $ALL_LINGUAS; do \ + glibcxx_MOFILES="$glibcxx_MOFILES $ling.mo"; \ + glibcxx_POFILES="$glibcxx_POFILES $ling.po"; \ + done + + + + CLOCALE_H=config/locale/gnu/c_locale.h + CLOCALE_CC=config/locale/gnu/c_locale.cc + CCODECVT_CC=config/locale/gnu/codecvt_members.cc + CCOLLATE_CC=config/locale/gnu/collate_members.cc + CCTYPE_CC=config/locale/gnu/ctype_members.cc + CMESSAGES_H=config/locale/gnu/messages_members.h + CMESSAGES_CC=config/locale/gnu/messages_members.cc + CMONEY_CC=config/locale/gnu/monetary_members.cc + CNUMERIC_CC=config/locale/gnu/numeric_members.cc + CTIME_H=config/locale/gnu/time_members.h + CTIME_CC=config/locale/gnu/time_members.cc + CLOCALE_INTERNAL_H=config/locale/gnu/c++locale_internal.h + ;; + ieee_1003.1-2001) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: IEEE 1003.1" >&5 +$as_echo "IEEE 1003.1" >&6; } + + CLOCALE_H=config/locale/ieee_1003.1-2001/c_locale.h + CLOCALE_CC=config/locale/ieee_1003.1-2001/c_locale.cc + CCODECVT_CC=config/locale/generic/codecvt_members.cc + CCOLLATE_CC=config/locale/generic/collate_members.cc + CCTYPE_CC=config/locale/generic/ctype_members.cc + CMESSAGES_H=config/locale/ieee_1003.1-2001/messages_members.h + CMESSAGES_CC=config/locale/ieee_1003.1-2001/messages_members.cc + CMONEY_CC=config/locale/generic/monetary_members.cc + CNUMERIC_CC=config/locale/generic/numeric_members.cc + CTIME_H=config/locale/generic/time_members.h + CTIME_CC=config/locale/generic/time_members.cc + CLOCALE_INTERNAL_H=config/locale/generic/c++locale_internal.h + ;; + newlib) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: newlib" >&5 +$as_echo "newlib" >&6; } + + CLOCALE_H=config/locale/generic/c_locale.h + CLOCALE_CC=config/locale/generic/c_locale.cc + CCODECVT_CC=config/locale/generic/codecvt_members.cc + CCOLLATE_CC=config/locale/generic/collate_members.cc + CCTYPE_CC=config/locale/newlib/ctype_members.cc + CMESSAGES_H=config/locale/generic/messages_members.h + CMESSAGES_CC=config/locale/generic/messages_members.cc + CMONEY_CC=config/locale/generic/monetary_members.cc + CNUMERIC_CC=config/locale/generic/numeric_members.cc + CTIME_H=config/locale/generic/time_members.h + CTIME_CC=config/locale/generic/time_members.cc + CLOCALE_INTERNAL_H=config/locale/generic/c++locale_internal.h + ;; + esac + + # This is where the testsuite looks for locale catalogs, using the + # -DLOCALEDIR define during testsuite compilation. + glibcxx_localedir=${glibcxx_builddir}/po/share/locale + + + # A standalone libintl (e.g., GNU libintl) may be in use. + if test $USE_NLS = yes; then + for ac_header in libintl.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "libintl.h" "ac_cv_header_libintl_h" "$ac_includes_default" +if test "x$ac_cv_header_libintl_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBINTL_H 1 +_ACEOF + +else + USE_NLS=no +fi + +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gettext" >&5 +$as_echo_n "checking for library containing gettext... " >&6; } +if ${ac_cv_search_gettext+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gettext (); +int +main () +{ +return gettext (); + ; + return 0; +} +_ACEOF +for ac_lib in '' intl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_gettext=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_gettext+:} false; then : + break +fi +done +if ${ac_cv_search_gettext+:} false; then : + +else + ac_cv_search_gettext=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gettext" >&5 +$as_echo "$ac_cv_search_gettext" >&6; } +ac_res=$ac_cv_search_gettext +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +else + USE_NLS=no +fi + + fi + if test $USE_NLS = yes; then + +$as_echo "#define _GLIBCXX_USE_NLS 1" >>confdefs.h + + fi + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for std::allocator base class" >&5 +$as_echo_n "checking for std::allocator base class... " >&6; } + # Check whether --enable-libstdcxx-allocator was given. +if test "${enable_libstdcxx_allocator+set}" = set; then : + enableval=$enable_libstdcxx_allocator; + case "$enableval" in + new|malloc|mt|bitmap|pool|yes|no|auto) ;; + *) as_fn_error $? "Unknown argument to enable/disable libstdcxx-allocator" "$LINENO" 5 ;; + esac + +else + enable_libstdcxx_allocator=auto +fi + + + + # If they didn't use this option switch, or if they specified --enable + # with no specific model, we'll have to look for one. If they + # specified --disable (???), do likewise. + if test $enable_libstdcxx_allocator = no || + test $enable_libstdcxx_allocator = yes; + then + enable_libstdcxx_allocator=auto + fi + + # Either a known package, or "auto". Auto implies the default choice + # for a particular platform. + enable_libstdcxx_allocator_flag=$enable_libstdcxx_allocator + + # Probe for host-specific support if no specific model is specified. + # Default to "new". + if test $enable_libstdcxx_allocator_flag = auto; then + case ${target_os} in + linux* | gnu* | kfreebsd*-gnu | knetbsd*-gnu) + enable_libstdcxx_allocator_flag=new + ;; + *) + enable_libstdcxx_allocator_flag=new + ;; + esac + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libstdcxx_allocator_flag" >&5 +$as_echo "$enable_libstdcxx_allocator_flag" >&6; } + + + # Set configure bits for specified locale package + case ${enable_libstdcxx_allocator_flag} in + bitmap) + ALLOCATOR_H=config/allocator/bitmap_allocator_base.h + ALLOCATOR_NAME=__gnu_cxx::bitmap_allocator + ;; + malloc) + ALLOCATOR_H=config/allocator/malloc_allocator_base.h + ALLOCATOR_NAME=__gnu_cxx::malloc_allocator + ;; + mt) + ALLOCATOR_H=config/allocator/mt_allocator_base.h + ALLOCATOR_NAME=__gnu_cxx::__mt_alloc + ;; + new) + ALLOCATOR_H=config/allocator/new_allocator_base.h + ALLOCATOR_NAME=__gnu_cxx::new_allocator + ;; + pool) + ALLOCATOR_H=config/allocator/pool_allocator_base.h + ALLOCATOR_NAME=__gnu_cxx::__pool_alloc + ;; + esac + + + + + + + # Check whether --enable-cheaders-obsolete was given. +if test "${enable_cheaders_obsolete+set}" = set; then : + enableval=$enable_cheaders_obsolete; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable cheaders-obsolete must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_cheaders_obsolete=no +fi + + + # Check whether --enable-cheaders was given. +if test "${enable_cheaders+set}" = set; then : + enableval=$enable_cheaders; + case "$enableval" in + c|c_global|c_std) ;; + *) as_fn_error $? "Unknown argument to enable/disable cheaders" "$LINENO" 5 ;; + esac + +else + enable_cheaders=$c_model +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: \"C\" header strategy set to $enable_cheaders" >&5 +$as_echo "$as_me: \"C\" header strategy set to $enable_cheaders" >&6;} + if test $enable_cheaders = c_std ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: the --enable-cheaders=c_std configuration is obsolete, c_global should be used instead" >&5 +$as_echo "$as_me: WARNING: the --enable-cheaders=c_std configuration is obsolete, c_global should be used instead" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: if you are unable to use c_global please report a bug or inform libstdc++@gcc.gnu.org" >&5 +$as_echo "$as_me: WARNING: if you are unable to use c_global please report a bug or inform libstdc++@gcc.gnu.org" >&2;} + if test $enable_cheaders_obsolete != yes ; then + as_fn_error $? "use --enable-cheaders-obsolete to use c_std \"C\" headers" "$LINENO" 5 + fi + fi + + C_INCLUDE_DIR='${glibcxx_srcdir}/include/'$enable_cheaders + + # Allow overrides to configure.host here. + if test $enable_cheaders = c_global; then + c_compatibility=yes + fi + + + + + + + + # Check whether --enable-long-long was given. +if test "${enable_long_long+set}" = set; then : + enableval=$enable_long_long; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable long-long must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_long_long=yes +fi + + + if test $enable_long_long = yes; then + +$as_echo "#define _GLIBCXX_USE_LONG_LONG 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for enabled long long specializations" >&5 +$as_echo_n "checking for enabled long long specializations... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_long_long" >&5 +$as_echo "$enable_long_long" >&6; } + + + # Check whether --enable-wchar_t was given. +if test "${enable_wchar_t+set}" = set; then : + enableval=$enable_wchar_t; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable wchar_t must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_wchar_t=yes +fi + + + + # Test wchar.h for mbstate_t, which is needed for char_traits and fpos. + for ac_header in wchar.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" +if test "x$ac_cv_header_wchar_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WCHAR_H 1 +_ACEOF + ac_has_wchar_h=yes +else + ac_has_wchar_h=no +fi + +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mbstate_t" >&5 +$as_echo_n "checking for mbstate_t... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +mbstate_t teststate; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_mbstate_t=yes +else + have_mbstate_t=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_mbstate_t" >&5 +$as_echo "$have_mbstate_t" >&6; } + if test x"$have_mbstate_t" = xyes; then + +$as_echo "#define HAVE_MBSTATE_T 1" >>confdefs.h + + fi + + # Test it always, for use in GLIBCXX_ENABLE_C99, together with + # ac_has_wchar_h. + for ac_header in wctype.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "wctype.h" "ac_cv_header_wctype_h" "$ac_includes_default" +if test "x$ac_cv_header_wctype_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WCTYPE_H 1 +_ACEOF + ac_has_wctype_h=yes +else + ac_has_wctype_h=no +fi + +done + + + if test x"$enable_wchar_t" = x"yes"; then + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + if test x"$ac_has_wchar_h" = xyes && + test x"$ac_has_wctype_h" = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + wint_t i; + long l = WEOF; + long j = WCHAR_MIN; + long k = WCHAR_MAX; + namespace test + { + using ::btowc; + using ::fgetwc; + using ::fgetws; + using ::fputwc; + using ::fputws; + using ::fwide; + using ::fwprintf; + using ::fwscanf; + using ::getwc; + using ::getwchar; + using ::mbrlen; + using ::mbrtowc; + using ::mbsinit; + using ::mbsrtowcs; + using ::putwc; + using ::putwchar; + using ::swprintf; + using ::swscanf; + using ::ungetwc; + using ::vfwprintf; + using ::vswprintf; + using ::vwprintf; + using ::wcrtomb; + using ::wcscat; + using ::wcschr; + using ::wcscmp; + using ::wcscoll; + using ::wcscpy; + using ::wcscspn; + using ::wcsftime; + using ::wcslen; + using ::wcsncat; + using ::wcsncmp; + using ::wcsncpy; + using ::wcspbrk; + using ::wcsrchr; + using ::wcsrtombs; + using ::wcsspn; + using ::wcsstr; + using ::wcstod; + using ::wcstok; + using ::wcstol; + using ::wcstoul; + using ::wcsxfrm; + using ::wctob; + using ::wmemchr; + using ::wmemcmp; + using ::wmemcpy; + using ::wmemmove; + using ::wmemset; + using ::wprintf; + using ::wscanf; + } + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + enable_wchar_t=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + else + enable_wchar_t=no + fi + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + fi + + if test x"$enable_wchar_t" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_WCHAR_T 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for enabled wchar_t specializations" >&5 +$as_echo_n "checking for enabled wchar_t specializations... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_wchar_t" >&5 +$as_echo "$enable_wchar_t" >&6; } + + + + # Check whether --enable-c99 was given. +if test "${enable_c99+set}" = set; then : + enableval=$enable_c99; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable c99 must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_c99=yes +fi + + + + if test x"$enable_c99" = x"yes"; then + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Use -std=c++98 (instead of -std=gnu++98) because leaving __STRICT_ANSI__ + # undefined may cause fake C99 facilities, like pre-standard snprintf, + # to be spuriously enabled. + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=c++98" + ac_save_LIBS="$LIBS" + ac_save_gcc_no_link="$gcc_no_link" + + if test x$gcc_no_link != xyes; then + # Use -fno-exceptions to that the C driver can link these tests without + # hitting undefined references to personality routines. + CXXFLAGS="$CXXFLAGS -fno-exceptions" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + LIBS="$LIBS -lm" +else + + # Use the default compile-only tests in GCC_TRY_COMPILE_OR_LINK + gcc_no_link=yes + +fi + + fi + + # Check for the existence of functions used if C99 is enabled. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++98" >&5 +$as_echo_n "checking for ISO C99 support in for C++98... " >&6; } + if ${glibcxx_cv_c99_math_cxx98+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + volatile double d1, d2; + volatile int i; +int +main () +{ +i = fpclassify(d1); + i = isfinite(d1); + i = isinf(d1); + i = isnan(d1); + i = isnormal(d1); + i = signbit(d1); + i = isgreater(d1, d2); + i = isgreaterequal(d1, d2); + i = isless(d1, d2); + i = islessequal(d1, d2); + i = islessgreater(d1, d2); + i = islessgreater(d1, d2); + i = isunordered(d1, d2); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_math_cxx98=yes +else + glibcxx_cv_c99_math_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + volatile double d1, d2; + volatile int i; +int +main () +{ +i = fpclassify(d1); + i = isfinite(d1); + i = isinf(d1); + i = isnan(d1); + i = isnormal(d1); + i = signbit(d1); + i = isgreater(d1, d2); + i = isgreaterequal(d1, d2); + i = isless(d1, d2); + i = islessequal(d1, d2); + i = islessgreater(d1, d2); + i = islessgreater(d1, d2); + i = isunordered(d1, d2); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_c99_math_cxx98=yes +else + glibcxx_cv_c99_math_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_math_cxx98" >&5 +$as_echo "$glibcxx_cv_c99_math_cxx98" >&6; } + if test x"$glibcxx_cv_c99_math_cxx98" = x"yes"; then + +$as_echo "#define _GLIBCXX98_USE_C99_MATH 1" >>confdefs.h + + fi + + # Check for the existence of complex math functions. + # This is necessary even though libstdc++ uses the builtin versions + # of these functions, because if the builtin cannot be used, a reference + # to the library function is emitted. + for ac_header in tgmath.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "tgmath.h" "ac_cv_header_tgmath_h" "$ac_includes_default" +if test "x$ac_cv_header_tgmath_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_TGMATH_H 1 +_ACEOF + ac_has_tgmath_h=yes +else + ac_has_tgmath_h=no +fi + +done + + for ac_header in complex.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "complex.h" "ac_cv_header_complex_h" "$ac_includes_default" +if test "x$ac_cv_header_complex_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_COMPLEX_H 1 +_ACEOF + ac_has_complex_h=yes +else + ac_has_complex_h=no +fi + +done + + if test x"$ac_has_complex_h" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++98" >&5 +$as_echo_n "checking for ISO C99 support in for C++98... " >&6; } + if ${glibcxx_cv_c99_complex_cxx98+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + typedef __complex__ float float_type; + typedef __complex__ double double_type; + typedef __complex__ long double ld_type; + volatile float_type tmpf; + volatile double_type tmpd; + volatile ld_type tmpld; + volatile float f; + volatile double d; + volatile long double ld; +int +main () +{ +f = cabsf(tmpf); + f = cargf(tmpf); + tmpf = ccosf(tmpf); + tmpf = ccoshf(tmpf); + tmpf = cexpf(tmpf); + tmpf = clogf(tmpf); + tmpf = csinf(tmpf); + tmpf = csinhf(tmpf); + tmpf = csqrtf(tmpf); + tmpf = ctanf(tmpf); + tmpf = ctanhf(tmpf); + tmpf = cpowf(tmpf, tmpf); + tmpf = cprojf(tmpf); + d = cabs(tmpd); + d = carg(tmpd); + tmpd = ccos(tmpd); + tmpd = ccosh(tmpd); + tmpd = cexp(tmpd); + tmpd = clog(tmpd); + tmpd = csin(tmpd); + tmpd = csinh(tmpd); + tmpd = csqrt(tmpd); + tmpd = ctan(tmpd); + tmpd = ctanh(tmpd); + tmpd = cpow(tmpd, tmpd); + tmpd = cproj(tmpd); + ld = cabsl(tmpld); + ld = cargl(tmpld); + tmpld = ccosl(tmpld); + tmpld = ccoshl(tmpld); + tmpld = cexpl(tmpld); + tmpld = clogl(tmpld); + tmpld = csinl(tmpld); + tmpld = csinhl(tmpld); + tmpld = csqrtl(tmpld); + tmpld = ctanl(tmpld); + tmpld = ctanhl(tmpld); + tmpld = cpowl(tmpld, tmpld); + tmpld = cprojl(tmpld); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_complex_cxx98=yes +else + glibcxx_cv_c99_complex_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + typedef __complex__ float float_type; + typedef __complex__ double double_type; + typedef __complex__ long double ld_type; + volatile float_type tmpf; + volatile double_type tmpd; + volatile ld_type tmpld; + volatile float f; + volatile double d; + volatile long double ld; +int +main () +{ +f = cabsf(tmpf); + f = cargf(tmpf); + tmpf = ccosf(tmpf); + tmpf = ccoshf(tmpf); + tmpf = cexpf(tmpf); + tmpf = clogf(tmpf); + tmpf = csinf(tmpf); + tmpf = csinhf(tmpf); + tmpf = csqrtf(tmpf); + tmpf = ctanf(tmpf); + tmpf = ctanhf(tmpf); + tmpf = cpowf(tmpf, tmpf); + tmpf = cprojf(tmpf); + d = cabs(tmpd); + d = carg(tmpd); + tmpd = ccos(tmpd); + tmpd = ccosh(tmpd); + tmpd = cexp(tmpd); + tmpd = clog(tmpd); + tmpd = csin(tmpd); + tmpd = csinh(tmpd); + tmpd = csqrt(tmpd); + tmpd = ctan(tmpd); + tmpd = ctanh(tmpd); + tmpd = cpow(tmpd, tmpd); + tmpd = cproj(tmpd); + ld = cabsl(tmpld); + ld = cargl(tmpld); + tmpld = ccosl(tmpld); + tmpld = ccoshl(tmpld); + tmpld = cexpl(tmpld); + tmpld = clogl(tmpld); + tmpld = csinl(tmpld); + tmpld = csinhl(tmpld); + tmpld = csqrtl(tmpld); + tmpld = ctanl(tmpld); + tmpld = ctanhl(tmpld); + tmpld = cpowl(tmpld, tmpld); + tmpld = cprojl(tmpld); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_c99_complex_cxx98=yes +else + glibcxx_cv_c99_complex_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_complex_cxx98" >&5 +$as_echo "$glibcxx_cv_c99_complex_cxx98" >&6; } + if test x"$glibcxx_cv_c99_complex_cxx98" = x"yes"; then + +$as_echo "#define _GLIBCXX98_USE_C99_COMPLEX 1" >>confdefs.h + + fi + + # Check for the existence in of vscanf, et. al. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++98" >&5 +$as_echo_n "checking for ISO C99 support in for C++98... " >&6; } + if ${glibcxx_cv_c99_stdio_cxx98+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + void foo(char* fmt, ...) + { + va_list args; va_start(args, fmt); + vfscanf(stderr, "%i", args); + vscanf("%i", args); + vsnprintf(fmt, 0, "%i", args); + vsscanf(fmt, "%i", args); + snprintf(fmt, 0, "%i"); + } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_stdio_cxx98=yes +else + glibcxx_cv_c99_stdio_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + void foo(char* fmt, ...) + { + va_list args; va_start(args, fmt); + vfscanf(stderr, "%i", args); + vscanf("%i", args); + vsnprintf(fmt, 0, "%i", args); + vsscanf(fmt, "%i", args); + snprintf(fmt, 0, "%i"); + } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_c99_stdio_cxx98=yes +else + glibcxx_cv_c99_stdio_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_stdio_cxx98" >&5 +$as_echo "$glibcxx_cv_c99_stdio_cxx98" >&6; } + if test x"$glibcxx_cv_c99_stdio_cxx98" = x"yes"; then + +$as_echo "#define _GLIBCXX98_USE_C99_STDIO 1" >>confdefs.h + + fi + + # Check for the existence in of lldiv_t, et. al. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++98" >&5 +$as_echo_n "checking for ISO C99 support in for C++98... " >&6; } + if ${glibcxx_cv_c99_stdlib_cxx98+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + volatile float f; + volatile long double ld; + volatile unsigned long long ll; + lldiv_t mydivt; +int +main () +{ +char* tmp; + f = strtof("gnu", &tmp); + ld = strtold("gnu", &tmp); + ll = strtoll("gnu", &tmp, 10); + ll = strtoull("gnu", &tmp, 10); + ll = llabs(10); + mydivt = lldiv(10,1); + ll = mydivt.quot; + ll = mydivt.rem; + ll = atoll("10"); + _Exit(0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_stdlib_cxx98=yes +else + glibcxx_cv_c99_stdlib_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + volatile float f; + volatile long double ld; + volatile unsigned long long ll; + lldiv_t mydivt; +int +main () +{ +char* tmp; + f = strtof("gnu", &tmp); + ld = strtold("gnu", &tmp); + ll = strtoll("gnu", &tmp, 10); + ll = strtoull("gnu", &tmp, 10); + ll = llabs(10); + mydivt = lldiv(10,1); + ll = mydivt.quot; + ll = mydivt.rem; + ll = atoll("10"); + _Exit(0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_c99_stdlib_cxx98=yes +else + glibcxx_cv_c99_stdlib_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_stdlib_cxx98" >&5 +$as_echo "$glibcxx_cv_c99_stdlib_cxx98" >&6; } + if test x"$glibcxx_cv_c99_stdlib_cxx98" = x"yes"; then + +$as_echo "#define _GLIBCXX98_USE_C99_STDLIB 1" >>confdefs.h + + fi + + # Check for the existence in of wcstold, etc. + if test x"$ac_has_wchar_h" = xyes && + test x"$ac_has_wctype_h" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++98" >&5 +$as_echo_n "checking for ISO C99 support in for C++98... " >&6; } + if ${glibcxx_cv_c99_wchar_cxx98+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test + { + using ::wcstold; + using ::wcstoll; + using ::wcstoull; + } + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_wchar_cxx98=yes +else + glibcxx_cv_c99_wchar_cxx98=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + + # Checks for wide character functions that may not be present. + # Injection of these is wrapped with guard macros. + # NB: only put functions here, instead of immediately above, if + # absolutely necessary. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test { using ::vfwscanf; } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_VFWSCANF 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test { using ::vswscanf; } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_VSWSCANF 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test { using ::vwscanf; } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_VWSCANF 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test { using ::wcstof; } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_WCSTOF 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +wint_t t; int i = iswblank(t); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_ISWBLANK 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_wchar_cxx98" >&5 +$as_echo "$glibcxx_cv_c99_wchar_cxx98" >&6; } + if test x"$glibcxx_cv_c99_wchar_cxx98" = x"yes"; then + +$as_echo "#define _GLIBCXX98_USE_C99_WCHAR 1" >>confdefs.h + + fi + fi + + # Option parsed, now set things appropriately. + if test x"$glibcxx_cv_c99_math_cxx98" = x"no" || + test x"$glibcxx_cv_c99_complex_cxx98" = x"no" || + test x"$glibcxx_cv_c99_stdio_cxx98" = x"no" || + test x"$glibcxx_cv_c99_stdlib_cxx98" = x"no" || + test x"$glibcxx_cv_c99_wchar_cxx98" = x"no"; then + enable_c99=no; + else + +$as_echo "#define _GLIBCXX_USE_C99 1" >>confdefs.h + + fi + + gcc_no_link="$ac_save_gcc_no_link" + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Use -std=c++11 and test again for C99 library feature in C++11 mode. + # For the reasons given above we use -std=c++11 not -std=gnu++11. + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=c++11" + ac_save_LIBS="$LIBS" + ac_save_gcc_no_link="$gcc_no_link" + + if test x$gcc_no_link != xyes; then + # Use -fno-exceptions to that the C driver can link these tests without + # hitting undefined references to personality routines. + CXXFLAGS="$CXXFLAGS -fno-exceptions" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + LIBS="$LIBS -lm" +else + + # Use the default compile-only tests in GCC_TRY_COMPILE_OR_LINK + gcc_no_link=yes + +fi + + fi + + # Check for the existence of functions used if C99 is enabled. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++11" >&5 +$as_echo_n "checking for ISO C99 support in for C++11... " >&6; } + if ${glibcxx_cv_c99_math_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + volatile double d1, d2; + volatile int i; +int +main () +{ +i = fpclassify(d1); + i = isfinite(d1); + i = isinf(d1); + i = isnan(d1); + i = isnormal(d1); + i = signbit(d1); + i = isgreater(d1, d2); + i = isgreaterequal(d1, d2); + i = isless(d1, d2); + i = islessequal(d1, d2); + i = islessgreater(d1, d2); + i = islessgreater(d1, d2); + i = isunordered(d1, d2); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_math_cxx11=yes +else + glibcxx_cv_c99_math_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + volatile double d1, d2; + volatile int i; +int +main () +{ +i = fpclassify(d1); + i = isfinite(d1); + i = isinf(d1); + i = isnan(d1); + i = isnormal(d1); + i = signbit(d1); + i = isgreater(d1, d2); + i = isgreaterequal(d1, d2); + i = isless(d1, d2); + i = islessequal(d1, d2); + i = islessgreater(d1, d2); + i = islessgreater(d1, d2); + i = isunordered(d1, d2); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_c99_math_cxx11=yes +else + glibcxx_cv_c99_math_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_math_cxx11" >&5 +$as_echo "$glibcxx_cv_c99_math_cxx11" >&6; } + if test x"$glibcxx_cv_c99_math_cxx11" = x"yes"; then + +$as_echo "#define _GLIBCXX11_USE_C99_MATH 1" >>confdefs.h + + fi + + # Check for the existence of complex math functions. + # This is necessary even though libstdc++ uses the builtin versions + # of these functions, because if the builtin cannot be used, a reference + # to the library function is emitted. + for ac_header in tgmath.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "tgmath.h" "ac_cv_header_tgmath_h" "$ac_includes_default" +if test "x$ac_cv_header_tgmath_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_TGMATH_H 1 +_ACEOF + ac_has_tgmath_h=yes +else + ac_has_tgmath_h=no +fi + +done + + for ac_header in complex.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "complex.h" "ac_cv_header_complex_h" "$ac_includes_default" +if test "x$ac_cv_header_complex_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_COMPLEX_H 1 +_ACEOF + ac_has_complex_h=yes +else + ac_has_complex_h=no +fi + +done + + if test x"$ac_has_complex_h" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++11" >&5 +$as_echo_n "checking for ISO C99 support in for C++11... " >&6; } + if ${glibcxx_cv_c99_complex_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + typedef __complex__ float float_type; + typedef __complex__ double double_type; + typedef __complex__ long double ld_type; + volatile float_type tmpf; + volatile double_type tmpd; + volatile ld_type tmpld; + volatile float f; + volatile double d; + volatile long double ld; +int +main () +{ +f = cabsf(tmpf); + f = cargf(tmpf); + tmpf = ccosf(tmpf); + tmpf = ccoshf(tmpf); + tmpf = cexpf(tmpf); + tmpf = clogf(tmpf); + tmpf = csinf(tmpf); + tmpf = csinhf(tmpf); + tmpf = csqrtf(tmpf); + tmpf = ctanf(tmpf); + tmpf = ctanhf(tmpf); + tmpf = cpowf(tmpf, tmpf); + tmpf = cprojf(tmpf); + d = cabs(tmpd); + d = carg(tmpd); + tmpd = ccos(tmpd); + tmpd = ccosh(tmpd); + tmpd = cexp(tmpd); + tmpd = clog(tmpd); + tmpd = csin(tmpd); + tmpd = csinh(tmpd); + tmpd = csqrt(tmpd); + tmpd = ctan(tmpd); + tmpd = ctanh(tmpd); + tmpd = cpow(tmpd, tmpd); + tmpd = cproj(tmpd); + ld = cabsl(tmpld); + ld = cargl(tmpld); + tmpld = ccosl(tmpld); + tmpld = ccoshl(tmpld); + tmpld = cexpl(tmpld); + tmpld = clogl(tmpld); + tmpld = csinl(tmpld); + tmpld = csinhl(tmpld); + tmpld = csqrtl(tmpld); + tmpld = ctanl(tmpld); + tmpld = ctanhl(tmpld); + tmpld = cpowl(tmpld, tmpld); + tmpld = cprojl(tmpld); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_complex_cxx11=yes +else + glibcxx_cv_c99_complex_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + typedef __complex__ float float_type; + typedef __complex__ double double_type; + typedef __complex__ long double ld_type; + volatile float_type tmpf; + volatile double_type tmpd; + volatile ld_type tmpld; + volatile float f; + volatile double d; + volatile long double ld; +int +main () +{ +f = cabsf(tmpf); + f = cargf(tmpf); + tmpf = ccosf(tmpf); + tmpf = ccoshf(tmpf); + tmpf = cexpf(tmpf); + tmpf = clogf(tmpf); + tmpf = csinf(tmpf); + tmpf = csinhf(tmpf); + tmpf = csqrtf(tmpf); + tmpf = ctanf(tmpf); + tmpf = ctanhf(tmpf); + tmpf = cpowf(tmpf, tmpf); + tmpf = cprojf(tmpf); + d = cabs(tmpd); + d = carg(tmpd); + tmpd = ccos(tmpd); + tmpd = ccosh(tmpd); + tmpd = cexp(tmpd); + tmpd = clog(tmpd); + tmpd = csin(tmpd); + tmpd = csinh(tmpd); + tmpd = csqrt(tmpd); + tmpd = ctan(tmpd); + tmpd = ctanh(tmpd); + tmpd = cpow(tmpd, tmpd); + tmpd = cproj(tmpd); + ld = cabsl(tmpld); + ld = cargl(tmpld); + tmpld = ccosl(tmpld); + tmpld = ccoshl(tmpld); + tmpld = cexpl(tmpld); + tmpld = clogl(tmpld); + tmpld = csinl(tmpld); + tmpld = csinhl(tmpld); + tmpld = csqrtl(tmpld); + tmpld = ctanl(tmpld); + tmpld = ctanhl(tmpld); + tmpld = cpowl(tmpld, tmpld); + tmpld = cprojl(tmpld); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_c99_complex_cxx11=yes +else + glibcxx_cv_c99_complex_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_complex_cxx11" >&5 +$as_echo "$glibcxx_cv_c99_complex_cxx11" >&6; } + if test x"$glibcxx_cv_c99_complex_cxx11" = x"yes"; then + +$as_echo "#define _GLIBCXX11_USE_C99_COMPLEX 1" >>confdefs.h + + fi + + # Check for the existence in of vscanf, et. al. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++11" >&5 +$as_echo_n "checking for ISO C99 support in for C++11... " >&6; } + if ${glibcxx_cv_c99_stdio_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + void foo(char* fmt, ...) + { + va_list args; va_start(args, fmt); + vfscanf(stderr, "%i", args); + vscanf("%i", args); + vsnprintf(fmt, 0, "%i", args); + vsscanf(fmt, "%i", args); + snprintf(fmt, 0, "%i"); + } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_stdio_cxx11=yes +else + glibcxx_cv_c99_stdio_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + void foo(char* fmt, ...) + { + va_list args; va_start(args, fmt); + vfscanf(stderr, "%i", args); + vscanf("%i", args); + vsnprintf(fmt, 0, "%i", args); + vsscanf(fmt, "%i", args); + snprintf(fmt, 0, "%i"); + } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_c99_stdio_cxx11=yes +else + glibcxx_cv_c99_stdio_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_stdio_cxx11" >&5 +$as_echo "$glibcxx_cv_c99_stdio_cxx11" >&6; } + if test x"$glibcxx_cv_c99_stdio_cxx11" = x"yes"; then + +$as_echo "#define _GLIBCXX11_USE_C99_STDIO 1" >>confdefs.h + + fi + + # Check for the existence in of lldiv_t, et. al. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++11" >&5 +$as_echo_n "checking for ISO C99 support in for C++11... " >&6; } + if ${glibcxx_cv_c99_stdlib_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + volatile float f; + volatile long double ld; + volatile unsigned long long ll; + lldiv_t mydivt; +int +main () +{ +char* tmp; + f = strtof("gnu", &tmp); + ld = strtold("gnu", &tmp); + ll = strtoll("gnu", &tmp, 10); + ll = strtoull("gnu", &tmp, 10); + ll = llabs(10); + mydivt = lldiv(10,1); + ll = mydivt.quot; + ll = mydivt.rem; + ll = atoll("10"); + _Exit(0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_stdlib_cxx11=yes +else + glibcxx_cv_c99_stdlib_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + volatile float f; + volatile long double ld; + volatile unsigned long long ll; + lldiv_t mydivt; +int +main () +{ +char* tmp; + f = strtof("gnu", &tmp); + ld = strtold("gnu", &tmp); + ll = strtoll("gnu", &tmp, 10); + ll = strtoull("gnu", &tmp, 10); + ll = llabs(10); + mydivt = lldiv(10,1); + ll = mydivt.quot; + ll = mydivt.rem; + ll = atoll("10"); + _Exit(0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_c99_stdlib_cxx11=yes +else + glibcxx_cv_c99_stdlib_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_stdlib_cxx11" >&5 +$as_echo "$glibcxx_cv_c99_stdlib_cxx11" >&6; } + if test x"$glibcxx_cv_c99_stdlib_cxx11" = x"yes"; then + +$as_echo "#define _GLIBCXX11_USE_C99_STDLIB 1" >>confdefs.h + + fi + + # Check for the existence in of wcstold, etc. + if test x"$ac_has_wchar_h" = xyes && + test x"$ac_has_wctype_h" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support in for C++11" >&5 +$as_echo_n "checking for ISO C99 support in for C++11... " >&6; } + if ${glibcxx_cv_c99_wchar_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test + { + using ::wcstold; + using ::wcstoll; + using ::wcstoull; + } + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_wchar_cxx11=yes +else + glibcxx_cv_c99_wchar_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + + # Checks for wide character functions that may not be present. + # Injection of these is wrapped with guard macros. + # NB: only put functions here, instead of immediately above, if + # absolutely necessary. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test { using ::vfwscanf; } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_VFWSCANF 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test { using ::vswscanf; } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_VSWSCANF 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test { using ::vwscanf; } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_VWSCANF 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test { using ::wcstof; } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_WCSTOF 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +wint_t t; int i = iswblank(t); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_ISWBLANK 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_wchar_cxx11" >&5 +$as_echo "$glibcxx_cv_c99_wchar_cxx11" >&6; } + if test x"$glibcxx_cv_c99_wchar_cxx11" = x"yes"; then + +$as_echo "#define _GLIBCXX11_USE_C99_WCHAR 1" >>confdefs.h + + fi + fi + + gcc_no_link="$ac_save_gcc_no_link" + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fully enabled ISO C99 support" >&5 +$as_echo_n "checking for fully enabled ISO C99 support... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_c99" >&5 +$as_echo "$enable_c99" >&6; } + + + # Check whether --enable-concept-checks was given. +if test "${enable_concept_checks+set}" = set; then : + enableval=$enable_concept_checks; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable concept-checks must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_concept_checks=no +fi + + + if test $enable_concept_checks = yes; then + +$as_echo "#define _GLIBCXX_CONCEPT_CHECKS 1" >>confdefs.h + + fi + + + # Check whether --enable-libstdcxx-debug-flags was given. +if test "${enable_libstdcxx_debug_flags+set}" = set; then : + enableval=$enable_libstdcxx_debug_flags; case "x$enable_libstdcxx_debug_flags" in + xno | x) enable_libstdcxx_debug_flags= ;; + x-*) ;; + *) as_fn_error $? "--enable-libstdcxx-debug-flags needs compiler flags as arguments" "$LINENO" 5 ;; + esac +else + enable_libstdcxx_debug_flags="-gdwarf-4 -g3 -O0 -D_GLIBCXX_ASSERTIONS" +fi + + + + # Option parsed, now set things appropriately + DEBUG_FLAGS="$enable_libstdcxx_debug_flags" + + + { $as_echo "$as_me:${as_lineno-$LINENO}: Debug build flags set to $DEBUG_FLAGS" >&5 +$as_echo "$as_me: Debug build flags set to $DEBUG_FLAGS" >&6;} + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for additional debug build" >&5 +$as_echo_n "checking for additional debug build... " >&6; } + skip_debug_build= + # Check whether --enable-libstdcxx-debug was given. +if test "${enable_libstdcxx_debug+set}" = set; then : + enableval=$enable_libstdcxx_debug; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable libstdcxx-debug must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_libstdcxx_debug=no +fi + + + if test x$enable_libstdcxx_debug = xyes; then + if test -f $toplevel_builddir/../stage_final \ + && test -f $toplevel_builddir/../stage_current; then + stage_final=`cat $toplevel_builddir/../stage_final` + stage_current=`cat $toplevel_builddir/../stage_current` + if test x$stage_current != x$stage_final ; then + skip_debug_build=" (skipped for bootstrap stage $stage_current)" + enable_libstdcxx_debug=no + fi + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libstdcxx_debug$skip_debug_build" >&5 +$as_echo "$enable_libstdcxx_debug$skip_debug_build" >&6; } + + + + + enable_parallel=no; + + # See if configured libgomp/omp.h exists. (libgomp may be in + # noconfigdirs but not explicitly disabled.) + if echo " ${TARGET_CONFIGDIRS} " | grep " libgomp " > /dev/null 2>&1 ; then + enable_parallel=yes; + else + { $as_echo "$as_me:${as_lineno-$LINENO}: target-libgomp not built" >&5 +$as_echo "$as_me: target-libgomp not built" >&6;} + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for parallel mode support" >&5 +$as_echo_n "checking for parallel mode support... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_parallel" >&5 +$as_echo "$enable_parallel" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra compiler flags for building" >&5 +$as_echo_n "checking for extra compiler flags for building... " >&6; } + # Check whether --enable-cxx-flags was given. +if test "${enable_cxx_flags+set}" = set; then : + enableval=$enable_cxx_flags; case "x$enable_cxx_flags" in + xno | x) enable_cxx_flags= ;; + x-*) ;; + *) as_fn_error $? "--enable-cxx-flags needs compiler flags as arguments" "$LINENO" 5 ;; + esac +else + enable_cxx_flags= +fi + + + + # Run through flags (either default or command-line) and set anything + # extra (e.g., #defines) that must accompany particular g++ options. + if test -n "$enable_cxx_flags"; then + for f in $enable_cxx_flags; do + case "$f" in + -fhonor-std) ;; + -*) ;; + *) # and we're trying to pass /what/ exactly? + as_fn_error $? "compiler flags start with a -" "$LINENO" 5 ;; + esac + done + fi + + EXTRA_CXX_FLAGS="$enable_cxx_flags" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXTRA_CXX_FLAGS" >&5 +$as_echo "$EXTRA_CXX_FLAGS" >&6; } + + + + # Check whether --enable-fully-dynamic-string was given. +if test "${enable_fully_dynamic_string+set}" = set; then : + enableval=$enable_fully_dynamic_string; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable fully-dynamic-string must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_fully_dynamic_string=no +fi + + + if test $enable_fully_dynamic_string = yes; then + enable_fully_dynamic_string_def=1 + else + enable_fully_dynamic_string_def=0 + fi + +cat >>confdefs.h <<_ACEOF +#define _GLIBCXX_FULLY_DYNAMIC_STRING ${enable_fully_dynamic_string_def} +_ACEOF + + + + + # Check whether --enable-extern-template was given. +if test "${enable_extern_template+set}" = set; then : + enableval=$enable_extern_template; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable extern-template must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_extern_template=yes +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extern template support" >&5 +$as_echo_n "checking for extern template support... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_extern_template" >&5 +$as_echo "$enable_extern_template" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for custom python install directory" >&5 +$as_echo_n "checking for custom python install directory... " >&6; } + +# Check whether --with-python-dir was given. +if test "${with_python_dir+set}" = set; then : + withval=$with_python_dir; with_python_dir=$withval +else + with_python_dir="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_python_dir}" >&5 +$as_echo "${with_python_dir}" >&6; } + +# Needed for installing Python modules during make install. +python_mod_dir="${with_python_dir}" + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Werror" >&5 +$as_echo_n "checking for -Werror... " >&6; } + # Check whether --enable-werror was given. +if test "${enable_werror+set}" = set; then : + enableval=$enable_werror; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable werror must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_werror=no +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_werror" >&5 +$as_echo "$enable_werror" >&6; } + + + + + # Check whether --enable-vtable-verify was given. +if test "${enable_vtable_verify+set}" = set; then : + enableval=$enable_vtable_verify; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable vtable-verify must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_vtable_verify=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vtable verify support" >&5 +$as_echo_n "checking for vtable verify support... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_vtable_verify" >&5 +$as_echo "$enable_vtable_verify" >&6; } + + vtv_cygmin=no + if test $enable_vtable_verify = yes; then + case ${target_os} in + cygwin*|mingw32*) + VTV_CXXFLAGS="-fvtable-verify=std -Wl,-lvtv,-u_vtable_map_vars_start,-u_vtable_map_vars_end" + VTV_CXXLINKFLAGS="-L${toplevel_builddir}/libvtv/.libs -Wl,--rpath -Wl,${toplevel_builddir}/libvtv/.libs" + vtv_cygmin=yes + ;; + darwin*) + VTV_CXXFLAGS="-fvtable-verify=std -Wl,-u,_vtable_map_vars_start -Wl,-u,_vtable_map_vars_end" + VTV_CXXLINKFLAGS="-L${toplevel_builddir}/libvtv/.libs -Wl,-rpath,${toplevel_builddir}/libvtv/.libs" + ;; + solaris2*) + VTV_CXXFLAGS="-fvtable-verify=std -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end" + VTV_CXXLINKFLAGS="-L${toplevel_builddir}/libvtv/.libs -Wl,-R -Wl,${toplevel_builddir}/libvtv/.libs" + ;; + *) + VTV_CXXFLAGS="-fvtable-verify=std -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end" + VTV_CXXLINKFLAGS="-L${toplevel_builddir}/libvtv/.libs -Wl,--rpath -Wl,${toplevel_builddir}/libvtv/.libs" + ;; + esac + VTV_PCH_CXXFLAGS="-fvtable-verify=std" + else + VTV_CXXFLAGS= + VTV_PCH_CXXFLAGS= + VTV_CXXLINKFLAGS= + fi + + + + + if test x$vtv_cygmin = xyes; then + VTV_CYGMIN_TRUE= + VTV_CYGMIN_FALSE='#' +else + VTV_CYGMIN_TRUE='#' + VTV_CYGMIN_FALSE= +fi + + + + +# Checks for operating systems support that doesn't require linking. + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + # Use C++11 because a conforming won't define gets for C++14, + # and we don't need a declaration for C++14 anyway. + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=gnu++11" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gets declaration" >&5 +$as_echo_n "checking for gets declaration... " >&6; } + if ${glibcxx_cv_gets+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace test + { + using ::gets; + } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_gets=yes +else + glibcxx_cv_gets=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + + if test $glibcxx_cv_gets = yes; then + +$as_echo "#define HAVE_GETS 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_gets" >&5 +$as_echo "$glibcxx_cv_gets" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=c++11" + + case "$host" in + *-*-solaris2.*) + # Solaris 12 Build 86, Solaris 11.3 SRU 3.6, and Solaris 10 Patch + # 11996[67]-02 introduced the C++11 floating point overloads. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++11 floating point overloads" >&5 +$as_echo_n "checking for C++11 floating point overloads... " >&6; } + if ${glibcxx_cv_math11_fp_overload+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #undef isfinite + namespace std { + inline bool isfinite(float __x) + { return __builtin_isfinite(__x); } + } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_math11_fp_overload=no +else + glibcxx_cv_math11_fp_overload=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + + # autoheader cannot handle indented templates. + + + if test $glibcxx_cv_math11_fp_overload = yes; then + $as_echo "#define __CORRECT_ISO_CPP11_MATH_H_PROTO_FP 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_math11_fp_overload" >&5 +$as_echo "$glibcxx_cv_math11_fp_overload" >&6; } + + # Solaris 12 Build 90, Solaris 11.3 SRU 5.6, and Solaris 10 Patch + # 11996[67]-02 introduced the C++11 integral type overloads. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++11 integral type overloads" >&5 +$as_echo_n "checking for C++11 integral type overloads... " >&6; } + if ${glibcxx_cv_math11_int_overload+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + namespace std { + template + struct __is_integer; + template<> + struct __is_integer + { + enum { __value = 1 }; + }; + } + namespace __gnu_cxx { + template + struct __enable_if; + template + struct __enable_if + { typedef _Tp __type; }; + } + namespace std { + template + constexpr typename __gnu_cxx::__enable_if + <__is_integer<_Tp>::__value, double>::__type + log2(_Tp __x) + { return __builtin_log2(__x); } + } + int + main (void) + { + int i = 1000; + return std::log2(i); + } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_math11_int_overload=no +else + glibcxx_cv_math11_int_overload=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + + # autoheader cannot handle indented templates. + + + if test $glibcxx_cv_math11_int_overload = yes; then + $as_echo "#define __CORRECT_ISO_CPP11_MATH_H_PROTO_INT 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_math11_int_overload" >&5 +$as_echo "$glibcxx_cv_math11_int_overload" >&6; } + ;; + *) + # If defines the obsolete isinf(double) and isnan(double) + # functions (instead of or as well as the C99 generic macros) then we + # can't define std::isinf(double) and std::isnan(double) in + # and must use the ones from instead. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for obsolete isinf function in " >&5 +$as_echo_n "checking for obsolete isinf function in ... " >&6; } + if ${glibcxx_cv_obsolete_isinf+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS + #include + #undef isinf + namespace std { + using ::isinf; + bool isinf(float); + bool isinf(long double); + } + using std::isinf; + bool b = isinf(0.0); + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_obsolete_isinf=yes +else + glibcxx_cv_obsolete_isinf=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_obsolete_isinf" >&5 +$as_echo "$glibcxx_cv_obsolete_isinf" >&6; } + if test $glibcxx_cv_obsolete_isinf = yes; then + +$as_echo "#define HAVE_OBSOLETE_ISINF 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for obsolete isnan function in " >&5 +$as_echo_n "checking for obsolete isnan function in ... " >&6; } + if ${glibcxx_cv_obsolete_isnan+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS + #include + #undef isnan + namespace std { + using ::isnan; + bool isnan(float); + bool isnan(long double); + } + using std::isnan; + bool b = isnan(0.0); + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_obsolete_isnan=yes +else + glibcxx_cv_obsolete_isnan=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_obsolete_isnan" >&5 +$as_echo "$glibcxx_cv_obsolete_isnan" >&6; } + if test $glibcxx_cv_obsolete_isnan = yes; then + +$as_echo "#define HAVE_OBSOLETE_ISNAN 1" >>confdefs.h + + fi + ;; + esac + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + # Test uchar.h. + for ac_header in uchar.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "uchar.h" "ac_cv_header_uchar_h" "$ac_includes_default" +if test "x$ac_cv_header_uchar_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_UCHAR_H 1 +_ACEOF + ac_has_uchar_h=yes +else + ac_has_uchar_h=no +fi + +done + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=c++11" + + if test x"$ac_has_uchar_h" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C11 support for " >&5 +$as_echo_n "checking for ISO C11 support for ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef __STDC_UTF_16__ + long i = __STDC_UTF_16__; + #endif + #ifdef __STDC_UTF_32__ + long j = __STDC_UTF_32__; + #endif + namespace test + { + using ::c16rtomb; + using ::c32rtomb; + using ::mbrtoc16; + using ::mbrtoc32; + } + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_c11_uchar_cxx11=yes +else + ac_c11_uchar_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + else + ac_c11_uchar_cxx11=no + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_c11_uchar_cxx11" >&5 +$as_echo "$ac_c11_uchar_cxx11" >&6; } + if test x"$ac_c11_uchar_cxx11" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_C11_UCHAR_CXX11 1" >>confdefs.h + + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For the streamoff typedef. + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int64_t" >&5 +$as_echo_n "checking for int64_t... " >&6; } + if ${glibcxx_cv_INT64_T+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int64_t var; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_INT64_T=yes +else + glibcxx_cv_INT64_T=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + + if test $glibcxx_cv_INT64_T = yes; then + +$as_echo "#define HAVE_INT64_T 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_INT64_T" >&5 +$as_echo "$glibcxx_cv_INT64_T" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int64_t as long" >&5 +$as_echo_n "checking for int64_t as long... " >&6; } + if ${glibcxx_cv_int64_t_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + template struct same { enum { value = -1 }; }; + template struct same { enum { value = 1 }; }; + int array[same::value]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_int64_t_long=yes +else + glibcxx_cv_int64_t_long=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + + if test $glibcxx_cv_int64_t_long = yes; then + +$as_echo "#define HAVE_INT64_T_LONG 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_int64_t_long" >&5 +$as_echo "$glibcxx_cv_int64_t_long" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int64_t as long long" >&5 +$as_echo_n "checking for int64_t as long long... " >&6; } + if ${glibcxx_cv_int64_t_long_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + template struct same { enum { value = -1 }; }; + template struct same { enum { value = 1 }; }; + int array[same::value]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_int64_t_long_long=yes +else + glibcxx_cv_int64_t_long_long=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + + if test $glibcxx_cv_int64_t_long_long = yes; then + +$as_echo "#define HAVE_INT64_T_LONG_LONG 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_int64_t_long_long" >&5 +$as_echo "$glibcxx_cv_int64_t_long_long" >&6; } + fi + fi + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For LFS support. + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LFS support" >&5 +$as_echo_n "checking for LFS support... " >&6; } + if ${glibcxx_cv_LFS+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ +FILE* fp; + fopen64("t", "w"); + fseeko64(fp, 0, SEEK_CUR); + ftello64(fp); + lseek64(1, 0, SEEK_CUR); + struct stat64 buf; + fstat64(1, &buf); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_LFS=yes +else + glibcxx_cv_LFS=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ +FILE* fp; + fopen64("t", "w"); + fseeko64(fp, 0, SEEK_CUR); + ftello64(fp); + lseek64(1, 0, SEEK_CUR); + struct stat64 buf; + fstat64(1, &buf); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_LFS=yes +else + glibcxx_cv_LFS=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_LFS = yes; then + +$as_echo "#define _GLIBCXX_USE_LFS 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_LFS" >&5 +$as_echo "$glibcxx_cv_LFS" >&6; } + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For showmanyc_helper(). +for ac_header in sys/ioctl.h sys/filio.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for poll" >&5 +$as_echo_n "checking for poll... " >&6; } + if ${glibcxx_cv_POLL+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct pollfd pfd[1]; + pfd[0].events = POLLIN; + poll(pfd, 1, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_POLL=yes +else + glibcxx_cv_POLL=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct pollfd pfd[1]; + pfd[0].events = POLLIN; + poll(pfd, 1, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_POLL=yes +else + glibcxx_cv_POLL=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_POLL = yes; then + +$as_echo "#define HAVE_POLL 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_POLL" >&5 +$as_echo "$glibcxx_cv_POLL" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for S_ISREG or S_IFREG" >&5 +$as_echo_n "checking for S_ISREG or S_IFREG... " >&6; } + if ${glibcxx_cv_S_ISREG+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct stat buffer; + fstat(0, &buffer); + S_ISREG(buffer.st_mode); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_S_ISREG=yes +else + glibcxx_cv_S_ISREG=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct stat buffer; + fstat(0, &buffer); + S_ISREG(buffer.st_mode); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_S_ISREG=yes +else + glibcxx_cv_S_ISREG=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if ${glibcxx_cv_S_IFREG+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct stat buffer; + fstat(0, &buffer); + S_IFREG & buffer.st_mode; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_S_IFREG=yes +else + glibcxx_cv_S_IFREG=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct stat buffer; + fstat(0, &buffer); + S_IFREG & buffer.st_mode; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_S_IFREG=yes +else + glibcxx_cv_S_IFREG=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + res=no + if test $glibcxx_cv_S_ISREG = yes; then + +$as_echo "#define HAVE_S_ISREG 1" >>confdefs.h + + res=S_ISREG + elif test $glibcxx_cv_S_IFREG = yes; then + +$as_echo "#define HAVE_S_IFREG 1" >>confdefs.h + + res=S_IFREG + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $res" >&5 +$as_echo "$res" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For xsputn_2(). +for ac_header in sys/uio.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/uio.h" "ac_cv_header_sys_uio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_uio_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_UIO_H 1 +_ACEOF + +fi + +done + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for writev" >&5 +$as_echo_n "checking for writev... " >&6; } + if ${glibcxx_cv_WRITEV+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct iovec iov[2]; + writev(0, iov, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_WRITEV=yes +else + glibcxx_cv_WRITEV=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +struct iovec iov[2]; + writev(0, iov, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_WRITEV=yes +else + glibcxx_cv_WRITEV=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_WRITEV = yes; then + +$as_echo "#define HAVE_WRITEV 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_WRITEV" >&5 +$as_echo "$glibcxx_cv_WRITEV" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# Check for fenv.h and complex.h before GLIBCXX_CHECK_C99_TR1 +# so that the check is done with the C compiler (not C++). +# Checking with C++ can break a canadian cross build if either +# file does not exist in C but does in C++. +for ac_header in fenv.h complex.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# For C99 support to TR1. + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + # Use -std=c++98 because the default (-std=gnu++98) leaves __STRICT_ANSI__ + # undefined and fake C99 facilities may be spuriously enabled. + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=c++98" + + # Check for the existence of complex math functions used + # by tr1/complex. + for ac_header in complex.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "complex.h" "ac_cv_header_complex_h" "$ac_includes_default" +if test "x$ac_cv_header_complex_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_COMPLEX_H 1 +_ACEOF + ac_has_complex_h=yes +else + ac_has_complex_h=no +fi + +done + + ac_c99_complex_tr1=no; + if test x"$ac_has_complex_h" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support to TR1 in " >&5 +$as_echo_n "checking for ISO C99 support to TR1 in ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +typedef __complex__ float float_type; float_type tmpf; + cacosf(tmpf); + casinf(tmpf); + catanf(tmpf); + cacoshf(tmpf); + casinhf(tmpf); + catanhf(tmpf); + typedef __complex__ double double_type; double_type tmpd; + cacos(tmpd); + casin(tmpd); + catan(tmpd); + cacosh(tmpd); + casinh(tmpd); + catanh(tmpd); + typedef __complex__ long double ld_type; ld_type tmpld; + cacosl(tmpld); + casinl(tmpld); + catanl(tmpld); + cacoshl(tmpld); + casinhl(tmpld); + catanhl(tmpld); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_c99_complex_tr1=yes +else + ac_c99_complex_tr1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_c99_complex_tr1" >&5 +$as_echo "$ac_c99_complex_tr1" >&6; } + if test x"$ac_c99_complex_tr1" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_C99_COMPLEX_TR1 1" >>confdefs.h + + fi + + # Check for the existence of functions. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support to TR1 in " >&5 +$as_echo_n "checking for ISO C99 support to TR1 in ... " >&6; } + if ${glibcxx_cv_c99_ctype_tr1+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int ch; + int ret; + ret = isblank(ch); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_ctype_tr1=yes +else + glibcxx_cv_c99_ctype_tr1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_ctype_tr1" >&5 +$as_echo "$glibcxx_cv_c99_ctype_tr1" >&6; } + if test x"$glibcxx_cv_c99_ctype_tr1" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_C99_CTYPE_TR1 1" >>confdefs.h + + fi + + # Check for the existence of functions. + for ac_header in fenv.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "fenv.h" "ac_cv_header_fenv_h" "$ac_includes_default" +if test "x$ac_cv_header_fenv_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FENV_H 1 +_ACEOF + ac_has_fenv_h=yes +else + ac_has_fenv_h=no +fi + +done + + ac_c99_fenv_tr1=no; + if test x"$ac_has_fenv_h" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support to TR1 in " >&5 +$as_echo_n "checking for ISO C99 support to TR1 in ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int except, mode; + fexcept_t* pflag; + fenv_t* penv; + int ret; + ret = feclearexcept(except); + ret = fegetexceptflag(pflag, except); + ret = feraiseexcept(except); + ret = fesetexceptflag(pflag, except); + ret = fetestexcept(except); + ret = fegetround(); + ret = fesetround(mode); + ret = fegetenv(penv); + ret = feholdexcept(penv); + ret = fesetenv(penv); + ret = feupdateenv(penv); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_c99_fenv_tr1=yes +else + ac_c99_fenv_tr1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_c99_fenv_tr1" >&5 +$as_echo "$ac_c99_fenv_tr1" >&6; } + if test x"$ac_c99_fenv_tr1" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_C99_FENV_TR1 1" >>confdefs.h + + fi + + # Check for the existence of types. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support to TR1 in " >&5 +$as_echo_n "checking for ISO C99 support to TR1 in ... " >&6; } + if ${glibcxx_cv_c99_stdint_tr1+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define __STDC_LIMIT_MACROS + #define __STDC_CONSTANT_MACROS + #include +int +main () +{ +typedef int8_t my_int8_t; + my_int8_t i8 = INT8_MIN; + i8 = INT8_MAX; + typedef int16_t my_int16_t; + my_int16_t i16 = INT16_MIN; + i16 = INT16_MAX; + typedef int32_t my_int32_t; + my_int32_t i32 = INT32_MIN; + i32 = INT32_MAX; + typedef int64_t my_int64_t; + my_int64_t i64 = INT64_MIN; + i64 = INT64_MAX; + typedef int_fast8_t my_int_fast8_t; + my_int_fast8_t if8 = INT_FAST8_MIN; + if8 = INT_FAST8_MAX; + typedef int_fast16_t my_int_fast16_t; + my_int_fast16_t if16 = INT_FAST16_MIN; + if16 = INT_FAST16_MAX; + typedef int_fast32_t my_int_fast32_t; + my_int_fast32_t if32 = INT_FAST32_MIN; + if32 = INT_FAST32_MAX; + typedef int_fast64_t my_int_fast64_t; + my_int_fast64_t if64 = INT_FAST64_MIN; + if64 = INT_FAST64_MAX; + typedef int_least8_t my_int_least8_t; + my_int_least8_t il8 = INT_LEAST8_MIN; + il8 = INT_LEAST8_MAX; + typedef int_least16_t my_int_least16_t; + my_int_least16_t il16 = INT_LEAST16_MIN; + il16 = INT_LEAST16_MAX; + typedef int_least32_t my_int_least32_t; + my_int_least32_t il32 = INT_LEAST32_MIN; + il32 = INT_LEAST32_MAX; + typedef int_least64_t my_int_least64_t; + my_int_least64_t il64 = INT_LEAST64_MIN; + il64 = INT_LEAST64_MAX; + typedef intmax_t my_intmax_t; + my_intmax_t im = INTMAX_MAX; + im = INTMAX_MIN; + typedef intptr_t my_intptr_t; + my_intptr_t ip = INTPTR_MAX; + ip = INTPTR_MIN; + typedef uint8_t my_uint8_t; + my_uint8_t ui8 = UINT8_MAX; + ui8 = UINT8_MAX; + typedef uint16_t my_uint16_t; + my_uint16_t ui16 = UINT16_MAX; + ui16 = UINT16_MAX; + typedef uint32_t my_uint32_t; + my_uint32_t ui32 = UINT32_MAX; + ui32 = UINT32_MAX; + typedef uint64_t my_uint64_t; + my_uint64_t ui64 = UINT64_MAX; + ui64 = UINT64_MAX; + typedef uint_fast8_t my_uint_fast8_t; + my_uint_fast8_t uif8 = UINT_FAST8_MAX; + uif8 = UINT_FAST8_MAX; + typedef uint_fast16_t my_uint_fast16_t; + my_uint_fast16_t uif16 = UINT_FAST16_MAX; + uif16 = UINT_FAST16_MAX; + typedef uint_fast32_t my_uint_fast32_t; + my_uint_fast32_t uif32 = UINT_FAST32_MAX; + uif32 = UINT_FAST32_MAX; + typedef uint_fast64_t my_uint_fast64_t; + my_uint_fast64_t uif64 = UINT_FAST64_MAX; + uif64 = UINT_FAST64_MAX; + typedef uint_least8_t my_uint_least8_t; + my_uint_least8_t uil8 = UINT_LEAST8_MAX; + uil8 = UINT_LEAST8_MAX; + typedef uint_least16_t my_uint_least16_t; + my_uint_least16_t uil16 = UINT_LEAST16_MAX; + uil16 = UINT_LEAST16_MAX; + typedef uint_least32_t my_uint_least32_t; + my_uint_least32_t uil32 = UINT_LEAST32_MAX; + uil32 = UINT_LEAST32_MAX; + typedef uint_least64_t my_uint_least64_t; + my_uint_least64_t uil64 = UINT_LEAST64_MAX; + uil64 = UINT_LEAST64_MAX; + typedef uintmax_t my_uintmax_t; + my_uintmax_t uim = UINTMAX_MAX; + uim = UINTMAX_MAX; + typedef uintptr_t my_uintptr_t; + my_uintptr_t uip = UINTPTR_MAX; + uip = UINTPTR_MAX; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_stdint_tr1=yes +else + glibcxx_cv_c99_stdint_tr1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_stdint_tr1" >&5 +$as_echo "$glibcxx_cv_c99_stdint_tr1" >&6; } + if test x"$glibcxx_cv_c99_stdint_tr1" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_C99_STDINT_TR1 1" >>confdefs.h + + fi + + # Check for the existence of functions. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support to TR1 in " >&5 +$as_echo_n "checking for ISO C99 support to TR1 in ... " >&6; } + if ${glibcxx_cv_c99_math_tr1+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +typedef double_t my_double_t; + typedef float_t my_float_t; + acosh(0.0); + acoshf(0.0f); + acoshl(0.0l); + asinh(0.0); + asinhf(0.0f); + asinhl(0.0l); + atanh(0.0); + atanhf(0.0f); + atanhl(0.0l); + cbrt(0.0); + cbrtf(0.0f); + cbrtl(0.0l); + copysign(0.0, 0.0); + copysignf(0.0f, 0.0f); + copysignl(0.0l, 0.0l); + erf(0.0); + erff(0.0f); + erfl(0.0l); + erfc(0.0); + erfcf(0.0f); + erfcl(0.0l); + exp2(0.0); + exp2f(0.0f); + exp2l(0.0l); + expm1(0.0); + expm1f(0.0f); + expm1l(0.0l); + fdim(0.0, 0.0); + fdimf(0.0f, 0.0f); + fdiml(0.0l, 0.0l); + fma(0.0, 0.0, 0.0); + fmaf(0.0f, 0.0f, 0.0f); + fmal(0.0l, 0.0l, 0.0l); + fmax(0.0, 0.0); + fmaxf(0.0f, 0.0f); + fmaxl(0.0l, 0.0l); + fmin(0.0, 0.0); + fminf(0.0f, 0.0f); + fminl(0.0l, 0.0l); + hypot(0.0, 0.0); + hypotf(0.0f, 0.0f); + hypotl(0.0l, 0.0l); + ilogb(0.0); + ilogbf(0.0f); + ilogbl(0.0l); + lgamma(0.0); + lgammaf(0.0f); + lgammal(0.0l); + #ifndef __APPLE__ /* see below */ + llrint(0.0); + llrintf(0.0f); + llrintl(0.0l); + llround(0.0); + llroundf(0.0f); + llroundl(0.0l); + #endif + log1p(0.0); + log1pf(0.0f); + log1pl(0.0l); + log2(0.0); + log2f(0.0f); + log2l(0.0l); + logb(0.0); + logbf(0.0f); + logbl(0.0l); + lrint(0.0); + lrintf(0.0f); + lrintl(0.0l); + lround(0.0); + lroundf(0.0f); + lroundl(0.0l); + nan(0); + nanf(0); + nanl(0); + nearbyint(0.0); + nearbyintf(0.0f); + nearbyintl(0.0l); + nextafter(0.0, 0.0); + nextafterf(0.0f, 0.0f); + nextafterl(0.0l, 0.0l); + nexttoward(0.0, 0.0); + nexttowardf(0.0f, 0.0f); + nexttowardl(0.0l, 0.0l); + remainder(0.0, 0.0); + remainderf(0.0f, 0.0f); + remainderl(0.0l, 0.0l); + remquo(0.0, 0.0, 0); + remquof(0.0f, 0.0f, 0); + remquol(0.0l, 0.0l, 0); + rint(0.0); + rintf(0.0f); + rintl(0.0l); + round(0.0); + roundf(0.0f); + roundl(0.0l); + scalbln(0.0, 0l); + scalblnf(0.0f, 0l); + scalblnl(0.0l, 0l); + scalbn(0.0, 0); + scalbnf(0.0f, 0); + scalbnl(0.0l, 0); + tgamma(0.0); + tgammaf(0.0f); + tgammal(0.0l); + trunc(0.0); + truncf(0.0f); + truncl(0.0l); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_math_tr1=yes +else + glibcxx_cv_c99_math_tr1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_math_tr1" >&5 +$as_echo "$glibcxx_cv_c99_math_tr1" >&6; } + if test x"$glibcxx_cv_c99_math_tr1" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_C99_MATH_TR1 1" >>confdefs.h + + + case "${target_os}" in + darwin*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 rounding functions in " >&5 +$as_echo_n "checking for ISO C99 rounding functions in ... " >&6; } + if ${glibcxx_cv_c99_math_llround+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +llrint(0.0); + llrintf(0.0f); + llrintl(0.0l); + llround(0.0); + llroundf(0.0f); + llroundl(0.0l); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_c99_math_llround=yes +else + glibcxx_cv_c99_math_llround=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_c99_math_llround" >&5 +$as_echo "$glibcxx_cv_c99_math_llround" >&6; } + ;; + esac + if test x"$glibcxx_cv_c99_math_llround" = x"no"; then + +$as_echo "#define _GLIBCXX_NO_C99_ROUNDING_FUNCS 1" >>confdefs.h + + fi + fi + + # Check for the existence of functions (NB: doesn't make + # sense if the glibcxx_cv_c99_stdint_tr1 check fails, per C99, 7.8/1). + ac_c99_inttypes_tr1=no; + if test x"$glibcxx_cv_c99_stdint_tr1" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISO C99 support to TR1 in " >&5 +$as_echo_n "checking for ISO C99 support to TR1 in ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +intmax_t i, numer, denom, base; + const char* s; + char** endptr; + intmax_t ret = imaxabs(i); + imaxdiv_t dret = imaxdiv(numer, denom); + ret = strtoimax(s, endptr, base); + uintmax_t uret = strtoumax(s, endptr, base); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_c99_inttypes_tr1=yes +else + ac_c99_inttypes_tr1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_c99_inttypes_tr1" >&5 +$as_echo "$ac_c99_inttypes_tr1" >&6; } + if test x"$ac_c99_inttypes_tr1" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_C99_INTTYPES_TR1 1" >>confdefs.h + + fi + + # Check for the existence of wchar_t functions (NB: doesn't + # make sense if the glibcxx_cv_c99_stdint_tr1 check fails, per C99, 7.8/1). + ac_c99_inttypes_wchar_t_tr1=no; + if test x"$glibcxx_cv_c99_stdint_tr1" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wchar_t ISO C99 support to TR1 in " >&5 +$as_echo_n "checking for wchar_t ISO C99 support to TR1 in ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +intmax_t base; + const wchar_t* s; + wchar_t** endptr; + intmax_t ret = wcstoimax(s, endptr, base); + uintmax_t uret = wcstoumax(s, endptr, base); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_c99_inttypes_wchar_t_tr1=yes +else + ac_c99_inttypes_wchar_t_tr1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_c99_inttypes_wchar_t_tr1" >&5 +$as_echo "$ac_c99_inttypes_wchar_t_tr1" >&6; } + if test x"$ac_c99_inttypes_wchar_t_tr1" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_C99_INTTYPES_WCHAR_T_TR1 1" >>confdefs.h + + fi + + # Check for the existence of the header. + for ac_header in stdbool.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default" +if test "x$ac_cv_header_stdbool_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDBOOL_H 1 +_ACEOF + +fi + +done + + + # Check for the existence of the header. + for ac_header in stdalign.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "stdalign.h" "ac_cv_header_stdalign_h" "$ac_includes_default" +if test "x$ac_cv_header_stdalign_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDALIGN_H 1 +_ACEOF + +fi + +done + + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For the EOF, SEEK_CUR, and SEEK_END integer constants. + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the value of EOF" >&5 +$as_echo_n "checking for the value of EOF... " >&6; } +if ${glibcxx_cv_stdio_eof+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if ac_fn_c_compute_int "$LINENO" "EOF" "glibcxx_cv_stdio_eof" "#include "; then : + +else + as_fn_error $? "computing EOF failed" "$LINENO" 5 +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_stdio_eof" >&5 +$as_echo "$glibcxx_cv_stdio_eof" >&6; } + +cat >>confdefs.h <<_ACEOF +#define _GLIBCXX_STDIO_EOF $glibcxx_cv_stdio_eof +_ACEOF + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the value of SEEK_CUR" >&5 +$as_echo_n "checking for the value of SEEK_CUR... " >&6; } +if ${glibcxx_cv_stdio_seek_cur+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if ac_fn_c_compute_int "$LINENO" "SEEK_CUR" "glibcxx_cv_stdio_seek_cur" "#include "; then : + +else + as_fn_error $? "computing SEEK_CUR failed" "$LINENO" 5 +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_stdio_seek_cur" >&5 +$as_echo "$glibcxx_cv_stdio_seek_cur" >&6; } + +cat >>confdefs.h <<_ACEOF +#define _GLIBCXX_STDIO_SEEK_CUR $glibcxx_cv_stdio_seek_cur +_ACEOF + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the value of SEEK_END" >&5 +$as_echo_n "checking for the value of SEEK_END... " >&6; } +if ${glibcxx_cv_stdio_seek_end+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if ac_fn_c_compute_int "$LINENO" "SEEK_END" "glibcxx_cv_stdio_seek_end" "#include "; then : + +else + as_fn_error $? "computing SEEK_END failed" "$LINENO" 5 +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_stdio_seek_end" >&5 +$as_echo "$glibcxx_cv_stdio_seek_end" >&6; } + +cat >>confdefs.h <<_ACEOF +#define _GLIBCXX_STDIO_SEEK_END $glibcxx_cv_stdio_seek_end +_ACEOF + + + +# For gettimeofday support. + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettimeofday" >&5 +$as_echo_n "checking for gettimeofday... " >&6; } + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + ac_has_gettimeofday=no; + for ac_header in sys/time.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_time_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_TIME_H 1 +_ACEOF + ac_has_sys_time_h=yes +else + ac_has_sys_time_h=no +fi + +done + + if test x"$ac_has_sys_time_h" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettimeofday" >&5 +$as_echo_n "checking for gettimeofday... " >&6; } + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +timeval tv; gettimeofday(&tv, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_has_gettimeofday=yes +else + ac_has_gettimeofday=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +timeval tv; gettimeofday(&tv, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_has_gettimeofday=yes +else + ac_has_gettimeofday=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_gettimeofday" >&5 +$as_echo "$ac_has_gettimeofday" >&6; } + fi + + if test x"$ac_has_gettimeofday" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_GETTIMEOFDAY 1" >>confdefs.h + + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For clock_gettime, nanosleep and sched_yield support. + + + # Check whether --enable-libstdcxx-time was given. +if test "${enable_libstdcxx_time+set}" = set; then : + enableval=$enable_libstdcxx_time; + case "$enableval" in + yes|no|rt) ;; + *) as_fn_error $? "Unknown argument to enable/disable libstdcxx-time" "$LINENO" 5 ;; + esac + +else + enable_libstdcxx_time=auto +fi + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + ac_save_LIBS="$LIBS" + + ac_has_clock_monotonic=no + ac_has_clock_realtime=no + ac_has_nanosleep=no + ac_has_sched_yield=no + + if test x"$enable_libstdcxx_time" = x"auto"; then + + case "${target_os}" in + cygwin*) + ac_has_nanosleep=yes + ;; + darwin*) + ac_has_nanosleep=yes + ac_has_sched_yield=yes + ;; + # VxWorks has nanosleep as soon as the kernel is configured with + # INCLUDE_POSIX_TIMERS, which is normally/most-often the case. + vxworks*) + ac_has_nanosleep=yes + ;; + gnu* | linux* | kfreebsd*-gnu | knetbsd*-gnu) + # Don't use link test for freestanding library, in case gcc_no_link=yes + if test x"$is_hosted" = xyes; then + # Versions of glibc before 2.17 needed -lrt for clock_gettime. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 +$as_echo_n "checking for library containing clock_gettime... " >&6; } +if ${ac_cv_search_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_clock_gettime=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_clock_gettime+:} false; then : + break +fi +done +if ${ac_cv_search_clock_gettime+:} false; then : + +else + ac_cv_search_clock_gettime=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 +$as_echo "$ac_cv_search_clock_gettime" >&6; } +ac_res=$ac_cv_search_clock_gettime +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + if test x"$ac_cv_search_clock_gettime" = x"none required"; then + ac_has_clock_monotonic=yes + ac_has_clock_realtime=yes + fi + fi + ac_has_nanosleep=yes + ac_has_sched_yield=yes + ;; + freebsd*|netbsd*|dragonfly*|rtems*) + ac_has_clock_monotonic=yes + ac_has_clock_realtime=yes + ac_has_nanosleep=yes + ac_has_sched_yield=yes + ;; + openbsd*) + ac_has_clock_monotonic=yes + ac_has_clock_realtime=yes + ac_has_nanosleep=yes + ;; + solaris*) + ac_has_clock_monotonic=yes + ac_has_clock_realtime=yes + ac_has_nanosleep=yes + ac_has_sched_yield=yes + ;; + uclinux*) + ac_has_nanosleep=yes + ac_has_sched_yield=yes + esac + + elif test x"$enable_libstdcxx_time" != x"no"; then + + if test x"$enable_libstdcxx_time" = x"rt"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 +$as_echo_n "checking for library containing clock_gettime... " >&6; } +if ${ac_cv_search_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_clock_gettime=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_clock_gettime+:} false; then : + break +fi +done +if ${ac_cv_search_clock_gettime+:} false; then : + +else + ac_cv_search_clock_gettime=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 +$as_echo "$ac_cv_search_clock_gettime" >&6; } +ac_res=$ac_cv_search_clock_gettime +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing nanosleep" >&5 +$as_echo_n "checking for library containing nanosleep... " >&6; } +if ${ac_cv_search_nanosleep+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char nanosleep (); +int +main () +{ +return nanosleep (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_nanosleep=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_nanosleep+:} false; then : + break +fi +done +if ${ac_cv_search_nanosleep+:} false; then : + +else + ac_cv_search_nanosleep=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_nanosleep" >&5 +$as_echo "$ac_cv_search_nanosleep" >&6; } +ac_res=$ac_cv_search_nanosleep +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + else + ac_fn_cxx_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" +if test "x$ac_cv_func_clock_gettime" = xyes; then : + +fi + + ac_fn_cxx_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep" +if test "x$ac_cv_func_nanosleep" = xyes; then : + +fi + + fi + + case "$ac_cv_search_clock_gettime" in + -l*) GLIBCXX_LIBS=$ac_cv_search_clock_gettime + ;; + esac + case "$ac_cv_search_nanosleep" in + -l*) GLIBCXX_LIBS="$GLIBCXX_LIBS $ac_cv_search_nanosleep" + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sched_yield" >&5 +$as_echo_n "checking for library containing sched_yield... " >&6; } +if ${ac_cv_search_sched_yield+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sched_yield (); +int +main () +{ +return sched_yield (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_sched_yield=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_sched_yield+:} false; then : + break +fi +done +if ${ac_cv_search_sched_yield+:} false; then : + +else + ac_cv_search_sched_yield=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sched_yield" >&5 +$as_echo "$ac_cv_search_sched_yield" >&6; } +ac_res=$ac_cv_search_sched_yield +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + + case "$ac_cv_search_sched_yield" in + -lrt*) + if test x"$enable_libstdcxx_time" = x"rt"; then + GLIBCXX_LIBS="$GLIBCXX_LIBS $ac_cv_search_sched_yield" + ac_has_sched_yield=yes + fi + ;; + *) + ac_has_sched_yield=yes + ;; + esac + + for ac_header in unistd.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" +if test "x$ac_cv_header_unistd_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_UNISTD_H 1 +_ACEOF + ac_has_unistd_h=yes +else + ac_has_unistd_h=no +fi + +done + + + if test x"$ac_has_unistd_h" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for monotonic clock" >&5 +$as_echo_n "checking for monotonic clock... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) + timespec tp; + #endif + clock_gettime(CLOCK_MONOTONIC, &tp); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_has_clock_monotonic=yes +else + ac_has_clock_monotonic=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_clock_monotonic" >&5 +$as_echo "$ac_has_clock_monotonic" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for realtime clock" >&5 +$as_echo_n "checking for realtime clock... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if _POSIX_TIMERS > 0 + timespec tp; + #endif + clock_gettime(CLOCK_REALTIME, &tp); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_has_clock_realtime=yes +else + ac_has_clock_realtime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_clock_realtime" >&5 +$as_echo "$ac_has_clock_realtime" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep" >&5 +$as_echo_n "checking for nanosleep... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if _POSIX_TIMERS > 0 + timespec tp; + #endif + nanosleep(&tp, 0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_has_nanosleep=yes +else + ac_has_nanosleep=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_nanosleep" >&5 +$as_echo "$ac_has_nanosleep" >&6; } + fi + fi + + if test x"$ac_has_clock_monotonic" != x"yes"; then + case ${target_os} in + linux* | uclinux*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime syscall" >&5 +$as_echo_n "checking for clock_gettime syscall... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ +#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) + timespec tp; + #endif + syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &tp); + syscall(SYS_clock_gettime, CLOCK_REALTIME, &tp); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_has_clock_gettime_syscall=yes +else + ac_has_clock_gettime_syscall=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_clock_gettime_syscall" >&5 +$as_echo "$ac_has_clock_gettime_syscall" >&6; } + if test x"$ac_has_clock_gettime_syscall" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL 1" >>confdefs.h + + ac_has_clock_monotonic=yes + ac_has_clock_realtime=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct timespec that matches syscall" >&5 +$as_echo_n "checking for struct timespec that matches syscall... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#ifdef SYS_clock_gettime64 + #if SYS_clock_gettime64 != SYS_clock_gettime + // We need to use SYS_clock_gettime and libc appears to + // also know about the SYS_clock_gettime64 syscall. + // Check that userspace doesn't use time64 version of timespec. + static_assert(sizeof(timespec::tv_sec) == sizeof(long), + "struct timespec must be compatible with SYS_clock_gettime"); + #endif + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_timespec_matches_syscall=yes +else + ac_timespec_matches_syscall=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_timespec_matches_syscall" >&5 +$as_echo "$ac_timespec_matches_syscall" >&6; } + if test x"$ac_timespec_matches_syscall" = no; then + as_fn_error $? "struct timespec is not compatible with SYS_clock_gettime, please report a bug to http://gcc.gnu.org/bugzilla" "$LINENO" 5 + fi + fi;; + esac + fi + + if test x"$ac_has_clock_monotonic" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_CLOCK_MONOTONIC 1" >>confdefs.h + + fi + + if test x"$ac_has_clock_realtime" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_CLOCK_REALTIME 1" >>confdefs.h + + fi + + if test x"$ac_has_sched_yield" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_SCHED_YIELD 1" >>confdefs.h + + fi + + if test x"$ac_has_nanosleep" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_NANOSLEEP 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sleep" >&5 +$as_echo_n "checking for sleep... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +sleep(1) + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_has_sleep=yes +else + ac_has_sleep=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test x"$ac_has_sleep" = x"yes"; then + +$as_echo "#define HAVE_SLEEP 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_sleep" >&5 +$as_echo "$ac_has_sleep" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usleep" >&5 +$as_echo_n "checking for usleep... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +sleep(1); + usleep(100); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_has_usleep=yes +else + ac_has_usleep=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test x"$ac_has_usleep" = x"yes"; then + +$as_echo "#define HAVE_USLEEP 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_usleep" >&5 +$as_echo "$ac_has_usleep" >&6; } + fi + + if test x"$ac_has_nanosleep$ac_has_sleep" = x"nono"; then + ac_no_sleep=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Sleep" >&5 +$as_echo_n "checking for Sleep... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +Sleep(1) + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_has_win32_sleep=yes +else + ac_has_win32_sleep=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test x"$ac_has_win32_sleep" = x"yes"; then + +$as_echo "#define HAVE_WIN32_SLEEP 1" >>confdefs.h + + ac_no_sleep=no + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_win32_sleep" >&5 +$as_echo "$ac_has_win32_sleep" >&6; } + fi + + if test x"$ac_no_sleep" = x"yes"; then + +$as_echo "#define NO_SLEEP 1" >>confdefs.h + + fi + + + + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# Check for tmpnam which is obsolescent in POSIX.1-2008 + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tmpnam" >&5 +$as_echo_n "checking for tmpnam... " >&6; } + if ${glibcxx_cv_TMPNAM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char *tmp = tmpnam(NULL); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_TMPNAM=yes +else + glibcxx_cv_TMPNAM=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char *tmp = tmpnam(NULL); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_TMPNAM=yes +else + glibcxx_cv_TMPNAM=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_TMPNAM = yes; then + +$as_echo "#define _GLIBCXX_USE_TMPNAM 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_TMPNAM" >&5 +$as_echo "$glibcxx_cv_TMPNAM" >&6; } + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For pthread_cond_clockwait + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + ac_save_LIBS="$LIBS" + LIBS="$LIBS -lpthread" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_cond_clockwait" >&5 +$as_echo_n "checking for pthread_cond_clockwait... " >&6; } + if ${glibcxx_cv_PTHREAD_COND_CLOCKWAIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +pthread_mutex_t mutex; pthread_cond_t cond; struct timespec ts; int n = pthread_cond_clockwait(&cond, &mutex, 0, &ts); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_PTHREAD_COND_CLOCKWAIT=yes +else + glibcxx_cv_PTHREAD_COND_CLOCKWAIT=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +pthread_mutex_t mutex; pthread_cond_t cond; struct timespec ts; int n = pthread_cond_clockwait(&cond, &mutex, 0, &ts); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_PTHREAD_COND_CLOCKWAIT=yes +else + glibcxx_cv_PTHREAD_COND_CLOCKWAIT=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_PTHREAD_COND_CLOCKWAIT = yes; then + +$as_echo "#define _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_PTHREAD_COND_CLOCKWAIT" >&5 +$as_echo "$glibcxx_cv_PTHREAD_COND_CLOCKWAIT" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For pthread_mutex_clocklock + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + ac_save_LIBS="$LIBS" + LIBS="$LIBS -lpthread" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_clocklock" >&5 +$as_echo_n "checking for pthread_mutex_clocklock... " >&6; } + if ${glibcxx_cv_PTHREAD_MUTEX_CLOCKLOCK+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +pthread_mutex_t mutex; struct timespec ts; int n = pthread_mutex_clocklock(&mutex, CLOCK_REALTIME, &ts); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_PTHREAD_MUTEX_CLOCKLOCK=yes +else + glibcxx_cv_PTHREAD_MUTEX_CLOCKLOCK=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +pthread_mutex_t mutex; struct timespec ts; int n = pthread_mutex_clocklock(&mutex, CLOCK_REALTIME, &ts); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_PTHREAD_MUTEX_CLOCKLOCK=yes +else + glibcxx_cv_PTHREAD_MUTEX_CLOCKLOCK=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_PTHREAD_MUTEX_CLOCKLOCK = yes; then + +$as_echo "#define _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_PTHREAD_MUTEX_CLOCKLOCK" >&5 +$as_echo "$glibcxx_cv_PTHREAD_MUTEX_CLOCKLOCK" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + ac_save_LIBS="$LIBS" + LIBS="$LIBS -lpthread" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_rwlock_clockrdlock, pthread_wlock_clockwrlock" >&5 +$as_echo_n "checking for pthread_rwlock_clockrdlock, pthread_wlock_clockwrlock... " >&6; } + if ${glibcxx_cv_PTHREAD_RWLOCK_CLOCKLOCK+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +pthread_rwlock_t rwl; struct timespec ts; + int n = pthread_rwlock_clockrdlock(&rwl, CLOCK_REALTIME, &ts); + int m = pthread_rwlock_clockwrlock(&rwl, CLOCK_REALTIME, &ts); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_PTHREAD_RWLOCK_CLOCKLOCK=yes +else + glibcxx_cv_PTHREAD_RWLOCK_CLOCKLOCK=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +pthread_rwlock_t rwl; struct timespec ts; + int n = pthread_rwlock_clockrdlock(&rwl, CLOCK_REALTIME, &ts); + int m = pthread_rwlock_clockwrlock(&rwl, CLOCK_REALTIME, &ts); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_PTHREAD_RWLOCK_CLOCKLOCK=yes +else + glibcxx_cv_PTHREAD_RWLOCK_CLOCKLOCK=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_PTHREAD_RWLOCK_CLOCKLOCK = yes; then + +$as_echo "#define _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_PTHREAD_RWLOCK_CLOCKLOCK" >&5 +$as_echo "$glibcxx_cv_PTHREAD_RWLOCK_CLOCKLOCK" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + ac_fn_c_check_header_mongrel "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" +if test "x$ac_cv_header_locale_h" = xyes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LC_MESSAGES" >&5 +$as_echo_n "checking for LC_MESSAGES... " >&6; } +if ${ac_cv_val_LC_MESSAGES+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +return LC_MESSAGES + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_val_LC_MESSAGES=yes +else + ac_cv_val_LC_MESSAGES=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_val_LC_MESSAGES" >&5 +$as_echo "$ac_cv_val_LC_MESSAGES" >&6; } + if test $ac_cv_val_LC_MESSAGES = yes; then + +$as_echo "#define HAVE_LC_MESSAGES 1" >>confdefs.h + + fi + +fi + + + + +# For hardware_concurrency +for ac_header in sys/sysinfo.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/sysinfo.h" "ac_cv_header_sys_sysinfo_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sysinfo_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_SYSINFO_H 1 +_ACEOF + +fi + +done + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for get_nprocs" >&5 +$as_echo_n "checking for get_nprocs... " >&6; } + if ${glibcxx_cv_GET_NPROCS+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int n = get_nprocs(); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_GET_NPROCS=yes +else + glibcxx_cv_GET_NPROCS=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int n = get_nprocs(); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_GET_NPROCS=yes +else + glibcxx_cv_GET_NPROCS=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_GET_NPROCS = yes; then + +$as_echo "#define _GLIBCXX_USE_GET_NPROCS 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_GET_NPROCS" >&5 +$as_echo "$glibcxx_cv_GET_NPROCS" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +for ac_header in unistd.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" +if test "x$ac_cv_header_unistd_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_UNISTD_H 1 +_ACEOF + +fi + +done + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _SC_NPROCESSORS_ONLN" >&5 +$as_echo_n "checking for _SC_NPROCESSORS_ONLN... " >&6; } + if ${glibcxx_cv_SC_NPROCESSORS_ONLN+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int n = sysconf(_SC_NPROCESSORS_ONLN); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_SC_NPROCESSORS_ONLN=yes +else + glibcxx_cv_SC_NPROCESSORS_ONLN=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int n = sysconf(_SC_NPROCESSORS_ONLN); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_SC_NPROCESSORS_ONLN=yes +else + glibcxx_cv_SC_NPROCESSORS_ONLN=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_SC_NPROCESSORS_ONLN = yes; then + +$as_echo "#define _GLIBCXX_USE_SC_NPROCESSORS_ONLN 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_SC_NPROCESSORS_ONLN" >&5 +$as_echo "$glibcxx_cv_SC_NPROCESSORS_ONLN" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _SC_NPROC_ONLN" >&5 +$as_echo_n "checking for _SC_NPROC_ONLN... " >&6; } + if ${glibcxx_cv_SC_NPROC_ONLN+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int n = sysconf(_SC_NPROC_ONLN); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_SC_NPROC_ONLN=yes +else + glibcxx_cv_SC_NPROC_ONLN=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int n = sysconf(_SC_NPROC_ONLN); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_SC_NPROC_ONLN=yes +else + glibcxx_cv_SC_NPROC_ONLN=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_SC_NPROC_ONLN = yes; then + +$as_echo "#define _GLIBCXX_USE_SC_NPROC_ONLN 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_SC_NPROC_ONLN" >&5 +$as_echo "$glibcxx_cv_SC_NPROC_ONLN" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthreads_num_processors_np" >&5 +$as_echo_n "checking for pthreads_num_processors_np... " >&6; } + if ${glibcxx_cv_PTHREADS_NUM_PROCESSORS_NP+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int n = pthread_num_processors_np(); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_PTHREADS_NUM_PROCESSORS_NP=yes +else + glibcxx_cv_PTHREADS_NUM_PROCESSORS_NP=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int n = pthread_num_processors_np(); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_PTHREADS_NUM_PROCESSORS_NP=yes +else + glibcxx_cv_PTHREADS_NUM_PROCESSORS_NP=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_PTHREADS_NUM_PROCESSORS_NP = yes; then + +$as_echo "#define _GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_PTHREADS_NUM_PROCESSORS_NP" >&5 +$as_echo "$glibcxx_cv_PTHREADS_NUM_PROCESSORS_NP" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hw.ncpu sysctl" >&5 +$as_echo_n "checking for hw.ncpu sysctl... " >&6; } + if ${glibcxx_cv_SYSCTL_HW_NCPU+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + int count; + size_t size = sizeof(count); + int mib[] = { CTL_HW, HW_NCPU }; + sysctl(mib, 2, &count, &size, NULL, 0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_SYSCTL_HW_NCPU=yes +else + glibcxx_cv_SYSCTL_HW_NCPU=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + int count; + size_t size = sizeof(count); + int mib[] = { CTL_HW, HW_NCPU }; + sysctl(mib, 2, &count, &size, NULL, 0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_SYSCTL_HW_NCPU=yes +else + glibcxx_cv_SYSCTL_HW_NCPU=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_SYSCTL_HW_NCPU = yes; then + +$as_echo "#define _GLIBCXX_USE_SYSCTL_HW_NCPU 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_SYSCTL_HW_NCPU" >&5 +$as_echo "$glibcxx_cv_SYSCTL_HW_NCPU" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suitable sys/sdt.h" >&5 +$as_echo_n "checking for suitable sys/sdt.h... " >&6; } + # Note that this test has to be run with the C language. + # Otherwise, sdt.h will try to include some headers from + # libstdc++ itself. + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + if ${glibcxx_cv_sys_sdt_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # Because we have to run the test in C, we use grep rather + # than the compiler to check for the bug. The bug is that + # were strings without trailing whitespace, causing g++ + # to look for operator"". The pattern searches for the fixed + # output. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + int f() { STAP_PROBE(hi, bob); } + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP " \",\" " >/dev/null 2>&1; then : + glibcxx_cv_sys_sdt_h=yes +else + glibcxx_cv_sys_sdt_h=no +fi +rm -f conftest* + + +fi + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + if test $glibcxx_cv_sys_sdt_h = yes; then + +$as_echo "#define HAVE_SYS_SDT_H 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_sys_sdt_h" >&5 +$as_echo "$glibcxx_cv_sys_sdt_h" >&6; } + + +# Check for available headers. +for ac_header in endian.h execinfo.h float.h fp.h ieeefp.h inttypes.h \ +locale.h machine/endian.h machine/param.h nan.h stdint.h stdlib.h string.h \ +strings.h sys/ipc.h sys/isa_defs.h sys/machine.h sys/param.h \ +sys/resource.h sys/sem.h sys/stat.h sys/time.h sys/types.h unistd.h \ +wchar.h wctype.h linux/types.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in linux/random.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/random.h" "ac_cv_header_linux_random_h" "#ifdef HAVE_LINUX_TYPES_H +# include +#endif + +" +if test "x$ac_cv_header_linux_random_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_RANDOM_H 1 +_ACEOF + +fi + +done + + +for ac_header in xlocale.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "xlocale.h" "ac_cv_header_xlocale_h" "$ac_includes_default" +if test "x$ac_cv_header_xlocale_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_XLOCALE_H 1 +_ACEOF + +fi + +done + + +# Only do link tests if native. Else, hardcode. +if $GLIBCXX_IS_NATIVE; then + + # We can do more elaborate tests that assume a working linker. + CANADIAN=no + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + libm="-lm" +fi + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $libm" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf declaration" >&5 +$as_echo_n "checking for isinf declaration... " >&6; } + if test x${glibcxx_cv_func_isinf_use+set} != xset; then + if ${glibcxx_cv_func_isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinf_use=yes +else + glibcxx_cv_func_isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinf_use" >&5 +$as_echo "$glibcxx_cv_func_isinf_use" >&6; } + + if test x$glibcxx_cv_func_isinf_use = x"yes"; then + for ac_func in isinf +do : + ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinf declaration" >&5 +$as_echo_n "checking for _isinf declaration... " >&6; } + if test x${glibcxx_cv_func__isinf_use+set} != xset; then + if ${glibcxx_cv_func__isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinf_use=yes +else + glibcxx_cv_func__isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinf_use" >&5 +$as_echo "$glibcxx_cv_func__isinf_use" >&6; } + + if test x$glibcxx_cv_func__isinf_use = x"yes"; then + for ac_func in _isinf +do : + ac_fn_c_check_func "$LINENO" "_isinf" "ac_cv_func__isinf" +if test "x$ac_cv_func__isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan declaration" >&5 +$as_echo_n "checking for isnan declaration... " >&6; } + if test x${glibcxx_cv_func_isnan_use+set} != xset; then + if ${glibcxx_cv_func_isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnan_use=yes +else + glibcxx_cv_func_isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnan_use" >&5 +$as_echo "$glibcxx_cv_func_isnan_use" >&6; } + + if test x$glibcxx_cv_func_isnan_use = x"yes"; then + for ac_func in isnan +do : + ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNAN 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnan declaration" >&5 +$as_echo_n "checking for _isnan declaration... " >&6; } + if test x${glibcxx_cv_func__isnan_use+set} != xset; then + if ${glibcxx_cv_func__isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnan_use=yes +else + glibcxx_cv_func__isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnan_use" >&5 +$as_echo "$glibcxx_cv_func__isnan_use" >&6; } + + if test x$glibcxx_cv_func__isnan_use = x"yes"; then + for ac_func in _isnan +do : + ac_fn_c_check_func "$LINENO" "_isnan" "ac_cv_func__isnan" +if test "x$ac_cv_func__isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNAN 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finite declaration" >&5 +$as_echo_n "checking for finite declaration... " >&6; } + if test x${glibcxx_cv_func_finite_use+set} != xset; then + if ${glibcxx_cv_func_finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finite_use=yes +else + glibcxx_cv_func_finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finite_use" >&5 +$as_echo "$glibcxx_cv_func_finite_use" >&6; } + + if test x$glibcxx_cv_func_finite_use = x"yes"; then + for ac_func in finite +do : + ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITE 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finite declaration" >&5 +$as_echo_n "checking for _finite declaration... " >&6; } + if test x${glibcxx_cv_func__finite_use+set} != xset; then + if ${glibcxx_cv_func__finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finite_use=yes +else + glibcxx_cv_func__finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finite_use" >&5 +$as_echo "$glibcxx_cv_func__finite_use" >&6; } + + if test x$glibcxx_cv_func__finite_use = x"yes"; then + for ac_func in _finite +do : + ac_fn_c_check_func "$LINENO" "_finite" "ac_cv_func__finite" +if test "x$ac_cv_func__finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITE 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincos declaration" >&5 +$as_echo_n "checking for sincos declaration... " >&6; } + if test x${glibcxx_cv_func_sincos_use+set} != xset; then + if ${glibcxx_cv_func_sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincos_use=yes +else + glibcxx_cv_func_sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincos_use" >&5 +$as_echo "$glibcxx_cv_func_sincos_use" >&6; } + + if test x$glibcxx_cv_func_sincos_use = x"yes"; then + for ac_func in sincos +do : + ac_fn_c_check_func "$LINENO" "sincos" "ac_cv_func_sincos" +if test "x$ac_cv_func_sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincos declaration" >&5 +$as_echo_n "checking for _sincos declaration... " >&6; } + if test x${glibcxx_cv_func__sincos_use+set} != xset; then + if ${glibcxx_cv_func__sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincos_use=yes +else + glibcxx_cv_func__sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincos_use" >&5 +$as_echo "$glibcxx_cv_func__sincos_use" >&6; } + + if test x$glibcxx_cv_func__sincos_use = x"yes"; then + for ac_func in _sincos +do : + ac_fn_c_check_func "$LINENO" "_sincos" "ac_cv_func__sincos" +if test "x$ac_cv_func__sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpclass declaration" >&5 +$as_echo_n "checking for fpclass declaration... " >&6; } + if test x${glibcxx_cv_func_fpclass_use+set} != xset; then + if ${glibcxx_cv_func_fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fpclass_use=yes +else + glibcxx_cv_func_fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fpclass_use" >&5 +$as_echo "$glibcxx_cv_func_fpclass_use" >&6; } + + if test x$glibcxx_cv_func_fpclass_use = x"yes"; then + for ac_func in fpclass +do : + ac_fn_c_check_func "$LINENO" "fpclass" "ac_cv_func_fpclass" +if test "x$ac_cv_func_fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fpclass declaration" >&5 +$as_echo_n "checking for _fpclass declaration... " >&6; } + if test x${glibcxx_cv_func__fpclass_use+set} != xset; then + if ${glibcxx_cv_func__fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fpclass_use=yes +else + glibcxx_cv_func__fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fpclass_use" >&5 +$as_echo "$glibcxx_cv_func__fpclass_use" >&6; } + + if test x$glibcxx_cv_func__fpclass_use = x"yes"; then + for ac_func in _fpclass +do : + ac_fn_c_check_func "$LINENO" "_fpclass" "ac_cv_func__fpclass" +if test "x$ac_cv_func__fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for qfpclass declaration" >&5 +$as_echo_n "checking for qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func_qfpclass_use+set} != xset; then + if ${glibcxx_cv_func_qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_qfpclass_use=yes +else + glibcxx_cv_func_qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func_qfpclass_use" >&6; } + + if test x$glibcxx_cv_func_qfpclass_use = x"yes"; then + for ac_func in qfpclass +do : + ac_fn_c_check_func "$LINENO" "qfpclass" "ac_cv_func_qfpclass" +if test "x$ac_cv_func_qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QFPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _qfpclass declaration" >&5 +$as_echo_n "checking for _qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func__qfpclass_use+set} != xset; then + if ${glibcxx_cv_func__qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__qfpclass_use=yes +else + glibcxx_cv_func__qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func__qfpclass_use" >&6; } + + if test x$glibcxx_cv_func__qfpclass_use = x"yes"; then + for ac_func in _qfpclass +do : + ac_fn_c_check_func "$LINENO" "_qfpclass" "ac_cv_func__qfpclass" +if test "x$ac_cv_func__qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__QFPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypot declaration" >&5 +$as_echo_n "checking for hypot declaration... " >&6; } + if test x${glibcxx_cv_func_hypot_use+set} != xset; then + if ${glibcxx_cv_func_hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypot_use=yes +else + glibcxx_cv_func_hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypot_use" >&5 +$as_echo "$glibcxx_cv_func_hypot_use" >&6; } + + if test x$glibcxx_cv_func_hypot_use = x"yes"; then + for ac_func in hypot +do : + ac_fn_c_check_func "$LINENO" "hypot" "ac_cv_func_hypot" +if test "x$ac_cv_func_hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOT 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypot declaration" >&5 +$as_echo_n "checking for _hypot declaration... " >&6; } + if test x${glibcxx_cv_func__hypot_use+set} != xset; then + if ${glibcxx_cv_func__hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypot_use=yes +else + glibcxx_cv_func__hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypot_use" >&5 +$as_echo "$glibcxx_cv_func__hypot_use" >&6; } + + if test x$glibcxx_cv_func__hypot_use = x"yes"; then + for ac_func in _hypot +do : + ac_fn_c_check_func "$LINENO" "_hypot" "ac_cv_func__hypot" +if test "x$ac_cv_func__hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOT 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float trig functions" >&5 +$as_echo_n "checking for float trig functions... " >&6; } + if ${glibcxx_cv_func_float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosf (0); asinf (0); atanf (0); cosf (0); sinf (0); tanf (0); coshf (0); sinhf (0); tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_trig_use=yes +else + glibcxx_cv_func_float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_trig_use" >&5 +$as_echo "$glibcxx_cv_func_float_trig_use" >&6; } + if test x$glibcxx_cv_func_float_trig_use = x"yes"; then + for ac_func in acosf asinf atanf cosf sinf tanf coshf sinhf tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float trig functions" >&5 +$as_echo_n "checking for _float trig functions... " >&6; } + if ${glibcxx_cv_func__float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosf (0); _asinf (0); _atanf (0); _cosf (0); _sinf (0); _tanf (0); _coshf (0); _sinhf (0); _tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_trig_use=yes +else + glibcxx_cv_func__float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_trig_use" >&5 +$as_echo "$glibcxx_cv_func__float_trig_use" >&6; } + if test x$glibcxx_cv_func__float_trig_use = x"yes"; then + for ac_func in _acosf _asinf _atanf _cosf _sinf _tanf _coshf _sinhf _tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float round functions" >&5 +$as_echo_n "checking for float round functions... " >&6; } + if ${glibcxx_cv_func_float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceilf (0); floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_round_use=yes +else + glibcxx_cv_func_float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_round_use" >&5 +$as_echo "$glibcxx_cv_func_float_round_use" >&6; } + if test x$glibcxx_cv_func_float_round_use = x"yes"; then + for ac_func in ceilf floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float round functions" >&5 +$as_echo_n "checking for _float round functions... " >&6; } + if ${glibcxx_cv_func__float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceilf (0); _floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_round_use=yes +else + glibcxx_cv_func__float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_round_use" >&5 +$as_echo "$glibcxx_cv_func__float_round_use" >&6; } + if test x$glibcxx_cv_func__float_round_use = x"yes"; then + for ac_func in _ceilf _floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expf declaration" >&5 +$as_echo_n "checking for expf declaration... " >&6; } + if test x${glibcxx_cv_func_expf_use+set} != xset; then + if ${glibcxx_cv_func_expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expf_use=yes +else + glibcxx_cv_func_expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expf_use" >&5 +$as_echo "$glibcxx_cv_func_expf_use" >&6; } + + if test x$glibcxx_cv_func_expf_use = x"yes"; then + for ac_func in expf +do : + ac_fn_c_check_func "$LINENO" "expf" "ac_cv_func_expf" +if test "x$ac_cv_func_expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expf declaration" >&5 +$as_echo_n "checking for _expf declaration... " >&6; } + if test x${glibcxx_cv_func__expf_use+set} != xset; then + if ${glibcxx_cv_func__expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expf_use=yes +else + glibcxx_cv_func__expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expf_use" >&5 +$as_echo "$glibcxx_cv_func__expf_use" >&6; } + + if test x$glibcxx_cv_func__expf_use = x"yes"; then + for ac_func in _expf +do : + ac_fn_c_check_func "$LINENO" "_expf" "ac_cv_func__expf" +if test "x$ac_cv_func__expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanf declaration" >&5 +$as_echo_n "checking for isnanf declaration... " >&6; } + if test x${glibcxx_cv_func_isnanf_use+set} != xset; then + if ${glibcxx_cv_func_isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanf_use=yes +else + glibcxx_cv_func_isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanf_use" >&5 +$as_echo "$glibcxx_cv_func_isnanf_use" >&6; } + + if test x$glibcxx_cv_func_isnanf_use = x"yes"; then + for ac_func in isnanf +do : + ac_fn_c_check_func "$LINENO" "isnanf" "ac_cv_func_isnanf" +if test "x$ac_cv_func_isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanf declaration" >&5 +$as_echo_n "checking for _isnanf declaration... " >&6; } + if test x${glibcxx_cv_func__isnanf_use+set} != xset; then + if ${glibcxx_cv_func__isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanf_use=yes +else + glibcxx_cv_func__isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanf_use" >&5 +$as_echo "$glibcxx_cv_func__isnanf_use" >&6; } + + if test x$glibcxx_cv_func__isnanf_use = x"yes"; then + for ac_func in _isnanf +do : + ac_fn_c_check_func "$LINENO" "_isnanf" "ac_cv_func__isnanf" +if test "x$ac_cv_func__isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinff declaration" >&5 +$as_echo_n "checking for isinff declaration... " >&6; } + if test x${glibcxx_cv_func_isinff_use+set} != xset; then + if ${glibcxx_cv_func_isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinff_use=yes +else + glibcxx_cv_func_isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinff_use" >&5 +$as_echo "$glibcxx_cv_func_isinff_use" >&6; } + + if test x$glibcxx_cv_func_isinff_use = x"yes"; then + for ac_func in isinff +do : + ac_fn_c_check_func "$LINENO" "isinff" "ac_cv_func_isinff" +if test "x$ac_cv_func_isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinff declaration" >&5 +$as_echo_n "checking for _isinff declaration... " >&6; } + if test x${glibcxx_cv_func__isinff_use+set} != xset; then + if ${glibcxx_cv_func__isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinff_use=yes +else + glibcxx_cv_func__isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinff_use" >&5 +$as_echo "$glibcxx_cv_func__isinff_use" >&6; } + + if test x$glibcxx_cv_func__isinff_use = x"yes"; then + for ac_func in _isinff +do : + ac_fn_c_check_func "$LINENO" "_isinff" "ac_cv_func__isinff" +if test "x$ac_cv_func__isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f declaration" >&5 +$as_echo_n "checking for atan2f declaration... " >&6; } + if test x${glibcxx_cv_func_atan2f_use+set} != xset; then + if ${glibcxx_cv_func_atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2f_use=yes +else + glibcxx_cv_func_atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2f_use" >&5 +$as_echo "$glibcxx_cv_func_atan2f_use" >&6; } + + if test x$glibcxx_cv_func_atan2f_use = x"yes"; then + for ac_func in atan2f +do : + ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2f declaration" >&5 +$as_echo_n "checking for _atan2f declaration... " >&6; } + if test x${glibcxx_cv_func__atan2f_use+set} != xset; then + if ${glibcxx_cv_func__atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2f_use=yes +else + glibcxx_cv_func__atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2f_use" >&5 +$as_echo "$glibcxx_cv_func__atan2f_use" >&6; } + + if test x$glibcxx_cv_func__atan2f_use = x"yes"; then + for ac_func in _atan2f +do : + ac_fn_c_check_func "$LINENO" "_atan2f" "ac_cv_func__atan2f" +if test "x$ac_cv_func__atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsf declaration" >&5 +$as_echo_n "checking for fabsf declaration... " >&6; } + if test x${glibcxx_cv_func_fabsf_use+set} != xset; then + if ${glibcxx_cv_func_fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsf_use=yes +else + glibcxx_cv_func_fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsf_use" >&5 +$as_echo "$glibcxx_cv_func_fabsf_use" >&6; } + + if test x$glibcxx_cv_func_fabsf_use = x"yes"; then + for ac_func in fabsf +do : + ac_fn_c_check_func "$LINENO" "fabsf" "ac_cv_func_fabsf" +if test "x$ac_cv_func_fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsf declaration" >&5 +$as_echo_n "checking for _fabsf declaration... " >&6; } + if test x${glibcxx_cv_func__fabsf_use+set} != xset; then + if ${glibcxx_cv_func__fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsf_use=yes +else + glibcxx_cv_func__fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsf_use" >&5 +$as_echo "$glibcxx_cv_func__fabsf_use" >&6; } + + if test x$glibcxx_cv_func__fabsf_use = x"yes"; then + for ac_func in _fabsf +do : + ac_fn_c_check_func "$LINENO" "_fabsf" "ac_cv_func__fabsf" +if test "x$ac_cv_func__fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf declaration" >&5 +$as_echo_n "checking for fmodf declaration... " >&6; } + if test x${glibcxx_cv_func_fmodf_use+set} != xset; then + if ${glibcxx_cv_func_fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodf_use=yes +else + glibcxx_cv_func_fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodf_use" >&5 +$as_echo "$glibcxx_cv_func_fmodf_use" >&6; } + + if test x$glibcxx_cv_func_fmodf_use = x"yes"; then + for ac_func in fmodf +do : + ac_fn_c_check_func "$LINENO" "fmodf" "ac_cv_func_fmodf" +if test "x$ac_cv_func_fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodf declaration" >&5 +$as_echo_n "checking for _fmodf declaration... " >&6; } + if test x${glibcxx_cv_func__fmodf_use+set} != xset; then + if ${glibcxx_cv_func__fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodf_use=yes +else + glibcxx_cv_func__fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodf_use" >&5 +$as_echo "$glibcxx_cv_func__fmodf_use" >&6; } + + if test x$glibcxx_cv_func__fmodf_use = x"yes"; then + for ac_func in _fmodf +do : + ac_fn_c_check_func "$LINENO" "_fmodf" "ac_cv_func__fmodf" +if test "x$ac_cv_func__fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } + if test x${glibcxx_cv_func_frexpf_use+set} != xset; then + if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + + if test x$glibcxx_cv_func_frexpf_use = x"yes"; then + for ac_func in frexpf +do : + ac_fn_c_check_func "$LINENO" "frexpf" "ac_cv_func_frexpf" +if test "x$ac_cv_func_frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpf declaration" >&5 +$as_echo_n "checking for _frexpf declaration... " >&6; } + if test x${glibcxx_cv_func__frexpf_use+set} != xset; then + if ${glibcxx_cv_func__frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpf_use=yes +else + glibcxx_cv_func__frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpf_use" >&5 +$as_echo "$glibcxx_cv_func__frexpf_use" >&6; } + + if test x$glibcxx_cv_func__frexpf_use = x"yes"; then + for ac_func in _frexpf +do : + ac_fn_c_check_func "$LINENO" "_frexpf" "ac_cv_func__frexpf" +if test "x$ac_cv_func__frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } + if test x${glibcxx_cv_func_hypotf_use+set} != xset; then + if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + + if test x$glibcxx_cv_func_hypotf_use = x"yes"; then + for ac_func in hypotf +do : + ac_fn_c_check_func "$LINENO" "hypotf" "ac_cv_func_hypotf" +if test "x$ac_cv_func_hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotf declaration" >&5 +$as_echo_n "checking for _hypotf declaration... " >&6; } + if test x${glibcxx_cv_func__hypotf_use+set} != xset; then + if ${glibcxx_cv_func__hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotf_use=yes +else + glibcxx_cv_func__hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotf_use" >&5 +$as_echo "$glibcxx_cv_func__hypotf_use" >&6; } + + if test x$glibcxx_cv_func__hypotf_use = x"yes"; then + for ac_func in _hypotf +do : + ac_fn_c_check_func "$LINENO" "_hypotf" "ac_cv_func__hypotf" +if test "x$ac_cv_func__hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpf_use+set} != xset; then + if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + + if test x$glibcxx_cv_func_ldexpf_use = x"yes"; then + for ac_func in ldexpf +do : + ac_fn_c_check_func "$LINENO" "ldexpf" "ac_cv_func_ldexpf" +if test "x$ac_cv_func_ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpf declaration" >&5 +$as_echo_n "checking for _ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpf_use+set} != xset; then + if ${glibcxx_cv_func__ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpf_use=yes +else + glibcxx_cv_func__ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpf_use" >&6; } + + if test x$glibcxx_cv_func__ldexpf_use = x"yes"; then + for ac_func in _ldexpf +do : + ac_fn_c_check_func "$LINENO" "_ldexpf" "ac_cv_func__ldexpf" +if test "x$ac_cv_func__ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logf declaration" >&5 +$as_echo_n "checking for logf declaration... " >&6; } + if test x${glibcxx_cv_func_logf_use+set} != xset; then + if ${glibcxx_cv_func_logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logf_use=yes +else + glibcxx_cv_func_logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logf_use" >&5 +$as_echo "$glibcxx_cv_func_logf_use" >&6; } + + if test x$glibcxx_cv_func_logf_use = x"yes"; then + for ac_func in logf +do : + ac_fn_c_check_func "$LINENO" "logf" "ac_cv_func_logf" +if test "x$ac_cv_func_logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logf declaration" >&5 +$as_echo_n "checking for _logf declaration... " >&6; } + if test x${glibcxx_cv_func__logf_use+set} != xset; then + if ${glibcxx_cv_func__logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logf_use=yes +else + glibcxx_cv_func__logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logf_use" >&5 +$as_echo "$glibcxx_cv_func__logf_use" >&6; } + + if test x$glibcxx_cv_func__logf_use = x"yes"; then + for ac_func in _logf +do : + ac_fn_c_check_func "$LINENO" "_logf" "ac_cv_func__logf" +if test "x$ac_cv_func__logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10f declaration" >&5 +$as_echo_n "checking for log10f declaration... " >&6; } + if test x${glibcxx_cv_func_log10f_use+set} != xset; then + if ${glibcxx_cv_func_log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10f_use=yes +else + glibcxx_cv_func_log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10f_use" >&5 +$as_echo "$glibcxx_cv_func_log10f_use" >&6; } + + if test x$glibcxx_cv_func_log10f_use = x"yes"; then + for ac_func in log10f +do : + ac_fn_c_check_func "$LINENO" "log10f" "ac_cv_func_log10f" +if test "x$ac_cv_func_log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10f declaration" >&5 +$as_echo_n "checking for _log10f declaration... " >&6; } + if test x${glibcxx_cv_func__log10f_use+set} != xset; then + if ${glibcxx_cv_func__log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10f_use=yes +else + glibcxx_cv_func__log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10f_use" >&5 +$as_echo "$glibcxx_cv_func__log10f_use" >&6; } + + if test x$glibcxx_cv_func__log10f_use = x"yes"; then + for ac_func in _log10f +do : + ac_fn_c_check_func "$LINENO" "_log10f" "ac_cv_func__log10f" +if test "x$ac_cv_func__log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } + if test x${glibcxx_cv_func_modff_use+set} != xset; then + if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + + if test x$glibcxx_cv_func_modff_use = x"yes"; then + for ac_func in modff +do : + ac_fn_c_check_func "$LINENO" "modff" "ac_cv_func_modff" +if test "x$ac_cv_func_modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modff declaration" >&5 +$as_echo_n "checking for _modff declaration... " >&6; } + if test x${glibcxx_cv_func__modff_use+set} != xset; then + if ${glibcxx_cv_func__modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modff_use=yes +else + glibcxx_cv_func__modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modff_use" >&5 +$as_echo "$glibcxx_cv_func__modff_use" >&6; } + + if test x$glibcxx_cv_func__modff_use = x"yes"; then + for ac_func in _modff +do : + ac_fn_c_check_func "$LINENO" "_modff" "ac_cv_func__modff" +if test "x$ac_cv_func__modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modf declaration" >&5 +$as_echo_n "checking for modf declaration... " >&6; } + if test x${glibcxx_cv_func_modf_use+set} != xset; then + if ${glibcxx_cv_func_modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modf_use=yes +else + glibcxx_cv_func_modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modf_use" >&5 +$as_echo "$glibcxx_cv_func_modf_use" >&6; } + + if test x$glibcxx_cv_func_modf_use = x"yes"; then + for ac_func in modf +do : + ac_fn_c_check_func "$LINENO" "modf" "ac_cv_func_modf" +if test "x$ac_cv_func_modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modf declaration" >&5 +$as_echo_n "checking for _modf declaration... " >&6; } + if test x${glibcxx_cv_func__modf_use+set} != xset; then + if ${glibcxx_cv_func__modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modf_use=yes +else + glibcxx_cv_func__modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modf_use" >&5 +$as_echo "$glibcxx_cv_func__modf_use" >&6; } + + if test x$glibcxx_cv_func__modf_use = x"yes"; then + for ac_func in _modf +do : + ac_fn_c_check_func "$LINENO" "_modf" "ac_cv_func__modf" +if test "x$ac_cv_func__modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powf declaration" >&5 +$as_echo_n "checking for powf declaration... " >&6; } + if test x${glibcxx_cv_func_powf_use+set} != xset; then + if ${glibcxx_cv_func_powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powf_use=yes +else + glibcxx_cv_func_powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powf_use" >&5 +$as_echo "$glibcxx_cv_func_powf_use" >&6; } + + if test x$glibcxx_cv_func_powf_use = x"yes"; then + for ac_func in powf +do : + ac_fn_c_check_func "$LINENO" "powf" "ac_cv_func_powf" +if test "x$ac_cv_func_powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powf declaration" >&5 +$as_echo_n "checking for _powf declaration... " >&6; } + if test x${glibcxx_cv_func__powf_use+set} != xset; then + if ${glibcxx_cv_func__powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powf_use=yes +else + glibcxx_cv_func__powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powf_use" >&5 +$as_echo "$glibcxx_cv_func__powf_use" >&6; } + + if test x$glibcxx_cv_func__powf_use = x"yes"; then + for ac_func in _powf +do : + ac_fn_c_check_func "$LINENO" "_powf" "ac_cv_func__powf" +if test "x$ac_cv_func__powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtf declaration" >&5 +$as_echo_n "checking for sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtf_use+set} != xset; then + if ${glibcxx_cv_func_sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtf_use=yes +else + glibcxx_cv_func_sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtf_use" >&6; } + + if test x$glibcxx_cv_func_sqrtf_use = x"yes"; then + for ac_func in sqrtf +do : + ac_fn_c_check_func "$LINENO" "sqrtf" "ac_cv_func_sqrtf" +if test "x$ac_cv_func_sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtf declaration" >&5 +$as_echo_n "checking for _sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtf_use+set} != xset; then + if ${glibcxx_cv_func__sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtf_use=yes +else + glibcxx_cv_func__sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtf_use" >&6; } + + if test x$glibcxx_cv_func__sqrtf_use = x"yes"; then + for ac_func in _sqrtf +do : + ac_fn_c_check_func "$LINENO" "_sqrtf" "ac_cv_func__sqrtf" +if test "x$ac_cv_func__sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosf declaration" >&5 +$as_echo_n "checking for sincosf declaration... " >&6; } + if test x${glibcxx_cv_func_sincosf_use+set} != xset; then + if ${glibcxx_cv_func_sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosf_use=yes +else + glibcxx_cv_func_sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosf_use" >&5 +$as_echo "$glibcxx_cv_func_sincosf_use" >&6; } + + if test x$glibcxx_cv_func_sincosf_use = x"yes"; then + for ac_func in sincosf +do : + ac_fn_c_check_func "$LINENO" "sincosf" "ac_cv_func_sincosf" +if test "x$ac_cv_func_sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosf declaration" >&5 +$as_echo_n "checking for _sincosf declaration... " >&6; } + if test x${glibcxx_cv_func__sincosf_use+set} != xset; then + if ${glibcxx_cv_func__sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosf_use=yes +else + glibcxx_cv_func__sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosf_use" >&5 +$as_echo "$glibcxx_cv_func__sincosf_use" >&6; } + + if test x$glibcxx_cv_func__sincosf_use = x"yes"; then + for ac_func in _sincosf +do : + ac_fn_c_check_func "$LINENO" "_sincosf" "ac_cv_func__sincosf" +if test "x$ac_cv_func__sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitef declaration" >&5 +$as_echo_n "checking for finitef declaration... " >&6; } + if test x${glibcxx_cv_func_finitef_use+set} != xset; then + if ${glibcxx_cv_func_finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitef_use=yes +else + glibcxx_cv_func_finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitef_use" >&5 +$as_echo "$glibcxx_cv_func_finitef_use" >&6; } + + if test x$glibcxx_cv_func_finitef_use = x"yes"; then + for ac_func in finitef +do : + ac_fn_c_check_func "$LINENO" "finitef" "ac_cv_func_finitef" +if test "x$ac_cv_func_finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitef declaration" >&5 +$as_echo_n "checking for _finitef declaration... " >&6; } + if test x${glibcxx_cv_func__finitef_use+set} != xset; then + if ${glibcxx_cv_func__finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitef_use=yes +else + glibcxx_cv_func__finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitef_use" >&5 +$as_echo "$glibcxx_cv_func__finitef_use" >&6; } + + if test x$glibcxx_cv_func__finitef_use = x"yes"; then + for ac_func in _finitef +do : + ac_fn_c_check_func "$LINENO" "_finitef" "ac_cv_func__finitef" +if test "x$ac_cv_func__finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double trig functions" >&5 +$as_echo_n "checking for long double trig functions... " >&6; } + if ${glibcxx_cv_func_long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosl (0); asinl (0); atanl (0); cosl (0); sinl (0); tanl (0); coshl (0); sinhl (0); tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_trig_use=yes +else + glibcxx_cv_func_long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_trig_use" >&6; } + if test x$glibcxx_cv_func_long_double_trig_use = x"yes"; then + for ac_func in acosl asinl atanl cosl sinl tanl coshl sinhl tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double trig functions" >&5 +$as_echo_n "checking for _long double trig functions... " >&6; } + if ${glibcxx_cv_func__long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosl (0); _asinl (0); _atanl (0); _cosl (0); _sinl (0); _tanl (0); _coshl (0); _sinhl (0); _tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_trig_use=yes +else + glibcxx_cv_func__long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_trig_use" >&6; } + if test x$glibcxx_cv_func__long_double_trig_use = x"yes"; then + for ac_func in _acosl _asinl _atanl _cosl _sinl _tanl _coshl _sinhl _tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double round functions" >&5 +$as_echo_n "checking for long double round functions... " >&6; } + if ${glibcxx_cv_func_long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceill (0); floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_round_use=yes +else + glibcxx_cv_func_long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_round_use" >&6; } + if test x$glibcxx_cv_func_long_double_round_use = x"yes"; then + for ac_func in ceill floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double round functions" >&5 +$as_echo_n "checking for _long double round functions... " >&6; } + if ${glibcxx_cv_func__long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceill (0); _floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_round_use=yes +else + glibcxx_cv_func__long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_round_use" >&6; } + if test x$glibcxx_cv_func__long_double_round_use = x"yes"; then + for ac_func in _ceill _floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanl declaration" >&5 +$as_echo_n "checking for isnanl declaration... " >&6; } + if test x${glibcxx_cv_func_isnanl_use+set} != xset; then + if ${glibcxx_cv_func_isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanl_use=yes +else + glibcxx_cv_func_isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanl_use" >&5 +$as_echo "$glibcxx_cv_func_isnanl_use" >&6; } + + if test x$glibcxx_cv_func_isnanl_use = x"yes"; then + for ac_func in isnanl +do : + ac_fn_c_check_func "$LINENO" "isnanl" "ac_cv_func_isnanl" +if test "x$ac_cv_func_isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanl declaration" >&5 +$as_echo_n "checking for _isnanl declaration... " >&6; } + if test x${glibcxx_cv_func__isnanl_use+set} != xset; then + if ${glibcxx_cv_func__isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanl_use=yes +else + glibcxx_cv_func__isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanl_use" >&5 +$as_echo "$glibcxx_cv_func__isnanl_use" >&6; } + + if test x$glibcxx_cv_func__isnanl_use = x"yes"; then + for ac_func in _isnanl +do : + ac_fn_c_check_func "$LINENO" "_isnanl" "ac_cv_func__isnanl" +if test "x$ac_cv_func__isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinfl declaration" >&5 +$as_echo_n "checking for isinfl declaration... " >&6; } + if test x${glibcxx_cv_func_isinfl_use+set} != xset; then + if ${glibcxx_cv_func_isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinfl_use=yes +else + glibcxx_cv_func_isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinfl_use" >&5 +$as_echo "$glibcxx_cv_func_isinfl_use" >&6; } + + if test x$glibcxx_cv_func_isinfl_use = x"yes"; then + for ac_func in isinfl +do : + ac_fn_c_check_func "$LINENO" "isinfl" "ac_cv_func_isinfl" +if test "x$ac_cv_func_isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinfl declaration" >&5 +$as_echo_n "checking for _isinfl declaration... " >&6; } + if test x${glibcxx_cv_func__isinfl_use+set} != xset; then + if ${glibcxx_cv_func__isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinfl_use=yes +else + glibcxx_cv_func__isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinfl_use" >&5 +$as_echo "$glibcxx_cv_func__isinfl_use" >&6; } + + if test x$glibcxx_cv_func__isinfl_use = x"yes"; then + for ac_func in _isinfl +do : + ac_fn_c_check_func "$LINENO" "_isinfl" "ac_cv_func__isinfl" +if test "x$ac_cv_func__isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } + if test x${glibcxx_cv_func_atan2l_use+set} != xset; then + if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + + if test x$glibcxx_cv_func_atan2l_use = x"yes"; then + for ac_func in atan2l +do : + ac_fn_c_check_func "$LINENO" "atan2l" "ac_cv_func_atan2l" +if test "x$ac_cv_func_atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2l declaration" >&5 +$as_echo_n "checking for _atan2l declaration... " >&6; } + if test x${glibcxx_cv_func__atan2l_use+set} != xset; then + if ${glibcxx_cv_func__atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2l_use=yes +else + glibcxx_cv_func__atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2l_use" >&5 +$as_echo "$glibcxx_cv_func__atan2l_use" >&6; } + + if test x$glibcxx_cv_func__atan2l_use = x"yes"; then + for ac_func in _atan2l +do : + ac_fn_c_check_func "$LINENO" "_atan2l" "ac_cv_func__atan2l" +if test "x$ac_cv_func__atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } + if test x${glibcxx_cv_func_expl_use+set} != xset; then + if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + + if test x$glibcxx_cv_func_expl_use = x"yes"; then + for ac_func in expl +do : + ac_fn_c_check_func "$LINENO" "expl" "ac_cv_func_expl" +if test "x$ac_cv_func_expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expl declaration" >&5 +$as_echo_n "checking for _expl declaration... " >&6; } + if test x${glibcxx_cv_func__expl_use+set} != xset; then + if ${glibcxx_cv_func__expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expl_use=yes +else + glibcxx_cv_func__expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expl_use" >&5 +$as_echo "$glibcxx_cv_func__expl_use" >&6; } + + if test x$glibcxx_cv_func__expl_use = x"yes"; then + for ac_func in _expl +do : + ac_fn_c_check_func "$LINENO" "_expl" "ac_cv_func__expl" +if test "x$ac_cv_func__expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } + if test x${glibcxx_cv_func_fabsl_use+set} != xset; then + if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + + if test x$glibcxx_cv_func_fabsl_use = x"yes"; then + for ac_func in fabsl +do : + ac_fn_c_check_func "$LINENO" "fabsl" "ac_cv_func_fabsl" +if test "x$ac_cv_func_fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsl declaration" >&5 +$as_echo_n "checking for _fabsl declaration... " >&6; } + if test x${glibcxx_cv_func__fabsl_use+set} != xset; then + if ${glibcxx_cv_func__fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsl_use=yes +else + glibcxx_cv_func__fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsl_use" >&5 +$as_echo "$glibcxx_cv_func__fabsl_use" >&6; } + + if test x$glibcxx_cv_func__fabsl_use = x"yes"; then + for ac_func in _fabsl +do : + ac_fn_c_check_func "$LINENO" "_fabsl" "ac_cv_func__fabsl" +if test "x$ac_cv_func__fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } + if test x${glibcxx_cv_func_fmodl_use+set} != xset; then + if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + + if test x$glibcxx_cv_func_fmodl_use = x"yes"; then + for ac_func in fmodl +do : + ac_fn_c_check_func "$LINENO" "fmodl" "ac_cv_func_fmodl" +if test "x$ac_cv_func_fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodl declaration" >&5 +$as_echo_n "checking for _fmodl declaration... " >&6; } + if test x${glibcxx_cv_func__fmodl_use+set} != xset; then + if ${glibcxx_cv_func__fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodl_use=yes +else + glibcxx_cv_func__fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodl_use" >&5 +$as_echo "$glibcxx_cv_func__fmodl_use" >&6; } + + if test x$glibcxx_cv_func__fmodl_use = x"yes"; then + for ac_func in _fmodl +do : + ac_fn_c_check_func "$LINENO" "_fmodl" "ac_cv_func__fmodl" +if test "x$ac_cv_func__fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } + if test x${glibcxx_cv_func_frexpl_use+set} != xset; then + if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + + if test x$glibcxx_cv_func_frexpl_use = x"yes"; then + for ac_func in frexpl +do : + ac_fn_c_check_func "$LINENO" "frexpl" "ac_cv_func_frexpl" +if test "x$ac_cv_func_frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpl declaration" >&5 +$as_echo_n "checking for _frexpl declaration... " >&6; } + if test x${glibcxx_cv_func__frexpl_use+set} != xset; then + if ${glibcxx_cv_func__frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpl_use=yes +else + glibcxx_cv_func__frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpl_use" >&5 +$as_echo "$glibcxx_cv_func__frexpl_use" >&6; } + + if test x$glibcxx_cv_func__frexpl_use = x"yes"; then + for ac_func in _frexpl +do : + ac_fn_c_check_func "$LINENO" "_frexpl" "ac_cv_func__frexpl" +if test "x$ac_cv_func__frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } + if test x${glibcxx_cv_func_hypotl_use+set} != xset; then + if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + + if test x$glibcxx_cv_func_hypotl_use = x"yes"; then + for ac_func in hypotl +do : + ac_fn_c_check_func "$LINENO" "hypotl" "ac_cv_func_hypotl" +if test "x$ac_cv_func_hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotl declaration" >&5 +$as_echo_n "checking for _hypotl declaration... " >&6; } + if test x${glibcxx_cv_func__hypotl_use+set} != xset; then + if ${glibcxx_cv_func__hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotl_use=yes +else + glibcxx_cv_func__hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotl_use" >&5 +$as_echo "$glibcxx_cv_func__hypotl_use" >&6; } + + if test x$glibcxx_cv_func__hypotl_use = x"yes"; then + for ac_func in _hypotl +do : + ac_fn_c_check_func "$LINENO" "_hypotl" "ac_cv_func__hypotl" +if test "x$ac_cv_func__hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpl_use+set} != xset; then + if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + + if test x$glibcxx_cv_func_ldexpl_use = x"yes"; then + for ac_func in ldexpl +do : + ac_fn_c_check_func "$LINENO" "ldexpl" "ac_cv_func_ldexpl" +if test "x$ac_cv_func_ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpl declaration" >&5 +$as_echo_n "checking for _ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpl_use+set} != xset; then + if ${glibcxx_cv_func__ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpl_use=yes +else + glibcxx_cv_func__ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpl_use" >&6; } + + if test x$glibcxx_cv_func__ldexpl_use = x"yes"; then + for ac_func in _ldexpl +do : + ac_fn_c_check_func "$LINENO" "_ldexpl" "ac_cv_func__ldexpl" +if test "x$ac_cv_func__ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } + if test x${glibcxx_cv_func_logl_use+set} != xset; then + if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + + if test x$glibcxx_cv_func_logl_use = x"yes"; then + for ac_func in logl +do : + ac_fn_c_check_func "$LINENO" "logl" "ac_cv_func_logl" +if test "x$ac_cv_func_logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logl declaration" >&5 +$as_echo_n "checking for _logl declaration... " >&6; } + if test x${glibcxx_cv_func__logl_use+set} != xset; then + if ${glibcxx_cv_func__logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logl_use=yes +else + glibcxx_cv_func__logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logl_use" >&5 +$as_echo "$glibcxx_cv_func__logl_use" >&6; } + + if test x$glibcxx_cv_func__logl_use = x"yes"; then + for ac_func in _logl +do : + ac_fn_c_check_func "$LINENO" "_logl" "ac_cv_func__logl" +if test "x$ac_cv_func__logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } + if test x${glibcxx_cv_func_log10l_use+set} != xset; then + if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + + if test x$glibcxx_cv_func_log10l_use = x"yes"; then + for ac_func in log10l +do : + ac_fn_c_check_func "$LINENO" "log10l" "ac_cv_func_log10l" +if test "x$ac_cv_func_log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10l declaration" >&5 +$as_echo_n "checking for _log10l declaration... " >&6; } + if test x${glibcxx_cv_func__log10l_use+set} != xset; then + if ${glibcxx_cv_func__log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10l_use=yes +else + glibcxx_cv_func__log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10l_use" >&5 +$as_echo "$glibcxx_cv_func__log10l_use" >&6; } + + if test x$glibcxx_cv_func__log10l_use = x"yes"; then + for ac_func in _log10l +do : + ac_fn_c_check_func "$LINENO" "_log10l" "ac_cv_func__log10l" +if test "x$ac_cv_func__log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } + if test x${glibcxx_cv_func_modfl_use+set} != xset; then + if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + + if test x$glibcxx_cv_func_modfl_use = x"yes"; then + for ac_func in modfl +do : + ac_fn_c_check_func "$LINENO" "modfl" "ac_cv_func_modfl" +if test "x$ac_cv_func_modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modfl declaration" >&5 +$as_echo_n "checking for _modfl declaration... " >&6; } + if test x${glibcxx_cv_func__modfl_use+set} != xset; then + if ${glibcxx_cv_func__modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modfl_use=yes +else + glibcxx_cv_func__modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modfl_use" >&5 +$as_echo "$glibcxx_cv_func__modfl_use" >&6; } + + if test x$glibcxx_cv_func__modfl_use = x"yes"; then + for ac_func in _modfl +do : + ac_fn_c_check_func "$LINENO" "_modfl" "ac_cv_func__modfl" +if test "x$ac_cv_func__modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } + if test x${glibcxx_cv_func_powl_use+set} != xset; then + if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + + if test x$glibcxx_cv_func_powl_use = x"yes"; then + for ac_func in powl +do : + ac_fn_c_check_func "$LINENO" "powl" "ac_cv_func_powl" +if test "x$ac_cv_func_powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powl declaration" >&5 +$as_echo_n "checking for _powl declaration... " >&6; } + if test x${glibcxx_cv_func__powl_use+set} != xset; then + if ${glibcxx_cv_func__powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powl_use=yes +else + glibcxx_cv_func__powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powl_use" >&5 +$as_echo "$glibcxx_cv_func__powl_use" >&6; } + + if test x$glibcxx_cv_func__powl_use = x"yes"; then + for ac_func in _powl +do : + ac_fn_c_check_func "$LINENO" "_powl" "ac_cv_func__powl" +if test "x$ac_cv_func__powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtl_use+set} != xset; then + if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + + if test x$glibcxx_cv_func_sqrtl_use = x"yes"; then + for ac_func in sqrtl +do : + ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl" +if test "x$ac_cv_func_sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtl declaration" >&5 +$as_echo_n "checking for _sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtl_use+set} != xset; then + if ${glibcxx_cv_func__sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtl_use=yes +else + glibcxx_cv_func__sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtl_use" >&6; } + + if test x$glibcxx_cv_func__sqrtl_use = x"yes"; then + for ac_func in _sqrtl +do : + ac_fn_c_check_func "$LINENO" "_sqrtl" "ac_cv_func__sqrtl" +if test "x$ac_cv_func__sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosl declaration" >&5 +$as_echo_n "checking for sincosl declaration... " >&6; } + if test x${glibcxx_cv_func_sincosl_use+set} != xset; then + if ${glibcxx_cv_func_sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosl_use=yes +else + glibcxx_cv_func_sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosl_use" >&5 +$as_echo "$glibcxx_cv_func_sincosl_use" >&6; } + + if test x$glibcxx_cv_func_sincosl_use = x"yes"; then + for ac_func in sincosl +do : + ac_fn_c_check_func "$LINENO" "sincosl" "ac_cv_func_sincosl" +if test "x$ac_cv_func_sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosl declaration" >&5 +$as_echo_n "checking for _sincosl declaration... " >&6; } + if test x${glibcxx_cv_func__sincosl_use+set} != xset; then + if ${glibcxx_cv_func__sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosl_use=yes +else + glibcxx_cv_func__sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosl_use" >&5 +$as_echo "$glibcxx_cv_func__sincosl_use" >&6; } + + if test x$glibcxx_cv_func__sincosl_use = x"yes"; then + for ac_func in _sincosl +do : + ac_fn_c_check_func "$LINENO" "_sincosl" "ac_cv_func__sincosl" +if test "x$ac_cv_func__sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitel declaration" >&5 +$as_echo_n "checking for finitel declaration... " >&6; } + if test x${glibcxx_cv_func_finitel_use+set} != xset; then + if ${glibcxx_cv_func_finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitel_use=yes +else + glibcxx_cv_func_finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitel_use" >&5 +$as_echo "$glibcxx_cv_func_finitel_use" >&6; } + + if test x$glibcxx_cv_func_finitel_use = x"yes"; then + for ac_func in finitel +do : + ac_fn_c_check_func "$LINENO" "finitel" "ac_cv_func_finitel" +if test "x$ac_cv_func_finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitel declaration" >&5 +$as_echo_n "checking for _finitel declaration... " >&6; } + if test x${glibcxx_cv_func__finitel_use+set} != xset; then + if ${glibcxx_cv_func__finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitel_use=yes +else + glibcxx_cv_func__finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitel_use" >&5 +$as_echo "$glibcxx_cv_func__finitel_use" >&6; } + + if test x$glibcxx_cv_func__finitel_use = x"yes"; then + for ac_func in _finitel +do : + ac_fn_c_check_func "$LINENO" "_finitel" "ac_cv_func__finitel" +if test "x$ac_cv_func__finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEL 1 +_ACEOF + +fi +done + + fi + fi + + + + + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for at_quick_exit declaration" >&5 +$as_echo_n "checking for at_quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_at_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_at_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + at_quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_at_quick_exit_use=yes +else + glibcxx_cv_func_at_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_at_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_at_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_at_quick_exit_use = x"yes"; then + for ac_func in at_quick_exit +do : + ac_fn_c_check_func "$LINENO" "at_quick_exit" "ac_cv_func_at_quick_exit" +if test "x$ac_cv_func_at_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AT_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for quick_exit declaration" >&5 +$as_echo_n "checking for quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_quick_exit_use=yes +else + glibcxx_cv_func_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_quick_exit_use = x"yes"; then + for ac_func in quick_exit +do : + ac_fn_c_check_func "$LINENO" "quick_exit" "ac_cv_func_quick_exit" +if test "x$ac_cv_func_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtold declaration" >&5 +$as_echo_n "checking for strtold declaration... " >&6; } + if test x${glibcxx_cv_func_strtold_use+set} != xset; then + if ${glibcxx_cv_func_strtold_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtold(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtold_use=yes +else + glibcxx_cv_func_strtold_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtold_use" >&5 +$as_echo "$glibcxx_cv_func_strtold_use" >&6; } + if test x$glibcxx_cv_func_strtold_use = x"yes"; then + for ac_func in strtold +do : + ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold" +if test "x$ac_cv_func_strtold" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOLD 1 +_ACEOF + +fi +done + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtof declaration" >&5 +$as_echo_n "checking for strtof declaration... " >&6; } + if test x${glibcxx_cv_func_strtof_use+set} != xset; then + if ${glibcxx_cv_func_strtof_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtof(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtof_use=yes +else + glibcxx_cv_func_strtof_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtof_use" >&5 +$as_echo "$glibcxx_cv_func_strtof_use" >&6; } + if test x$glibcxx_cv_func_strtof_use = x"yes"; then + for ac_func in strtof +do : + ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof" +if test "x$ac_cv_func_strtof" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOF 1 +_ACEOF + +fi +done + + fi + + + + + CXXFLAGS="$ac_save_CXXFLAGS" + + + # For /dev/random and /dev/urandom for std::random_device. + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"/dev/random\" and \"/dev/urandom\" for std::random_device" >&5 +$as_echo_n "checking for \"/dev/random\" and \"/dev/urandom\" for std::random_device... " >&6; } + if ${glibcxx_cv_dev_random+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test -r /dev/random && test -r /dev/urandom; then + ## For MSys environment the test above is detected as false-positive + ## on mingw-targets. So disable it explicitly for them. + case ${target_os} in + *mingw*) glibcxx_cv_dev_random=no ;; + *) glibcxx_cv_dev_random=yes ;; + esac + else + glibcxx_cv_dev_random=no; + fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_dev_random" >&5 +$as_echo "$glibcxx_cv_dev_random" >&6; } + + if test x"$glibcxx_cv_dev_random" = x"yes"; then + +$as_echo "#define _GLIBCXX_USE_DEV_RANDOM 1" >>confdefs.h + + +$as_echo "#define _GLIBCXX_USE_RANDOM_TR1 1" >>confdefs.h + + fi + + + + # For TLS support. + + + # Check whether --enable-tls was given. +if test "${enable_tls+set}" = set; then : + enableval=$enable_tls; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable tls must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_tls=yes +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports thread-local storage" >&5 +$as_echo_n "checking whether the target supports thread-local storage... " >&6; } +if ${gcc_cv_have_tls+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + chktls_save_LDFLAGS="$LDFLAGS" + case $host in + *-*-linux* | -*-uclinuxfdpic*) + LDFLAGS="-shared -Wl,--no-undefined $LDFLAGS" + ;; + esac + chktls_save_CFLAGS="$CFLAGS" + CFLAGS="-fPIC $CFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int f() { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int f() { return a = b; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + gcc_cv_have_tls=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$chktls_save_CFLAGS" + LDFLAGS="$chktls_save_LDFLAGS" +else + gcc_cv_have_tls=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + chktls_save_LDFLAGS="$LDFLAGS" + LDFLAGS="-static $LDFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main() { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +else + gcc_cv_have_tls=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$chktls_save_LDFLAGS" + if test $gcc_cv_have_tls = yes; then + chktls_save_CFLAGS="$CFLAGS" + thread_CFLAGS=failed + for flag in '' '-pthread' '-lpthread'; do + CFLAGS="$flag $chktls_save_CFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + void *g(void *d) { return NULL; } +int +main () +{ +pthread_t t; pthread_create(&t,NULL,g,NULL); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + thread_CFLAGS="$flag" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "X$thread_CFLAGS" != Xfailed; then + break + fi + done + CFLAGS="$chktls_save_CFLAGS" + if test "X$thread_CFLAGS" != Xfailed; then + CFLAGS="$thread_CFLAGS $chktls_save_CFLAGS" + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + __thread int a; + static int *volatile a_in_other_thread; + static void * + thread_func (void *arg) + { + a_in_other_thread = &a; + return (void *)0; + } +int +main () +{ +pthread_t thread; + void *thread_retval; + int *volatile a_in_main_thread; + a_in_main_thread = &a; + if (pthread_create (&thread, (pthread_attr_t *)0, + thread_func, (void *)0)) + return 0; + if (pthread_join (thread, &thread_retval)) + return 0; + return (a_in_other_thread == a_in_main_thread); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$chktls_save_CFLAGS" + fi + fi +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_have_tls" >&5 +$as_echo "$gcc_cv_have_tls" >&6; } + if test "$enable_tls $gcc_cv_have_tls" = "yes yes"; then + +$as_echo "#define HAVE_TLS 1" >>confdefs.h + + fi + + for ac_func in __cxa_thread_atexit_impl __cxa_thread_atexit +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + for ac_func in aligned_alloc posix_memalign memalign _aligned_malloc +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + for ac_func in _wfopen +do : + ac_fn_c_check_func "$LINENO" "_wfopen" "ac_cv_func__wfopen" +if test "x$ac_cv_func__wfopen" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__WFOPEN 1 +_ACEOF + +fi +done + + + # C11 functions for C++17 library + for ac_func in timespec_get +do : + ac_fn_c_check_func "$LINENO" "timespec_get" "ac_cv_func_timespec_get" +if test "x$ac_cv_func_timespec_get" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_TIMESPEC_GET 1 +_ACEOF + +fi +done + + + # For Networking TS. + for ac_func in sockatmark +do : + ac_fn_c_check_func "$LINENO" "sockatmark" "ac_cv_func_sockatmark" +if test "x$ac_cv_func_sockatmark" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKATMARK 1 +_ACEOF + +fi +done + + + # Non-standard functions used by C++17 std::from_chars + for ac_func in uselocale +do : + ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale" +if test "x$ac_cv_func_uselocale" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_USELOCALE 1 +_ACEOF + +fi +done + + + # For iconv support. + + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 +$as_echo_n "checking for ld used by GCC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${acl_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$acl_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$acl_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${acl_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + acl_cv_prog_gnu_ld=yes +else + acl_cv_prog_gnu_ld=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_prog_gnu_ld" >&5 +$as_echo "$acl_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$acl_cv_prog_gnu_ld + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 +$as_echo_n "checking for shared library run path origin... " >&6; } +if ${acl_cv_rpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 +$as_echo "$acl_cv_rpath" >&6; } + wl="$acl_cv_wl" + libext="$acl_cv_libext" + shlibext="$acl_cv_shlibext" + hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + hardcode_direct="$acl_cv_hardcode_direct" + hardcode_minus_L="$acl_cv_hardcode_minus_L" + # Check whether --enable-rpath was given. +if test "${enable_rpath+set}" = set; then : + enableval=$enable_rpath; : +else + enable_rpath=yes +fi + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libiconv-prefix was given. +if test "${with_libiconv_prefix+set}" = set; then : + withval=$with_libiconv_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi + +fi + + +# Check whether --with-libiconv-type was given. +if test "${with_libiconv_type+set}" = set; then : + withval=$with_libiconv_type; with_libiconv_type=$withval +else + with_libiconv_type=auto +fi + + lib_type=`eval echo \$with_libiconv_type` + + LIBICONV= + LTLIBICONV= + INCICONV= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='iconv ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext" && test x$lib_type != xstatic; then + found_dir="$additional_libdir" + found_so="$additional_libdir/lib$name.$shlibext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + elif test x$lib_type != xshared; then + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext" && test x$lib_type != xstatic; then + found_dir="$dir" + found_so="$dir/lib$name.$shlibext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + elif test x$lib_type != xshared; then + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */lib | */lib/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" + ;; + esac + done + fi + else + if test "x$lib_type" = "xauto" || test "x$lib_type" = "xshared"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l:lib$name.$libext" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l:lib$name.$libext" + fi + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" + done + fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if ${am_cv_func_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + am_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCICONV" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + + if test "$am_cv_func_iconv" != yes && test -d ../libiconv; then + for _libs in .libs _libs; do + am_save_CPPFLAGS="$CPPFLAGS" + am_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS -I../libiconv/include" + LIBS="$LIBS ../libiconv/lib/$_libs/libiconv.a" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + INCICONV="-I../libiconv/include" + LIBICONV='${top_builddir}'/../libiconv/lib/$_libs/libiconv.a + LTLIBICONV='${top_builddir}'/../libiconv/lib/libiconv.la + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + LIBS="$am_save_LIBS" + if test "$am_cv_func_iconv" = "yes"; then + break + fi + done + fi + + if test "$am_cv_func_iconv" != yes; then + am_save_CPPFLAGS="$CPPFLAGS" + am_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $INCICONV" + LIBS="$LIBS $LIBICONV" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + fi + if test "$am_cv_lib_iconv" = yes; then + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 +$as_echo_n "checking how to link with libiconv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +$as_echo "$LIBICONV" >&6; } + else + LIBICONV= + LTLIBICONV= + fi + + + + if test "$am_cv_func_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 +$as_echo_n "checking for iconv declaration... " >&6; } + if ${am_cv_proto_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_cv_proto_iconv_arg1="" +else + am_cv_proto_iconv_arg1="const" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +fi + + am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- + }$am_cv_proto_iconv" >&5 +$as_echo "${ac_t:- + }$am_cv_proto_iconv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define ICONV_CONST $am_cv_proto_iconv_arg1 +_ACEOF + + fi + + +else + + # This lets us hard-code the functionality we know we'll have in the cross + # target environment. "Let" is a sugar-coated word placed on an especially + # dull and tedious hack, actually. + # + # Here's why GLIBCXX_CHECK_MATH_SUPPORT, and other autoconf macros + # that involve linking, can't be used: + # "cannot open sim-crt0.o" + # "cannot open crt0.o" + # etc. All this is because there currently exists no unified, consistent + # way for top level CC information to be passed down to target directories: + # newlib includes, newlib linking info, libgloss versus newlib crt0.o, etc. + # When all of that is done, all of this hokey, excessive AC_DEFINE junk for + # crosses can be removed. + + # If Canadian cross, then don't pick up tools from the build directory. + # Used only in GLIBCXX_EXPORT_INCLUDES. + if test -n "$with_cross_host" && + test x"$build_alias" != x"$with_cross_host" && + test x"$build" != x"$target"; + then + CANADIAN=yes + else + CANADIAN=no + fi + + # Construct crosses by hand, eliminating bits that need ld... + # GLIBCXX_CHECK_MATH_SUPPORT + + # First, test for "known" system libraries. We may be using newlib even + # on a hosted environment. + if test "x${with_newlib}" = "xyes"; then + os_include_dir="os/newlib" + $as_echo "#define HAVE_HYPOT 1" >>confdefs.h + + + # GLIBCXX_CHECK_STDLIB_SUPPORT + $as_echo "#define HAVE_STRTOF 1" >>confdefs.h + + + $as_echo "#define HAVE_ACOSF 1" >>confdefs.h + + $as_echo "#define HAVE_ASINF 1" >>confdefs.h + + $as_echo "#define HAVE_ATAN2F 1" >>confdefs.h + + $as_echo "#define HAVE_ATANF 1" >>confdefs.h + + $as_echo "#define HAVE_CEILF 1" >>confdefs.h + + $as_echo "#define HAVE_COSF 1" >>confdefs.h + + $as_echo "#define HAVE_COSHF 1" >>confdefs.h + + $as_echo "#define HAVE_EXPF 1" >>confdefs.h + + $as_echo "#define HAVE_FABSF 1" >>confdefs.h + + $as_echo "#define HAVE_FLOORF 1" >>confdefs.h + + $as_echo "#define HAVE_FMODF 1" >>confdefs.h + + $as_echo "#define HAVE_FREXPF 1" >>confdefs.h + + $as_echo "#define HAVE_LDEXPF 1" >>confdefs.h + + $as_echo "#define HAVE_LOG10F 1" >>confdefs.h + + $as_echo "#define HAVE_LOGF 1" >>confdefs.h + + $as_echo "#define HAVE_MODFF 1" >>confdefs.h + + $as_echo "#define HAVE_POWF 1" >>confdefs.h + + $as_echo "#define HAVE_SINF 1" >>confdefs.h + + $as_echo "#define HAVE_SINHF 1" >>confdefs.h + + $as_echo "#define HAVE_SQRTF 1" >>confdefs.h + + $as_echo "#define HAVE_TANF 1" >>confdefs.h + + $as_echo "#define HAVE_TANHF 1" >>confdefs.h + + + $as_echo "#define HAVE_ICONV 1" >>confdefs.h + + $as_echo "#define HAVE_MEMALIGN 1" >>confdefs.h + + else + +# Base decisions on target environment. +case "${host}" in + arm*-*-symbianelf*) + # This is a freestanding configuration; there is nothing to do here. + ;; + + avr*-*-*) + $as_echo "#define HAVE_ACOSF 1" >>confdefs.h + + $as_echo "#define HAVE_ASINF 1" >>confdefs.h + + $as_echo "#define HAVE_ATAN2F 1" >>confdefs.h + + $as_echo "#define HAVE_ATANF 1" >>confdefs.h + + $as_echo "#define HAVE_CEILF 1" >>confdefs.h + + $as_echo "#define HAVE_COSF 1" >>confdefs.h + + $as_echo "#define HAVE_COSHF 1" >>confdefs.h + + $as_echo "#define HAVE_EXPF 1" >>confdefs.h + + $as_echo "#define HAVE_FABSF 1" >>confdefs.h + + $as_echo "#define HAVE_FLOORF 1" >>confdefs.h + + $as_echo "#define HAVE_FMODF 1" >>confdefs.h + + $as_echo "#define HAVE_FREXPF 1" >>confdefs.h + + $as_echo "#define HAVE_SQRTF 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOTF 1" >>confdefs.h + + $as_echo "#define HAVE_LDEXPF 1" >>confdefs.h + + $as_echo "#define HAVE_LOG10F 1" >>confdefs.h + + $as_echo "#define HAVE_LOGF 1" >>confdefs.h + + $as_echo "#define HAVE_MODFF 1" >>confdefs.h + + $as_echo "#define HAVE_POWF 1" >>confdefs.h + + $as_echo "#define HAVE_SINF 1" >>confdefs.h + + $as_echo "#define HAVE_SINHF 1" >>confdefs.h + + $as_echo "#define HAVE_TANF 1" >>confdefs.h + + $as_echo "#define HAVE_TANHF 1" >>confdefs.h + + ;; + + mips*-sde-elf*) + # These definitions are for the SDE C library rather than newlib. + SECTION_FLAGS='-ffunction-sections -fdata-sections' + + + # All these tests are for C++; save the language and the compiler flags. + # The CXXFLAGS thing is suspicious, but based on similar bits previously + # found in GLIBCXX_CONFIGURE. + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + + # Check for -ffunction-sections -fdata-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for g++ that supports -ffunction-sections -fdata-sections" >&5 +$as_echo_n "checking for g++ that supports -ffunction-sections -fdata-sections... " >&6; } + CXXFLAGS='-g -Werror -ffunction-sections -fdata-sections' + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo; void bar() { }; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_fdsections=yes +else + ac_fdsections=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" + else + # this is the suspicious part + CXXFLAGS='' + fi + if test x"$ac_fdsections" = x"yes"; then + SECTION_FLAGS='-ffunction-sections -fdata-sections' + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_fdsections" >&5 +$as_echo "$ac_fdsections" >&6; } + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + libm="-lm" +fi + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $libm" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf declaration" >&5 +$as_echo_n "checking for isinf declaration... " >&6; } + if test x${glibcxx_cv_func_isinf_use+set} != xset; then + if ${glibcxx_cv_func_isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinf_use=yes +else + glibcxx_cv_func_isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinf_use" >&5 +$as_echo "$glibcxx_cv_func_isinf_use" >&6; } + + if test x$glibcxx_cv_func_isinf_use = x"yes"; then + for ac_func in isinf +do : + ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinf declaration" >&5 +$as_echo_n "checking for _isinf declaration... " >&6; } + if test x${glibcxx_cv_func__isinf_use+set} != xset; then + if ${glibcxx_cv_func__isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinf_use=yes +else + glibcxx_cv_func__isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinf_use" >&5 +$as_echo "$glibcxx_cv_func__isinf_use" >&6; } + + if test x$glibcxx_cv_func__isinf_use = x"yes"; then + for ac_func in _isinf +do : + ac_fn_c_check_func "$LINENO" "_isinf" "ac_cv_func__isinf" +if test "x$ac_cv_func__isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan declaration" >&5 +$as_echo_n "checking for isnan declaration... " >&6; } + if test x${glibcxx_cv_func_isnan_use+set} != xset; then + if ${glibcxx_cv_func_isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnan_use=yes +else + glibcxx_cv_func_isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnan_use" >&5 +$as_echo "$glibcxx_cv_func_isnan_use" >&6; } + + if test x$glibcxx_cv_func_isnan_use = x"yes"; then + for ac_func in isnan +do : + ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNAN 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnan declaration" >&5 +$as_echo_n "checking for _isnan declaration... " >&6; } + if test x${glibcxx_cv_func__isnan_use+set} != xset; then + if ${glibcxx_cv_func__isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnan_use=yes +else + glibcxx_cv_func__isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnan_use" >&5 +$as_echo "$glibcxx_cv_func__isnan_use" >&6; } + + if test x$glibcxx_cv_func__isnan_use = x"yes"; then + for ac_func in _isnan +do : + ac_fn_c_check_func "$LINENO" "_isnan" "ac_cv_func__isnan" +if test "x$ac_cv_func__isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNAN 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finite declaration" >&5 +$as_echo_n "checking for finite declaration... " >&6; } + if test x${glibcxx_cv_func_finite_use+set} != xset; then + if ${glibcxx_cv_func_finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finite_use=yes +else + glibcxx_cv_func_finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finite_use" >&5 +$as_echo "$glibcxx_cv_func_finite_use" >&6; } + + if test x$glibcxx_cv_func_finite_use = x"yes"; then + for ac_func in finite +do : + ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITE 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finite declaration" >&5 +$as_echo_n "checking for _finite declaration... " >&6; } + if test x${glibcxx_cv_func__finite_use+set} != xset; then + if ${glibcxx_cv_func__finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finite_use=yes +else + glibcxx_cv_func__finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finite_use" >&5 +$as_echo "$glibcxx_cv_func__finite_use" >&6; } + + if test x$glibcxx_cv_func__finite_use = x"yes"; then + for ac_func in _finite +do : + ac_fn_c_check_func "$LINENO" "_finite" "ac_cv_func__finite" +if test "x$ac_cv_func__finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITE 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincos declaration" >&5 +$as_echo_n "checking for sincos declaration... " >&6; } + if test x${glibcxx_cv_func_sincos_use+set} != xset; then + if ${glibcxx_cv_func_sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincos_use=yes +else + glibcxx_cv_func_sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincos_use" >&5 +$as_echo "$glibcxx_cv_func_sincos_use" >&6; } + + if test x$glibcxx_cv_func_sincos_use = x"yes"; then + for ac_func in sincos +do : + ac_fn_c_check_func "$LINENO" "sincos" "ac_cv_func_sincos" +if test "x$ac_cv_func_sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincos declaration" >&5 +$as_echo_n "checking for _sincos declaration... " >&6; } + if test x${glibcxx_cv_func__sincos_use+set} != xset; then + if ${glibcxx_cv_func__sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincos_use=yes +else + glibcxx_cv_func__sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincos_use" >&5 +$as_echo "$glibcxx_cv_func__sincos_use" >&6; } + + if test x$glibcxx_cv_func__sincos_use = x"yes"; then + for ac_func in _sincos +do : + ac_fn_c_check_func "$LINENO" "_sincos" "ac_cv_func__sincos" +if test "x$ac_cv_func__sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpclass declaration" >&5 +$as_echo_n "checking for fpclass declaration... " >&6; } + if test x${glibcxx_cv_func_fpclass_use+set} != xset; then + if ${glibcxx_cv_func_fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fpclass_use=yes +else + glibcxx_cv_func_fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fpclass_use" >&5 +$as_echo "$glibcxx_cv_func_fpclass_use" >&6; } + + if test x$glibcxx_cv_func_fpclass_use = x"yes"; then + for ac_func in fpclass +do : + ac_fn_c_check_func "$LINENO" "fpclass" "ac_cv_func_fpclass" +if test "x$ac_cv_func_fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fpclass declaration" >&5 +$as_echo_n "checking for _fpclass declaration... " >&6; } + if test x${glibcxx_cv_func__fpclass_use+set} != xset; then + if ${glibcxx_cv_func__fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fpclass_use=yes +else + glibcxx_cv_func__fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fpclass_use" >&5 +$as_echo "$glibcxx_cv_func__fpclass_use" >&6; } + + if test x$glibcxx_cv_func__fpclass_use = x"yes"; then + for ac_func in _fpclass +do : + ac_fn_c_check_func "$LINENO" "_fpclass" "ac_cv_func__fpclass" +if test "x$ac_cv_func__fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for qfpclass declaration" >&5 +$as_echo_n "checking for qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func_qfpclass_use+set} != xset; then + if ${glibcxx_cv_func_qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_qfpclass_use=yes +else + glibcxx_cv_func_qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func_qfpclass_use" >&6; } + + if test x$glibcxx_cv_func_qfpclass_use = x"yes"; then + for ac_func in qfpclass +do : + ac_fn_c_check_func "$LINENO" "qfpclass" "ac_cv_func_qfpclass" +if test "x$ac_cv_func_qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QFPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _qfpclass declaration" >&5 +$as_echo_n "checking for _qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func__qfpclass_use+set} != xset; then + if ${glibcxx_cv_func__qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__qfpclass_use=yes +else + glibcxx_cv_func__qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func__qfpclass_use" >&6; } + + if test x$glibcxx_cv_func__qfpclass_use = x"yes"; then + for ac_func in _qfpclass +do : + ac_fn_c_check_func "$LINENO" "_qfpclass" "ac_cv_func__qfpclass" +if test "x$ac_cv_func__qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__QFPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypot declaration" >&5 +$as_echo_n "checking for hypot declaration... " >&6; } + if test x${glibcxx_cv_func_hypot_use+set} != xset; then + if ${glibcxx_cv_func_hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypot_use=yes +else + glibcxx_cv_func_hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypot_use" >&5 +$as_echo "$glibcxx_cv_func_hypot_use" >&6; } + + if test x$glibcxx_cv_func_hypot_use = x"yes"; then + for ac_func in hypot +do : + ac_fn_c_check_func "$LINENO" "hypot" "ac_cv_func_hypot" +if test "x$ac_cv_func_hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOT 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypot declaration" >&5 +$as_echo_n "checking for _hypot declaration... " >&6; } + if test x${glibcxx_cv_func__hypot_use+set} != xset; then + if ${glibcxx_cv_func__hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypot_use=yes +else + glibcxx_cv_func__hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypot_use" >&5 +$as_echo "$glibcxx_cv_func__hypot_use" >&6; } + + if test x$glibcxx_cv_func__hypot_use = x"yes"; then + for ac_func in _hypot +do : + ac_fn_c_check_func "$LINENO" "_hypot" "ac_cv_func__hypot" +if test "x$ac_cv_func__hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOT 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float trig functions" >&5 +$as_echo_n "checking for float trig functions... " >&6; } + if ${glibcxx_cv_func_float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosf (0); asinf (0); atanf (0); cosf (0); sinf (0); tanf (0); coshf (0); sinhf (0); tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_trig_use=yes +else + glibcxx_cv_func_float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_trig_use" >&5 +$as_echo "$glibcxx_cv_func_float_trig_use" >&6; } + if test x$glibcxx_cv_func_float_trig_use = x"yes"; then + for ac_func in acosf asinf atanf cosf sinf tanf coshf sinhf tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float trig functions" >&5 +$as_echo_n "checking for _float trig functions... " >&6; } + if ${glibcxx_cv_func__float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosf (0); _asinf (0); _atanf (0); _cosf (0); _sinf (0); _tanf (0); _coshf (0); _sinhf (0); _tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_trig_use=yes +else + glibcxx_cv_func__float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_trig_use" >&5 +$as_echo "$glibcxx_cv_func__float_trig_use" >&6; } + if test x$glibcxx_cv_func__float_trig_use = x"yes"; then + for ac_func in _acosf _asinf _atanf _cosf _sinf _tanf _coshf _sinhf _tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float round functions" >&5 +$as_echo_n "checking for float round functions... " >&6; } + if ${glibcxx_cv_func_float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceilf (0); floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_round_use=yes +else + glibcxx_cv_func_float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_round_use" >&5 +$as_echo "$glibcxx_cv_func_float_round_use" >&6; } + if test x$glibcxx_cv_func_float_round_use = x"yes"; then + for ac_func in ceilf floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float round functions" >&5 +$as_echo_n "checking for _float round functions... " >&6; } + if ${glibcxx_cv_func__float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceilf (0); _floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_round_use=yes +else + glibcxx_cv_func__float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_round_use" >&5 +$as_echo "$glibcxx_cv_func__float_round_use" >&6; } + if test x$glibcxx_cv_func__float_round_use = x"yes"; then + for ac_func in _ceilf _floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expf declaration" >&5 +$as_echo_n "checking for expf declaration... " >&6; } + if test x${glibcxx_cv_func_expf_use+set} != xset; then + if ${glibcxx_cv_func_expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expf_use=yes +else + glibcxx_cv_func_expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expf_use" >&5 +$as_echo "$glibcxx_cv_func_expf_use" >&6; } + + if test x$glibcxx_cv_func_expf_use = x"yes"; then + for ac_func in expf +do : + ac_fn_c_check_func "$LINENO" "expf" "ac_cv_func_expf" +if test "x$ac_cv_func_expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expf declaration" >&5 +$as_echo_n "checking for _expf declaration... " >&6; } + if test x${glibcxx_cv_func__expf_use+set} != xset; then + if ${glibcxx_cv_func__expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expf_use=yes +else + glibcxx_cv_func__expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expf_use" >&5 +$as_echo "$glibcxx_cv_func__expf_use" >&6; } + + if test x$glibcxx_cv_func__expf_use = x"yes"; then + for ac_func in _expf +do : + ac_fn_c_check_func "$LINENO" "_expf" "ac_cv_func__expf" +if test "x$ac_cv_func__expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanf declaration" >&5 +$as_echo_n "checking for isnanf declaration... " >&6; } + if test x${glibcxx_cv_func_isnanf_use+set} != xset; then + if ${glibcxx_cv_func_isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanf_use=yes +else + glibcxx_cv_func_isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanf_use" >&5 +$as_echo "$glibcxx_cv_func_isnanf_use" >&6; } + + if test x$glibcxx_cv_func_isnanf_use = x"yes"; then + for ac_func in isnanf +do : + ac_fn_c_check_func "$LINENO" "isnanf" "ac_cv_func_isnanf" +if test "x$ac_cv_func_isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanf declaration" >&5 +$as_echo_n "checking for _isnanf declaration... " >&6; } + if test x${glibcxx_cv_func__isnanf_use+set} != xset; then + if ${glibcxx_cv_func__isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanf_use=yes +else + glibcxx_cv_func__isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanf_use" >&5 +$as_echo "$glibcxx_cv_func__isnanf_use" >&6; } + + if test x$glibcxx_cv_func__isnanf_use = x"yes"; then + for ac_func in _isnanf +do : + ac_fn_c_check_func "$LINENO" "_isnanf" "ac_cv_func__isnanf" +if test "x$ac_cv_func__isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinff declaration" >&5 +$as_echo_n "checking for isinff declaration... " >&6; } + if test x${glibcxx_cv_func_isinff_use+set} != xset; then + if ${glibcxx_cv_func_isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinff_use=yes +else + glibcxx_cv_func_isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinff_use" >&5 +$as_echo "$glibcxx_cv_func_isinff_use" >&6; } + + if test x$glibcxx_cv_func_isinff_use = x"yes"; then + for ac_func in isinff +do : + ac_fn_c_check_func "$LINENO" "isinff" "ac_cv_func_isinff" +if test "x$ac_cv_func_isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinff declaration" >&5 +$as_echo_n "checking for _isinff declaration... " >&6; } + if test x${glibcxx_cv_func__isinff_use+set} != xset; then + if ${glibcxx_cv_func__isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinff_use=yes +else + glibcxx_cv_func__isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinff_use" >&5 +$as_echo "$glibcxx_cv_func__isinff_use" >&6; } + + if test x$glibcxx_cv_func__isinff_use = x"yes"; then + for ac_func in _isinff +do : + ac_fn_c_check_func "$LINENO" "_isinff" "ac_cv_func__isinff" +if test "x$ac_cv_func__isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f declaration" >&5 +$as_echo_n "checking for atan2f declaration... " >&6; } + if test x${glibcxx_cv_func_atan2f_use+set} != xset; then + if ${glibcxx_cv_func_atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2f_use=yes +else + glibcxx_cv_func_atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2f_use" >&5 +$as_echo "$glibcxx_cv_func_atan2f_use" >&6; } + + if test x$glibcxx_cv_func_atan2f_use = x"yes"; then + for ac_func in atan2f +do : + ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2f declaration" >&5 +$as_echo_n "checking for _atan2f declaration... " >&6; } + if test x${glibcxx_cv_func__atan2f_use+set} != xset; then + if ${glibcxx_cv_func__atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2f_use=yes +else + glibcxx_cv_func__atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2f_use" >&5 +$as_echo "$glibcxx_cv_func__atan2f_use" >&6; } + + if test x$glibcxx_cv_func__atan2f_use = x"yes"; then + for ac_func in _atan2f +do : + ac_fn_c_check_func "$LINENO" "_atan2f" "ac_cv_func__atan2f" +if test "x$ac_cv_func__atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsf declaration" >&5 +$as_echo_n "checking for fabsf declaration... " >&6; } + if test x${glibcxx_cv_func_fabsf_use+set} != xset; then + if ${glibcxx_cv_func_fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsf_use=yes +else + glibcxx_cv_func_fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsf_use" >&5 +$as_echo "$glibcxx_cv_func_fabsf_use" >&6; } + + if test x$glibcxx_cv_func_fabsf_use = x"yes"; then + for ac_func in fabsf +do : + ac_fn_c_check_func "$LINENO" "fabsf" "ac_cv_func_fabsf" +if test "x$ac_cv_func_fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsf declaration" >&5 +$as_echo_n "checking for _fabsf declaration... " >&6; } + if test x${glibcxx_cv_func__fabsf_use+set} != xset; then + if ${glibcxx_cv_func__fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsf_use=yes +else + glibcxx_cv_func__fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsf_use" >&5 +$as_echo "$glibcxx_cv_func__fabsf_use" >&6; } + + if test x$glibcxx_cv_func__fabsf_use = x"yes"; then + for ac_func in _fabsf +do : + ac_fn_c_check_func "$LINENO" "_fabsf" "ac_cv_func__fabsf" +if test "x$ac_cv_func__fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf declaration" >&5 +$as_echo_n "checking for fmodf declaration... " >&6; } + if test x${glibcxx_cv_func_fmodf_use+set} != xset; then + if ${glibcxx_cv_func_fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodf_use=yes +else + glibcxx_cv_func_fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodf_use" >&5 +$as_echo "$glibcxx_cv_func_fmodf_use" >&6; } + + if test x$glibcxx_cv_func_fmodf_use = x"yes"; then + for ac_func in fmodf +do : + ac_fn_c_check_func "$LINENO" "fmodf" "ac_cv_func_fmodf" +if test "x$ac_cv_func_fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodf declaration" >&5 +$as_echo_n "checking for _fmodf declaration... " >&6; } + if test x${glibcxx_cv_func__fmodf_use+set} != xset; then + if ${glibcxx_cv_func__fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodf_use=yes +else + glibcxx_cv_func__fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodf_use" >&5 +$as_echo "$glibcxx_cv_func__fmodf_use" >&6; } + + if test x$glibcxx_cv_func__fmodf_use = x"yes"; then + for ac_func in _fmodf +do : + ac_fn_c_check_func "$LINENO" "_fmodf" "ac_cv_func__fmodf" +if test "x$ac_cv_func__fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } + if test x${glibcxx_cv_func_frexpf_use+set} != xset; then + if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + + if test x$glibcxx_cv_func_frexpf_use = x"yes"; then + for ac_func in frexpf +do : + ac_fn_c_check_func "$LINENO" "frexpf" "ac_cv_func_frexpf" +if test "x$ac_cv_func_frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpf declaration" >&5 +$as_echo_n "checking for _frexpf declaration... " >&6; } + if test x${glibcxx_cv_func__frexpf_use+set} != xset; then + if ${glibcxx_cv_func__frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpf_use=yes +else + glibcxx_cv_func__frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpf_use" >&5 +$as_echo "$glibcxx_cv_func__frexpf_use" >&6; } + + if test x$glibcxx_cv_func__frexpf_use = x"yes"; then + for ac_func in _frexpf +do : + ac_fn_c_check_func "$LINENO" "_frexpf" "ac_cv_func__frexpf" +if test "x$ac_cv_func__frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } + if test x${glibcxx_cv_func_hypotf_use+set} != xset; then + if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + + if test x$glibcxx_cv_func_hypotf_use = x"yes"; then + for ac_func in hypotf +do : + ac_fn_c_check_func "$LINENO" "hypotf" "ac_cv_func_hypotf" +if test "x$ac_cv_func_hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotf declaration" >&5 +$as_echo_n "checking for _hypotf declaration... " >&6; } + if test x${glibcxx_cv_func__hypotf_use+set} != xset; then + if ${glibcxx_cv_func__hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotf_use=yes +else + glibcxx_cv_func__hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotf_use" >&5 +$as_echo "$glibcxx_cv_func__hypotf_use" >&6; } + + if test x$glibcxx_cv_func__hypotf_use = x"yes"; then + for ac_func in _hypotf +do : + ac_fn_c_check_func "$LINENO" "_hypotf" "ac_cv_func__hypotf" +if test "x$ac_cv_func__hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpf_use+set} != xset; then + if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + + if test x$glibcxx_cv_func_ldexpf_use = x"yes"; then + for ac_func in ldexpf +do : + ac_fn_c_check_func "$LINENO" "ldexpf" "ac_cv_func_ldexpf" +if test "x$ac_cv_func_ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpf declaration" >&5 +$as_echo_n "checking for _ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpf_use+set} != xset; then + if ${glibcxx_cv_func__ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpf_use=yes +else + glibcxx_cv_func__ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpf_use" >&6; } + + if test x$glibcxx_cv_func__ldexpf_use = x"yes"; then + for ac_func in _ldexpf +do : + ac_fn_c_check_func "$LINENO" "_ldexpf" "ac_cv_func__ldexpf" +if test "x$ac_cv_func__ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logf declaration" >&5 +$as_echo_n "checking for logf declaration... " >&6; } + if test x${glibcxx_cv_func_logf_use+set} != xset; then + if ${glibcxx_cv_func_logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logf_use=yes +else + glibcxx_cv_func_logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logf_use" >&5 +$as_echo "$glibcxx_cv_func_logf_use" >&6; } + + if test x$glibcxx_cv_func_logf_use = x"yes"; then + for ac_func in logf +do : + ac_fn_c_check_func "$LINENO" "logf" "ac_cv_func_logf" +if test "x$ac_cv_func_logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logf declaration" >&5 +$as_echo_n "checking for _logf declaration... " >&6; } + if test x${glibcxx_cv_func__logf_use+set} != xset; then + if ${glibcxx_cv_func__logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logf_use=yes +else + glibcxx_cv_func__logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logf_use" >&5 +$as_echo "$glibcxx_cv_func__logf_use" >&6; } + + if test x$glibcxx_cv_func__logf_use = x"yes"; then + for ac_func in _logf +do : + ac_fn_c_check_func "$LINENO" "_logf" "ac_cv_func__logf" +if test "x$ac_cv_func__logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10f declaration" >&5 +$as_echo_n "checking for log10f declaration... " >&6; } + if test x${glibcxx_cv_func_log10f_use+set} != xset; then + if ${glibcxx_cv_func_log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10f_use=yes +else + glibcxx_cv_func_log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10f_use" >&5 +$as_echo "$glibcxx_cv_func_log10f_use" >&6; } + + if test x$glibcxx_cv_func_log10f_use = x"yes"; then + for ac_func in log10f +do : + ac_fn_c_check_func "$LINENO" "log10f" "ac_cv_func_log10f" +if test "x$ac_cv_func_log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10f declaration" >&5 +$as_echo_n "checking for _log10f declaration... " >&6; } + if test x${glibcxx_cv_func__log10f_use+set} != xset; then + if ${glibcxx_cv_func__log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10f_use=yes +else + glibcxx_cv_func__log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10f_use" >&5 +$as_echo "$glibcxx_cv_func__log10f_use" >&6; } + + if test x$glibcxx_cv_func__log10f_use = x"yes"; then + for ac_func in _log10f +do : + ac_fn_c_check_func "$LINENO" "_log10f" "ac_cv_func__log10f" +if test "x$ac_cv_func__log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } + if test x${glibcxx_cv_func_modff_use+set} != xset; then + if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + + if test x$glibcxx_cv_func_modff_use = x"yes"; then + for ac_func in modff +do : + ac_fn_c_check_func "$LINENO" "modff" "ac_cv_func_modff" +if test "x$ac_cv_func_modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modff declaration" >&5 +$as_echo_n "checking for _modff declaration... " >&6; } + if test x${glibcxx_cv_func__modff_use+set} != xset; then + if ${glibcxx_cv_func__modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modff_use=yes +else + glibcxx_cv_func__modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modff_use" >&5 +$as_echo "$glibcxx_cv_func__modff_use" >&6; } + + if test x$glibcxx_cv_func__modff_use = x"yes"; then + for ac_func in _modff +do : + ac_fn_c_check_func "$LINENO" "_modff" "ac_cv_func__modff" +if test "x$ac_cv_func__modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modf declaration" >&5 +$as_echo_n "checking for modf declaration... " >&6; } + if test x${glibcxx_cv_func_modf_use+set} != xset; then + if ${glibcxx_cv_func_modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modf_use=yes +else + glibcxx_cv_func_modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modf_use" >&5 +$as_echo "$glibcxx_cv_func_modf_use" >&6; } + + if test x$glibcxx_cv_func_modf_use = x"yes"; then + for ac_func in modf +do : + ac_fn_c_check_func "$LINENO" "modf" "ac_cv_func_modf" +if test "x$ac_cv_func_modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modf declaration" >&5 +$as_echo_n "checking for _modf declaration... " >&6; } + if test x${glibcxx_cv_func__modf_use+set} != xset; then + if ${glibcxx_cv_func__modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modf_use=yes +else + glibcxx_cv_func__modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modf_use" >&5 +$as_echo "$glibcxx_cv_func__modf_use" >&6; } + + if test x$glibcxx_cv_func__modf_use = x"yes"; then + for ac_func in _modf +do : + ac_fn_c_check_func "$LINENO" "_modf" "ac_cv_func__modf" +if test "x$ac_cv_func__modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powf declaration" >&5 +$as_echo_n "checking for powf declaration... " >&6; } + if test x${glibcxx_cv_func_powf_use+set} != xset; then + if ${glibcxx_cv_func_powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powf_use=yes +else + glibcxx_cv_func_powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powf_use" >&5 +$as_echo "$glibcxx_cv_func_powf_use" >&6; } + + if test x$glibcxx_cv_func_powf_use = x"yes"; then + for ac_func in powf +do : + ac_fn_c_check_func "$LINENO" "powf" "ac_cv_func_powf" +if test "x$ac_cv_func_powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powf declaration" >&5 +$as_echo_n "checking for _powf declaration... " >&6; } + if test x${glibcxx_cv_func__powf_use+set} != xset; then + if ${glibcxx_cv_func__powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powf_use=yes +else + glibcxx_cv_func__powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powf_use" >&5 +$as_echo "$glibcxx_cv_func__powf_use" >&6; } + + if test x$glibcxx_cv_func__powf_use = x"yes"; then + for ac_func in _powf +do : + ac_fn_c_check_func "$LINENO" "_powf" "ac_cv_func__powf" +if test "x$ac_cv_func__powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtf declaration" >&5 +$as_echo_n "checking for sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtf_use+set} != xset; then + if ${glibcxx_cv_func_sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtf_use=yes +else + glibcxx_cv_func_sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtf_use" >&6; } + + if test x$glibcxx_cv_func_sqrtf_use = x"yes"; then + for ac_func in sqrtf +do : + ac_fn_c_check_func "$LINENO" "sqrtf" "ac_cv_func_sqrtf" +if test "x$ac_cv_func_sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtf declaration" >&5 +$as_echo_n "checking for _sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtf_use+set} != xset; then + if ${glibcxx_cv_func__sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtf_use=yes +else + glibcxx_cv_func__sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtf_use" >&6; } + + if test x$glibcxx_cv_func__sqrtf_use = x"yes"; then + for ac_func in _sqrtf +do : + ac_fn_c_check_func "$LINENO" "_sqrtf" "ac_cv_func__sqrtf" +if test "x$ac_cv_func__sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosf declaration" >&5 +$as_echo_n "checking for sincosf declaration... " >&6; } + if test x${glibcxx_cv_func_sincosf_use+set} != xset; then + if ${glibcxx_cv_func_sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosf_use=yes +else + glibcxx_cv_func_sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosf_use" >&5 +$as_echo "$glibcxx_cv_func_sincosf_use" >&6; } + + if test x$glibcxx_cv_func_sincosf_use = x"yes"; then + for ac_func in sincosf +do : + ac_fn_c_check_func "$LINENO" "sincosf" "ac_cv_func_sincosf" +if test "x$ac_cv_func_sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosf declaration" >&5 +$as_echo_n "checking for _sincosf declaration... " >&6; } + if test x${glibcxx_cv_func__sincosf_use+set} != xset; then + if ${glibcxx_cv_func__sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosf_use=yes +else + glibcxx_cv_func__sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosf_use" >&5 +$as_echo "$glibcxx_cv_func__sincosf_use" >&6; } + + if test x$glibcxx_cv_func__sincosf_use = x"yes"; then + for ac_func in _sincosf +do : + ac_fn_c_check_func "$LINENO" "_sincosf" "ac_cv_func__sincosf" +if test "x$ac_cv_func__sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitef declaration" >&5 +$as_echo_n "checking for finitef declaration... " >&6; } + if test x${glibcxx_cv_func_finitef_use+set} != xset; then + if ${glibcxx_cv_func_finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitef_use=yes +else + glibcxx_cv_func_finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitef_use" >&5 +$as_echo "$glibcxx_cv_func_finitef_use" >&6; } + + if test x$glibcxx_cv_func_finitef_use = x"yes"; then + for ac_func in finitef +do : + ac_fn_c_check_func "$LINENO" "finitef" "ac_cv_func_finitef" +if test "x$ac_cv_func_finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitef declaration" >&5 +$as_echo_n "checking for _finitef declaration... " >&6; } + if test x${glibcxx_cv_func__finitef_use+set} != xset; then + if ${glibcxx_cv_func__finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitef_use=yes +else + glibcxx_cv_func__finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitef_use" >&5 +$as_echo "$glibcxx_cv_func__finitef_use" >&6; } + + if test x$glibcxx_cv_func__finitef_use = x"yes"; then + for ac_func in _finitef +do : + ac_fn_c_check_func "$LINENO" "_finitef" "ac_cv_func__finitef" +if test "x$ac_cv_func__finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double trig functions" >&5 +$as_echo_n "checking for long double trig functions... " >&6; } + if ${glibcxx_cv_func_long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosl (0); asinl (0); atanl (0); cosl (0); sinl (0); tanl (0); coshl (0); sinhl (0); tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_trig_use=yes +else + glibcxx_cv_func_long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_trig_use" >&6; } + if test x$glibcxx_cv_func_long_double_trig_use = x"yes"; then + for ac_func in acosl asinl atanl cosl sinl tanl coshl sinhl tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double trig functions" >&5 +$as_echo_n "checking for _long double trig functions... " >&6; } + if ${glibcxx_cv_func__long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosl (0); _asinl (0); _atanl (0); _cosl (0); _sinl (0); _tanl (0); _coshl (0); _sinhl (0); _tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_trig_use=yes +else + glibcxx_cv_func__long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_trig_use" >&6; } + if test x$glibcxx_cv_func__long_double_trig_use = x"yes"; then + for ac_func in _acosl _asinl _atanl _cosl _sinl _tanl _coshl _sinhl _tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double round functions" >&5 +$as_echo_n "checking for long double round functions... " >&6; } + if ${glibcxx_cv_func_long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceill (0); floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_round_use=yes +else + glibcxx_cv_func_long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_round_use" >&6; } + if test x$glibcxx_cv_func_long_double_round_use = x"yes"; then + for ac_func in ceill floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double round functions" >&5 +$as_echo_n "checking for _long double round functions... " >&6; } + if ${glibcxx_cv_func__long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceill (0); _floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_round_use=yes +else + glibcxx_cv_func__long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_round_use" >&6; } + if test x$glibcxx_cv_func__long_double_round_use = x"yes"; then + for ac_func in _ceill _floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanl declaration" >&5 +$as_echo_n "checking for isnanl declaration... " >&6; } + if test x${glibcxx_cv_func_isnanl_use+set} != xset; then + if ${glibcxx_cv_func_isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanl_use=yes +else + glibcxx_cv_func_isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanl_use" >&5 +$as_echo "$glibcxx_cv_func_isnanl_use" >&6; } + + if test x$glibcxx_cv_func_isnanl_use = x"yes"; then + for ac_func in isnanl +do : + ac_fn_c_check_func "$LINENO" "isnanl" "ac_cv_func_isnanl" +if test "x$ac_cv_func_isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanl declaration" >&5 +$as_echo_n "checking for _isnanl declaration... " >&6; } + if test x${glibcxx_cv_func__isnanl_use+set} != xset; then + if ${glibcxx_cv_func__isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanl_use=yes +else + glibcxx_cv_func__isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanl_use" >&5 +$as_echo "$glibcxx_cv_func__isnanl_use" >&6; } + + if test x$glibcxx_cv_func__isnanl_use = x"yes"; then + for ac_func in _isnanl +do : + ac_fn_c_check_func "$LINENO" "_isnanl" "ac_cv_func__isnanl" +if test "x$ac_cv_func__isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinfl declaration" >&5 +$as_echo_n "checking for isinfl declaration... " >&6; } + if test x${glibcxx_cv_func_isinfl_use+set} != xset; then + if ${glibcxx_cv_func_isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinfl_use=yes +else + glibcxx_cv_func_isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinfl_use" >&5 +$as_echo "$glibcxx_cv_func_isinfl_use" >&6; } + + if test x$glibcxx_cv_func_isinfl_use = x"yes"; then + for ac_func in isinfl +do : + ac_fn_c_check_func "$LINENO" "isinfl" "ac_cv_func_isinfl" +if test "x$ac_cv_func_isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinfl declaration" >&5 +$as_echo_n "checking for _isinfl declaration... " >&6; } + if test x${glibcxx_cv_func__isinfl_use+set} != xset; then + if ${glibcxx_cv_func__isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinfl_use=yes +else + glibcxx_cv_func__isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinfl_use" >&5 +$as_echo "$glibcxx_cv_func__isinfl_use" >&6; } + + if test x$glibcxx_cv_func__isinfl_use = x"yes"; then + for ac_func in _isinfl +do : + ac_fn_c_check_func "$LINENO" "_isinfl" "ac_cv_func__isinfl" +if test "x$ac_cv_func__isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } + if test x${glibcxx_cv_func_atan2l_use+set} != xset; then + if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + + if test x$glibcxx_cv_func_atan2l_use = x"yes"; then + for ac_func in atan2l +do : + ac_fn_c_check_func "$LINENO" "atan2l" "ac_cv_func_atan2l" +if test "x$ac_cv_func_atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2l declaration" >&5 +$as_echo_n "checking for _atan2l declaration... " >&6; } + if test x${glibcxx_cv_func__atan2l_use+set} != xset; then + if ${glibcxx_cv_func__atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2l_use=yes +else + glibcxx_cv_func__atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2l_use" >&5 +$as_echo "$glibcxx_cv_func__atan2l_use" >&6; } + + if test x$glibcxx_cv_func__atan2l_use = x"yes"; then + for ac_func in _atan2l +do : + ac_fn_c_check_func "$LINENO" "_atan2l" "ac_cv_func__atan2l" +if test "x$ac_cv_func__atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } + if test x${glibcxx_cv_func_expl_use+set} != xset; then + if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + + if test x$glibcxx_cv_func_expl_use = x"yes"; then + for ac_func in expl +do : + ac_fn_c_check_func "$LINENO" "expl" "ac_cv_func_expl" +if test "x$ac_cv_func_expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expl declaration" >&5 +$as_echo_n "checking for _expl declaration... " >&6; } + if test x${glibcxx_cv_func__expl_use+set} != xset; then + if ${glibcxx_cv_func__expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expl_use=yes +else + glibcxx_cv_func__expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expl_use" >&5 +$as_echo "$glibcxx_cv_func__expl_use" >&6; } + + if test x$glibcxx_cv_func__expl_use = x"yes"; then + for ac_func in _expl +do : + ac_fn_c_check_func "$LINENO" "_expl" "ac_cv_func__expl" +if test "x$ac_cv_func__expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } + if test x${glibcxx_cv_func_fabsl_use+set} != xset; then + if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + + if test x$glibcxx_cv_func_fabsl_use = x"yes"; then + for ac_func in fabsl +do : + ac_fn_c_check_func "$LINENO" "fabsl" "ac_cv_func_fabsl" +if test "x$ac_cv_func_fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsl declaration" >&5 +$as_echo_n "checking for _fabsl declaration... " >&6; } + if test x${glibcxx_cv_func__fabsl_use+set} != xset; then + if ${glibcxx_cv_func__fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsl_use=yes +else + glibcxx_cv_func__fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsl_use" >&5 +$as_echo "$glibcxx_cv_func__fabsl_use" >&6; } + + if test x$glibcxx_cv_func__fabsl_use = x"yes"; then + for ac_func in _fabsl +do : + ac_fn_c_check_func "$LINENO" "_fabsl" "ac_cv_func__fabsl" +if test "x$ac_cv_func__fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } + if test x${glibcxx_cv_func_fmodl_use+set} != xset; then + if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + + if test x$glibcxx_cv_func_fmodl_use = x"yes"; then + for ac_func in fmodl +do : + ac_fn_c_check_func "$LINENO" "fmodl" "ac_cv_func_fmodl" +if test "x$ac_cv_func_fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodl declaration" >&5 +$as_echo_n "checking for _fmodl declaration... " >&6; } + if test x${glibcxx_cv_func__fmodl_use+set} != xset; then + if ${glibcxx_cv_func__fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodl_use=yes +else + glibcxx_cv_func__fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodl_use" >&5 +$as_echo "$glibcxx_cv_func__fmodl_use" >&6; } + + if test x$glibcxx_cv_func__fmodl_use = x"yes"; then + for ac_func in _fmodl +do : + ac_fn_c_check_func "$LINENO" "_fmodl" "ac_cv_func__fmodl" +if test "x$ac_cv_func__fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } + if test x${glibcxx_cv_func_frexpl_use+set} != xset; then + if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + + if test x$glibcxx_cv_func_frexpl_use = x"yes"; then + for ac_func in frexpl +do : + ac_fn_c_check_func "$LINENO" "frexpl" "ac_cv_func_frexpl" +if test "x$ac_cv_func_frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpl declaration" >&5 +$as_echo_n "checking for _frexpl declaration... " >&6; } + if test x${glibcxx_cv_func__frexpl_use+set} != xset; then + if ${glibcxx_cv_func__frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpl_use=yes +else + glibcxx_cv_func__frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpl_use" >&5 +$as_echo "$glibcxx_cv_func__frexpl_use" >&6; } + + if test x$glibcxx_cv_func__frexpl_use = x"yes"; then + for ac_func in _frexpl +do : + ac_fn_c_check_func "$LINENO" "_frexpl" "ac_cv_func__frexpl" +if test "x$ac_cv_func__frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } + if test x${glibcxx_cv_func_hypotl_use+set} != xset; then + if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + + if test x$glibcxx_cv_func_hypotl_use = x"yes"; then + for ac_func in hypotl +do : + ac_fn_c_check_func "$LINENO" "hypotl" "ac_cv_func_hypotl" +if test "x$ac_cv_func_hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotl declaration" >&5 +$as_echo_n "checking for _hypotl declaration... " >&6; } + if test x${glibcxx_cv_func__hypotl_use+set} != xset; then + if ${glibcxx_cv_func__hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotl_use=yes +else + glibcxx_cv_func__hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotl_use" >&5 +$as_echo "$glibcxx_cv_func__hypotl_use" >&6; } + + if test x$glibcxx_cv_func__hypotl_use = x"yes"; then + for ac_func in _hypotl +do : + ac_fn_c_check_func "$LINENO" "_hypotl" "ac_cv_func__hypotl" +if test "x$ac_cv_func__hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpl_use+set} != xset; then + if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + + if test x$glibcxx_cv_func_ldexpl_use = x"yes"; then + for ac_func in ldexpl +do : + ac_fn_c_check_func "$LINENO" "ldexpl" "ac_cv_func_ldexpl" +if test "x$ac_cv_func_ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpl declaration" >&5 +$as_echo_n "checking for _ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpl_use+set} != xset; then + if ${glibcxx_cv_func__ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpl_use=yes +else + glibcxx_cv_func__ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpl_use" >&6; } + + if test x$glibcxx_cv_func__ldexpl_use = x"yes"; then + for ac_func in _ldexpl +do : + ac_fn_c_check_func "$LINENO" "_ldexpl" "ac_cv_func__ldexpl" +if test "x$ac_cv_func__ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } + if test x${glibcxx_cv_func_logl_use+set} != xset; then + if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + + if test x$glibcxx_cv_func_logl_use = x"yes"; then + for ac_func in logl +do : + ac_fn_c_check_func "$LINENO" "logl" "ac_cv_func_logl" +if test "x$ac_cv_func_logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logl declaration" >&5 +$as_echo_n "checking for _logl declaration... " >&6; } + if test x${glibcxx_cv_func__logl_use+set} != xset; then + if ${glibcxx_cv_func__logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logl_use=yes +else + glibcxx_cv_func__logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logl_use" >&5 +$as_echo "$glibcxx_cv_func__logl_use" >&6; } + + if test x$glibcxx_cv_func__logl_use = x"yes"; then + for ac_func in _logl +do : + ac_fn_c_check_func "$LINENO" "_logl" "ac_cv_func__logl" +if test "x$ac_cv_func__logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } + if test x${glibcxx_cv_func_log10l_use+set} != xset; then + if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + + if test x$glibcxx_cv_func_log10l_use = x"yes"; then + for ac_func in log10l +do : + ac_fn_c_check_func "$LINENO" "log10l" "ac_cv_func_log10l" +if test "x$ac_cv_func_log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10l declaration" >&5 +$as_echo_n "checking for _log10l declaration... " >&6; } + if test x${glibcxx_cv_func__log10l_use+set} != xset; then + if ${glibcxx_cv_func__log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10l_use=yes +else + glibcxx_cv_func__log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10l_use" >&5 +$as_echo "$glibcxx_cv_func__log10l_use" >&6; } + + if test x$glibcxx_cv_func__log10l_use = x"yes"; then + for ac_func in _log10l +do : + ac_fn_c_check_func "$LINENO" "_log10l" "ac_cv_func__log10l" +if test "x$ac_cv_func__log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } + if test x${glibcxx_cv_func_modfl_use+set} != xset; then + if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + + if test x$glibcxx_cv_func_modfl_use = x"yes"; then + for ac_func in modfl +do : + ac_fn_c_check_func "$LINENO" "modfl" "ac_cv_func_modfl" +if test "x$ac_cv_func_modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modfl declaration" >&5 +$as_echo_n "checking for _modfl declaration... " >&6; } + if test x${glibcxx_cv_func__modfl_use+set} != xset; then + if ${glibcxx_cv_func__modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modfl_use=yes +else + glibcxx_cv_func__modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modfl_use" >&5 +$as_echo "$glibcxx_cv_func__modfl_use" >&6; } + + if test x$glibcxx_cv_func__modfl_use = x"yes"; then + for ac_func in _modfl +do : + ac_fn_c_check_func "$LINENO" "_modfl" "ac_cv_func__modfl" +if test "x$ac_cv_func__modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } + if test x${glibcxx_cv_func_powl_use+set} != xset; then + if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + + if test x$glibcxx_cv_func_powl_use = x"yes"; then + for ac_func in powl +do : + ac_fn_c_check_func "$LINENO" "powl" "ac_cv_func_powl" +if test "x$ac_cv_func_powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powl declaration" >&5 +$as_echo_n "checking for _powl declaration... " >&6; } + if test x${glibcxx_cv_func__powl_use+set} != xset; then + if ${glibcxx_cv_func__powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powl_use=yes +else + glibcxx_cv_func__powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powl_use" >&5 +$as_echo "$glibcxx_cv_func__powl_use" >&6; } + + if test x$glibcxx_cv_func__powl_use = x"yes"; then + for ac_func in _powl +do : + ac_fn_c_check_func "$LINENO" "_powl" "ac_cv_func__powl" +if test "x$ac_cv_func__powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtl_use+set} != xset; then + if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + + if test x$glibcxx_cv_func_sqrtl_use = x"yes"; then + for ac_func in sqrtl +do : + ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl" +if test "x$ac_cv_func_sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtl declaration" >&5 +$as_echo_n "checking for _sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtl_use+set} != xset; then + if ${glibcxx_cv_func__sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtl_use=yes +else + glibcxx_cv_func__sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtl_use" >&6; } + + if test x$glibcxx_cv_func__sqrtl_use = x"yes"; then + for ac_func in _sqrtl +do : + ac_fn_c_check_func "$LINENO" "_sqrtl" "ac_cv_func__sqrtl" +if test "x$ac_cv_func__sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosl declaration" >&5 +$as_echo_n "checking for sincosl declaration... " >&6; } + if test x${glibcxx_cv_func_sincosl_use+set} != xset; then + if ${glibcxx_cv_func_sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosl_use=yes +else + glibcxx_cv_func_sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosl_use" >&5 +$as_echo "$glibcxx_cv_func_sincosl_use" >&6; } + + if test x$glibcxx_cv_func_sincosl_use = x"yes"; then + for ac_func in sincosl +do : + ac_fn_c_check_func "$LINENO" "sincosl" "ac_cv_func_sincosl" +if test "x$ac_cv_func_sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosl declaration" >&5 +$as_echo_n "checking for _sincosl declaration... " >&6; } + if test x${glibcxx_cv_func__sincosl_use+set} != xset; then + if ${glibcxx_cv_func__sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosl_use=yes +else + glibcxx_cv_func__sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosl_use" >&5 +$as_echo "$glibcxx_cv_func__sincosl_use" >&6; } + + if test x$glibcxx_cv_func__sincosl_use = x"yes"; then + for ac_func in _sincosl +do : + ac_fn_c_check_func "$LINENO" "_sincosl" "ac_cv_func__sincosl" +if test "x$ac_cv_func__sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitel declaration" >&5 +$as_echo_n "checking for finitel declaration... " >&6; } + if test x${glibcxx_cv_func_finitel_use+set} != xset; then + if ${glibcxx_cv_func_finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitel_use=yes +else + glibcxx_cv_func_finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitel_use" >&5 +$as_echo "$glibcxx_cv_func_finitel_use" >&6; } + + if test x$glibcxx_cv_func_finitel_use = x"yes"; then + for ac_func in finitel +do : + ac_fn_c_check_func "$LINENO" "finitel" "ac_cv_func_finitel" +if test "x$ac_cv_func_finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitel declaration" >&5 +$as_echo_n "checking for _finitel declaration... " >&6; } + if test x${glibcxx_cv_func__finitel_use+set} != xset; then + if ${glibcxx_cv_func__finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitel_use=yes +else + glibcxx_cv_func__finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitel_use" >&5 +$as_echo "$glibcxx_cv_func__finitel_use" >&6; } + + if test x$glibcxx_cv_func__finitel_use = x"yes"; then + for ac_func in _finitel +do : + ac_fn_c_check_func "$LINENO" "_finitel" "ac_cv_func__finitel" +if test "x$ac_cv_func__finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEL 1 +_ACEOF + +fi +done + + fi + fi + + + + + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for at_quick_exit declaration" >&5 +$as_echo_n "checking for at_quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_at_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_at_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + at_quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_at_quick_exit_use=yes +else + glibcxx_cv_func_at_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_at_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_at_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_at_quick_exit_use = x"yes"; then + for ac_func in at_quick_exit +do : + ac_fn_c_check_func "$LINENO" "at_quick_exit" "ac_cv_func_at_quick_exit" +if test "x$ac_cv_func_at_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AT_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for quick_exit declaration" >&5 +$as_echo_n "checking for quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_quick_exit_use=yes +else + glibcxx_cv_func_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_quick_exit_use = x"yes"; then + for ac_func in quick_exit +do : + ac_fn_c_check_func "$LINENO" "quick_exit" "ac_cv_func_quick_exit" +if test "x$ac_cv_func_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtold declaration" >&5 +$as_echo_n "checking for strtold declaration... " >&6; } + if test x${glibcxx_cv_func_strtold_use+set} != xset; then + if ${glibcxx_cv_func_strtold_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtold(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtold_use=yes +else + glibcxx_cv_func_strtold_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtold_use" >&5 +$as_echo "$glibcxx_cv_func_strtold_use" >&6; } + if test x$glibcxx_cv_func_strtold_use = x"yes"; then + for ac_func in strtold +do : + ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold" +if test "x$ac_cv_func_strtold" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOLD 1 +_ACEOF + +fi +done + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtof declaration" >&5 +$as_echo_n "checking for strtof declaration... " >&6; } + if test x${glibcxx_cv_func_strtof_use+set} != xset; then + if ${glibcxx_cv_func_strtof_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtof(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtof_use=yes +else + glibcxx_cv_func_strtof_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtof_use" >&5 +$as_echo "$glibcxx_cv_func_strtof_use" >&6; } + if test x$glibcxx_cv_func_strtof_use = x"yes"; then + for ac_func in strtof +do : + ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof" +if test "x$ac_cv_func_strtof" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOF 1 +_ACEOF + +fi +done + + fi + + + + + CXXFLAGS="$ac_save_CXXFLAGS" + + + $as_echo "#define HAVE_FINITE 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOT 1" >>confdefs.h + + $as_echo "#define HAVE_ISNAN 1" >>confdefs.h + + $as_echo "#define HAVE_ISINF 1" >>confdefs.h + + + $as_echo "#define HAVE_LDEXPF 1" >>confdefs.h + + $as_echo "#define HAVE_MODF 1" >>confdefs.h + + $as_echo "#define HAVE_SQRTF 1" >>confdefs.h + + ;; + + *-aix*) + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + libm="-lm" +fi + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $libm" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf declaration" >&5 +$as_echo_n "checking for isinf declaration... " >&6; } + if test x${glibcxx_cv_func_isinf_use+set} != xset; then + if ${glibcxx_cv_func_isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinf_use=yes +else + glibcxx_cv_func_isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinf_use" >&5 +$as_echo "$glibcxx_cv_func_isinf_use" >&6; } + + if test x$glibcxx_cv_func_isinf_use = x"yes"; then + for ac_func in isinf +do : + ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinf declaration" >&5 +$as_echo_n "checking for _isinf declaration... " >&6; } + if test x${glibcxx_cv_func__isinf_use+set} != xset; then + if ${glibcxx_cv_func__isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinf_use=yes +else + glibcxx_cv_func__isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinf_use" >&5 +$as_echo "$glibcxx_cv_func__isinf_use" >&6; } + + if test x$glibcxx_cv_func__isinf_use = x"yes"; then + for ac_func in _isinf +do : + ac_fn_c_check_func "$LINENO" "_isinf" "ac_cv_func__isinf" +if test "x$ac_cv_func__isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan declaration" >&5 +$as_echo_n "checking for isnan declaration... " >&6; } + if test x${glibcxx_cv_func_isnan_use+set} != xset; then + if ${glibcxx_cv_func_isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnan_use=yes +else + glibcxx_cv_func_isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnan_use" >&5 +$as_echo "$glibcxx_cv_func_isnan_use" >&6; } + + if test x$glibcxx_cv_func_isnan_use = x"yes"; then + for ac_func in isnan +do : + ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNAN 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnan declaration" >&5 +$as_echo_n "checking for _isnan declaration... " >&6; } + if test x${glibcxx_cv_func__isnan_use+set} != xset; then + if ${glibcxx_cv_func__isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnan_use=yes +else + glibcxx_cv_func__isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnan_use" >&5 +$as_echo "$glibcxx_cv_func__isnan_use" >&6; } + + if test x$glibcxx_cv_func__isnan_use = x"yes"; then + for ac_func in _isnan +do : + ac_fn_c_check_func "$LINENO" "_isnan" "ac_cv_func__isnan" +if test "x$ac_cv_func__isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNAN 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finite declaration" >&5 +$as_echo_n "checking for finite declaration... " >&6; } + if test x${glibcxx_cv_func_finite_use+set} != xset; then + if ${glibcxx_cv_func_finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finite_use=yes +else + glibcxx_cv_func_finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finite_use" >&5 +$as_echo "$glibcxx_cv_func_finite_use" >&6; } + + if test x$glibcxx_cv_func_finite_use = x"yes"; then + for ac_func in finite +do : + ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITE 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finite declaration" >&5 +$as_echo_n "checking for _finite declaration... " >&6; } + if test x${glibcxx_cv_func__finite_use+set} != xset; then + if ${glibcxx_cv_func__finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finite_use=yes +else + glibcxx_cv_func__finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finite_use" >&5 +$as_echo "$glibcxx_cv_func__finite_use" >&6; } + + if test x$glibcxx_cv_func__finite_use = x"yes"; then + for ac_func in _finite +do : + ac_fn_c_check_func "$LINENO" "_finite" "ac_cv_func__finite" +if test "x$ac_cv_func__finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITE 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincos declaration" >&5 +$as_echo_n "checking for sincos declaration... " >&6; } + if test x${glibcxx_cv_func_sincos_use+set} != xset; then + if ${glibcxx_cv_func_sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincos_use=yes +else + glibcxx_cv_func_sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincos_use" >&5 +$as_echo "$glibcxx_cv_func_sincos_use" >&6; } + + if test x$glibcxx_cv_func_sincos_use = x"yes"; then + for ac_func in sincos +do : + ac_fn_c_check_func "$LINENO" "sincos" "ac_cv_func_sincos" +if test "x$ac_cv_func_sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincos declaration" >&5 +$as_echo_n "checking for _sincos declaration... " >&6; } + if test x${glibcxx_cv_func__sincos_use+set} != xset; then + if ${glibcxx_cv_func__sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincos_use=yes +else + glibcxx_cv_func__sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincos_use" >&5 +$as_echo "$glibcxx_cv_func__sincos_use" >&6; } + + if test x$glibcxx_cv_func__sincos_use = x"yes"; then + for ac_func in _sincos +do : + ac_fn_c_check_func "$LINENO" "_sincos" "ac_cv_func__sincos" +if test "x$ac_cv_func__sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpclass declaration" >&5 +$as_echo_n "checking for fpclass declaration... " >&6; } + if test x${glibcxx_cv_func_fpclass_use+set} != xset; then + if ${glibcxx_cv_func_fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fpclass_use=yes +else + glibcxx_cv_func_fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fpclass_use" >&5 +$as_echo "$glibcxx_cv_func_fpclass_use" >&6; } + + if test x$glibcxx_cv_func_fpclass_use = x"yes"; then + for ac_func in fpclass +do : + ac_fn_c_check_func "$LINENO" "fpclass" "ac_cv_func_fpclass" +if test "x$ac_cv_func_fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fpclass declaration" >&5 +$as_echo_n "checking for _fpclass declaration... " >&6; } + if test x${glibcxx_cv_func__fpclass_use+set} != xset; then + if ${glibcxx_cv_func__fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fpclass_use=yes +else + glibcxx_cv_func__fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fpclass_use" >&5 +$as_echo "$glibcxx_cv_func__fpclass_use" >&6; } + + if test x$glibcxx_cv_func__fpclass_use = x"yes"; then + for ac_func in _fpclass +do : + ac_fn_c_check_func "$LINENO" "_fpclass" "ac_cv_func__fpclass" +if test "x$ac_cv_func__fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for qfpclass declaration" >&5 +$as_echo_n "checking for qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func_qfpclass_use+set} != xset; then + if ${glibcxx_cv_func_qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_qfpclass_use=yes +else + glibcxx_cv_func_qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func_qfpclass_use" >&6; } + + if test x$glibcxx_cv_func_qfpclass_use = x"yes"; then + for ac_func in qfpclass +do : + ac_fn_c_check_func "$LINENO" "qfpclass" "ac_cv_func_qfpclass" +if test "x$ac_cv_func_qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QFPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _qfpclass declaration" >&5 +$as_echo_n "checking for _qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func__qfpclass_use+set} != xset; then + if ${glibcxx_cv_func__qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__qfpclass_use=yes +else + glibcxx_cv_func__qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func__qfpclass_use" >&6; } + + if test x$glibcxx_cv_func__qfpclass_use = x"yes"; then + for ac_func in _qfpclass +do : + ac_fn_c_check_func "$LINENO" "_qfpclass" "ac_cv_func__qfpclass" +if test "x$ac_cv_func__qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__QFPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypot declaration" >&5 +$as_echo_n "checking for hypot declaration... " >&6; } + if test x${glibcxx_cv_func_hypot_use+set} != xset; then + if ${glibcxx_cv_func_hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypot_use=yes +else + glibcxx_cv_func_hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypot_use" >&5 +$as_echo "$glibcxx_cv_func_hypot_use" >&6; } + + if test x$glibcxx_cv_func_hypot_use = x"yes"; then + for ac_func in hypot +do : + ac_fn_c_check_func "$LINENO" "hypot" "ac_cv_func_hypot" +if test "x$ac_cv_func_hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOT 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypot declaration" >&5 +$as_echo_n "checking for _hypot declaration... " >&6; } + if test x${glibcxx_cv_func__hypot_use+set} != xset; then + if ${glibcxx_cv_func__hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypot_use=yes +else + glibcxx_cv_func__hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypot_use" >&5 +$as_echo "$glibcxx_cv_func__hypot_use" >&6; } + + if test x$glibcxx_cv_func__hypot_use = x"yes"; then + for ac_func in _hypot +do : + ac_fn_c_check_func "$LINENO" "_hypot" "ac_cv_func__hypot" +if test "x$ac_cv_func__hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOT 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float trig functions" >&5 +$as_echo_n "checking for float trig functions... " >&6; } + if ${glibcxx_cv_func_float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosf (0); asinf (0); atanf (0); cosf (0); sinf (0); tanf (0); coshf (0); sinhf (0); tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_trig_use=yes +else + glibcxx_cv_func_float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_trig_use" >&5 +$as_echo "$glibcxx_cv_func_float_trig_use" >&6; } + if test x$glibcxx_cv_func_float_trig_use = x"yes"; then + for ac_func in acosf asinf atanf cosf sinf tanf coshf sinhf tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float trig functions" >&5 +$as_echo_n "checking for _float trig functions... " >&6; } + if ${glibcxx_cv_func__float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosf (0); _asinf (0); _atanf (0); _cosf (0); _sinf (0); _tanf (0); _coshf (0); _sinhf (0); _tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_trig_use=yes +else + glibcxx_cv_func__float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_trig_use" >&5 +$as_echo "$glibcxx_cv_func__float_trig_use" >&6; } + if test x$glibcxx_cv_func__float_trig_use = x"yes"; then + for ac_func in _acosf _asinf _atanf _cosf _sinf _tanf _coshf _sinhf _tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float round functions" >&5 +$as_echo_n "checking for float round functions... " >&6; } + if ${glibcxx_cv_func_float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceilf (0); floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_round_use=yes +else + glibcxx_cv_func_float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_round_use" >&5 +$as_echo "$glibcxx_cv_func_float_round_use" >&6; } + if test x$glibcxx_cv_func_float_round_use = x"yes"; then + for ac_func in ceilf floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float round functions" >&5 +$as_echo_n "checking for _float round functions... " >&6; } + if ${glibcxx_cv_func__float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceilf (0); _floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_round_use=yes +else + glibcxx_cv_func__float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_round_use" >&5 +$as_echo "$glibcxx_cv_func__float_round_use" >&6; } + if test x$glibcxx_cv_func__float_round_use = x"yes"; then + for ac_func in _ceilf _floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expf declaration" >&5 +$as_echo_n "checking for expf declaration... " >&6; } + if test x${glibcxx_cv_func_expf_use+set} != xset; then + if ${glibcxx_cv_func_expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expf_use=yes +else + glibcxx_cv_func_expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expf_use" >&5 +$as_echo "$glibcxx_cv_func_expf_use" >&6; } + + if test x$glibcxx_cv_func_expf_use = x"yes"; then + for ac_func in expf +do : + ac_fn_c_check_func "$LINENO" "expf" "ac_cv_func_expf" +if test "x$ac_cv_func_expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expf declaration" >&5 +$as_echo_n "checking for _expf declaration... " >&6; } + if test x${glibcxx_cv_func__expf_use+set} != xset; then + if ${glibcxx_cv_func__expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expf_use=yes +else + glibcxx_cv_func__expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expf_use" >&5 +$as_echo "$glibcxx_cv_func__expf_use" >&6; } + + if test x$glibcxx_cv_func__expf_use = x"yes"; then + for ac_func in _expf +do : + ac_fn_c_check_func "$LINENO" "_expf" "ac_cv_func__expf" +if test "x$ac_cv_func__expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanf declaration" >&5 +$as_echo_n "checking for isnanf declaration... " >&6; } + if test x${glibcxx_cv_func_isnanf_use+set} != xset; then + if ${glibcxx_cv_func_isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanf_use=yes +else + glibcxx_cv_func_isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanf_use" >&5 +$as_echo "$glibcxx_cv_func_isnanf_use" >&6; } + + if test x$glibcxx_cv_func_isnanf_use = x"yes"; then + for ac_func in isnanf +do : + ac_fn_c_check_func "$LINENO" "isnanf" "ac_cv_func_isnanf" +if test "x$ac_cv_func_isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanf declaration" >&5 +$as_echo_n "checking for _isnanf declaration... " >&6; } + if test x${glibcxx_cv_func__isnanf_use+set} != xset; then + if ${glibcxx_cv_func__isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanf_use=yes +else + glibcxx_cv_func__isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanf_use" >&5 +$as_echo "$glibcxx_cv_func__isnanf_use" >&6; } + + if test x$glibcxx_cv_func__isnanf_use = x"yes"; then + for ac_func in _isnanf +do : + ac_fn_c_check_func "$LINENO" "_isnanf" "ac_cv_func__isnanf" +if test "x$ac_cv_func__isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinff declaration" >&5 +$as_echo_n "checking for isinff declaration... " >&6; } + if test x${glibcxx_cv_func_isinff_use+set} != xset; then + if ${glibcxx_cv_func_isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinff_use=yes +else + glibcxx_cv_func_isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinff_use" >&5 +$as_echo "$glibcxx_cv_func_isinff_use" >&6; } + + if test x$glibcxx_cv_func_isinff_use = x"yes"; then + for ac_func in isinff +do : + ac_fn_c_check_func "$LINENO" "isinff" "ac_cv_func_isinff" +if test "x$ac_cv_func_isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinff declaration" >&5 +$as_echo_n "checking for _isinff declaration... " >&6; } + if test x${glibcxx_cv_func__isinff_use+set} != xset; then + if ${glibcxx_cv_func__isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinff_use=yes +else + glibcxx_cv_func__isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinff_use" >&5 +$as_echo "$glibcxx_cv_func__isinff_use" >&6; } + + if test x$glibcxx_cv_func__isinff_use = x"yes"; then + for ac_func in _isinff +do : + ac_fn_c_check_func "$LINENO" "_isinff" "ac_cv_func__isinff" +if test "x$ac_cv_func__isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f declaration" >&5 +$as_echo_n "checking for atan2f declaration... " >&6; } + if test x${glibcxx_cv_func_atan2f_use+set} != xset; then + if ${glibcxx_cv_func_atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2f_use=yes +else + glibcxx_cv_func_atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2f_use" >&5 +$as_echo "$glibcxx_cv_func_atan2f_use" >&6; } + + if test x$glibcxx_cv_func_atan2f_use = x"yes"; then + for ac_func in atan2f +do : + ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2f declaration" >&5 +$as_echo_n "checking for _atan2f declaration... " >&6; } + if test x${glibcxx_cv_func__atan2f_use+set} != xset; then + if ${glibcxx_cv_func__atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2f_use=yes +else + glibcxx_cv_func__atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2f_use" >&5 +$as_echo "$glibcxx_cv_func__atan2f_use" >&6; } + + if test x$glibcxx_cv_func__atan2f_use = x"yes"; then + for ac_func in _atan2f +do : + ac_fn_c_check_func "$LINENO" "_atan2f" "ac_cv_func__atan2f" +if test "x$ac_cv_func__atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsf declaration" >&5 +$as_echo_n "checking for fabsf declaration... " >&6; } + if test x${glibcxx_cv_func_fabsf_use+set} != xset; then + if ${glibcxx_cv_func_fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsf_use=yes +else + glibcxx_cv_func_fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsf_use" >&5 +$as_echo "$glibcxx_cv_func_fabsf_use" >&6; } + + if test x$glibcxx_cv_func_fabsf_use = x"yes"; then + for ac_func in fabsf +do : + ac_fn_c_check_func "$LINENO" "fabsf" "ac_cv_func_fabsf" +if test "x$ac_cv_func_fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsf declaration" >&5 +$as_echo_n "checking for _fabsf declaration... " >&6; } + if test x${glibcxx_cv_func__fabsf_use+set} != xset; then + if ${glibcxx_cv_func__fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsf_use=yes +else + glibcxx_cv_func__fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsf_use" >&5 +$as_echo "$glibcxx_cv_func__fabsf_use" >&6; } + + if test x$glibcxx_cv_func__fabsf_use = x"yes"; then + for ac_func in _fabsf +do : + ac_fn_c_check_func "$LINENO" "_fabsf" "ac_cv_func__fabsf" +if test "x$ac_cv_func__fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf declaration" >&5 +$as_echo_n "checking for fmodf declaration... " >&6; } + if test x${glibcxx_cv_func_fmodf_use+set} != xset; then + if ${glibcxx_cv_func_fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodf_use=yes +else + glibcxx_cv_func_fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodf_use" >&5 +$as_echo "$glibcxx_cv_func_fmodf_use" >&6; } + + if test x$glibcxx_cv_func_fmodf_use = x"yes"; then + for ac_func in fmodf +do : + ac_fn_c_check_func "$LINENO" "fmodf" "ac_cv_func_fmodf" +if test "x$ac_cv_func_fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodf declaration" >&5 +$as_echo_n "checking for _fmodf declaration... " >&6; } + if test x${glibcxx_cv_func__fmodf_use+set} != xset; then + if ${glibcxx_cv_func__fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodf_use=yes +else + glibcxx_cv_func__fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodf_use" >&5 +$as_echo "$glibcxx_cv_func__fmodf_use" >&6; } + + if test x$glibcxx_cv_func__fmodf_use = x"yes"; then + for ac_func in _fmodf +do : + ac_fn_c_check_func "$LINENO" "_fmodf" "ac_cv_func__fmodf" +if test "x$ac_cv_func__fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } + if test x${glibcxx_cv_func_frexpf_use+set} != xset; then + if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + + if test x$glibcxx_cv_func_frexpf_use = x"yes"; then + for ac_func in frexpf +do : + ac_fn_c_check_func "$LINENO" "frexpf" "ac_cv_func_frexpf" +if test "x$ac_cv_func_frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpf declaration" >&5 +$as_echo_n "checking for _frexpf declaration... " >&6; } + if test x${glibcxx_cv_func__frexpf_use+set} != xset; then + if ${glibcxx_cv_func__frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpf_use=yes +else + glibcxx_cv_func__frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpf_use" >&5 +$as_echo "$glibcxx_cv_func__frexpf_use" >&6; } + + if test x$glibcxx_cv_func__frexpf_use = x"yes"; then + for ac_func in _frexpf +do : + ac_fn_c_check_func "$LINENO" "_frexpf" "ac_cv_func__frexpf" +if test "x$ac_cv_func__frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } + if test x${glibcxx_cv_func_hypotf_use+set} != xset; then + if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + + if test x$glibcxx_cv_func_hypotf_use = x"yes"; then + for ac_func in hypotf +do : + ac_fn_c_check_func "$LINENO" "hypotf" "ac_cv_func_hypotf" +if test "x$ac_cv_func_hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotf declaration" >&5 +$as_echo_n "checking for _hypotf declaration... " >&6; } + if test x${glibcxx_cv_func__hypotf_use+set} != xset; then + if ${glibcxx_cv_func__hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotf_use=yes +else + glibcxx_cv_func__hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotf_use" >&5 +$as_echo "$glibcxx_cv_func__hypotf_use" >&6; } + + if test x$glibcxx_cv_func__hypotf_use = x"yes"; then + for ac_func in _hypotf +do : + ac_fn_c_check_func "$LINENO" "_hypotf" "ac_cv_func__hypotf" +if test "x$ac_cv_func__hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpf_use+set} != xset; then + if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + + if test x$glibcxx_cv_func_ldexpf_use = x"yes"; then + for ac_func in ldexpf +do : + ac_fn_c_check_func "$LINENO" "ldexpf" "ac_cv_func_ldexpf" +if test "x$ac_cv_func_ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpf declaration" >&5 +$as_echo_n "checking for _ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpf_use+set} != xset; then + if ${glibcxx_cv_func__ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpf_use=yes +else + glibcxx_cv_func__ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpf_use" >&6; } + + if test x$glibcxx_cv_func__ldexpf_use = x"yes"; then + for ac_func in _ldexpf +do : + ac_fn_c_check_func "$LINENO" "_ldexpf" "ac_cv_func__ldexpf" +if test "x$ac_cv_func__ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logf declaration" >&5 +$as_echo_n "checking for logf declaration... " >&6; } + if test x${glibcxx_cv_func_logf_use+set} != xset; then + if ${glibcxx_cv_func_logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logf_use=yes +else + glibcxx_cv_func_logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logf_use" >&5 +$as_echo "$glibcxx_cv_func_logf_use" >&6; } + + if test x$glibcxx_cv_func_logf_use = x"yes"; then + for ac_func in logf +do : + ac_fn_c_check_func "$LINENO" "logf" "ac_cv_func_logf" +if test "x$ac_cv_func_logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logf declaration" >&5 +$as_echo_n "checking for _logf declaration... " >&6; } + if test x${glibcxx_cv_func__logf_use+set} != xset; then + if ${glibcxx_cv_func__logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logf_use=yes +else + glibcxx_cv_func__logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logf_use" >&5 +$as_echo "$glibcxx_cv_func__logf_use" >&6; } + + if test x$glibcxx_cv_func__logf_use = x"yes"; then + for ac_func in _logf +do : + ac_fn_c_check_func "$LINENO" "_logf" "ac_cv_func__logf" +if test "x$ac_cv_func__logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10f declaration" >&5 +$as_echo_n "checking for log10f declaration... " >&6; } + if test x${glibcxx_cv_func_log10f_use+set} != xset; then + if ${glibcxx_cv_func_log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10f_use=yes +else + glibcxx_cv_func_log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10f_use" >&5 +$as_echo "$glibcxx_cv_func_log10f_use" >&6; } + + if test x$glibcxx_cv_func_log10f_use = x"yes"; then + for ac_func in log10f +do : + ac_fn_c_check_func "$LINENO" "log10f" "ac_cv_func_log10f" +if test "x$ac_cv_func_log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10f declaration" >&5 +$as_echo_n "checking for _log10f declaration... " >&6; } + if test x${glibcxx_cv_func__log10f_use+set} != xset; then + if ${glibcxx_cv_func__log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10f_use=yes +else + glibcxx_cv_func__log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10f_use" >&5 +$as_echo "$glibcxx_cv_func__log10f_use" >&6; } + + if test x$glibcxx_cv_func__log10f_use = x"yes"; then + for ac_func in _log10f +do : + ac_fn_c_check_func "$LINENO" "_log10f" "ac_cv_func__log10f" +if test "x$ac_cv_func__log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } + if test x${glibcxx_cv_func_modff_use+set} != xset; then + if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + + if test x$glibcxx_cv_func_modff_use = x"yes"; then + for ac_func in modff +do : + ac_fn_c_check_func "$LINENO" "modff" "ac_cv_func_modff" +if test "x$ac_cv_func_modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modff declaration" >&5 +$as_echo_n "checking for _modff declaration... " >&6; } + if test x${glibcxx_cv_func__modff_use+set} != xset; then + if ${glibcxx_cv_func__modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modff_use=yes +else + glibcxx_cv_func__modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modff_use" >&5 +$as_echo "$glibcxx_cv_func__modff_use" >&6; } + + if test x$glibcxx_cv_func__modff_use = x"yes"; then + for ac_func in _modff +do : + ac_fn_c_check_func "$LINENO" "_modff" "ac_cv_func__modff" +if test "x$ac_cv_func__modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modf declaration" >&5 +$as_echo_n "checking for modf declaration... " >&6; } + if test x${glibcxx_cv_func_modf_use+set} != xset; then + if ${glibcxx_cv_func_modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modf_use=yes +else + glibcxx_cv_func_modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modf_use" >&5 +$as_echo "$glibcxx_cv_func_modf_use" >&6; } + + if test x$glibcxx_cv_func_modf_use = x"yes"; then + for ac_func in modf +do : + ac_fn_c_check_func "$LINENO" "modf" "ac_cv_func_modf" +if test "x$ac_cv_func_modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modf declaration" >&5 +$as_echo_n "checking for _modf declaration... " >&6; } + if test x${glibcxx_cv_func__modf_use+set} != xset; then + if ${glibcxx_cv_func__modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modf_use=yes +else + glibcxx_cv_func__modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modf_use" >&5 +$as_echo "$glibcxx_cv_func__modf_use" >&6; } + + if test x$glibcxx_cv_func__modf_use = x"yes"; then + for ac_func in _modf +do : + ac_fn_c_check_func "$LINENO" "_modf" "ac_cv_func__modf" +if test "x$ac_cv_func__modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powf declaration" >&5 +$as_echo_n "checking for powf declaration... " >&6; } + if test x${glibcxx_cv_func_powf_use+set} != xset; then + if ${glibcxx_cv_func_powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powf_use=yes +else + glibcxx_cv_func_powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powf_use" >&5 +$as_echo "$glibcxx_cv_func_powf_use" >&6; } + + if test x$glibcxx_cv_func_powf_use = x"yes"; then + for ac_func in powf +do : + ac_fn_c_check_func "$LINENO" "powf" "ac_cv_func_powf" +if test "x$ac_cv_func_powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powf declaration" >&5 +$as_echo_n "checking for _powf declaration... " >&6; } + if test x${glibcxx_cv_func__powf_use+set} != xset; then + if ${glibcxx_cv_func__powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powf_use=yes +else + glibcxx_cv_func__powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powf_use" >&5 +$as_echo "$glibcxx_cv_func__powf_use" >&6; } + + if test x$glibcxx_cv_func__powf_use = x"yes"; then + for ac_func in _powf +do : + ac_fn_c_check_func "$LINENO" "_powf" "ac_cv_func__powf" +if test "x$ac_cv_func__powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtf declaration" >&5 +$as_echo_n "checking for sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtf_use+set} != xset; then + if ${glibcxx_cv_func_sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtf_use=yes +else + glibcxx_cv_func_sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtf_use" >&6; } + + if test x$glibcxx_cv_func_sqrtf_use = x"yes"; then + for ac_func in sqrtf +do : + ac_fn_c_check_func "$LINENO" "sqrtf" "ac_cv_func_sqrtf" +if test "x$ac_cv_func_sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtf declaration" >&5 +$as_echo_n "checking for _sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtf_use+set} != xset; then + if ${glibcxx_cv_func__sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtf_use=yes +else + glibcxx_cv_func__sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtf_use" >&6; } + + if test x$glibcxx_cv_func__sqrtf_use = x"yes"; then + for ac_func in _sqrtf +do : + ac_fn_c_check_func "$LINENO" "_sqrtf" "ac_cv_func__sqrtf" +if test "x$ac_cv_func__sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosf declaration" >&5 +$as_echo_n "checking for sincosf declaration... " >&6; } + if test x${glibcxx_cv_func_sincosf_use+set} != xset; then + if ${glibcxx_cv_func_sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosf_use=yes +else + glibcxx_cv_func_sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosf_use" >&5 +$as_echo "$glibcxx_cv_func_sincosf_use" >&6; } + + if test x$glibcxx_cv_func_sincosf_use = x"yes"; then + for ac_func in sincosf +do : + ac_fn_c_check_func "$LINENO" "sincosf" "ac_cv_func_sincosf" +if test "x$ac_cv_func_sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosf declaration" >&5 +$as_echo_n "checking for _sincosf declaration... " >&6; } + if test x${glibcxx_cv_func__sincosf_use+set} != xset; then + if ${glibcxx_cv_func__sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosf_use=yes +else + glibcxx_cv_func__sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosf_use" >&5 +$as_echo "$glibcxx_cv_func__sincosf_use" >&6; } + + if test x$glibcxx_cv_func__sincosf_use = x"yes"; then + for ac_func in _sincosf +do : + ac_fn_c_check_func "$LINENO" "_sincosf" "ac_cv_func__sincosf" +if test "x$ac_cv_func__sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitef declaration" >&5 +$as_echo_n "checking for finitef declaration... " >&6; } + if test x${glibcxx_cv_func_finitef_use+set} != xset; then + if ${glibcxx_cv_func_finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitef_use=yes +else + glibcxx_cv_func_finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitef_use" >&5 +$as_echo "$glibcxx_cv_func_finitef_use" >&6; } + + if test x$glibcxx_cv_func_finitef_use = x"yes"; then + for ac_func in finitef +do : + ac_fn_c_check_func "$LINENO" "finitef" "ac_cv_func_finitef" +if test "x$ac_cv_func_finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitef declaration" >&5 +$as_echo_n "checking for _finitef declaration... " >&6; } + if test x${glibcxx_cv_func__finitef_use+set} != xset; then + if ${glibcxx_cv_func__finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitef_use=yes +else + glibcxx_cv_func__finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitef_use" >&5 +$as_echo "$glibcxx_cv_func__finitef_use" >&6; } + + if test x$glibcxx_cv_func__finitef_use = x"yes"; then + for ac_func in _finitef +do : + ac_fn_c_check_func "$LINENO" "_finitef" "ac_cv_func__finitef" +if test "x$ac_cv_func__finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double trig functions" >&5 +$as_echo_n "checking for long double trig functions... " >&6; } + if ${glibcxx_cv_func_long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosl (0); asinl (0); atanl (0); cosl (0); sinl (0); tanl (0); coshl (0); sinhl (0); tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_trig_use=yes +else + glibcxx_cv_func_long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_trig_use" >&6; } + if test x$glibcxx_cv_func_long_double_trig_use = x"yes"; then + for ac_func in acosl asinl atanl cosl sinl tanl coshl sinhl tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double trig functions" >&5 +$as_echo_n "checking for _long double trig functions... " >&6; } + if ${glibcxx_cv_func__long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosl (0); _asinl (0); _atanl (0); _cosl (0); _sinl (0); _tanl (0); _coshl (0); _sinhl (0); _tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_trig_use=yes +else + glibcxx_cv_func__long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_trig_use" >&6; } + if test x$glibcxx_cv_func__long_double_trig_use = x"yes"; then + for ac_func in _acosl _asinl _atanl _cosl _sinl _tanl _coshl _sinhl _tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double round functions" >&5 +$as_echo_n "checking for long double round functions... " >&6; } + if ${glibcxx_cv_func_long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceill (0); floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_round_use=yes +else + glibcxx_cv_func_long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_round_use" >&6; } + if test x$glibcxx_cv_func_long_double_round_use = x"yes"; then + for ac_func in ceill floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double round functions" >&5 +$as_echo_n "checking for _long double round functions... " >&6; } + if ${glibcxx_cv_func__long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceill (0); _floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_round_use=yes +else + glibcxx_cv_func__long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_round_use" >&6; } + if test x$glibcxx_cv_func__long_double_round_use = x"yes"; then + for ac_func in _ceill _floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanl declaration" >&5 +$as_echo_n "checking for isnanl declaration... " >&6; } + if test x${glibcxx_cv_func_isnanl_use+set} != xset; then + if ${glibcxx_cv_func_isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanl_use=yes +else + glibcxx_cv_func_isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanl_use" >&5 +$as_echo "$glibcxx_cv_func_isnanl_use" >&6; } + + if test x$glibcxx_cv_func_isnanl_use = x"yes"; then + for ac_func in isnanl +do : + ac_fn_c_check_func "$LINENO" "isnanl" "ac_cv_func_isnanl" +if test "x$ac_cv_func_isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanl declaration" >&5 +$as_echo_n "checking for _isnanl declaration... " >&6; } + if test x${glibcxx_cv_func__isnanl_use+set} != xset; then + if ${glibcxx_cv_func__isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanl_use=yes +else + glibcxx_cv_func__isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanl_use" >&5 +$as_echo "$glibcxx_cv_func__isnanl_use" >&6; } + + if test x$glibcxx_cv_func__isnanl_use = x"yes"; then + for ac_func in _isnanl +do : + ac_fn_c_check_func "$LINENO" "_isnanl" "ac_cv_func__isnanl" +if test "x$ac_cv_func__isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinfl declaration" >&5 +$as_echo_n "checking for isinfl declaration... " >&6; } + if test x${glibcxx_cv_func_isinfl_use+set} != xset; then + if ${glibcxx_cv_func_isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinfl_use=yes +else + glibcxx_cv_func_isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinfl_use" >&5 +$as_echo "$glibcxx_cv_func_isinfl_use" >&6; } + + if test x$glibcxx_cv_func_isinfl_use = x"yes"; then + for ac_func in isinfl +do : + ac_fn_c_check_func "$LINENO" "isinfl" "ac_cv_func_isinfl" +if test "x$ac_cv_func_isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinfl declaration" >&5 +$as_echo_n "checking for _isinfl declaration... " >&6; } + if test x${glibcxx_cv_func__isinfl_use+set} != xset; then + if ${glibcxx_cv_func__isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinfl_use=yes +else + glibcxx_cv_func__isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinfl_use" >&5 +$as_echo "$glibcxx_cv_func__isinfl_use" >&6; } + + if test x$glibcxx_cv_func__isinfl_use = x"yes"; then + for ac_func in _isinfl +do : + ac_fn_c_check_func "$LINENO" "_isinfl" "ac_cv_func__isinfl" +if test "x$ac_cv_func__isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } + if test x${glibcxx_cv_func_atan2l_use+set} != xset; then + if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + + if test x$glibcxx_cv_func_atan2l_use = x"yes"; then + for ac_func in atan2l +do : + ac_fn_c_check_func "$LINENO" "atan2l" "ac_cv_func_atan2l" +if test "x$ac_cv_func_atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2l declaration" >&5 +$as_echo_n "checking for _atan2l declaration... " >&6; } + if test x${glibcxx_cv_func__atan2l_use+set} != xset; then + if ${glibcxx_cv_func__atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2l_use=yes +else + glibcxx_cv_func__atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2l_use" >&5 +$as_echo "$glibcxx_cv_func__atan2l_use" >&6; } + + if test x$glibcxx_cv_func__atan2l_use = x"yes"; then + for ac_func in _atan2l +do : + ac_fn_c_check_func "$LINENO" "_atan2l" "ac_cv_func__atan2l" +if test "x$ac_cv_func__atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } + if test x${glibcxx_cv_func_expl_use+set} != xset; then + if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + + if test x$glibcxx_cv_func_expl_use = x"yes"; then + for ac_func in expl +do : + ac_fn_c_check_func "$LINENO" "expl" "ac_cv_func_expl" +if test "x$ac_cv_func_expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expl declaration" >&5 +$as_echo_n "checking for _expl declaration... " >&6; } + if test x${glibcxx_cv_func__expl_use+set} != xset; then + if ${glibcxx_cv_func__expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expl_use=yes +else + glibcxx_cv_func__expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expl_use" >&5 +$as_echo "$glibcxx_cv_func__expl_use" >&6; } + + if test x$glibcxx_cv_func__expl_use = x"yes"; then + for ac_func in _expl +do : + ac_fn_c_check_func "$LINENO" "_expl" "ac_cv_func__expl" +if test "x$ac_cv_func__expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } + if test x${glibcxx_cv_func_fabsl_use+set} != xset; then + if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + + if test x$glibcxx_cv_func_fabsl_use = x"yes"; then + for ac_func in fabsl +do : + ac_fn_c_check_func "$LINENO" "fabsl" "ac_cv_func_fabsl" +if test "x$ac_cv_func_fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsl declaration" >&5 +$as_echo_n "checking for _fabsl declaration... " >&6; } + if test x${glibcxx_cv_func__fabsl_use+set} != xset; then + if ${glibcxx_cv_func__fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsl_use=yes +else + glibcxx_cv_func__fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsl_use" >&5 +$as_echo "$glibcxx_cv_func__fabsl_use" >&6; } + + if test x$glibcxx_cv_func__fabsl_use = x"yes"; then + for ac_func in _fabsl +do : + ac_fn_c_check_func "$LINENO" "_fabsl" "ac_cv_func__fabsl" +if test "x$ac_cv_func__fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } + if test x${glibcxx_cv_func_fmodl_use+set} != xset; then + if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + + if test x$glibcxx_cv_func_fmodl_use = x"yes"; then + for ac_func in fmodl +do : + ac_fn_c_check_func "$LINENO" "fmodl" "ac_cv_func_fmodl" +if test "x$ac_cv_func_fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodl declaration" >&5 +$as_echo_n "checking for _fmodl declaration... " >&6; } + if test x${glibcxx_cv_func__fmodl_use+set} != xset; then + if ${glibcxx_cv_func__fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodl_use=yes +else + glibcxx_cv_func__fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodl_use" >&5 +$as_echo "$glibcxx_cv_func__fmodl_use" >&6; } + + if test x$glibcxx_cv_func__fmodl_use = x"yes"; then + for ac_func in _fmodl +do : + ac_fn_c_check_func "$LINENO" "_fmodl" "ac_cv_func__fmodl" +if test "x$ac_cv_func__fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } + if test x${glibcxx_cv_func_frexpl_use+set} != xset; then + if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + + if test x$glibcxx_cv_func_frexpl_use = x"yes"; then + for ac_func in frexpl +do : + ac_fn_c_check_func "$LINENO" "frexpl" "ac_cv_func_frexpl" +if test "x$ac_cv_func_frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpl declaration" >&5 +$as_echo_n "checking for _frexpl declaration... " >&6; } + if test x${glibcxx_cv_func__frexpl_use+set} != xset; then + if ${glibcxx_cv_func__frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpl_use=yes +else + glibcxx_cv_func__frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpl_use" >&5 +$as_echo "$glibcxx_cv_func__frexpl_use" >&6; } + + if test x$glibcxx_cv_func__frexpl_use = x"yes"; then + for ac_func in _frexpl +do : + ac_fn_c_check_func "$LINENO" "_frexpl" "ac_cv_func__frexpl" +if test "x$ac_cv_func__frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } + if test x${glibcxx_cv_func_hypotl_use+set} != xset; then + if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + + if test x$glibcxx_cv_func_hypotl_use = x"yes"; then + for ac_func in hypotl +do : + ac_fn_c_check_func "$LINENO" "hypotl" "ac_cv_func_hypotl" +if test "x$ac_cv_func_hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotl declaration" >&5 +$as_echo_n "checking for _hypotl declaration... " >&6; } + if test x${glibcxx_cv_func__hypotl_use+set} != xset; then + if ${glibcxx_cv_func__hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotl_use=yes +else + glibcxx_cv_func__hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotl_use" >&5 +$as_echo "$glibcxx_cv_func__hypotl_use" >&6; } + + if test x$glibcxx_cv_func__hypotl_use = x"yes"; then + for ac_func in _hypotl +do : + ac_fn_c_check_func "$LINENO" "_hypotl" "ac_cv_func__hypotl" +if test "x$ac_cv_func__hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpl_use+set} != xset; then + if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + + if test x$glibcxx_cv_func_ldexpl_use = x"yes"; then + for ac_func in ldexpl +do : + ac_fn_c_check_func "$LINENO" "ldexpl" "ac_cv_func_ldexpl" +if test "x$ac_cv_func_ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpl declaration" >&5 +$as_echo_n "checking for _ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpl_use+set} != xset; then + if ${glibcxx_cv_func__ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpl_use=yes +else + glibcxx_cv_func__ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpl_use" >&6; } + + if test x$glibcxx_cv_func__ldexpl_use = x"yes"; then + for ac_func in _ldexpl +do : + ac_fn_c_check_func "$LINENO" "_ldexpl" "ac_cv_func__ldexpl" +if test "x$ac_cv_func__ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } + if test x${glibcxx_cv_func_logl_use+set} != xset; then + if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + + if test x$glibcxx_cv_func_logl_use = x"yes"; then + for ac_func in logl +do : + ac_fn_c_check_func "$LINENO" "logl" "ac_cv_func_logl" +if test "x$ac_cv_func_logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logl declaration" >&5 +$as_echo_n "checking for _logl declaration... " >&6; } + if test x${glibcxx_cv_func__logl_use+set} != xset; then + if ${glibcxx_cv_func__logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logl_use=yes +else + glibcxx_cv_func__logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logl_use" >&5 +$as_echo "$glibcxx_cv_func__logl_use" >&6; } + + if test x$glibcxx_cv_func__logl_use = x"yes"; then + for ac_func in _logl +do : + ac_fn_c_check_func "$LINENO" "_logl" "ac_cv_func__logl" +if test "x$ac_cv_func__logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } + if test x${glibcxx_cv_func_log10l_use+set} != xset; then + if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + + if test x$glibcxx_cv_func_log10l_use = x"yes"; then + for ac_func in log10l +do : + ac_fn_c_check_func "$LINENO" "log10l" "ac_cv_func_log10l" +if test "x$ac_cv_func_log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10l declaration" >&5 +$as_echo_n "checking for _log10l declaration... " >&6; } + if test x${glibcxx_cv_func__log10l_use+set} != xset; then + if ${glibcxx_cv_func__log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10l_use=yes +else + glibcxx_cv_func__log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10l_use" >&5 +$as_echo "$glibcxx_cv_func__log10l_use" >&6; } + + if test x$glibcxx_cv_func__log10l_use = x"yes"; then + for ac_func in _log10l +do : + ac_fn_c_check_func "$LINENO" "_log10l" "ac_cv_func__log10l" +if test "x$ac_cv_func__log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } + if test x${glibcxx_cv_func_modfl_use+set} != xset; then + if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + + if test x$glibcxx_cv_func_modfl_use = x"yes"; then + for ac_func in modfl +do : + ac_fn_c_check_func "$LINENO" "modfl" "ac_cv_func_modfl" +if test "x$ac_cv_func_modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modfl declaration" >&5 +$as_echo_n "checking for _modfl declaration... " >&6; } + if test x${glibcxx_cv_func__modfl_use+set} != xset; then + if ${glibcxx_cv_func__modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modfl_use=yes +else + glibcxx_cv_func__modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modfl_use" >&5 +$as_echo "$glibcxx_cv_func__modfl_use" >&6; } + + if test x$glibcxx_cv_func__modfl_use = x"yes"; then + for ac_func in _modfl +do : + ac_fn_c_check_func "$LINENO" "_modfl" "ac_cv_func__modfl" +if test "x$ac_cv_func__modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } + if test x${glibcxx_cv_func_powl_use+set} != xset; then + if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + + if test x$glibcxx_cv_func_powl_use = x"yes"; then + for ac_func in powl +do : + ac_fn_c_check_func "$LINENO" "powl" "ac_cv_func_powl" +if test "x$ac_cv_func_powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powl declaration" >&5 +$as_echo_n "checking for _powl declaration... " >&6; } + if test x${glibcxx_cv_func__powl_use+set} != xset; then + if ${glibcxx_cv_func__powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powl_use=yes +else + glibcxx_cv_func__powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powl_use" >&5 +$as_echo "$glibcxx_cv_func__powl_use" >&6; } + + if test x$glibcxx_cv_func__powl_use = x"yes"; then + for ac_func in _powl +do : + ac_fn_c_check_func "$LINENO" "_powl" "ac_cv_func__powl" +if test "x$ac_cv_func__powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtl_use+set} != xset; then + if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + + if test x$glibcxx_cv_func_sqrtl_use = x"yes"; then + for ac_func in sqrtl +do : + ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl" +if test "x$ac_cv_func_sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtl declaration" >&5 +$as_echo_n "checking for _sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtl_use+set} != xset; then + if ${glibcxx_cv_func__sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtl_use=yes +else + glibcxx_cv_func__sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtl_use" >&6; } + + if test x$glibcxx_cv_func__sqrtl_use = x"yes"; then + for ac_func in _sqrtl +do : + ac_fn_c_check_func "$LINENO" "_sqrtl" "ac_cv_func__sqrtl" +if test "x$ac_cv_func__sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosl declaration" >&5 +$as_echo_n "checking for sincosl declaration... " >&6; } + if test x${glibcxx_cv_func_sincosl_use+set} != xset; then + if ${glibcxx_cv_func_sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosl_use=yes +else + glibcxx_cv_func_sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosl_use" >&5 +$as_echo "$glibcxx_cv_func_sincosl_use" >&6; } + + if test x$glibcxx_cv_func_sincosl_use = x"yes"; then + for ac_func in sincosl +do : + ac_fn_c_check_func "$LINENO" "sincosl" "ac_cv_func_sincosl" +if test "x$ac_cv_func_sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosl declaration" >&5 +$as_echo_n "checking for _sincosl declaration... " >&6; } + if test x${glibcxx_cv_func__sincosl_use+set} != xset; then + if ${glibcxx_cv_func__sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosl_use=yes +else + glibcxx_cv_func__sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosl_use" >&5 +$as_echo "$glibcxx_cv_func__sincosl_use" >&6; } + + if test x$glibcxx_cv_func__sincosl_use = x"yes"; then + for ac_func in _sincosl +do : + ac_fn_c_check_func "$LINENO" "_sincosl" "ac_cv_func__sincosl" +if test "x$ac_cv_func__sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitel declaration" >&5 +$as_echo_n "checking for finitel declaration... " >&6; } + if test x${glibcxx_cv_func_finitel_use+set} != xset; then + if ${glibcxx_cv_func_finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitel_use=yes +else + glibcxx_cv_func_finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitel_use" >&5 +$as_echo "$glibcxx_cv_func_finitel_use" >&6; } + + if test x$glibcxx_cv_func_finitel_use = x"yes"; then + for ac_func in finitel +do : + ac_fn_c_check_func "$LINENO" "finitel" "ac_cv_func_finitel" +if test "x$ac_cv_func_finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitel declaration" >&5 +$as_echo_n "checking for _finitel declaration... " >&6; } + if test x${glibcxx_cv_func__finitel_use+set} != xset; then + if ${glibcxx_cv_func__finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitel_use=yes +else + glibcxx_cv_func__finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitel_use" >&5 +$as_echo "$glibcxx_cv_func__finitel_use" >&6; } + + if test x$glibcxx_cv_func__finitel_use = x"yes"; then + for ac_func in _finitel +do : + ac_fn_c_check_func "$LINENO" "_finitel" "ac_cv_func__finitel" +if test "x$ac_cv_func__finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEL 1 +_ACEOF + +fi +done + + fi + fi + + + + + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for at_quick_exit declaration" >&5 +$as_echo_n "checking for at_quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_at_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_at_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + at_quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_at_quick_exit_use=yes +else + glibcxx_cv_func_at_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_at_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_at_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_at_quick_exit_use = x"yes"; then + for ac_func in at_quick_exit +do : + ac_fn_c_check_func "$LINENO" "at_quick_exit" "ac_cv_func_at_quick_exit" +if test "x$ac_cv_func_at_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AT_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for quick_exit declaration" >&5 +$as_echo_n "checking for quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_quick_exit_use=yes +else + glibcxx_cv_func_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_quick_exit_use = x"yes"; then + for ac_func in quick_exit +do : + ac_fn_c_check_func "$LINENO" "quick_exit" "ac_cv_func_quick_exit" +if test "x$ac_cv_func_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtold declaration" >&5 +$as_echo_n "checking for strtold declaration... " >&6; } + if test x${glibcxx_cv_func_strtold_use+set} != xset; then + if ${glibcxx_cv_func_strtold_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtold(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtold_use=yes +else + glibcxx_cv_func_strtold_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtold_use" >&5 +$as_echo "$glibcxx_cv_func_strtold_use" >&6; } + if test x$glibcxx_cv_func_strtold_use = x"yes"; then + for ac_func in strtold +do : + ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold" +if test "x$ac_cv_func_strtold" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOLD 1 +_ACEOF + +fi +done + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtof declaration" >&5 +$as_echo_n "checking for strtof declaration... " >&6; } + if test x${glibcxx_cv_func_strtof_use+set} != xset; then + if ${glibcxx_cv_func_strtof_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtof(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtof_use=yes +else + glibcxx_cv_func_strtof_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtof_use" >&5 +$as_echo "$glibcxx_cv_func_strtof_use" >&6; } + if test x$glibcxx_cv_func_strtof_use = x"yes"; then + for ac_func in strtof +do : + ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof" +if test "x$ac_cv_func_strtof" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOF 1 +_ACEOF + +fi +done + + fi + + + + + CXXFLAGS="$ac_save_CXXFLAGS" + + $as_echo "#define _GLIBCXX_USE_DEV_RANDOM 1" >>confdefs.h + + $as_echo "#define _GLIBCXX_USE_RANDOM_TR1 1" >>confdefs.h + + # We don't yet support AIX's TLS ABI. + #GCC_CHECK_TLS + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if ${am_cv_func_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + am_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCICONV" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + + if test "$am_cv_func_iconv" != yes && test -d ../libiconv; then + for _libs in .libs _libs; do + am_save_CPPFLAGS="$CPPFLAGS" + am_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS -I../libiconv/include" + LIBS="$LIBS ../libiconv/lib/$_libs/libiconv.a" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + INCICONV="-I../libiconv/include" + LIBICONV='${top_builddir}'/../libiconv/lib/$_libs/libiconv.a + LTLIBICONV='${top_builddir}'/../libiconv/lib/libiconv.la + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + LIBS="$am_save_LIBS" + if test "$am_cv_func_iconv" = "yes"; then + break + fi + done + fi + + if test "$am_cv_func_iconv" != yes; then + am_save_CPPFLAGS="$CPPFLAGS" + am_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $INCICONV" + LIBS="$LIBS $LIBICONV" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + fi + if test "$am_cv_lib_iconv" = yes; then + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 +$as_echo_n "checking how to link with libiconv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +$as_echo "$LIBICONV" >&6; } + else + LIBICONV= + LTLIBICONV= + fi + + + + if test "$am_cv_func_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 +$as_echo_n "checking for iconv declaration... " >&6; } + if ${am_cv_proto_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_cv_proto_iconv_arg1="" +else + am_cv_proto_iconv_arg1="const" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +fi + + am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- + }$am_cv_proto_iconv" >&5 +$as_echo "${ac_t:- + }$am_cv_proto_iconv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define ICONV_CONST $am_cv_proto_iconv_arg1 +_ACEOF + + fi + + + $as_echo "#define HAVE_USELOCALE 1" >>confdefs.h + + ;; + + *-darwin*) + # Darwin versions vary, but the linker should work in a cross environment, + # so we just check for all the features here. + # Check for available headers. + + # Don't call GLIBCXX_CHECK_LINKER_FEATURES, Darwin doesn't have a GNU ld + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + libm="-lm" +fi + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $libm" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf declaration" >&5 +$as_echo_n "checking for isinf declaration... " >&6; } + if test x${glibcxx_cv_func_isinf_use+set} != xset; then + if ${glibcxx_cv_func_isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinf_use=yes +else + glibcxx_cv_func_isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinf_use" >&5 +$as_echo "$glibcxx_cv_func_isinf_use" >&6; } + + if test x$glibcxx_cv_func_isinf_use = x"yes"; then + for ac_func in isinf +do : + ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinf declaration" >&5 +$as_echo_n "checking for _isinf declaration... " >&6; } + if test x${glibcxx_cv_func__isinf_use+set} != xset; then + if ${glibcxx_cv_func__isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinf_use=yes +else + glibcxx_cv_func__isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinf_use" >&5 +$as_echo "$glibcxx_cv_func__isinf_use" >&6; } + + if test x$glibcxx_cv_func__isinf_use = x"yes"; then + for ac_func in _isinf +do : + ac_fn_c_check_func "$LINENO" "_isinf" "ac_cv_func__isinf" +if test "x$ac_cv_func__isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan declaration" >&5 +$as_echo_n "checking for isnan declaration... " >&6; } + if test x${glibcxx_cv_func_isnan_use+set} != xset; then + if ${glibcxx_cv_func_isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnan_use=yes +else + glibcxx_cv_func_isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnan_use" >&5 +$as_echo "$glibcxx_cv_func_isnan_use" >&6; } + + if test x$glibcxx_cv_func_isnan_use = x"yes"; then + for ac_func in isnan +do : + ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNAN 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnan declaration" >&5 +$as_echo_n "checking for _isnan declaration... " >&6; } + if test x${glibcxx_cv_func__isnan_use+set} != xset; then + if ${glibcxx_cv_func__isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnan_use=yes +else + glibcxx_cv_func__isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnan_use" >&5 +$as_echo "$glibcxx_cv_func__isnan_use" >&6; } + + if test x$glibcxx_cv_func__isnan_use = x"yes"; then + for ac_func in _isnan +do : + ac_fn_c_check_func "$LINENO" "_isnan" "ac_cv_func__isnan" +if test "x$ac_cv_func__isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNAN 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finite declaration" >&5 +$as_echo_n "checking for finite declaration... " >&6; } + if test x${glibcxx_cv_func_finite_use+set} != xset; then + if ${glibcxx_cv_func_finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finite_use=yes +else + glibcxx_cv_func_finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finite_use" >&5 +$as_echo "$glibcxx_cv_func_finite_use" >&6; } + + if test x$glibcxx_cv_func_finite_use = x"yes"; then + for ac_func in finite +do : + ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITE 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finite declaration" >&5 +$as_echo_n "checking for _finite declaration... " >&6; } + if test x${glibcxx_cv_func__finite_use+set} != xset; then + if ${glibcxx_cv_func__finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finite_use=yes +else + glibcxx_cv_func__finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finite_use" >&5 +$as_echo "$glibcxx_cv_func__finite_use" >&6; } + + if test x$glibcxx_cv_func__finite_use = x"yes"; then + for ac_func in _finite +do : + ac_fn_c_check_func "$LINENO" "_finite" "ac_cv_func__finite" +if test "x$ac_cv_func__finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITE 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincos declaration" >&5 +$as_echo_n "checking for sincos declaration... " >&6; } + if test x${glibcxx_cv_func_sincos_use+set} != xset; then + if ${glibcxx_cv_func_sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincos_use=yes +else + glibcxx_cv_func_sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincos_use" >&5 +$as_echo "$glibcxx_cv_func_sincos_use" >&6; } + + if test x$glibcxx_cv_func_sincos_use = x"yes"; then + for ac_func in sincos +do : + ac_fn_c_check_func "$LINENO" "sincos" "ac_cv_func_sincos" +if test "x$ac_cv_func_sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincos declaration" >&5 +$as_echo_n "checking for _sincos declaration... " >&6; } + if test x${glibcxx_cv_func__sincos_use+set} != xset; then + if ${glibcxx_cv_func__sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincos_use=yes +else + glibcxx_cv_func__sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincos_use" >&5 +$as_echo "$glibcxx_cv_func__sincos_use" >&6; } + + if test x$glibcxx_cv_func__sincos_use = x"yes"; then + for ac_func in _sincos +do : + ac_fn_c_check_func "$LINENO" "_sincos" "ac_cv_func__sincos" +if test "x$ac_cv_func__sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpclass declaration" >&5 +$as_echo_n "checking for fpclass declaration... " >&6; } + if test x${glibcxx_cv_func_fpclass_use+set} != xset; then + if ${glibcxx_cv_func_fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fpclass_use=yes +else + glibcxx_cv_func_fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fpclass_use" >&5 +$as_echo "$glibcxx_cv_func_fpclass_use" >&6; } + + if test x$glibcxx_cv_func_fpclass_use = x"yes"; then + for ac_func in fpclass +do : + ac_fn_c_check_func "$LINENO" "fpclass" "ac_cv_func_fpclass" +if test "x$ac_cv_func_fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fpclass declaration" >&5 +$as_echo_n "checking for _fpclass declaration... " >&6; } + if test x${glibcxx_cv_func__fpclass_use+set} != xset; then + if ${glibcxx_cv_func__fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fpclass_use=yes +else + glibcxx_cv_func__fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fpclass_use" >&5 +$as_echo "$glibcxx_cv_func__fpclass_use" >&6; } + + if test x$glibcxx_cv_func__fpclass_use = x"yes"; then + for ac_func in _fpclass +do : + ac_fn_c_check_func "$LINENO" "_fpclass" "ac_cv_func__fpclass" +if test "x$ac_cv_func__fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for qfpclass declaration" >&5 +$as_echo_n "checking for qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func_qfpclass_use+set} != xset; then + if ${glibcxx_cv_func_qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_qfpclass_use=yes +else + glibcxx_cv_func_qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func_qfpclass_use" >&6; } + + if test x$glibcxx_cv_func_qfpclass_use = x"yes"; then + for ac_func in qfpclass +do : + ac_fn_c_check_func "$LINENO" "qfpclass" "ac_cv_func_qfpclass" +if test "x$ac_cv_func_qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QFPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _qfpclass declaration" >&5 +$as_echo_n "checking for _qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func__qfpclass_use+set} != xset; then + if ${glibcxx_cv_func__qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__qfpclass_use=yes +else + glibcxx_cv_func__qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func__qfpclass_use" >&6; } + + if test x$glibcxx_cv_func__qfpclass_use = x"yes"; then + for ac_func in _qfpclass +do : + ac_fn_c_check_func "$LINENO" "_qfpclass" "ac_cv_func__qfpclass" +if test "x$ac_cv_func__qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__QFPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypot declaration" >&5 +$as_echo_n "checking for hypot declaration... " >&6; } + if test x${glibcxx_cv_func_hypot_use+set} != xset; then + if ${glibcxx_cv_func_hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypot_use=yes +else + glibcxx_cv_func_hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypot_use" >&5 +$as_echo "$glibcxx_cv_func_hypot_use" >&6; } + + if test x$glibcxx_cv_func_hypot_use = x"yes"; then + for ac_func in hypot +do : + ac_fn_c_check_func "$LINENO" "hypot" "ac_cv_func_hypot" +if test "x$ac_cv_func_hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOT 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypot declaration" >&5 +$as_echo_n "checking for _hypot declaration... " >&6; } + if test x${glibcxx_cv_func__hypot_use+set} != xset; then + if ${glibcxx_cv_func__hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypot_use=yes +else + glibcxx_cv_func__hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypot_use" >&5 +$as_echo "$glibcxx_cv_func__hypot_use" >&6; } + + if test x$glibcxx_cv_func__hypot_use = x"yes"; then + for ac_func in _hypot +do : + ac_fn_c_check_func "$LINENO" "_hypot" "ac_cv_func__hypot" +if test "x$ac_cv_func__hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOT 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float trig functions" >&5 +$as_echo_n "checking for float trig functions... " >&6; } + if ${glibcxx_cv_func_float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosf (0); asinf (0); atanf (0); cosf (0); sinf (0); tanf (0); coshf (0); sinhf (0); tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_trig_use=yes +else + glibcxx_cv_func_float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_trig_use" >&5 +$as_echo "$glibcxx_cv_func_float_trig_use" >&6; } + if test x$glibcxx_cv_func_float_trig_use = x"yes"; then + for ac_func in acosf asinf atanf cosf sinf tanf coshf sinhf tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float trig functions" >&5 +$as_echo_n "checking for _float trig functions... " >&6; } + if ${glibcxx_cv_func__float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosf (0); _asinf (0); _atanf (0); _cosf (0); _sinf (0); _tanf (0); _coshf (0); _sinhf (0); _tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_trig_use=yes +else + glibcxx_cv_func__float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_trig_use" >&5 +$as_echo "$glibcxx_cv_func__float_trig_use" >&6; } + if test x$glibcxx_cv_func__float_trig_use = x"yes"; then + for ac_func in _acosf _asinf _atanf _cosf _sinf _tanf _coshf _sinhf _tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float round functions" >&5 +$as_echo_n "checking for float round functions... " >&6; } + if ${glibcxx_cv_func_float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceilf (0); floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_round_use=yes +else + glibcxx_cv_func_float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_round_use" >&5 +$as_echo "$glibcxx_cv_func_float_round_use" >&6; } + if test x$glibcxx_cv_func_float_round_use = x"yes"; then + for ac_func in ceilf floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float round functions" >&5 +$as_echo_n "checking for _float round functions... " >&6; } + if ${glibcxx_cv_func__float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceilf (0); _floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_round_use=yes +else + glibcxx_cv_func__float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_round_use" >&5 +$as_echo "$glibcxx_cv_func__float_round_use" >&6; } + if test x$glibcxx_cv_func__float_round_use = x"yes"; then + for ac_func in _ceilf _floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expf declaration" >&5 +$as_echo_n "checking for expf declaration... " >&6; } + if test x${glibcxx_cv_func_expf_use+set} != xset; then + if ${glibcxx_cv_func_expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expf_use=yes +else + glibcxx_cv_func_expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expf_use" >&5 +$as_echo "$glibcxx_cv_func_expf_use" >&6; } + + if test x$glibcxx_cv_func_expf_use = x"yes"; then + for ac_func in expf +do : + ac_fn_c_check_func "$LINENO" "expf" "ac_cv_func_expf" +if test "x$ac_cv_func_expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expf declaration" >&5 +$as_echo_n "checking for _expf declaration... " >&6; } + if test x${glibcxx_cv_func__expf_use+set} != xset; then + if ${glibcxx_cv_func__expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expf_use=yes +else + glibcxx_cv_func__expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expf_use" >&5 +$as_echo "$glibcxx_cv_func__expf_use" >&6; } + + if test x$glibcxx_cv_func__expf_use = x"yes"; then + for ac_func in _expf +do : + ac_fn_c_check_func "$LINENO" "_expf" "ac_cv_func__expf" +if test "x$ac_cv_func__expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanf declaration" >&5 +$as_echo_n "checking for isnanf declaration... " >&6; } + if test x${glibcxx_cv_func_isnanf_use+set} != xset; then + if ${glibcxx_cv_func_isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanf_use=yes +else + glibcxx_cv_func_isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanf_use" >&5 +$as_echo "$glibcxx_cv_func_isnanf_use" >&6; } + + if test x$glibcxx_cv_func_isnanf_use = x"yes"; then + for ac_func in isnanf +do : + ac_fn_c_check_func "$LINENO" "isnanf" "ac_cv_func_isnanf" +if test "x$ac_cv_func_isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanf declaration" >&5 +$as_echo_n "checking for _isnanf declaration... " >&6; } + if test x${glibcxx_cv_func__isnanf_use+set} != xset; then + if ${glibcxx_cv_func__isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanf_use=yes +else + glibcxx_cv_func__isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanf_use" >&5 +$as_echo "$glibcxx_cv_func__isnanf_use" >&6; } + + if test x$glibcxx_cv_func__isnanf_use = x"yes"; then + for ac_func in _isnanf +do : + ac_fn_c_check_func "$LINENO" "_isnanf" "ac_cv_func__isnanf" +if test "x$ac_cv_func__isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinff declaration" >&5 +$as_echo_n "checking for isinff declaration... " >&6; } + if test x${glibcxx_cv_func_isinff_use+set} != xset; then + if ${glibcxx_cv_func_isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinff_use=yes +else + glibcxx_cv_func_isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinff_use" >&5 +$as_echo "$glibcxx_cv_func_isinff_use" >&6; } + + if test x$glibcxx_cv_func_isinff_use = x"yes"; then + for ac_func in isinff +do : + ac_fn_c_check_func "$LINENO" "isinff" "ac_cv_func_isinff" +if test "x$ac_cv_func_isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinff declaration" >&5 +$as_echo_n "checking for _isinff declaration... " >&6; } + if test x${glibcxx_cv_func__isinff_use+set} != xset; then + if ${glibcxx_cv_func__isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinff_use=yes +else + glibcxx_cv_func__isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinff_use" >&5 +$as_echo "$glibcxx_cv_func__isinff_use" >&6; } + + if test x$glibcxx_cv_func__isinff_use = x"yes"; then + for ac_func in _isinff +do : + ac_fn_c_check_func "$LINENO" "_isinff" "ac_cv_func__isinff" +if test "x$ac_cv_func__isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f declaration" >&5 +$as_echo_n "checking for atan2f declaration... " >&6; } + if test x${glibcxx_cv_func_atan2f_use+set} != xset; then + if ${glibcxx_cv_func_atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2f_use=yes +else + glibcxx_cv_func_atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2f_use" >&5 +$as_echo "$glibcxx_cv_func_atan2f_use" >&6; } + + if test x$glibcxx_cv_func_atan2f_use = x"yes"; then + for ac_func in atan2f +do : + ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2f declaration" >&5 +$as_echo_n "checking for _atan2f declaration... " >&6; } + if test x${glibcxx_cv_func__atan2f_use+set} != xset; then + if ${glibcxx_cv_func__atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2f_use=yes +else + glibcxx_cv_func__atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2f_use" >&5 +$as_echo "$glibcxx_cv_func__atan2f_use" >&6; } + + if test x$glibcxx_cv_func__atan2f_use = x"yes"; then + for ac_func in _atan2f +do : + ac_fn_c_check_func "$LINENO" "_atan2f" "ac_cv_func__atan2f" +if test "x$ac_cv_func__atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsf declaration" >&5 +$as_echo_n "checking for fabsf declaration... " >&6; } + if test x${glibcxx_cv_func_fabsf_use+set} != xset; then + if ${glibcxx_cv_func_fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsf_use=yes +else + glibcxx_cv_func_fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsf_use" >&5 +$as_echo "$glibcxx_cv_func_fabsf_use" >&6; } + + if test x$glibcxx_cv_func_fabsf_use = x"yes"; then + for ac_func in fabsf +do : + ac_fn_c_check_func "$LINENO" "fabsf" "ac_cv_func_fabsf" +if test "x$ac_cv_func_fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsf declaration" >&5 +$as_echo_n "checking for _fabsf declaration... " >&6; } + if test x${glibcxx_cv_func__fabsf_use+set} != xset; then + if ${glibcxx_cv_func__fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsf_use=yes +else + glibcxx_cv_func__fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsf_use" >&5 +$as_echo "$glibcxx_cv_func__fabsf_use" >&6; } + + if test x$glibcxx_cv_func__fabsf_use = x"yes"; then + for ac_func in _fabsf +do : + ac_fn_c_check_func "$LINENO" "_fabsf" "ac_cv_func__fabsf" +if test "x$ac_cv_func__fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf declaration" >&5 +$as_echo_n "checking for fmodf declaration... " >&6; } + if test x${glibcxx_cv_func_fmodf_use+set} != xset; then + if ${glibcxx_cv_func_fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodf_use=yes +else + glibcxx_cv_func_fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodf_use" >&5 +$as_echo "$glibcxx_cv_func_fmodf_use" >&6; } + + if test x$glibcxx_cv_func_fmodf_use = x"yes"; then + for ac_func in fmodf +do : + ac_fn_c_check_func "$LINENO" "fmodf" "ac_cv_func_fmodf" +if test "x$ac_cv_func_fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodf declaration" >&5 +$as_echo_n "checking for _fmodf declaration... " >&6; } + if test x${glibcxx_cv_func__fmodf_use+set} != xset; then + if ${glibcxx_cv_func__fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodf_use=yes +else + glibcxx_cv_func__fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodf_use" >&5 +$as_echo "$glibcxx_cv_func__fmodf_use" >&6; } + + if test x$glibcxx_cv_func__fmodf_use = x"yes"; then + for ac_func in _fmodf +do : + ac_fn_c_check_func "$LINENO" "_fmodf" "ac_cv_func__fmodf" +if test "x$ac_cv_func__fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } + if test x${glibcxx_cv_func_frexpf_use+set} != xset; then + if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + + if test x$glibcxx_cv_func_frexpf_use = x"yes"; then + for ac_func in frexpf +do : + ac_fn_c_check_func "$LINENO" "frexpf" "ac_cv_func_frexpf" +if test "x$ac_cv_func_frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpf declaration" >&5 +$as_echo_n "checking for _frexpf declaration... " >&6; } + if test x${glibcxx_cv_func__frexpf_use+set} != xset; then + if ${glibcxx_cv_func__frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpf_use=yes +else + glibcxx_cv_func__frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpf_use" >&5 +$as_echo "$glibcxx_cv_func__frexpf_use" >&6; } + + if test x$glibcxx_cv_func__frexpf_use = x"yes"; then + for ac_func in _frexpf +do : + ac_fn_c_check_func "$LINENO" "_frexpf" "ac_cv_func__frexpf" +if test "x$ac_cv_func__frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } + if test x${glibcxx_cv_func_hypotf_use+set} != xset; then + if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + + if test x$glibcxx_cv_func_hypotf_use = x"yes"; then + for ac_func in hypotf +do : + ac_fn_c_check_func "$LINENO" "hypotf" "ac_cv_func_hypotf" +if test "x$ac_cv_func_hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotf declaration" >&5 +$as_echo_n "checking for _hypotf declaration... " >&6; } + if test x${glibcxx_cv_func__hypotf_use+set} != xset; then + if ${glibcxx_cv_func__hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotf_use=yes +else + glibcxx_cv_func__hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotf_use" >&5 +$as_echo "$glibcxx_cv_func__hypotf_use" >&6; } + + if test x$glibcxx_cv_func__hypotf_use = x"yes"; then + for ac_func in _hypotf +do : + ac_fn_c_check_func "$LINENO" "_hypotf" "ac_cv_func__hypotf" +if test "x$ac_cv_func__hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpf_use+set} != xset; then + if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + + if test x$glibcxx_cv_func_ldexpf_use = x"yes"; then + for ac_func in ldexpf +do : + ac_fn_c_check_func "$LINENO" "ldexpf" "ac_cv_func_ldexpf" +if test "x$ac_cv_func_ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpf declaration" >&5 +$as_echo_n "checking for _ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpf_use+set} != xset; then + if ${glibcxx_cv_func__ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpf_use=yes +else + glibcxx_cv_func__ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpf_use" >&6; } + + if test x$glibcxx_cv_func__ldexpf_use = x"yes"; then + for ac_func in _ldexpf +do : + ac_fn_c_check_func "$LINENO" "_ldexpf" "ac_cv_func__ldexpf" +if test "x$ac_cv_func__ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logf declaration" >&5 +$as_echo_n "checking for logf declaration... " >&6; } + if test x${glibcxx_cv_func_logf_use+set} != xset; then + if ${glibcxx_cv_func_logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logf_use=yes +else + glibcxx_cv_func_logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logf_use" >&5 +$as_echo "$glibcxx_cv_func_logf_use" >&6; } + + if test x$glibcxx_cv_func_logf_use = x"yes"; then + for ac_func in logf +do : + ac_fn_c_check_func "$LINENO" "logf" "ac_cv_func_logf" +if test "x$ac_cv_func_logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logf declaration" >&5 +$as_echo_n "checking for _logf declaration... " >&6; } + if test x${glibcxx_cv_func__logf_use+set} != xset; then + if ${glibcxx_cv_func__logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logf_use=yes +else + glibcxx_cv_func__logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logf_use" >&5 +$as_echo "$glibcxx_cv_func__logf_use" >&6; } + + if test x$glibcxx_cv_func__logf_use = x"yes"; then + for ac_func in _logf +do : + ac_fn_c_check_func "$LINENO" "_logf" "ac_cv_func__logf" +if test "x$ac_cv_func__logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10f declaration" >&5 +$as_echo_n "checking for log10f declaration... " >&6; } + if test x${glibcxx_cv_func_log10f_use+set} != xset; then + if ${glibcxx_cv_func_log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10f_use=yes +else + glibcxx_cv_func_log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10f_use" >&5 +$as_echo "$glibcxx_cv_func_log10f_use" >&6; } + + if test x$glibcxx_cv_func_log10f_use = x"yes"; then + for ac_func in log10f +do : + ac_fn_c_check_func "$LINENO" "log10f" "ac_cv_func_log10f" +if test "x$ac_cv_func_log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10f declaration" >&5 +$as_echo_n "checking for _log10f declaration... " >&6; } + if test x${glibcxx_cv_func__log10f_use+set} != xset; then + if ${glibcxx_cv_func__log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10f_use=yes +else + glibcxx_cv_func__log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10f_use" >&5 +$as_echo "$glibcxx_cv_func__log10f_use" >&6; } + + if test x$glibcxx_cv_func__log10f_use = x"yes"; then + for ac_func in _log10f +do : + ac_fn_c_check_func "$LINENO" "_log10f" "ac_cv_func__log10f" +if test "x$ac_cv_func__log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } + if test x${glibcxx_cv_func_modff_use+set} != xset; then + if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + + if test x$glibcxx_cv_func_modff_use = x"yes"; then + for ac_func in modff +do : + ac_fn_c_check_func "$LINENO" "modff" "ac_cv_func_modff" +if test "x$ac_cv_func_modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modff declaration" >&5 +$as_echo_n "checking for _modff declaration... " >&6; } + if test x${glibcxx_cv_func__modff_use+set} != xset; then + if ${glibcxx_cv_func__modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modff_use=yes +else + glibcxx_cv_func__modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modff_use" >&5 +$as_echo "$glibcxx_cv_func__modff_use" >&6; } + + if test x$glibcxx_cv_func__modff_use = x"yes"; then + for ac_func in _modff +do : + ac_fn_c_check_func "$LINENO" "_modff" "ac_cv_func__modff" +if test "x$ac_cv_func__modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modf declaration" >&5 +$as_echo_n "checking for modf declaration... " >&6; } + if test x${glibcxx_cv_func_modf_use+set} != xset; then + if ${glibcxx_cv_func_modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modf_use=yes +else + glibcxx_cv_func_modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modf_use" >&5 +$as_echo "$glibcxx_cv_func_modf_use" >&6; } + + if test x$glibcxx_cv_func_modf_use = x"yes"; then + for ac_func in modf +do : + ac_fn_c_check_func "$LINENO" "modf" "ac_cv_func_modf" +if test "x$ac_cv_func_modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modf declaration" >&5 +$as_echo_n "checking for _modf declaration... " >&6; } + if test x${glibcxx_cv_func__modf_use+set} != xset; then + if ${glibcxx_cv_func__modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modf_use=yes +else + glibcxx_cv_func__modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modf_use" >&5 +$as_echo "$glibcxx_cv_func__modf_use" >&6; } + + if test x$glibcxx_cv_func__modf_use = x"yes"; then + for ac_func in _modf +do : + ac_fn_c_check_func "$LINENO" "_modf" "ac_cv_func__modf" +if test "x$ac_cv_func__modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powf declaration" >&5 +$as_echo_n "checking for powf declaration... " >&6; } + if test x${glibcxx_cv_func_powf_use+set} != xset; then + if ${glibcxx_cv_func_powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powf_use=yes +else + glibcxx_cv_func_powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powf_use" >&5 +$as_echo "$glibcxx_cv_func_powf_use" >&6; } + + if test x$glibcxx_cv_func_powf_use = x"yes"; then + for ac_func in powf +do : + ac_fn_c_check_func "$LINENO" "powf" "ac_cv_func_powf" +if test "x$ac_cv_func_powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powf declaration" >&5 +$as_echo_n "checking for _powf declaration... " >&6; } + if test x${glibcxx_cv_func__powf_use+set} != xset; then + if ${glibcxx_cv_func__powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powf_use=yes +else + glibcxx_cv_func__powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powf_use" >&5 +$as_echo "$glibcxx_cv_func__powf_use" >&6; } + + if test x$glibcxx_cv_func__powf_use = x"yes"; then + for ac_func in _powf +do : + ac_fn_c_check_func "$LINENO" "_powf" "ac_cv_func__powf" +if test "x$ac_cv_func__powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtf declaration" >&5 +$as_echo_n "checking for sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtf_use+set} != xset; then + if ${glibcxx_cv_func_sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtf_use=yes +else + glibcxx_cv_func_sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtf_use" >&6; } + + if test x$glibcxx_cv_func_sqrtf_use = x"yes"; then + for ac_func in sqrtf +do : + ac_fn_c_check_func "$LINENO" "sqrtf" "ac_cv_func_sqrtf" +if test "x$ac_cv_func_sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtf declaration" >&5 +$as_echo_n "checking for _sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtf_use+set} != xset; then + if ${glibcxx_cv_func__sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtf_use=yes +else + glibcxx_cv_func__sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtf_use" >&6; } + + if test x$glibcxx_cv_func__sqrtf_use = x"yes"; then + for ac_func in _sqrtf +do : + ac_fn_c_check_func "$LINENO" "_sqrtf" "ac_cv_func__sqrtf" +if test "x$ac_cv_func__sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosf declaration" >&5 +$as_echo_n "checking for sincosf declaration... " >&6; } + if test x${glibcxx_cv_func_sincosf_use+set} != xset; then + if ${glibcxx_cv_func_sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosf_use=yes +else + glibcxx_cv_func_sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosf_use" >&5 +$as_echo "$glibcxx_cv_func_sincosf_use" >&6; } + + if test x$glibcxx_cv_func_sincosf_use = x"yes"; then + for ac_func in sincosf +do : + ac_fn_c_check_func "$LINENO" "sincosf" "ac_cv_func_sincosf" +if test "x$ac_cv_func_sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosf declaration" >&5 +$as_echo_n "checking for _sincosf declaration... " >&6; } + if test x${glibcxx_cv_func__sincosf_use+set} != xset; then + if ${glibcxx_cv_func__sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosf_use=yes +else + glibcxx_cv_func__sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosf_use" >&5 +$as_echo "$glibcxx_cv_func__sincosf_use" >&6; } + + if test x$glibcxx_cv_func__sincosf_use = x"yes"; then + for ac_func in _sincosf +do : + ac_fn_c_check_func "$LINENO" "_sincosf" "ac_cv_func__sincosf" +if test "x$ac_cv_func__sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitef declaration" >&5 +$as_echo_n "checking for finitef declaration... " >&6; } + if test x${glibcxx_cv_func_finitef_use+set} != xset; then + if ${glibcxx_cv_func_finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitef_use=yes +else + glibcxx_cv_func_finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitef_use" >&5 +$as_echo "$glibcxx_cv_func_finitef_use" >&6; } + + if test x$glibcxx_cv_func_finitef_use = x"yes"; then + for ac_func in finitef +do : + ac_fn_c_check_func "$LINENO" "finitef" "ac_cv_func_finitef" +if test "x$ac_cv_func_finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitef declaration" >&5 +$as_echo_n "checking for _finitef declaration... " >&6; } + if test x${glibcxx_cv_func__finitef_use+set} != xset; then + if ${glibcxx_cv_func__finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitef_use=yes +else + glibcxx_cv_func__finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitef_use" >&5 +$as_echo "$glibcxx_cv_func__finitef_use" >&6; } + + if test x$glibcxx_cv_func__finitef_use = x"yes"; then + for ac_func in _finitef +do : + ac_fn_c_check_func "$LINENO" "_finitef" "ac_cv_func__finitef" +if test "x$ac_cv_func__finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double trig functions" >&5 +$as_echo_n "checking for long double trig functions... " >&6; } + if ${glibcxx_cv_func_long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosl (0); asinl (0); atanl (0); cosl (0); sinl (0); tanl (0); coshl (0); sinhl (0); tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_trig_use=yes +else + glibcxx_cv_func_long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_trig_use" >&6; } + if test x$glibcxx_cv_func_long_double_trig_use = x"yes"; then + for ac_func in acosl asinl atanl cosl sinl tanl coshl sinhl tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double trig functions" >&5 +$as_echo_n "checking for _long double trig functions... " >&6; } + if ${glibcxx_cv_func__long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosl (0); _asinl (0); _atanl (0); _cosl (0); _sinl (0); _tanl (0); _coshl (0); _sinhl (0); _tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_trig_use=yes +else + glibcxx_cv_func__long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_trig_use" >&6; } + if test x$glibcxx_cv_func__long_double_trig_use = x"yes"; then + for ac_func in _acosl _asinl _atanl _cosl _sinl _tanl _coshl _sinhl _tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double round functions" >&5 +$as_echo_n "checking for long double round functions... " >&6; } + if ${glibcxx_cv_func_long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceill (0); floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_round_use=yes +else + glibcxx_cv_func_long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_round_use" >&6; } + if test x$glibcxx_cv_func_long_double_round_use = x"yes"; then + for ac_func in ceill floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double round functions" >&5 +$as_echo_n "checking for _long double round functions... " >&6; } + if ${glibcxx_cv_func__long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceill (0); _floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_round_use=yes +else + glibcxx_cv_func__long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_round_use" >&6; } + if test x$glibcxx_cv_func__long_double_round_use = x"yes"; then + for ac_func in _ceill _floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanl declaration" >&5 +$as_echo_n "checking for isnanl declaration... " >&6; } + if test x${glibcxx_cv_func_isnanl_use+set} != xset; then + if ${glibcxx_cv_func_isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanl_use=yes +else + glibcxx_cv_func_isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanl_use" >&5 +$as_echo "$glibcxx_cv_func_isnanl_use" >&6; } + + if test x$glibcxx_cv_func_isnanl_use = x"yes"; then + for ac_func in isnanl +do : + ac_fn_c_check_func "$LINENO" "isnanl" "ac_cv_func_isnanl" +if test "x$ac_cv_func_isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanl declaration" >&5 +$as_echo_n "checking for _isnanl declaration... " >&6; } + if test x${glibcxx_cv_func__isnanl_use+set} != xset; then + if ${glibcxx_cv_func__isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanl_use=yes +else + glibcxx_cv_func__isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanl_use" >&5 +$as_echo "$glibcxx_cv_func__isnanl_use" >&6; } + + if test x$glibcxx_cv_func__isnanl_use = x"yes"; then + for ac_func in _isnanl +do : + ac_fn_c_check_func "$LINENO" "_isnanl" "ac_cv_func__isnanl" +if test "x$ac_cv_func__isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinfl declaration" >&5 +$as_echo_n "checking for isinfl declaration... " >&6; } + if test x${glibcxx_cv_func_isinfl_use+set} != xset; then + if ${glibcxx_cv_func_isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinfl_use=yes +else + glibcxx_cv_func_isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinfl_use" >&5 +$as_echo "$glibcxx_cv_func_isinfl_use" >&6; } + + if test x$glibcxx_cv_func_isinfl_use = x"yes"; then + for ac_func in isinfl +do : + ac_fn_c_check_func "$LINENO" "isinfl" "ac_cv_func_isinfl" +if test "x$ac_cv_func_isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinfl declaration" >&5 +$as_echo_n "checking for _isinfl declaration... " >&6; } + if test x${glibcxx_cv_func__isinfl_use+set} != xset; then + if ${glibcxx_cv_func__isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinfl_use=yes +else + glibcxx_cv_func__isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinfl_use" >&5 +$as_echo "$glibcxx_cv_func__isinfl_use" >&6; } + + if test x$glibcxx_cv_func__isinfl_use = x"yes"; then + for ac_func in _isinfl +do : + ac_fn_c_check_func "$LINENO" "_isinfl" "ac_cv_func__isinfl" +if test "x$ac_cv_func__isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } + if test x${glibcxx_cv_func_atan2l_use+set} != xset; then + if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + + if test x$glibcxx_cv_func_atan2l_use = x"yes"; then + for ac_func in atan2l +do : + ac_fn_c_check_func "$LINENO" "atan2l" "ac_cv_func_atan2l" +if test "x$ac_cv_func_atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2l declaration" >&5 +$as_echo_n "checking for _atan2l declaration... " >&6; } + if test x${glibcxx_cv_func__atan2l_use+set} != xset; then + if ${glibcxx_cv_func__atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2l_use=yes +else + glibcxx_cv_func__atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2l_use" >&5 +$as_echo "$glibcxx_cv_func__atan2l_use" >&6; } + + if test x$glibcxx_cv_func__atan2l_use = x"yes"; then + for ac_func in _atan2l +do : + ac_fn_c_check_func "$LINENO" "_atan2l" "ac_cv_func__atan2l" +if test "x$ac_cv_func__atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } + if test x${glibcxx_cv_func_expl_use+set} != xset; then + if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + + if test x$glibcxx_cv_func_expl_use = x"yes"; then + for ac_func in expl +do : + ac_fn_c_check_func "$LINENO" "expl" "ac_cv_func_expl" +if test "x$ac_cv_func_expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expl declaration" >&5 +$as_echo_n "checking for _expl declaration... " >&6; } + if test x${glibcxx_cv_func__expl_use+set} != xset; then + if ${glibcxx_cv_func__expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expl_use=yes +else + glibcxx_cv_func__expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expl_use" >&5 +$as_echo "$glibcxx_cv_func__expl_use" >&6; } + + if test x$glibcxx_cv_func__expl_use = x"yes"; then + for ac_func in _expl +do : + ac_fn_c_check_func "$LINENO" "_expl" "ac_cv_func__expl" +if test "x$ac_cv_func__expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } + if test x${glibcxx_cv_func_fabsl_use+set} != xset; then + if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + + if test x$glibcxx_cv_func_fabsl_use = x"yes"; then + for ac_func in fabsl +do : + ac_fn_c_check_func "$LINENO" "fabsl" "ac_cv_func_fabsl" +if test "x$ac_cv_func_fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsl declaration" >&5 +$as_echo_n "checking for _fabsl declaration... " >&6; } + if test x${glibcxx_cv_func__fabsl_use+set} != xset; then + if ${glibcxx_cv_func__fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsl_use=yes +else + glibcxx_cv_func__fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsl_use" >&5 +$as_echo "$glibcxx_cv_func__fabsl_use" >&6; } + + if test x$glibcxx_cv_func__fabsl_use = x"yes"; then + for ac_func in _fabsl +do : + ac_fn_c_check_func "$LINENO" "_fabsl" "ac_cv_func__fabsl" +if test "x$ac_cv_func__fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } + if test x${glibcxx_cv_func_fmodl_use+set} != xset; then + if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + + if test x$glibcxx_cv_func_fmodl_use = x"yes"; then + for ac_func in fmodl +do : + ac_fn_c_check_func "$LINENO" "fmodl" "ac_cv_func_fmodl" +if test "x$ac_cv_func_fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodl declaration" >&5 +$as_echo_n "checking for _fmodl declaration... " >&6; } + if test x${glibcxx_cv_func__fmodl_use+set} != xset; then + if ${glibcxx_cv_func__fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodl_use=yes +else + glibcxx_cv_func__fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodl_use" >&5 +$as_echo "$glibcxx_cv_func__fmodl_use" >&6; } + + if test x$glibcxx_cv_func__fmodl_use = x"yes"; then + for ac_func in _fmodl +do : + ac_fn_c_check_func "$LINENO" "_fmodl" "ac_cv_func__fmodl" +if test "x$ac_cv_func__fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } + if test x${glibcxx_cv_func_frexpl_use+set} != xset; then + if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + + if test x$glibcxx_cv_func_frexpl_use = x"yes"; then + for ac_func in frexpl +do : + ac_fn_c_check_func "$LINENO" "frexpl" "ac_cv_func_frexpl" +if test "x$ac_cv_func_frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpl declaration" >&5 +$as_echo_n "checking for _frexpl declaration... " >&6; } + if test x${glibcxx_cv_func__frexpl_use+set} != xset; then + if ${glibcxx_cv_func__frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpl_use=yes +else + glibcxx_cv_func__frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpl_use" >&5 +$as_echo "$glibcxx_cv_func__frexpl_use" >&6; } + + if test x$glibcxx_cv_func__frexpl_use = x"yes"; then + for ac_func in _frexpl +do : + ac_fn_c_check_func "$LINENO" "_frexpl" "ac_cv_func__frexpl" +if test "x$ac_cv_func__frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } + if test x${glibcxx_cv_func_hypotl_use+set} != xset; then + if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + + if test x$glibcxx_cv_func_hypotl_use = x"yes"; then + for ac_func in hypotl +do : + ac_fn_c_check_func "$LINENO" "hypotl" "ac_cv_func_hypotl" +if test "x$ac_cv_func_hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotl declaration" >&5 +$as_echo_n "checking for _hypotl declaration... " >&6; } + if test x${glibcxx_cv_func__hypotl_use+set} != xset; then + if ${glibcxx_cv_func__hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotl_use=yes +else + glibcxx_cv_func__hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotl_use" >&5 +$as_echo "$glibcxx_cv_func__hypotl_use" >&6; } + + if test x$glibcxx_cv_func__hypotl_use = x"yes"; then + for ac_func in _hypotl +do : + ac_fn_c_check_func "$LINENO" "_hypotl" "ac_cv_func__hypotl" +if test "x$ac_cv_func__hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpl_use+set} != xset; then + if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + + if test x$glibcxx_cv_func_ldexpl_use = x"yes"; then + for ac_func in ldexpl +do : + ac_fn_c_check_func "$LINENO" "ldexpl" "ac_cv_func_ldexpl" +if test "x$ac_cv_func_ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpl declaration" >&5 +$as_echo_n "checking for _ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpl_use+set} != xset; then + if ${glibcxx_cv_func__ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpl_use=yes +else + glibcxx_cv_func__ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpl_use" >&6; } + + if test x$glibcxx_cv_func__ldexpl_use = x"yes"; then + for ac_func in _ldexpl +do : + ac_fn_c_check_func "$LINENO" "_ldexpl" "ac_cv_func__ldexpl" +if test "x$ac_cv_func__ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } + if test x${glibcxx_cv_func_logl_use+set} != xset; then + if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + + if test x$glibcxx_cv_func_logl_use = x"yes"; then + for ac_func in logl +do : + ac_fn_c_check_func "$LINENO" "logl" "ac_cv_func_logl" +if test "x$ac_cv_func_logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logl declaration" >&5 +$as_echo_n "checking for _logl declaration... " >&6; } + if test x${glibcxx_cv_func__logl_use+set} != xset; then + if ${glibcxx_cv_func__logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logl_use=yes +else + glibcxx_cv_func__logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logl_use" >&5 +$as_echo "$glibcxx_cv_func__logl_use" >&6; } + + if test x$glibcxx_cv_func__logl_use = x"yes"; then + for ac_func in _logl +do : + ac_fn_c_check_func "$LINENO" "_logl" "ac_cv_func__logl" +if test "x$ac_cv_func__logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } + if test x${glibcxx_cv_func_log10l_use+set} != xset; then + if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + + if test x$glibcxx_cv_func_log10l_use = x"yes"; then + for ac_func in log10l +do : + ac_fn_c_check_func "$LINENO" "log10l" "ac_cv_func_log10l" +if test "x$ac_cv_func_log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10l declaration" >&5 +$as_echo_n "checking for _log10l declaration... " >&6; } + if test x${glibcxx_cv_func__log10l_use+set} != xset; then + if ${glibcxx_cv_func__log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10l_use=yes +else + glibcxx_cv_func__log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10l_use" >&5 +$as_echo "$glibcxx_cv_func__log10l_use" >&6; } + + if test x$glibcxx_cv_func__log10l_use = x"yes"; then + for ac_func in _log10l +do : + ac_fn_c_check_func "$LINENO" "_log10l" "ac_cv_func__log10l" +if test "x$ac_cv_func__log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } + if test x${glibcxx_cv_func_modfl_use+set} != xset; then + if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + + if test x$glibcxx_cv_func_modfl_use = x"yes"; then + for ac_func in modfl +do : + ac_fn_c_check_func "$LINENO" "modfl" "ac_cv_func_modfl" +if test "x$ac_cv_func_modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modfl declaration" >&5 +$as_echo_n "checking for _modfl declaration... " >&6; } + if test x${glibcxx_cv_func__modfl_use+set} != xset; then + if ${glibcxx_cv_func__modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modfl_use=yes +else + glibcxx_cv_func__modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modfl_use" >&5 +$as_echo "$glibcxx_cv_func__modfl_use" >&6; } + + if test x$glibcxx_cv_func__modfl_use = x"yes"; then + for ac_func in _modfl +do : + ac_fn_c_check_func "$LINENO" "_modfl" "ac_cv_func__modfl" +if test "x$ac_cv_func__modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } + if test x${glibcxx_cv_func_powl_use+set} != xset; then + if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + + if test x$glibcxx_cv_func_powl_use = x"yes"; then + for ac_func in powl +do : + ac_fn_c_check_func "$LINENO" "powl" "ac_cv_func_powl" +if test "x$ac_cv_func_powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powl declaration" >&5 +$as_echo_n "checking for _powl declaration... " >&6; } + if test x${glibcxx_cv_func__powl_use+set} != xset; then + if ${glibcxx_cv_func__powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powl_use=yes +else + glibcxx_cv_func__powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powl_use" >&5 +$as_echo "$glibcxx_cv_func__powl_use" >&6; } + + if test x$glibcxx_cv_func__powl_use = x"yes"; then + for ac_func in _powl +do : + ac_fn_c_check_func "$LINENO" "_powl" "ac_cv_func__powl" +if test "x$ac_cv_func__powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtl_use+set} != xset; then + if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + + if test x$glibcxx_cv_func_sqrtl_use = x"yes"; then + for ac_func in sqrtl +do : + ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl" +if test "x$ac_cv_func_sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtl declaration" >&5 +$as_echo_n "checking for _sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtl_use+set} != xset; then + if ${glibcxx_cv_func__sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtl_use=yes +else + glibcxx_cv_func__sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtl_use" >&6; } + + if test x$glibcxx_cv_func__sqrtl_use = x"yes"; then + for ac_func in _sqrtl +do : + ac_fn_c_check_func "$LINENO" "_sqrtl" "ac_cv_func__sqrtl" +if test "x$ac_cv_func__sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosl declaration" >&5 +$as_echo_n "checking for sincosl declaration... " >&6; } + if test x${glibcxx_cv_func_sincosl_use+set} != xset; then + if ${glibcxx_cv_func_sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosl_use=yes +else + glibcxx_cv_func_sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosl_use" >&5 +$as_echo "$glibcxx_cv_func_sincosl_use" >&6; } + + if test x$glibcxx_cv_func_sincosl_use = x"yes"; then + for ac_func in sincosl +do : + ac_fn_c_check_func "$LINENO" "sincosl" "ac_cv_func_sincosl" +if test "x$ac_cv_func_sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosl declaration" >&5 +$as_echo_n "checking for _sincosl declaration... " >&6; } + if test x${glibcxx_cv_func__sincosl_use+set} != xset; then + if ${glibcxx_cv_func__sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosl_use=yes +else + glibcxx_cv_func__sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosl_use" >&5 +$as_echo "$glibcxx_cv_func__sincosl_use" >&6; } + + if test x$glibcxx_cv_func__sincosl_use = x"yes"; then + for ac_func in _sincosl +do : + ac_fn_c_check_func "$LINENO" "_sincosl" "ac_cv_func__sincosl" +if test "x$ac_cv_func__sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitel declaration" >&5 +$as_echo_n "checking for finitel declaration... " >&6; } + if test x${glibcxx_cv_func_finitel_use+set} != xset; then + if ${glibcxx_cv_func_finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitel_use=yes +else + glibcxx_cv_func_finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitel_use" >&5 +$as_echo "$glibcxx_cv_func_finitel_use" >&6; } + + if test x$glibcxx_cv_func_finitel_use = x"yes"; then + for ac_func in finitel +do : + ac_fn_c_check_func "$LINENO" "finitel" "ac_cv_func_finitel" +if test "x$ac_cv_func_finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitel declaration" >&5 +$as_echo_n "checking for _finitel declaration... " >&6; } + if test x${glibcxx_cv_func__finitel_use+set} != xset; then + if ${glibcxx_cv_func__finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitel_use=yes +else + glibcxx_cv_func__finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitel_use" >&5 +$as_echo "$glibcxx_cv_func__finitel_use" >&6; } + + if test x$glibcxx_cv_func__finitel_use = x"yes"; then + for ac_func in _finitel +do : + ac_fn_c_check_func "$LINENO" "_finitel" "ac_cv_func__finitel" +if test "x$ac_cv_func__finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEL 1 +_ACEOF + +fi +done + + fi + fi + + + + + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for at_quick_exit declaration" >&5 +$as_echo_n "checking for at_quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_at_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_at_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + at_quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_at_quick_exit_use=yes +else + glibcxx_cv_func_at_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_at_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_at_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_at_quick_exit_use = x"yes"; then + for ac_func in at_quick_exit +do : + ac_fn_c_check_func "$LINENO" "at_quick_exit" "ac_cv_func_at_quick_exit" +if test "x$ac_cv_func_at_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AT_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for quick_exit declaration" >&5 +$as_echo_n "checking for quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_quick_exit_use=yes +else + glibcxx_cv_func_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_quick_exit_use = x"yes"; then + for ac_func in quick_exit +do : + ac_fn_c_check_func "$LINENO" "quick_exit" "ac_cv_func_quick_exit" +if test "x$ac_cv_func_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtold declaration" >&5 +$as_echo_n "checking for strtold declaration... " >&6; } + if test x${glibcxx_cv_func_strtold_use+set} != xset; then + if ${glibcxx_cv_func_strtold_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtold(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtold_use=yes +else + glibcxx_cv_func_strtold_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtold_use" >&5 +$as_echo "$glibcxx_cv_func_strtold_use" >&6; } + if test x$glibcxx_cv_func_strtold_use = x"yes"; then + for ac_func in strtold +do : + ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold" +if test "x$ac_cv_func_strtold" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOLD 1 +_ACEOF + +fi +done + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtof declaration" >&5 +$as_echo_n "checking for strtof declaration... " >&6; } + if test x${glibcxx_cv_func_strtof_use+set} != xset; then + if ${glibcxx_cv_func_strtof_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtof(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtof_use=yes +else + glibcxx_cv_func_strtof_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtof_use" >&5 +$as_echo "$glibcxx_cv_func_strtof_use" >&6; } + if test x$glibcxx_cv_func_strtof_use = x"yes"; then + for ac_func in strtof +do : + ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof" +if test "x$ac_cv_func_strtof" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOF 1 +_ACEOF + +fi +done + + fi + + + + + CXXFLAGS="$ac_save_CXXFLAGS" + + + for ac_func in uselocale +do : + ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale" +if test "x$ac_cv_func_uselocale" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_USELOCALE 1 +_ACEOF + +fi +done + + ;; + + *djgpp) + # GLIBCXX_CHECK_MATH_SUPPORT + $as_echo "#define HAVE_ISINF 1" >>confdefs.h + + $as_echo "#define HAVE_ISNAN 1" >>confdefs.h + + $as_echo "#define HAVE_FINITE 1" >>confdefs.h + + $as_echo "#define HAVE_SINCOS 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOT 1" >>confdefs.h + + ;; + + *-freebsd*) + SECTION_FLAGS='-ffunction-sections -fdata-sections' + + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + $as_echo "#define HAVE_SETENV 1" >>confdefs.h + + $as_echo "#define HAVE_FINITEF 1" >>confdefs.h + + $as_echo "#define HAVE_FINITE 1" >>confdefs.h + + $as_echo "#define HAVE_FREXPF 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOT 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOTF 1" >>confdefs.h + + $as_echo "#define HAVE_ISINF 1" >>confdefs.h + + $as_echo "#define HAVE_ISNAN 1" >>confdefs.h + + $as_echo "#define HAVE_ISNANF 1" >>confdefs.h + + + $as_echo "#define HAVE_ACOSF 1" >>confdefs.h + + $as_echo "#define HAVE_ASINF 1" >>confdefs.h + + $as_echo "#define HAVE_ATAN2F 1" >>confdefs.h + + $as_echo "#define HAVE_ATANF 1" >>confdefs.h + + $as_echo "#define HAVE_CEILF 1" >>confdefs.h + + $as_echo "#define HAVE_COSF 1" >>confdefs.h + + $as_echo "#define HAVE_COSHF 1" >>confdefs.h + + $as_echo "#define HAVE_EXPF 1" >>confdefs.h + + $as_echo "#define HAVE_FABSF 1" >>confdefs.h + + $as_echo "#define HAVE_FLOORF 1" >>confdefs.h + + $as_echo "#define HAVE_FMODF 1" >>confdefs.h + + $as_echo "#define HAVE_FREXPF 1" >>confdefs.h + + $as_echo "#define HAVE_LDEXPF 1" >>confdefs.h + + $as_echo "#define HAVE_LOG10F 1" >>confdefs.h + + $as_echo "#define HAVE_LOGF 1" >>confdefs.h + + $as_echo "#define HAVE_MODFF 1" >>confdefs.h + + $as_echo "#define HAVE_POWF 1" >>confdefs.h + + $as_echo "#define HAVE_SINF 1" >>confdefs.h + + $as_echo "#define HAVE_SINHF 1" >>confdefs.h + + $as_echo "#define HAVE_SQRTF 1" >>confdefs.h + + $as_echo "#define HAVE_TANF 1" >>confdefs.h + + $as_echo "#define HAVE_TANHF 1" >>confdefs.h + + if test x"long_double_math_on_this_cpu" = x"yes"; then + $as_echo "#define HAVE_FINITEL 1" >>confdefs.h + + $as_echo "#define HAVE_ISINFL 1" >>confdefs.h + + $as_echo "#define HAVE_ISNANL 1" >>confdefs.h + + fi + for ac_func in __cxa_thread_atexit +do : + ac_fn_c_check_func "$LINENO" "__cxa_thread_atexit" "ac_cv_func___cxa_thread_atexit" +if test "x$ac_cv_func___cxa_thread_atexit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE___CXA_THREAD_ATEXIT 1 +_ACEOF + +fi +done + + for ac_func in aligned_alloc posix_memalign memalign _aligned_malloc +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + for ac_func in timespec_get +do : + ac_fn_c_check_func "$LINENO" "timespec_get" "ac_cv_func_timespec_get" +if test "x$ac_cv_func_timespec_get" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_TIMESPEC_GET 1 +_ACEOF + +fi +done + + for ac_func in sockatmark +do : + ac_fn_c_check_func "$LINENO" "sockatmark" "ac_cv_func_sockatmark" +if test "x$ac_cv_func_sockatmark" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKATMARK 1 +_ACEOF + +fi +done + + for ac_func in uselocale +do : + ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale" +if test "x$ac_cv_func_uselocale" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_USELOCALE 1 +_ACEOF + +fi +done + + ;; + + *-fuchsia*) + SECTION_FLAGS='-ffunction-sections -fdata-sections' + + ;; + + *-essence*) + + ;; + + *-hpux*) + SECTION_FLAGS='-ffunction-sections -fdata-sections' + + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + + # GLIBCXX_CHECK_MATH_SUPPORT + $as_echo "#define HAVE_ISNAN 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOT 1" >>confdefs.h + + $as_echo "#define HAVE_ACOSF 1" >>confdefs.h + + $as_echo "#define HAVE_ASINF 1" >>confdefs.h + + $as_echo "#define HAVE_ATANF 1" >>confdefs.h + + $as_echo "#define HAVE_COSF 1" >>confdefs.h + + $as_echo "#define HAVE_COSHF 1" >>confdefs.h + + $as_echo "#define HAVE_SINF 1" >>confdefs.h + + $as_echo "#define HAVE_SINHF 1" >>confdefs.h + + $as_echo "#define HAVE_TANF 1" >>confdefs.h + + $as_echo "#define HAVE_TANHF 1" >>confdefs.h + + $as_echo "#define HAVE_EXPF 1" >>confdefs.h + + $as_echo "#define HAVE_ATAN2F 1" >>confdefs.h + + $as_echo "#define HAVE_FABSF 1" >>confdefs.h + + $as_echo "#define HAVE_FMODF 1" >>confdefs.h + + $as_echo "#define HAVE_FREXPF 1" >>confdefs.h + + $as_echo "#define HAVE_LOGF 1" >>confdefs.h + + $as_echo "#define HAVE_LOG10F 1" >>confdefs.h + + $as_echo "#define HAVE_MODF 1" >>confdefs.h + + $as_echo "#define HAVE_POWF 1" >>confdefs.h + + $as_echo "#define HAVE_SQRTF 1" >>confdefs.h + + + # GLIBCXX_CHECK_STDLIB_SUPPORT + $as_echo "#define HAVE_STRTOLD 1" >>confdefs.h + + + + + # Check whether --enable-tls was given. +if test "${enable_tls+set}" = set; then : + enableval=$enable_tls; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable tls must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_tls=yes +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports thread-local storage" >&5 +$as_echo_n "checking whether the target supports thread-local storage... " >&6; } +if ${gcc_cv_have_tls+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + chktls_save_LDFLAGS="$LDFLAGS" + case $host in + *-*-linux* | -*-uclinuxfdpic*) + LDFLAGS="-shared -Wl,--no-undefined $LDFLAGS" + ;; + esac + chktls_save_CFLAGS="$CFLAGS" + CFLAGS="-fPIC $CFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int f() { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int f() { return a = b; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + gcc_cv_have_tls=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$chktls_save_CFLAGS" + LDFLAGS="$chktls_save_LDFLAGS" +else + gcc_cv_have_tls=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + chktls_save_LDFLAGS="$LDFLAGS" + LDFLAGS="-static $LDFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main() { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +else + gcc_cv_have_tls=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$chktls_save_LDFLAGS" + if test $gcc_cv_have_tls = yes; then + chktls_save_CFLAGS="$CFLAGS" + thread_CFLAGS=failed + for flag in '' '-pthread' '-lpthread'; do + CFLAGS="$flag $chktls_save_CFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + void *g(void *d) { return NULL; } +int +main () +{ +pthread_t t; pthread_create(&t,NULL,g,NULL); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + thread_CFLAGS="$flag" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "X$thread_CFLAGS" != Xfailed; then + break + fi + done + CFLAGS="$chktls_save_CFLAGS" + if test "X$thread_CFLAGS" != Xfailed; then + CFLAGS="$thread_CFLAGS $chktls_save_CFLAGS" + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + __thread int a; + static int *volatile a_in_other_thread; + static void * + thread_func (void *arg) + { + a_in_other_thread = &a; + return (void *)0; + } +int +main () +{ +pthread_t thread; + void *thread_retval; + int *volatile a_in_main_thread; + a_in_main_thread = &a; + if (pthread_create (&thread, (pthread_attr_t *)0, + thread_func, (void *)0)) + return 0; + if (pthread_join (thread, &thread_retval)) + return 0; + return (a_in_other_thread == a_in_main_thread); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$chktls_save_CFLAGS" + fi + fi +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_have_tls" >&5 +$as_echo "$gcc_cv_have_tls" >&6; } + if test "$enable_tls $gcc_cv_have_tls" = "yes yes"; then + +$as_echo "#define HAVE_TLS 1" >>confdefs.h + + fi + case "$target" in + *-hpux10*) + $as_echo "#define HAVE_ISINF 1" >>confdefs.h + + $as_echo "#define HAVE_ISINFF 1" >>confdefs.h + + $as_echo "#define HAVE_ISNANF 1" >>confdefs.h + + $as_echo "#define HAVE_FINITE 1" >>confdefs.h + + $as_echo "#define HAVE_FINITEF 1" >>confdefs.h + + ;; + esac + ;; + *-linux* | *-uclinux* | *-gnu* | *-kfreebsd*-gnu | *-cygwin* | *-solaris*) + + # All these tests are for C++; save the language and the compiler flags. + # The CXXFLAGS thing is suspicious, but based on similar bits previously + # found in GLIBCXX_CONFIGURE. + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + + # Check for -ffunction-sections -fdata-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for g++ that supports -ffunction-sections -fdata-sections" >&5 +$as_echo_n "checking for g++ that supports -ffunction-sections -fdata-sections... " >&6; } + CXXFLAGS='-g -Werror -ffunction-sections -fdata-sections' + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo; void bar() { }; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_fdsections=yes +else + ac_fdsections=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" + else + # this is the suspicious part + CXXFLAGS='' + fi + if test x"$ac_fdsections" = x"yes"; then + SECTION_FLAGS='-ffunction-sections -fdata-sections' + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_fdsections" >&5 +$as_echo "$ac_fdsections" >&6; } + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + libm="-lm" +fi + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $libm" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf declaration" >&5 +$as_echo_n "checking for isinf declaration... " >&6; } + if test x${glibcxx_cv_func_isinf_use+set} != xset; then + if ${glibcxx_cv_func_isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinf_use=yes +else + glibcxx_cv_func_isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinf_use" >&5 +$as_echo "$glibcxx_cv_func_isinf_use" >&6; } + + if test x$glibcxx_cv_func_isinf_use = x"yes"; then + for ac_func in isinf +do : + ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinf declaration" >&5 +$as_echo_n "checking for _isinf declaration... " >&6; } + if test x${glibcxx_cv_func__isinf_use+set} != xset; then + if ${glibcxx_cv_func__isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinf_use=yes +else + glibcxx_cv_func__isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinf_use" >&5 +$as_echo "$glibcxx_cv_func__isinf_use" >&6; } + + if test x$glibcxx_cv_func__isinf_use = x"yes"; then + for ac_func in _isinf +do : + ac_fn_c_check_func "$LINENO" "_isinf" "ac_cv_func__isinf" +if test "x$ac_cv_func__isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan declaration" >&5 +$as_echo_n "checking for isnan declaration... " >&6; } + if test x${glibcxx_cv_func_isnan_use+set} != xset; then + if ${glibcxx_cv_func_isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnan_use=yes +else + glibcxx_cv_func_isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnan_use" >&5 +$as_echo "$glibcxx_cv_func_isnan_use" >&6; } + + if test x$glibcxx_cv_func_isnan_use = x"yes"; then + for ac_func in isnan +do : + ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNAN 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnan declaration" >&5 +$as_echo_n "checking for _isnan declaration... " >&6; } + if test x${glibcxx_cv_func__isnan_use+set} != xset; then + if ${glibcxx_cv_func__isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnan_use=yes +else + glibcxx_cv_func__isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnan_use" >&5 +$as_echo "$glibcxx_cv_func__isnan_use" >&6; } + + if test x$glibcxx_cv_func__isnan_use = x"yes"; then + for ac_func in _isnan +do : + ac_fn_c_check_func "$LINENO" "_isnan" "ac_cv_func__isnan" +if test "x$ac_cv_func__isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNAN 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finite declaration" >&5 +$as_echo_n "checking for finite declaration... " >&6; } + if test x${glibcxx_cv_func_finite_use+set} != xset; then + if ${glibcxx_cv_func_finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finite_use=yes +else + glibcxx_cv_func_finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finite_use" >&5 +$as_echo "$glibcxx_cv_func_finite_use" >&6; } + + if test x$glibcxx_cv_func_finite_use = x"yes"; then + for ac_func in finite +do : + ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITE 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finite declaration" >&5 +$as_echo_n "checking for _finite declaration... " >&6; } + if test x${glibcxx_cv_func__finite_use+set} != xset; then + if ${glibcxx_cv_func__finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finite_use=yes +else + glibcxx_cv_func__finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finite_use" >&5 +$as_echo "$glibcxx_cv_func__finite_use" >&6; } + + if test x$glibcxx_cv_func__finite_use = x"yes"; then + for ac_func in _finite +do : + ac_fn_c_check_func "$LINENO" "_finite" "ac_cv_func__finite" +if test "x$ac_cv_func__finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITE 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincos declaration" >&5 +$as_echo_n "checking for sincos declaration... " >&6; } + if test x${glibcxx_cv_func_sincos_use+set} != xset; then + if ${glibcxx_cv_func_sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincos_use=yes +else + glibcxx_cv_func_sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincos_use" >&5 +$as_echo "$glibcxx_cv_func_sincos_use" >&6; } + + if test x$glibcxx_cv_func_sincos_use = x"yes"; then + for ac_func in sincos +do : + ac_fn_c_check_func "$LINENO" "sincos" "ac_cv_func_sincos" +if test "x$ac_cv_func_sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincos declaration" >&5 +$as_echo_n "checking for _sincos declaration... " >&6; } + if test x${glibcxx_cv_func__sincos_use+set} != xset; then + if ${glibcxx_cv_func__sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincos_use=yes +else + glibcxx_cv_func__sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincos_use" >&5 +$as_echo "$glibcxx_cv_func__sincos_use" >&6; } + + if test x$glibcxx_cv_func__sincos_use = x"yes"; then + for ac_func in _sincos +do : + ac_fn_c_check_func "$LINENO" "_sincos" "ac_cv_func__sincos" +if test "x$ac_cv_func__sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpclass declaration" >&5 +$as_echo_n "checking for fpclass declaration... " >&6; } + if test x${glibcxx_cv_func_fpclass_use+set} != xset; then + if ${glibcxx_cv_func_fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fpclass_use=yes +else + glibcxx_cv_func_fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fpclass_use" >&5 +$as_echo "$glibcxx_cv_func_fpclass_use" >&6; } + + if test x$glibcxx_cv_func_fpclass_use = x"yes"; then + for ac_func in fpclass +do : + ac_fn_c_check_func "$LINENO" "fpclass" "ac_cv_func_fpclass" +if test "x$ac_cv_func_fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fpclass declaration" >&5 +$as_echo_n "checking for _fpclass declaration... " >&6; } + if test x${glibcxx_cv_func__fpclass_use+set} != xset; then + if ${glibcxx_cv_func__fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fpclass_use=yes +else + glibcxx_cv_func__fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fpclass_use" >&5 +$as_echo "$glibcxx_cv_func__fpclass_use" >&6; } + + if test x$glibcxx_cv_func__fpclass_use = x"yes"; then + for ac_func in _fpclass +do : + ac_fn_c_check_func "$LINENO" "_fpclass" "ac_cv_func__fpclass" +if test "x$ac_cv_func__fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for qfpclass declaration" >&5 +$as_echo_n "checking for qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func_qfpclass_use+set} != xset; then + if ${glibcxx_cv_func_qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_qfpclass_use=yes +else + glibcxx_cv_func_qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func_qfpclass_use" >&6; } + + if test x$glibcxx_cv_func_qfpclass_use = x"yes"; then + for ac_func in qfpclass +do : + ac_fn_c_check_func "$LINENO" "qfpclass" "ac_cv_func_qfpclass" +if test "x$ac_cv_func_qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QFPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _qfpclass declaration" >&5 +$as_echo_n "checking for _qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func__qfpclass_use+set} != xset; then + if ${glibcxx_cv_func__qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__qfpclass_use=yes +else + glibcxx_cv_func__qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func__qfpclass_use" >&6; } + + if test x$glibcxx_cv_func__qfpclass_use = x"yes"; then + for ac_func in _qfpclass +do : + ac_fn_c_check_func "$LINENO" "_qfpclass" "ac_cv_func__qfpclass" +if test "x$ac_cv_func__qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__QFPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypot declaration" >&5 +$as_echo_n "checking for hypot declaration... " >&6; } + if test x${glibcxx_cv_func_hypot_use+set} != xset; then + if ${glibcxx_cv_func_hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypot_use=yes +else + glibcxx_cv_func_hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypot_use" >&5 +$as_echo "$glibcxx_cv_func_hypot_use" >&6; } + + if test x$glibcxx_cv_func_hypot_use = x"yes"; then + for ac_func in hypot +do : + ac_fn_c_check_func "$LINENO" "hypot" "ac_cv_func_hypot" +if test "x$ac_cv_func_hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOT 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypot declaration" >&5 +$as_echo_n "checking for _hypot declaration... " >&6; } + if test x${glibcxx_cv_func__hypot_use+set} != xset; then + if ${glibcxx_cv_func__hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypot_use=yes +else + glibcxx_cv_func__hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypot_use" >&5 +$as_echo "$glibcxx_cv_func__hypot_use" >&6; } + + if test x$glibcxx_cv_func__hypot_use = x"yes"; then + for ac_func in _hypot +do : + ac_fn_c_check_func "$LINENO" "_hypot" "ac_cv_func__hypot" +if test "x$ac_cv_func__hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOT 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float trig functions" >&5 +$as_echo_n "checking for float trig functions... " >&6; } + if ${glibcxx_cv_func_float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosf (0); asinf (0); atanf (0); cosf (0); sinf (0); tanf (0); coshf (0); sinhf (0); tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_trig_use=yes +else + glibcxx_cv_func_float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_trig_use" >&5 +$as_echo "$glibcxx_cv_func_float_trig_use" >&6; } + if test x$glibcxx_cv_func_float_trig_use = x"yes"; then + for ac_func in acosf asinf atanf cosf sinf tanf coshf sinhf tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float trig functions" >&5 +$as_echo_n "checking for _float trig functions... " >&6; } + if ${glibcxx_cv_func__float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosf (0); _asinf (0); _atanf (0); _cosf (0); _sinf (0); _tanf (0); _coshf (0); _sinhf (0); _tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_trig_use=yes +else + glibcxx_cv_func__float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_trig_use" >&5 +$as_echo "$glibcxx_cv_func__float_trig_use" >&6; } + if test x$glibcxx_cv_func__float_trig_use = x"yes"; then + for ac_func in _acosf _asinf _atanf _cosf _sinf _tanf _coshf _sinhf _tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float round functions" >&5 +$as_echo_n "checking for float round functions... " >&6; } + if ${glibcxx_cv_func_float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceilf (0); floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_round_use=yes +else + glibcxx_cv_func_float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_round_use" >&5 +$as_echo "$glibcxx_cv_func_float_round_use" >&6; } + if test x$glibcxx_cv_func_float_round_use = x"yes"; then + for ac_func in ceilf floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float round functions" >&5 +$as_echo_n "checking for _float round functions... " >&6; } + if ${glibcxx_cv_func__float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceilf (0); _floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_round_use=yes +else + glibcxx_cv_func__float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_round_use" >&5 +$as_echo "$glibcxx_cv_func__float_round_use" >&6; } + if test x$glibcxx_cv_func__float_round_use = x"yes"; then + for ac_func in _ceilf _floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expf declaration" >&5 +$as_echo_n "checking for expf declaration... " >&6; } + if test x${glibcxx_cv_func_expf_use+set} != xset; then + if ${glibcxx_cv_func_expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expf_use=yes +else + glibcxx_cv_func_expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expf_use" >&5 +$as_echo "$glibcxx_cv_func_expf_use" >&6; } + + if test x$glibcxx_cv_func_expf_use = x"yes"; then + for ac_func in expf +do : + ac_fn_c_check_func "$LINENO" "expf" "ac_cv_func_expf" +if test "x$ac_cv_func_expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expf declaration" >&5 +$as_echo_n "checking for _expf declaration... " >&6; } + if test x${glibcxx_cv_func__expf_use+set} != xset; then + if ${glibcxx_cv_func__expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expf_use=yes +else + glibcxx_cv_func__expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expf_use" >&5 +$as_echo "$glibcxx_cv_func__expf_use" >&6; } + + if test x$glibcxx_cv_func__expf_use = x"yes"; then + for ac_func in _expf +do : + ac_fn_c_check_func "$LINENO" "_expf" "ac_cv_func__expf" +if test "x$ac_cv_func__expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanf declaration" >&5 +$as_echo_n "checking for isnanf declaration... " >&6; } + if test x${glibcxx_cv_func_isnanf_use+set} != xset; then + if ${glibcxx_cv_func_isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanf_use=yes +else + glibcxx_cv_func_isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanf_use" >&5 +$as_echo "$glibcxx_cv_func_isnanf_use" >&6; } + + if test x$glibcxx_cv_func_isnanf_use = x"yes"; then + for ac_func in isnanf +do : + ac_fn_c_check_func "$LINENO" "isnanf" "ac_cv_func_isnanf" +if test "x$ac_cv_func_isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanf declaration" >&5 +$as_echo_n "checking for _isnanf declaration... " >&6; } + if test x${glibcxx_cv_func__isnanf_use+set} != xset; then + if ${glibcxx_cv_func__isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanf_use=yes +else + glibcxx_cv_func__isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanf_use" >&5 +$as_echo "$glibcxx_cv_func__isnanf_use" >&6; } + + if test x$glibcxx_cv_func__isnanf_use = x"yes"; then + for ac_func in _isnanf +do : + ac_fn_c_check_func "$LINENO" "_isnanf" "ac_cv_func__isnanf" +if test "x$ac_cv_func__isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinff declaration" >&5 +$as_echo_n "checking for isinff declaration... " >&6; } + if test x${glibcxx_cv_func_isinff_use+set} != xset; then + if ${glibcxx_cv_func_isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinff_use=yes +else + glibcxx_cv_func_isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinff_use" >&5 +$as_echo "$glibcxx_cv_func_isinff_use" >&6; } + + if test x$glibcxx_cv_func_isinff_use = x"yes"; then + for ac_func in isinff +do : + ac_fn_c_check_func "$LINENO" "isinff" "ac_cv_func_isinff" +if test "x$ac_cv_func_isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinff declaration" >&5 +$as_echo_n "checking for _isinff declaration... " >&6; } + if test x${glibcxx_cv_func__isinff_use+set} != xset; then + if ${glibcxx_cv_func__isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinff_use=yes +else + glibcxx_cv_func__isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinff_use" >&5 +$as_echo "$glibcxx_cv_func__isinff_use" >&6; } + + if test x$glibcxx_cv_func__isinff_use = x"yes"; then + for ac_func in _isinff +do : + ac_fn_c_check_func "$LINENO" "_isinff" "ac_cv_func__isinff" +if test "x$ac_cv_func__isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f declaration" >&5 +$as_echo_n "checking for atan2f declaration... " >&6; } + if test x${glibcxx_cv_func_atan2f_use+set} != xset; then + if ${glibcxx_cv_func_atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2f_use=yes +else + glibcxx_cv_func_atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2f_use" >&5 +$as_echo "$glibcxx_cv_func_atan2f_use" >&6; } + + if test x$glibcxx_cv_func_atan2f_use = x"yes"; then + for ac_func in atan2f +do : + ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2f declaration" >&5 +$as_echo_n "checking for _atan2f declaration... " >&6; } + if test x${glibcxx_cv_func__atan2f_use+set} != xset; then + if ${glibcxx_cv_func__atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2f_use=yes +else + glibcxx_cv_func__atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2f_use" >&5 +$as_echo "$glibcxx_cv_func__atan2f_use" >&6; } + + if test x$glibcxx_cv_func__atan2f_use = x"yes"; then + for ac_func in _atan2f +do : + ac_fn_c_check_func "$LINENO" "_atan2f" "ac_cv_func__atan2f" +if test "x$ac_cv_func__atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsf declaration" >&5 +$as_echo_n "checking for fabsf declaration... " >&6; } + if test x${glibcxx_cv_func_fabsf_use+set} != xset; then + if ${glibcxx_cv_func_fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsf_use=yes +else + glibcxx_cv_func_fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsf_use" >&5 +$as_echo "$glibcxx_cv_func_fabsf_use" >&6; } + + if test x$glibcxx_cv_func_fabsf_use = x"yes"; then + for ac_func in fabsf +do : + ac_fn_c_check_func "$LINENO" "fabsf" "ac_cv_func_fabsf" +if test "x$ac_cv_func_fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsf declaration" >&5 +$as_echo_n "checking for _fabsf declaration... " >&6; } + if test x${glibcxx_cv_func__fabsf_use+set} != xset; then + if ${glibcxx_cv_func__fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsf_use=yes +else + glibcxx_cv_func__fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsf_use" >&5 +$as_echo "$glibcxx_cv_func__fabsf_use" >&6; } + + if test x$glibcxx_cv_func__fabsf_use = x"yes"; then + for ac_func in _fabsf +do : + ac_fn_c_check_func "$LINENO" "_fabsf" "ac_cv_func__fabsf" +if test "x$ac_cv_func__fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf declaration" >&5 +$as_echo_n "checking for fmodf declaration... " >&6; } + if test x${glibcxx_cv_func_fmodf_use+set} != xset; then + if ${glibcxx_cv_func_fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodf_use=yes +else + glibcxx_cv_func_fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodf_use" >&5 +$as_echo "$glibcxx_cv_func_fmodf_use" >&6; } + + if test x$glibcxx_cv_func_fmodf_use = x"yes"; then + for ac_func in fmodf +do : + ac_fn_c_check_func "$LINENO" "fmodf" "ac_cv_func_fmodf" +if test "x$ac_cv_func_fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodf declaration" >&5 +$as_echo_n "checking for _fmodf declaration... " >&6; } + if test x${glibcxx_cv_func__fmodf_use+set} != xset; then + if ${glibcxx_cv_func__fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodf_use=yes +else + glibcxx_cv_func__fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodf_use" >&5 +$as_echo "$glibcxx_cv_func__fmodf_use" >&6; } + + if test x$glibcxx_cv_func__fmodf_use = x"yes"; then + for ac_func in _fmodf +do : + ac_fn_c_check_func "$LINENO" "_fmodf" "ac_cv_func__fmodf" +if test "x$ac_cv_func__fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } + if test x${glibcxx_cv_func_frexpf_use+set} != xset; then + if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + + if test x$glibcxx_cv_func_frexpf_use = x"yes"; then + for ac_func in frexpf +do : + ac_fn_c_check_func "$LINENO" "frexpf" "ac_cv_func_frexpf" +if test "x$ac_cv_func_frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpf declaration" >&5 +$as_echo_n "checking for _frexpf declaration... " >&6; } + if test x${glibcxx_cv_func__frexpf_use+set} != xset; then + if ${glibcxx_cv_func__frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpf_use=yes +else + glibcxx_cv_func__frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpf_use" >&5 +$as_echo "$glibcxx_cv_func__frexpf_use" >&6; } + + if test x$glibcxx_cv_func__frexpf_use = x"yes"; then + for ac_func in _frexpf +do : + ac_fn_c_check_func "$LINENO" "_frexpf" "ac_cv_func__frexpf" +if test "x$ac_cv_func__frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } + if test x${glibcxx_cv_func_hypotf_use+set} != xset; then + if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + + if test x$glibcxx_cv_func_hypotf_use = x"yes"; then + for ac_func in hypotf +do : + ac_fn_c_check_func "$LINENO" "hypotf" "ac_cv_func_hypotf" +if test "x$ac_cv_func_hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotf declaration" >&5 +$as_echo_n "checking for _hypotf declaration... " >&6; } + if test x${glibcxx_cv_func__hypotf_use+set} != xset; then + if ${glibcxx_cv_func__hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotf_use=yes +else + glibcxx_cv_func__hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotf_use" >&5 +$as_echo "$glibcxx_cv_func__hypotf_use" >&6; } + + if test x$glibcxx_cv_func__hypotf_use = x"yes"; then + for ac_func in _hypotf +do : + ac_fn_c_check_func "$LINENO" "_hypotf" "ac_cv_func__hypotf" +if test "x$ac_cv_func__hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpf_use+set} != xset; then + if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + + if test x$glibcxx_cv_func_ldexpf_use = x"yes"; then + for ac_func in ldexpf +do : + ac_fn_c_check_func "$LINENO" "ldexpf" "ac_cv_func_ldexpf" +if test "x$ac_cv_func_ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpf declaration" >&5 +$as_echo_n "checking for _ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpf_use+set} != xset; then + if ${glibcxx_cv_func__ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpf_use=yes +else + glibcxx_cv_func__ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpf_use" >&6; } + + if test x$glibcxx_cv_func__ldexpf_use = x"yes"; then + for ac_func in _ldexpf +do : + ac_fn_c_check_func "$LINENO" "_ldexpf" "ac_cv_func__ldexpf" +if test "x$ac_cv_func__ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logf declaration" >&5 +$as_echo_n "checking for logf declaration... " >&6; } + if test x${glibcxx_cv_func_logf_use+set} != xset; then + if ${glibcxx_cv_func_logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logf_use=yes +else + glibcxx_cv_func_logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logf_use" >&5 +$as_echo "$glibcxx_cv_func_logf_use" >&6; } + + if test x$glibcxx_cv_func_logf_use = x"yes"; then + for ac_func in logf +do : + ac_fn_c_check_func "$LINENO" "logf" "ac_cv_func_logf" +if test "x$ac_cv_func_logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logf declaration" >&5 +$as_echo_n "checking for _logf declaration... " >&6; } + if test x${glibcxx_cv_func__logf_use+set} != xset; then + if ${glibcxx_cv_func__logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logf_use=yes +else + glibcxx_cv_func__logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logf_use" >&5 +$as_echo "$glibcxx_cv_func__logf_use" >&6; } + + if test x$glibcxx_cv_func__logf_use = x"yes"; then + for ac_func in _logf +do : + ac_fn_c_check_func "$LINENO" "_logf" "ac_cv_func__logf" +if test "x$ac_cv_func__logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10f declaration" >&5 +$as_echo_n "checking for log10f declaration... " >&6; } + if test x${glibcxx_cv_func_log10f_use+set} != xset; then + if ${glibcxx_cv_func_log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10f_use=yes +else + glibcxx_cv_func_log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10f_use" >&5 +$as_echo "$glibcxx_cv_func_log10f_use" >&6; } + + if test x$glibcxx_cv_func_log10f_use = x"yes"; then + for ac_func in log10f +do : + ac_fn_c_check_func "$LINENO" "log10f" "ac_cv_func_log10f" +if test "x$ac_cv_func_log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10f declaration" >&5 +$as_echo_n "checking for _log10f declaration... " >&6; } + if test x${glibcxx_cv_func__log10f_use+set} != xset; then + if ${glibcxx_cv_func__log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10f_use=yes +else + glibcxx_cv_func__log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10f_use" >&5 +$as_echo "$glibcxx_cv_func__log10f_use" >&6; } + + if test x$glibcxx_cv_func__log10f_use = x"yes"; then + for ac_func in _log10f +do : + ac_fn_c_check_func "$LINENO" "_log10f" "ac_cv_func__log10f" +if test "x$ac_cv_func__log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } + if test x${glibcxx_cv_func_modff_use+set} != xset; then + if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + + if test x$glibcxx_cv_func_modff_use = x"yes"; then + for ac_func in modff +do : + ac_fn_c_check_func "$LINENO" "modff" "ac_cv_func_modff" +if test "x$ac_cv_func_modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modff declaration" >&5 +$as_echo_n "checking for _modff declaration... " >&6; } + if test x${glibcxx_cv_func__modff_use+set} != xset; then + if ${glibcxx_cv_func__modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modff_use=yes +else + glibcxx_cv_func__modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modff_use" >&5 +$as_echo "$glibcxx_cv_func__modff_use" >&6; } + + if test x$glibcxx_cv_func__modff_use = x"yes"; then + for ac_func in _modff +do : + ac_fn_c_check_func "$LINENO" "_modff" "ac_cv_func__modff" +if test "x$ac_cv_func__modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modf declaration" >&5 +$as_echo_n "checking for modf declaration... " >&6; } + if test x${glibcxx_cv_func_modf_use+set} != xset; then + if ${glibcxx_cv_func_modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modf_use=yes +else + glibcxx_cv_func_modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modf_use" >&5 +$as_echo "$glibcxx_cv_func_modf_use" >&6; } + + if test x$glibcxx_cv_func_modf_use = x"yes"; then + for ac_func in modf +do : + ac_fn_c_check_func "$LINENO" "modf" "ac_cv_func_modf" +if test "x$ac_cv_func_modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modf declaration" >&5 +$as_echo_n "checking for _modf declaration... " >&6; } + if test x${glibcxx_cv_func__modf_use+set} != xset; then + if ${glibcxx_cv_func__modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modf_use=yes +else + glibcxx_cv_func__modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modf_use" >&5 +$as_echo "$glibcxx_cv_func__modf_use" >&6; } + + if test x$glibcxx_cv_func__modf_use = x"yes"; then + for ac_func in _modf +do : + ac_fn_c_check_func "$LINENO" "_modf" "ac_cv_func__modf" +if test "x$ac_cv_func__modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powf declaration" >&5 +$as_echo_n "checking for powf declaration... " >&6; } + if test x${glibcxx_cv_func_powf_use+set} != xset; then + if ${glibcxx_cv_func_powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powf_use=yes +else + glibcxx_cv_func_powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powf_use" >&5 +$as_echo "$glibcxx_cv_func_powf_use" >&6; } + + if test x$glibcxx_cv_func_powf_use = x"yes"; then + for ac_func in powf +do : + ac_fn_c_check_func "$LINENO" "powf" "ac_cv_func_powf" +if test "x$ac_cv_func_powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powf declaration" >&5 +$as_echo_n "checking for _powf declaration... " >&6; } + if test x${glibcxx_cv_func__powf_use+set} != xset; then + if ${glibcxx_cv_func__powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powf_use=yes +else + glibcxx_cv_func__powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powf_use" >&5 +$as_echo "$glibcxx_cv_func__powf_use" >&6; } + + if test x$glibcxx_cv_func__powf_use = x"yes"; then + for ac_func in _powf +do : + ac_fn_c_check_func "$LINENO" "_powf" "ac_cv_func__powf" +if test "x$ac_cv_func__powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtf declaration" >&5 +$as_echo_n "checking for sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtf_use+set} != xset; then + if ${glibcxx_cv_func_sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtf_use=yes +else + glibcxx_cv_func_sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtf_use" >&6; } + + if test x$glibcxx_cv_func_sqrtf_use = x"yes"; then + for ac_func in sqrtf +do : + ac_fn_c_check_func "$LINENO" "sqrtf" "ac_cv_func_sqrtf" +if test "x$ac_cv_func_sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtf declaration" >&5 +$as_echo_n "checking for _sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtf_use+set} != xset; then + if ${glibcxx_cv_func__sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtf_use=yes +else + glibcxx_cv_func__sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtf_use" >&6; } + + if test x$glibcxx_cv_func__sqrtf_use = x"yes"; then + for ac_func in _sqrtf +do : + ac_fn_c_check_func "$LINENO" "_sqrtf" "ac_cv_func__sqrtf" +if test "x$ac_cv_func__sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosf declaration" >&5 +$as_echo_n "checking for sincosf declaration... " >&6; } + if test x${glibcxx_cv_func_sincosf_use+set} != xset; then + if ${glibcxx_cv_func_sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosf_use=yes +else + glibcxx_cv_func_sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosf_use" >&5 +$as_echo "$glibcxx_cv_func_sincosf_use" >&6; } + + if test x$glibcxx_cv_func_sincosf_use = x"yes"; then + for ac_func in sincosf +do : + ac_fn_c_check_func "$LINENO" "sincosf" "ac_cv_func_sincosf" +if test "x$ac_cv_func_sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosf declaration" >&5 +$as_echo_n "checking for _sincosf declaration... " >&6; } + if test x${glibcxx_cv_func__sincosf_use+set} != xset; then + if ${glibcxx_cv_func__sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosf_use=yes +else + glibcxx_cv_func__sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosf_use" >&5 +$as_echo "$glibcxx_cv_func__sincosf_use" >&6; } + + if test x$glibcxx_cv_func__sincosf_use = x"yes"; then + for ac_func in _sincosf +do : + ac_fn_c_check_func "$LINENO" "_sincosf" "ac_cv_func__sincosf" +if test "x$ac_cv_func__sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitef declaration" >&5 +$as_echo_n "checking for finitef declaration... " >&6; } + if test x${glibcxx_cv_func_finitef_use+set} != xset; then + if ${glibcxx_cv_func_finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitef_use=yes +else + glibcxx_cv_func_finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitef_use" >&5 +$as_echo "$glibcxx_cv_func_finitef_use" >&6; } + + if test x$glibcxx_cv_func_finitef_use = x"yes"; then + for ac_func in finitef +do : + ac_fn_c_check_func "$LINENO" "finitef" "ac_cv_func_finitef" +if test "x$ac_cv_func_finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitef declaration" >&5 +$as_echo_n "checking for _finitef declaration... " >&6; } + if test x${glibcxx_cv_func__finitef_use+set} != xset; then + if ${glibcxx_cv_func__finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitef_use=yes +else + glibcxx_cv_func__finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitef_use" >&5 +$as_echo "$glibcxx_cv_func__finitef_use" >&6; } + + if test x$glibcxx_cv_func__finitef_use = x"yes"; then + for ac_func in _finitef +do : + ac_fn_c_check_func "$LINENO" "_finitef" "ac_cv_func__finitef" +if test "x$ac_cv_func__finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double trig functions" >&5 +$as_echo_n "checking for long double trig functions... " >&6; } + if ${glibcxx_cv_func_long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosl (0); asinl (0); atanl (0); cosl (0); sinl (0); tanl (0); coshl (0); sinhl (0); tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_trig_use=yes +else + glibcxx_cv_func_long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_trig_use" >&6; } + if test x$glibcxx_cv_func_long_double_trig_use = x"yes"; then + for ac_func in acosl asinl atanl cosl sinl tanl coshl sinhl tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double trig functions" >&5 +$as_echo_n "checking for _long double trig functions... " >&6; } + if ${glibcxx_cv_func__long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosl (0); _asinl (0); _atanl (0); _cosl (0); _sinl (0); _tanl (0); _coshl (0); _sinhl (0); _tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_trig_use=yes +else + glibcxx_cv_func__long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_trig_use" >&6; } + if test x$glibcxx_cv_func__long_double_trig_use = x"yes"; then + for ac_func in _acosl _asinl _atanl _cosl _sinl _tanl _coshl _sinhl _tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double round functions" >&5 +$as_echo_n "checking for long double round functions... " >&6; } + if ${glibcxx_cv_func_long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceill (0); floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_round_use=yes +else + glibcxx_cv_func_long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_round_use" >&6; } + if test x$glibcxx_cv_func_long_double_round_use = x"yes"; then + for ac_func in ceill floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double round functions" >&5 +$as_echo_n "checking for _long double round functions... " >&6; } + if ${glibcxx_cv_func__long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceill (0); _floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_round_use=yes +else + glibcxx_cv_func__long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_round_use" >&6; } + if test x$glibcxx_cv_func__long_double_round_use = x"yes"; then + for ac_func in _ceill _floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanl declaration" >&5 +$as_echo_n "checking for isnanl declaration... " >&6; } + if test x${glibcxx_cv_func_isnanl_use+set} != xset; then + if ${glibcxx_cv_func_isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanl_use=yes +else + glibcxx_cv_func_isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanl_use" >&5 +$as_echo "$glibcxx_cv_func_isnanl_use" >&6; } + + if test x$glibcxx_cv_func_isnanl_use = x"yes"; then + for ac_func in isnanl +do : + ac_fn_c_check_func "$LINENO" "isnanl" "ac_cv_func_isnanl" +if test "x$ac_cv_func_isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanl declaration" >&5 +$as_echo_n "checking for _isnanl declaration... " >&6; } + if test x${glibcxx_cv_func__isnanl_use+set} != xset; then + if ${glibcxx_cv_func__isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanl_use=yes +else + glibcxx_cv_func__isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanl_use" >&5 +$as_echo "$glibcxx_cv_func__isnanl_use" >&6; } + + if test x$glibcxx_cv_func__isnanl_use = x"yes"; then + for ac_func in _isnanl +do : + ac_fn_c_check_func "$LINENO" "_isnanl" "ac_cv_func__isnanl" +if test "x$ac_cv_func__isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinfl declaration" >&5 +$as_echo_n "checking for isinfl declaration... " >&6; } + if test x${glibcxx_cv_func_isinfl_use+set} != xset; then + if ${glibcxx_cv_func_isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinfl_use=yes +else + glibcxx_cv_func_isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinfl_use" >&5 +$as_echo "$glibcxx_cv_func_isinfl_use" >&6; } + + if test x$glibcxx_cv_func_isinfl_use = x"yes"; then + for ac_func in isinfl +do : + ac_fn_c_check_func "$LINENO" "isinfl" "ac_cv_func_isinfl" +if test "x$ac_cv_func_isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinfl declaration" >&5 +$as_echo_n "checking for _isinfl declaration... " >&6; } + if test x${glibcxx_cv_func__isinfl_use+set} != xset; then + if ${glibcxx_cv_func__isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinfl_use=yes +else + glibcxx_cv_func__isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinfl_use" >&5 +$as_echo "$glibcxx_cv_func__isinfl_use" >&6; } + + if test x$glibcxx_cv_func__isinfl_use = x"yes"; then + for ac_func in _isinfl +do : + ac_fn_c_check_func "$LINENO" "_isinfl" "ac_cv_func__isinfl" +if test "x$ac_cv_func__isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } + if test x${glibcxx_cv_func_atan2l_use+set} != xset; then + if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + + if test x$glibcxx_cv_func_atan2l_use = x"yes"; then + for ac_func in atan2l +do : + ac_fn_c_check_func "$LINENO" "atan2l" "ac_cv_func_atan2l" +if test "x$ac_cv_func_atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2l declaration" >&5 +$as_echo_n "checking for _atan2l declaration... " >&6; } + if test x${glibcxx_cv_func__atan2l_use+set} != xset; then + if ${glibcxx_cv_func__atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2l_use=yes +else + glibcxx_cv_func__atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2l_use" >&5 +$as_echo "$glibcxx_cv_func__atan2l_use" >&6; } + + if test x$glibcxx_cv_func__atan2l_use = x"yes"; then + for ac_func in _atan2l +do : + ac_fn_c_check_func "$LINENO" "_atan2l" "ac_cv_func__atan2l" +if test "x$ac_cv_func__atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } + if test x${glibcxx_cv_func_expl_use+set} != xset; then + if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + + if test x$glibcxx_cv_func_expl_use = x"yes"; then + for ac_func in expl +do : + ac_fn_c_check_func "$LINENO" "expl" "ac_cv_func_expl" +if test "x$ac_cv_func_expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expl declaration" >&5 +$as_echo_n "checking for _expl declaration... " >&6; } + if test x${glibcxx_cv_func__expl_use+set} != xset; then + if ${glibcxx_cv_func__expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expl_use=yes +else + glibcxx_cv_func__expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expl_use" >&5 +$as_echo "$glibcxx_cv_func__expl_use" >&6; } + + if test x$glibcxx_cv_func__expl_use = x"yes"; then + for ac_func in _expl +do : + ac_fn_c_check_func "$LINENO" "_expl" "ac_cv_func__expl" +if test "x$ac_cv_func__expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } + if test x${glibcxx_cv_func_fabsl_use+set} != xset; then + if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + + if test x$glibcxx_cv_func_fabsl_use = x"yes"; then + for ac_func in fabsl +do : + ac_fn_c_check_func "$LINENO" "fabsl" "ac_cv_func_fabsl" +if test "x$ac_cv_func_fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsl declaration" >&5 +$as_echo_n "checking for _fabsl declaration... " >&6; } + if test x${glibcxx_cv_func__fabsl_use+set} != xset; then + if ${glibcxx_cv_func__fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsl_use=yes +else + glibcxx_cv_func__fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsl_use" >&5 +$as_echo "$glibcxx_cv_func__fabsl_use" >&6; } + + if test x$glibcxx_cv_func__fabsl_use = x"yes"; then + for ac_func in _fabsl +do : + ac_fn_c_check_func "$LINENO" "_fabsl" "ac_cv_func__fabsl" +if test "x$ac_cv_func__fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } + if test x${glibcxx_cv_func_fmodl_use+set} != xset; then + if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + + if test x$glibcxx_cv_func_fmodl_use = x"yes"; then + for ac_func in fmodl +do : + ac_fn_c_check_func "$LINENO" "fmodl" "ac_cv_func_fmodl" +if test "x$ac_cv_func_fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodl declaration" >&5 +$as_echo_n "checking for _fmodl declaration... " >&6; } + if test x${glibcxx_cv_func__fmodl_use+set} != xset; then + if ${glibcxx_cv_func__fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodl_use=yes +else + glibcxx_cv_func__fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodl_use" >&5 +$as_echo "$glibcxx_cv_func__fmodl_use" >&6; } + + if test x$glibcxx_cv_func__fmodl_use = x"yes"; then + for ac_func in _fmodl +do : + ac_fn_c_check_func "$LINENO" "_fmodl" "ac_cv_func__fmodl" +if test "x$ac_cv_func__fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } + if test x${glibcxx_cv_func_frexpl_use+set} != xset; then + if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + + if test x$glibcxx_cv_func_frexpl_use = x"yes"; then + for ac_func in frexpl +do : + ac_fn_c_check_func "$LINENO" "frexpl" "ac_cv_func_frexpl" +if test "x$ac_cv_func_frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpl declaration" >&5 +$as_echo_n "checking for _frexpl declaration... " >&6; } + if test x${glibcxx_cv_func__frexpl_use+set} != xset; then + if ${glibcxx_cv_func__frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpl_use=yes +else + glibcxx_cv_func__frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpl_use" >&5 +$as_echo "$glibcxx_cv_func__frexpl_use" >&6; } + + if test x$glibcxx_cv_func__frexpl_use = x"yes"; then + for ac_func in _frexpl +do : + ac_fn_c_check_func "$LINENO" "_frexpl" "ac_cv_func__frexpl" +if test "x$ac_cv_func__frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } + if test x${glibcxx_cv_func_hypotl_use+set} != xset; then + if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + + if test x$glibcxx_cv_func_hypotl_use = x"yes"; then + for ac_func in hypotl +do : + ac_fn_c_check_func "$LINENO" "hypotl" "ac_cv_func_hypotl" +if test "x$ac_cv_func_hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotl declaration" >&5 +$as_echo_n "checking for _hypotl declaration... " >&6; } + if test x${glibcxx_cv_func__hypotl_use+set} != xset; then + if ${glibcxx_cv_func__hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotl_use=yes +else + glibcxx_cv_func__hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotl_use" >&5 +$as_echo "$glibcxx_cv_func__hypotl_use" >&6; } + + if test x$glibcxx_cv_func__hypotl_use = x"yes"; then + for ac_func in _hypotl +do : + ac_fn_c_check_func "$LINENO" "_hypotl" "ac_cv_func__hypotl" +if test "x$ac_cv_func__hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpl_use+set} != xset; then + if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + + if test x$glibcxx_cv_func_ldexpl_use = x"yes"; then + for ac_func in ldexpl +do : + ac_fn_c_check_func "$LINENO" "ldexpl" "ac_cv_func_ldexpl" +if test "x$ac_cv_func_ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpl declaration" >&5 +$as_echo_n "checking for _ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpl_use+set} != xset; then + if ${glibcxx_cv_func__ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpl_use=yes +else + glibcxx_cv_func__ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpl_use" >&6; } + + if test x$glibcxx_cv_func__ldexpl_use = x"yes"; then + for ac_func in _ldexpl +do : + ac_fn_c_check_func "$LINENO" "_ldexpl" "ac_cv_func__ldexpl" +if test "x$ac_cv_func__ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } + if test x${glibcxx_cv_func_logl_use+set} != xset; then + if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + + if test x$glibcxx_cv_func_logl_use = x"yes"; then + for ac_func in logl +do : + ac_fn_c_check_func "$LINENO" "logl" "ac_cv_func_logl" +if test "x$ac_cv_func_logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logl declaration" >&5 +$as_echo_n "checking for _logl declaration... " >&6; } + if test x${glibcxx_cv_func__logl_use+set} != xset; then + if ${glibcxx_cv_func__logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logl_use=yes +else + glibcxx_cv_func__logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logl_use" >&5 +$as_echo "$glibcxx_cv_func__logl_use" >&6; } + + if test x$glibcxx_cv_func__logl_use = x"yes"; then + for ac_func in _logl +do : + ac_fn_c_check_func "$LINENO" "_logl" "ac_cv_func__logl" +if test "x$ac_cv_func__logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } + if test x${glibcxx_cv_func_log10l_use+set} != xset; then + if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + + if test x$glibcxx_cv_func_log10l_use = x"yes"; then + for ac_func in log10l +do : + ac_fn_c_check_func "$LINENO" "log10l" "ac_cv_func_log10l" +if test "x$ac_cv_func_log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10l declaration" >&5 +$as_echo_n "checking for _log10l declaration... " >&6; } + if test x${glibcxx_cv_func__log10l_use+set} != xset; then + if ${glibcxx_cv_func__log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10l_use=yes +else + glibcxx_cv_func__log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10l_use" >&5 +$as_echo "$glibcxx_cv_func__log10l_use" >&6; } + + if test x$glibcxx_cv_func__log10l_use = x"yes"; then + for ac_func in _log10l +do : + ac_fn_c_check_func "$LINENO" "_log10l" "ac_cv_func__log10l" +if test "x$ac_cv_func__log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } + if test x${glibcxx_cv_func_modfl_use+set} != xset; then + if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + + if test x$glibcxx_cv_func_modfl_use = x"yes"; then + for ac_func in modfl +do : + ac_fn_c_check_func "$LINENO" "modfl" "ac_cv_func_modfl" +if test "x$ac_cv_func_modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modfl declaration" >&5 +$as_echo_n "checking for _modfl declaration... " >&6; } + if test x${glibcxx_cv_func__modfl_use+set} != xset; then + if ${glibcxx_cv_func__modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modfl_use=yes +else + glibcxx_cv_func__modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modfl_use" >&5 +$as_echo "$glibcxx_cv_func__modfl_use" >&6; } + + if test x$glibcxx_cv_func__modfl_use = x"yes"; then + for ac_func in _modfl +do : + ac_fn_c_check_func "$LINENO" "_modfl" "ac_cv_func__modfl" +if test "x$ac_cv_func__modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } + if test x${glibcxx_cv_func_powl_use+set} != xset; then + if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + + if test x$glibcxx_cv_func_powl_use = x"yes"; then + for ac_func in powl +do : + ac_fn_c_check_func "$LINENO" "powl" "ac_cv_func_powl" +if test "x$ac_cv_func_powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powl declaration" >&5 +$as_echo_n "checking for _powl declaration... " >&6; } + if test x${glibcxx_cv_func__powl_use+set} != xset; then + if ${glibcxx_cv_func__powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powl_use=yes +else + glibcxx_cv_func__powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powl_use" >&5 +$as_echo "$glibcxx_cv_func__powl_use" >&6; } + + if test x$glibcxx_cv_func__powl_use = x"yes"; then + for ac_func in _powl +do : + ac_fn_c_check_func "$LINENO" "_powl" "ac_cv_func__powl" +if test "x$ac_cv_func__powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtl_use+set} != xset; then + if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + + if test x$glibcxx_cv_func_sqrtl_use = x"yes"; then + for ac_func in sqrtl +do : + ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl" +if test "x$ac_cv_func_sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtl declaration" >&5 +$as_echo_n "checking for _sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtl_use+set} != xset; then + if ${glibcxx_cv_func__sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtl_use=yes +else + glibcxx_cv_func__sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtl_use" >&6; } + + if test x$glibcxx_cv_func__sqrtl_use = x"yes"; then + for ac_func in _sqrtl +do : + ac_fn_c_check_func "$LINENO" "_sqrtl" "ac_cv_func__sqrtl" +if test "x$ac_cv_func__sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosl declaration" >&5 +$as_echo_n "checking for sincosl declaration... " >&6; } + if test x${glibcxx_cv_func_sincosl_use+set} != xset; then + if ${glibcxx_cv_func_sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosl_use=yes +else + glibcxx_cv_func_sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosl_use" >&5 +$as_echo "$glibcxx_cv_func_sincosl_use" >&6; } + + if test x$glibcxx_cv_func_sincosl_use = x"yes"; then + for ac_func in sincosl +do : + ac_fn_c_check_func "$LINENO" "sincosl" "ac_cv_func_sincosl" +if test "x$ac_cv_func_sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosl declaration" >&5 +$as_echo_n "checking for _sincosl declaration... " >&6; } + if test x${glibcxx_cv_func__sincosl_use+set} != xset; then + if ${glibcxx_cv_func__sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosl_use=yes +else + glibcxx_cv_func__sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosl_use" >&5 +$as_echo "$glibcxx_cv_func__sincosl_use" >&6; } + + if test x$glibcxx_cv_func__sincosl_use = x"yes"; then + for ac_func in _sincosl +do : + ac_fn_c_check_func "$LINENO" "_sincosl" "ac_cv_func__sincosl" +if test "x$ac_cv_func__sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitel declaration" >&5 +$as_echo_n "checking for finitel declaration... " >&6; } + if test x${glibcxx_cv_func_finitel_use+set} != xset; then + if ${glibcxx_cv_func_finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitel_use=yes +else + glibcxx_cv_func_finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitel_use" >&5 +$as_echo "$glibcxx_cv_func_finitel_use" >&6; } + + if test x$glibcxx_cv_func_finitel_use = x"yes"; then + for ac_func in finitel +do : + ac_fn_c_check_func "$LINENO" "finitel" "ac_cv_func_finitel" +if test "x$ac_cv_func_finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitel declaration" >&5 +$as_echo_n "checking for _finitel declaration... " >&6; } + if test x${glibcxx_cv_func__finitel_use+set} != xset; then + if ${glibcxx_cv_func__finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitel_use=yes +else + glibcxx_cv_func__finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitel_use" >&5 +$as_echo "$glibcxx_cv_func__finitel_use" >&6; } + + if test x$glibcxx_cv_func__finitel_use = x"yes"; then + for ac_func in _finitel +do : + ac_fn_c_check_func "$LINENO" "_finitel" "ac_cv_func__finitel" +if test "x$ac_cv_func__finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEL 1 +_ACEOF + +fi +done + + fi + fi + + + + + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for at_quick_exit declaration" >&5 +$as_echo_n "checking for at_quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_at_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_at_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + at_quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_at_quick_exit_use=yes +else + glibcxx_cv_func_at_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_at_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_at_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_at_quick_exit_use = x"yes"; then + for ac_func in at_quick_exit +do : + ac_fn_c_check_func "$LINENO" "at_quick_exit" "ac_cv_func_at_quick_exit" +if test "x$ac_cv_func_at_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AT_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for quick_exit declaration" >&5 +$as_echo_n "checking for quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_quick_exit_use=yes +else + glibcxx_cv_func_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_quick_exit_use = x"yes"; then + for ac_func in quick_exit +do : + ac_fn_c_check_func "$LINENO" "quick_exit" "ac_cv_func_quick_exit" +if test "x$ac_cv_func_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtold declaration" >&5 +$as_echo_n "checking for strtold declaration... " >&6; } + if test x${glibcxx_cv_func_strtold_use+set} != xset; then + if ${glibcxx_cv_func_strtold_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtold(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtold_use=yes +else + glibcxx_cv_func_strtold_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtold_use" >&5 +$as_echo "$glibcxx_cv_func_strtold_use" >&6; } + if test x$glibcxx_cv_func_strtold_use = x"yes"; then + for ac_func in strtold +do : + ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold" +if test "x$ac_cv_func_strtold" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOLD 1 +_ACEOF + +fi +done + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtof declaration" >&5 +$as_echo_n "checking for strtof declaration... " >&6; } + if test x${glibcxx_cv_func_strtof_use+set} != xset; then + if ${glibcxx_cv_func_strtof_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtof(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtof_use=yes +else + glibcxx_cv_func_strtof_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtof_use" >&5 +$as_echo "$glibcxx_cv_func_strtof_use" >&6; } + if test x$glibcxx_cv_func_strtof_use = x"yes"; then + for ac_func in strtof +do : + ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof" +if test "x$ac_cv_func_strtof" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOF 1 +_ACEOF + +fi +done + + fi + + + + + CXXFLAGS="$ac_save_CXXFLAGS" + + $as_echo "#define _GLIBCXX_USE_DEV_RANDOM 1" >>confdefs.h + + $as_echo "#define _GLIBCXX_USE_RANDOM_TR1 1" >>confdefs.h + + + + # Check whether --enable-tls was given. +if test "${enable_tls+set}" = set; then : + enableval=$enable_tls; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable tls must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_tls=yes +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports thread-local storage" >&5 +$as_echo_n "checking whether the target supports thread-local storage... " >&6; } +if ${gcc_cv_have_tls+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + chktls_save_LDFLAGS="$LDFLAGS" + case $host in + *-*-linux* | -*-uclinuxfdpic*) + LDFLAGS="-shared -Wl,--no-undefined $LDFLAGS" + ;; + esac + chktls_save_CFLAGS="$CFLAGS" + CFLAGS="-fPIC $CFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int f() { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int f() { return a = b; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + gcc_cv_have_tls=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$chktls_save_CFLAGS" + LDFLAGS="$chktls_save_LDFLAGS" +else + gcc_cv_have_tls=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + chktls_save_LDFLAGS="$LDFLAGS" + LDFLAGS="-static $LDFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main() { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int a; int b; int main() { return a = b; } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +else + gcc_cv_have_tls=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$chktls_save_LDFLAGS" + if test $gcc_cv_have_tls = yes; then + chktls_save_CFLAGS="$CFLAGS" + thread_CFLAGS=failed + for flag in '' '-pthread' '-lpthread'; do + CFLAGS="$flag $chktls_save_CFLAGS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + void *g(void *d) { return NULL; } +int +main () +{ +pthread_t t; pthread_create(&t,NULL,g,NULL); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + thread_CFLAGS="$flag" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "X$thread_CFLAGS" != Xfailed; then + break + fi + done + CFLAGS="$chktls_save_CFLAGS" + if test "X$thread_CFLAGS" != Xfailed; then + CFLAGS="$thread_CFLAGS $chktls_save_CFLAGS" + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + __thread int a; + static int *volatile a_in_other_thread; + static void * + thread_func (void *arg) + { + a_in_other_thread = &a; + return (void *)0; + } +int +main () +{ +pthread_t thread; + void *thread_retval; + int *volatile a_in_main_thread; + a_in_main_thread = &a; + if (pthread_create (&thread, (pthread_attr_t *)0, + thread_func, (void *)0)) + return 0; + if (pthread_join (thread, &thread_retval)) + return 0; + return (a_in_other_thread == a_in_main_thread); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + gcc_cv_have_tls=yes +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$chktls_save_CFLAGS" + fi + fi +else + gcc_cv_have_tls=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_have_tls" >&5 +$as_echo "$gcc_cv_have_tls" >&6; } + if test "$enable_tls $gcc_cv_have_tls" = "yes yes"; then + +$as_echo "#define HAVE_TLS 1" >>confdefs.h + + fi + for ac_func in __cxa_thread_atexit_impl +do : + ac_fn_c_check_func "$LINENO" "__cxa_thread_atexit_impl" "ac_cv_func___cxa_thread_atexit_impl" +if test "x$ac_cv_func___cxa_thread_atexit_impl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE___CXA_THREAD_ATEXIT_IMPL 1 +_ACEOF + +fi +done + + for ac_func in aligned_alloc posix_memalign memalign _aligned_malloc +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + for ac_func in timespec_get +do : + ac_fn_c_check_func "$LINENO" "timespec_get" "ac_cv_func_timespec_get" +if test "x$ac_cv_func_timespec_get" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_TIMESPEC_GET 1 +_ACEOF + +fi +done + + for ac_func in sockatmark +do : + ac_fn_c_check_func "$LINENO" "sockatmark" "ac_cv_func_sockatmark" +if test "x$ac_cv_func_sockatmark" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKATMARK 1 +_ACEOF + +fi +done + + for ac_func in uselocale +do : + ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale" +if test "x$ac_cv_func_uselocale" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_USELOCALE 1 +_ACEOF + +fi +done + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if ${am_cv_func_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + am_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCICONV" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + + if test "$am_cv_func_iconv" != yes && test -d ../libiconv; then + for _libs in .libs _libs; do + am_save_CPPFLAGS="$CPPFLAGS" + am_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS -I../libiconv/include" + LIBS="$LIBS ../libiconv/lib/$_libs/libiconv.a" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + INCICONV="-I../libiconv/include" + LIBICONV='${top_builddir}'/../libiconv/lib/$_libs/libiconv.a + LTLIBICONV='${top_builddir}'/../libiconv/lib/libiconv.la + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + LIBS="$am_save_LIBS" + if test "$am_cv_func_iconv" = "yes"; then + break + fi + done + fi + + if test "$am_cv_func_iconv" != yes; then + am_save_CPPFLAGS="$CPPFLAGS" + am_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $INCICONV" + LIBS="$LIBS $LIBICONV" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$am_save_CPPFLAGS" + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + fi + if test "$am_cv_lib_iconv" = yes; then + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 +$as_echo_n "checking how to link with libiconv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +$as_echo "$LIBICONV" >&6; } + else + LIBICONV= + LTLIBICONV= + fi + + + + if test "$am_cv_func_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 +$as_echo_n "checking for iconv declaration... " >&6; } + if ${am_cv_proto_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_cv_proto_iconv_arg1="" +else + am_cv_proto_iconv_arg1="const" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +fi + + am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- + }$am_cv_proto_iconv" >&5 +$as_echo "${ac_t:- + }$am_cv_proto_iconv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define ICONV_CONST $am_cv_proto_iconv_arg1 +_ACEOF + + fi + + ;; + *-mingw32*) + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + libm="-lm" +fi + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $libm" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf declaration" >&5 +$as_echo_n "checking for isinf declaration... " >&6; } + if test x${glibcxx_cv_func_isinf_use+set} != xset; then + if ${glibcxx_cv_func_isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinf_use=yes +else + glibcxx_cv_func_isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinf_use" >&5 +$as_echo "$glibcxx_cv_func_isinf_use" >&6; } + + if test x$glibcxx_cv_func_isinf_use = x"yes"; then + for ac_func in isinf +do : + ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinf declaration" >&5 +$as_echo_n "checking for _isinf declaration... " >&6; } + if test x${glibcxx_cv_func__isinf_use+set} != xset; then + if ${glibcxx_cv_func__isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinf_use=yes +else + glibcxx_cv_func__isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinf_use" >&5 +$as_echo "$glibcxx_cv_func__isinf_use" >&6; } + + if test x$glibcxx_cv_func__isinf_use = x"yes"; then + for ac_func in _isinf +do : + ac_fn_c_check_func "$LINENO" "_isinf" "ac_cv_func__isinf" +if test "x$ac_cv_func__isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan declaration" >&5 +$as_echo_n "checking for isnan declaration... " >&6; } + if test x${glibcxx_cv_func_isnan_use+set} != xset; then + if ${glibcxx_cv_func_isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnan_use=yes +else + glibcxx_cv_func_isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnan_use" >&5 +$as_echo "$glibcxx_cv_func_isnan_use" >&6; } + + if test x$glibcxx_cv_func_isnan_use = x"yes"; then + for ac_func in isnan +do : + ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNAN 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnan declaration" >&5 +$as_echo_n "checking for _isnan declaration... " >&6; } + if test x${glibcxx_cv_func__isnan_use+set} != xset; then + if ${glibcxx_cv_func__isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnan_use=yes +else + glibcxx_cv_func__isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnan_use" >&5 +$as_echo "$glibcxx_cv_func__isnan_use" >&6; } + + if test x$glibcxx_cv_func__isnan_use = x"yes"; then + for ac_func in _isnan +do : + ac_fn_c_check_func "$LINENO" "_isnan" "ac_cv_func__isnan" +if test "x$ac_cv_func__isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNAN 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finite declaration" >&5 +$as_echo_n "checking for finite declaration... " >&6; } + if test x${glibcxx_cv_func_finite_use+set} != xset; then + if ${glibcxx_cv_func_finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finite_use=yes +else + glibcxx_cv_func_finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finite_use" >&5 +$as_echo "$glibcxx_cv_func_finite_use" >&6; } + + if test x$glibcxx_cv_func_finite_use = x"yes"; then + for ac_func in finite +do : + ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITE 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finite declaration" >&5 +$as_echo_n "checking for _finite declaration... " >&6; } + if test x${glibcxx_cv_func__finite_use+set} != xset; then + if ${glibcxx_cv_func__finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finite_use=yes +else + glibcxx_cv_func__finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finite_use" >&5 +$as_echo "$glibcxx_cv_func__finite_use" >&6; } + + if test x$glibcxx_cv_func__finite_use = x"yes"; then + for ac_func in _finite +do : + ac_fn_c_check_func "$LINENO" "_finite" "ac_cv_func__finite" +if test "x$ac_cv_func__finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITE 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincos declaration" >&5 +$as_echo_n "checking for sincos declaration... " >&6; } + if test x${glibcxx_cv_func_sincos_use+set} != xset; then + if ${glibcxx_cv_func_sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincos_use=yes +else + glibcxx_cv_func_sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincos_use" >&5 +$as_echo "$glibcxx_cv_func_sincos_use" >&6; } + + if test x$glibcxx_cv_func_sincos_use = x"yes"; then + for ac_func in sincos +do : + ac_fn_c_check_func "$LINENO" "sincos" "ac_cv_func_sincos" +if test "x$ac_cv_func_sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincos declaration" >&5 +$as_echo_n "checking for _sincos declaration... " >&6; } + if test x${glibcxx_cv_func__sincos_use+set} != xset; then + if ${glibcxx_cv_func__sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincos_use=yes +else + glibcxx_cv_func__sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincos_use" >&5 +$as_echo "$glibcxx_cv_func__sincos_use" >&6; } + + if test x$glibcxx_cv_func__sincos_use = x"yes"; then + for ac_func in _sincos +do : + ac_fn_c_check_func "$LINENO" "_sincos" "ac_cv_func__sincos" +if test "x$ac_cv_func__sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpclass declaration" >&5 +$as_echo_n "checking for fpclass declaration... " >&6; } + if test x${glibcxx_cv_func_fpclass_use+set} != xset; then + if ${glibcxx_cv_func_fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fpclass_use=yes +else + glibcxx_cv_func_fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fpclass_use" >&5 +$as_echo "$glibcxx_cv_func_fpclass_use" >&6; } + + if test x$glibcxx_cv_func_fpclass_use = x"yes"; then + for ac_func in fpclass +do : + ac_fn_c_check_func "$LINENO" "fpclass" "ac_cv_func_fpclass" +if test "x$ac_cv_func_fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fpclass declaration" >&5 +$as_echo_n "checking for _fpclass declaration... " >&6; } + if test x${glibcxx_cv_func__fpclass_use+set} != xset; then + if ${glibcxx_cv_func__fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fpclass_use=yes +else + glibcxx_cv_func__fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fpclass_use" >&5 +$as_echo "$glibcxx_cv_func__fpclass_use" >&6; } + + if test x$glibcxx_cv_func__fpclass_use = x"yes"; then + for ac_func in _fpclass +do : + ac_fn_c_check_func "$LINENO" "_fpclass" "ac_cv_func__fpclass" +if test "x$ac_cv_func__fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for qfpclass declaration" >&5 +$as_echo_n "checking for qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func_qfpclass_use+set} != xset; then + if ${glibcxx_cv_func_qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_qfpclass_use=yes +else + glibcxx_cv_func_qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func_qfpclass_use" >&6; } + + if test x$glibcxx_cv_func_qfpclass_use = x"yes"; then + for ac_func in qfpclass +do : + ac_fn_c_check_func "$LINENO" "qfpclass" "ac_cv_func_qfpclass" +if test "x$ac_cv_func_qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QFPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _qfpclass declaration" >&5 +$as_echo_n "checking for _qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func__qfpclass_use+set} != xset; then + if ${glibcxx_cv_func__qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__qfpclass_use=yes +else + glibcxx_cv_func__qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func__qfpclass_use" >&6; } + + if test x$glibcxx_cv_func__qfpclass_use = x"yes"; then + for ac_func in _qfpclass +do : + ac_fn_c_check_func "$LINENO" "_qfpclass" "ac_cv_func__qfpclass" +if test "x$ac_cv_func__qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__QFPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypot declaration" >&5 +$as_echo_n "checking for hypot declaration... " >&6; } + if test x${glibcxx_cv_func_hypot_use+set} != xset; then + if ${glibcxx_cv_func_hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypot_use=yes +else + glibcxx_cv_func_hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypot_use" >&5 +$as_echo "$glibcxx_cv_func_hypot_use" >&6; } + + if test x$glibcxx_cv_func_hypot_use = x"yes"; then + for ac_func in hypot +do : + ac_fn_c_check_func "$LINENO" "hypot" "ac_cv_func_hypot" +if test "x$ac_cv_func_hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOT 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypot declaration" >&5 +$as_echo_n "checking for _hypot declaration... " >&6; } + if test x${glibcxx_cv_func__hypot_use+set} != xset; then + if ${glibcxx_cv_func__hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypot_use=yes +else + glibcxx_cv_func__hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypot_use" >&5 +$as_echo "$glibcxx_cv_func__hypot_use" >&6; } + + if test x$glibcxx_cv_func__hypot_use = x"yes"; then + for ac_func in _hypot +do : + ac_fn_c_check_func "$LINENO" "_hypot" "ac_cv_func__hypot" +if test "x$ac_cv_func__hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOT 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float trig functions" >&5 +$as_echo_n "checking for float trig functions... " >&6; } + if ${glibcxx_cv_func_float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosf (0); asinf (0); atanf (0); cosf (0); sinf (0); tanf (0); coshf (0); sinhf (0); tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_trig_use=yes +else + glibcxx_cv_func_float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_trig_use" >&5 +$as_echo "$glibcxx_cv_func_float_trig_use" >&6; } + if test x$glibcxx_cv_func_float_trig_use = x"yes"; then + for ac_func in acosf asinf atanf cosf sinf tanf coshf sinhf tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float trig functions" >&5 +$as_echo_n "checking for _float trig functions... " >&6; } + if ${glibcxx_cv_func__float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosf (0); _asinf (0); _atanf (0); _cosf (0); _sinf (0); _tanf (0); _coshf (0); _sinhf (0); _tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_trig_use=yes +else + glibcxx_cv_func__float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_trig_use" >&5 +$as_echo "$glibcxx_cv_func__float_trig_use" >&6; } + if test x$glibcxx_cv_func__float_trig_use = x"yes"; then + for ac_func in _acosf _asinf _atanf _cosf _sinf _tanf _coshf _sinhf _tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float round functions" >&5 +$as_echo_n "checking for float round functions... " >&6; } + if ${glibcxx_cv_func_float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceilf (0); floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_round_use=yes +else + glibcxx_cv_func_float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_round_use" >&5 +$as_echo "$glibcxx_cv_func_float_round_use" >&6; } + if test x$glibcxx_cv_func_float_round_use = x"yes"; then + for ac_func in ceilf floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float round functions" >&5 +$as_echo_n "checking for _float round functions... " >&6; } + if ${glibcxx_cv_func__float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceilf (0); _floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_round_use=yes +else + glibcxx_cv_func__float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_round_use" >&5 +$as_echo "$glibcxx_cv_func__float_round_use" >&6; } + if test x$glibcxx_cv_func__float_round_use = x"yes"; then + for ac_func in _ceilf _floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expf declaration" >&5 +$as_echo_n "checking for expf declaration... " >&6; } + if test x${glibcxx_cv_func_expf_use+set} != xset; then + if ${glibcxx_cv_func_expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expf_use=yes +else + glibcxx_cv_func_expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expf_use" >&5 +$as_echo "$glibcxx_cv_func_expf_use" >&6; } + + if test x$glibcxx_cv_func_expf_use = x"yes"; then + for ac_func in expf +do : + ac_fn_c_check_func "$LINENO" "expf" "ac_cv_func_expf" +if test "x$ac_cv_func_expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expf declaration" >&5 +$as_echo_n "checking for _expf declaration... " >&6; } + if test x${glibcxx_cv_func__expf_use+set} != xset; then + if ${glibcxx_cv_func__expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expf_use=yes +else + glibcxx_cv_func__expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expf_use" >&5 +$as_echo "$glibcxx_cv_func__expf_use" >&6; } + + if test x$glibcxx_cv_func__expf_use = x"yes"; then + for ac_func in _expf +do : + ac_fn_c_check_func "$LINENO" "_expf" "ac_cv_func__expf" +if test "x$ac_cv_func__expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanf declaration" >&5 +$as_echo_n "checking for isnanf declaration... " >&6; } + if test x${glibcxx_cv_func_isnanf_use+set} != xset; then + if ${glibcxx_cv_func_isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanf_use=yes +else + glibcxx_cv_func_isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanf_use" >&5 +$as_echo "$glibcxx_cv_func_isnanf_use" >&6; } + + if test x$glibcxx_cv_func_isnanf_use = x"yes"; then + for ac_func in isnanf +do : + ac_fn_c_check_func "$LINENO" "isnanf" "ac_cv_func_isnanf" +if test "x$ac_cv_func_isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanf declaration" >&5 +$as_echo_n "checking for _isnanf declaration... " >&6; } + if test x${glibcxx_cv_func__isnanf_use+set} != xset; then + if ${glibcxx_cv_func__isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanf_use=yes +else + glibcxx_cv_func__isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanf_use" >&5 +$as_echo "$glibcxx_cv_func__isnanf_use" >&6; } + + if test x$glibcxx_cv_func__isnanf_use = x"yes"; then + for ac_func in _isnanf +do : + ac_fn_c_check_func "$LINENO" "_isnanf" "ac_cv_func__isnanf" +if test "x$ac_cv_func__isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinff declaration" >&5 +$as_echo_n "checking for isinff declaration... " >&6; } + if test x${glibcxx_cv_func_isinff_use+set} != xset; then + if ${glibcxx_cv_func_isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinff_use=yes +else + glibcxx_cv_func_isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinff_use" >&5 +$as_echo "$glibcxx_cv_func_isinff_use" >&6; } + + if test x$glibcxx_cv_func_isinff_use = x"yes"; then + for ac_func in isinff +do : + ac_fn_c_check_func "$LINENO" "isinff" "ac_cv_func_isinff" +if test "x$ac_cv_func_isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinff declaration" >&5 +$as_echo_n "checking for _isinff declaration... " >&6; } + if test x${glibcxx_cv_func__isinff_use+set} != xset; then + if ${glibcxx_cv_func__isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinff_use=yes +else + glibcxx_cv_func__isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinff_use" >&5 +$as_echo "$glibcxx_cv_func__isinff_use" >&6; } + + if test x$glibcxx_cv_func__isinff_use = x"yes"; then + for ac_func in _isinff +do : + ac_fn_c_check_func "$LINENO" "_isinff" "ac_cv_func__isinff" +if test "x$ac_cv_func__isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f declaration" >&5 +$as_echo_n "checking for atan2f declaration... " >&6; } + if test x${glibcxx_cv_func_atan2f_use+set} != xset; then + if ${glibcxx_cv_func_atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2f_use=yes +else + glibcxx_cv_func_atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2f_use" >&5 +$as_echo "$glibcxx_cv_func_atan2f_use" >&6; } + + if test x$glibcxx_cv_func_atan2f_use = x"yes"; then + for ac_func in atan2f +do : + ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2f declaration" >&5 +$as_echo_n "checking for _atan2f declaration... " >&6; } + if test x${glibcxx_cv_func__atan2f_use+set} != xset; then + if ${glibcxx_cv_func__atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2f_use=yes +else + glibcxx_cv_func__atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2f_use" >&5 +$as_echo "$glibcxx_cv_func__atan2f_use" >&6; } + + if test x$glibcxx_cv_func__atan2f_use = x"yes"; then + for ac_func in _atan2f +do : + ac_fn_c_check_func "$LINENO" "_atan2f" "ac_cv_func__atan2f" +if test "x$ac_cv_func__atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsf declaration" >&5 +$as_echo_n "checking for fabsf declaration... " >&6; } + if test x${glibcxx_cv_func_fabsf_use+set} != xset; then + if ${glibcxx_cv_func_fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsf_use=yes +else + glibcxx_cv_func_fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsf_use" >&5 +$as_echo "$glibcxx_cv_func_fabsf_use" >&6; } + + if test x$glibcxx_cv_func_fabsf_use = x"yes"; then + for ac_func in fabsf +do : + ac_fn_c_check_func "$LINENO" "fabsf" "ac_cv_func_fabsf" +if test "x$ac_cv_func_fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsf declaration" >&5 +$as_echo_n "checking for _fabsf declaration... " >&6; } + if test x${glibcxx_cv_func__fabsf_use+set} != xset; then + if ${glibcxx_cv_func__fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsf_use=yes +else + glibcxx_cv_func__fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsf_use" >&5 +$as_echo "$glibcxx_cv_func__fabsf_use" >&6; } + + if test x$glibcxx_cv_func__fabsf_use = x"yes"; then + for ac_func in _fabsf +do : + ac_fn_c_check_func "$LINENO" "_fabsf" "ac_cv_func__fabsf" +if test "x$ac_cv_func__fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf declaration" >&5 +$as_echo_n "checking for fmodf declaration... " >&6; } + if test x${glibcxx_cv_func_fmodf_use+set} != xset; then + if ${glibcxx_cv_func_fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodf_use=yes +else + glibcxx_cv_func_fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodf_use" >&5 +$as_echo "$glibcxx_cv_func_fmodf_use" >&6; } + + if test x$glibcxx_cv_func_fmodf_use = x"yes"; then + for ac_func in fmodf +do : + ac_fn_c_check_func "$LINENO" "fmodf" "ac_cv_func_fmodf" +if test "x$ac_cv_func_fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodf declaration" >&5 +$as_echo_n "checking for _fmodf declaration... " >&6; } + if test x${glibcxx_cv_func__fmodf_use+set} != xset; then + if ${glibcxx_cv_func__fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodf_use=yes +else + glibcxx_cv_func__fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodf_use" >&5 +$as_echo "$glibcxx_cv_func__fmodf_use" >&6; } + + if test x$glibcxx_cv_func__fmodf_use = x"yes"; then + for ac_func in _fmodf +do : + ac_fn_c_check_func "$LINENO" "_fmodf" "ac_cv_func__fmodf" +if test "x$ac_cv_func__fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } + if test x${glibcxx_cv_func_frexpf_use+set} != xset; then + if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + + if test x$glibcxx_cv_func_frexpf_use = x"yes"; then + for ac_func in frexpf +do : + ac_fn_c_check_func "$LINENO" "frexpf" "ac_cv_func_frexpf" +if test "x$ac_cv_func_frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpf declaration" >&5 +$as_echo_n "checking for _frexpf declaration... " >&6; } + if test x${glibcxx_cv_func__frexpf_use+set} != xset; then + if ${glibcxx_cv_func__frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpf_use=yes +else + glibcxx_cv_func__frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpf_use" >&5 +$as_echo "$glibcxx_cv_func__frexpf_use" >&6; } + + if test x$glibcxx_cv_func__frexpf_use = x"yes"; then + for ac_func in _frexpf +do : + ac_fn_c_check_func "$LINENO" "_frexpf" "ac_cv_func__frexpf" +if test "x$ac_cv_func__frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } + if test x${glibcxx_cv_func_hypotf_use+set} != xset; then + if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + + if test x$glibcxx_cv_func_hypotf_use = x"yes"; then + for ac_func in hypotf +do : + ac_fn_c_check_func "$LINENO" "hypotf" "ac_cv_func_hypotf" +if test "x$ac_cv_func_hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotf declaration" >&5 +$as_echo_n "checking for _hypotf declaration... " >&6; } + if test x${glibcxx_cv_func__hypotf_use+set} != xset; then + if ${glibcxx_cv_func__hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotf_use=yes +else + glibcxx_cv_func__hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotf_use" >&5 +$as_echo "$glibcxx_cv_func__hypotf_use" >&6; } + + if test x$glibcxx_cv_func__hypotf_use = x"yes"; then + for ac_func in _hypotf +do : + ac_fn_c_check_func "$LINENO" "_hypotf" "ac_cv_func__hypotf" +if test "x$ac_cv_func__hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpf_use+set} != xset; then + if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + + if test x$glibcxx_cv_func_ldexpf_use = x"yes"; then + for ac_func in ldexpf +do : + ac_fn_c_check_func "$LINENO" "ldexpf" "ac_cv_func_ldexpf" +if test "x$ac_cv_func_ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpf declaration" >&5 +$as_echo_n "checking for _ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpf_use+set} != xset; then + if ${glibcxx_cv_func__ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpf_use=yes +else + glibcxx_cv_func__ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpf_use" >&6; } + + if test x$glibcxx_cv_func__ldexpf_use = x"yes"; then + for ac_func in _ldexpf +do : + ac_fn_c_check_func "$LINENO" "_ldexpf" "ac_cv_func__ldexpf" +if test "x$ac_cv_func__ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logf declaration" >&5 +$as_echo_n "checking for logf declaration... " >&6; } + if test x${glibcxx_cv_func_logf_use+set} != xset; then + if ${glibcxx_cv_func_logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logf_use=yes +else + glibcxx_cv_func_logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logf_use" >&5 +$as_echo "$glibcxx_cv_func_logf_use" >&6; } + + if test x$glibcxx_cv_func_logf_use = x"yes"; then + for ac_func in logf +do : + ac_fn_c_check_func "$LINENO" "logf" "ac_cv_func_logf" +if test "x$ac_cv_func_logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logf declaration" >&5 +$as_echo_n "checking for _logf declaration... " >&6; } + if test x${glibcxx_cv_func__logf_use+set} != xset; then + if ${glibcxx_cv_func__logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logf_use=yes +else + glibcxx_cv_func__logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logf_use" >&5 +$as_echo "$glibcxx_cv_func__logf_use" >&6; } + + if test x$glibcxx_cv_func__logf_use = x"yes"; then + for ac_func in _logf +do : + ac_fn_c_check_func "$LINENO" "_logf" "ac_cv_func__logf" +if test "x$ac_cv_func__logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10f declaration" >&5 +$as_echo_n "checking for log10f declaration... " >&6; } + if test x${glibcxx_cv_func_log10f_use+set} != xset; then + if ${glibcxx_cv_func_log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10f_use=yes +else + glibcxx_cv_func_log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10f_use" >&5 +$as_echo "$glibcxx_cv_func_log10f_use" >&6; } + + if test x$glibcxx_cv_func_log10f_use = x"yes"; then + for ac_func in log10f +do : + ac_fn_c_check_func "$LINENO" "log10f" "ac_cv_func_log10f" +if test "x$ac_cv_func_log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10f declaration" >&5 +$as_echo_n "checking for _log10f declaration... " >&6; } + if test x${glibcxx_cv_func__log10f_use+set} != xset; then + if ${glibcxx_cv_func__log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10f_use=yes +else + glibcxx_cv_func__log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10f_use" >&5 +$as_echo "$glibcxx_cv_func__log10f_use" >&6; } + + if test x$glibcxx_cv_func__log10f_use = x"yes"; then + for ac_func in _log10f +do : + ac_fn_c_check_func "$LINENO" "_log10f" "ac_cv_func__log10f" +if test "x$ac_cv_func__log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } + if test x${glibcxx_cv_func_modff_use+set} != xset; then + if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + + if test x$glibcxx_cv_func_modff_use = x"yes"; then + for ac_func in modff +do : + ac_fn_c_check_func "$LINENO" "modff" "ac_cv_func_modff" +if test "x$ac_cv_func_modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modff declaration" >&5 +$as_echo_n "checking for _modff declaration... " >&6; } + if test x${glibcxx_cv_func__modff_use+set} != xset; then + if ${glibcxx_cv_func__modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modff_use=yes +else + glibcxx_cv_func__modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modff_use" >&5 +$as_echo "$glibcxx_cv_func__modff_use" >&6; } + + if test x$glibcxx_cv_func__modff_use = x"yes"; then + for ac_func in _modff +do : + ac_fn_c_check_func "$LINENO" "_modff" "ac_cv_func__modff" +if test "x$ac_cv_func__modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modf declaration" >&5 +$as_echo_n "checking for modf declaration... " >&6; } + if test x${glibcxx_cv_func_modf_use+set} != xset; then + if ${glibcxx_cv_func_modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modf_use=yes +else + glibcxx_cv_func_modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modf_use" >&5 +$as_echo "$glibcxx_cv_func_modf_use" >&6; } + + if test x$glibcxx_cv_func_modf_use = x"yes"; then + for ac_func in modf +do : + ac_fn_c_check_func "$LINENO" "modf" "ac_cv_func_modf" +if test "x$ac_cv_func_modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modf declaration" >&5 +$as_echo_n "checking for _modf declaration... " >&6; } + if test x${glibcxx_cv_func__modf_use+set} != xset; then + if ${glibcxx_cv_func__modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modf_use=yes +else + glibcxx_cv_func__modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modf_use" >&5 +$as_echo "$glibcxx_cv_func__modf_use" >&6; } + + if test x$glibcxx_cv_func__modf_use = x"yes"; then + for ac_func in _modf +do : + ac_fn_c_check_func "$LINENO" "_modf" "ac_cv_func__modf" +if test "x$ac_cv_func__modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powf declaration" >&5 +$as_echo_n "checking for powf declaration... " >&6; } + if test x${glibcxx_cv_func_powf_use+set} != xset; then + if ${glibcxx_cv_func_powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powf_use=yes +else + glibcxx_cv_func_powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powf_use" >&5 +$as_echo "$glibcxx_cv_func_powf_use" >&6; } + + if test x$glibcxx_cv_func_powf_use = x"yes"; then + for ac_func in powf +do : + ac_fn_c_check_func "$LINENO" "powf" "ac_cv_func_powf" +if test "x$ac_cv_func_powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powf declaration" >&5 +$as_echo_n "checking for _powf declaration... " >&6; } + if test x${glibcxx_cv_func__powf_use+set} != xset; then + if ${glibcxx_cv_func__powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powf_use=yes +else + glibcxx_cv_func__powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powf_use" >&5 +$as_echo "$glibcxx_cv_func__powf_use" >&6; } + + if test x$glibcxx_cv_func__powf_use = x"yes"; then + for ac_func in _powf +do : + ac_fn_c_check_func "$LINENO" "_powf" "ac_cv_func__powf" +if test "x$ac_cv_func__powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtf declaration" >&5 +$as_echo_n "checking for sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtf_use+set} != xset; then + if ${glibcxx_cv_func_sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtf_use=yes +else + glibcxx_cv_func_sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtf_use" >&6; } + + if test x$glibcxx_cv_func_sqrtf_use = x"yes"; then + for ac_func in sqrtf +do : + ac_fn_c_check_func "$LINENO" "sqrtf" "ac_cv_func_sqrtf" +if test "x$ac_cv_func_sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtf declaration" >&5 +$as_echo_n "checking for _sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtf_use+set} != xset; then + if ${glibcxx_cv_func__sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtf_use=yes +else + glibcxx_cv_func__sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtf_use" >&6; } + + if test x$glibcxx_cv_func__sqrtf_use = x"yes"; then + for ac_func in _sqrtf +do : + ac_fn_c_check_func "$LINENO" "_sqrtf" "ac_cv_func__sqrtf" +if test "x$ac_cv_func__sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosf declaration" >&5 +$as_echo_n "checking for sincosf declaration... " >&6; } + if test x${glibcxx_cv_func_sincosf_use+set} != xset; then + if ${glibcxx_cv_func_sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosf_use=yes +else + glibcxx_cv_func_sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosf_use" >&5 +$as_echo "$glibcxx_cv_func_sincosf_use" >&6; } + + if test x$glibcxx_cv_func_sincosf_use = x"yes"; then + for ac_func in sincosf +do : + ac_fn_c_check_func "$LINENO" "sincosf" "ac_cv_func_sincosf" +if test "x$ac_cv_func_sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosf declaration" >&5 +$as_echo_n "checking for _sincosf declaration... " >&6; } + if test x${glibcxx_cv_func__sincosf_use+set} != xset; then + if ${glibcxx_cv_func__sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosf_use=yes +else + glibcxx_cv_func__sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosf_use" >&5 +$as_echo "$glibcxx_cv_func__sincosf_use" >&6; } + + if test x$glibcxx_cv_func__sincosf_use = x"yes"; then + for ac_func in _sincosf +do : + ac_fn_c_check_func "$LINENO" "_sincosf" "ac_cv_func__sincosf" +if test "x$ac_cv_func__sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitef declaration" >&5 +$as_echo_n "checking for finitef declaration... " >&6; } + if test x${glibcxx_cv_func_finitef_use+set} != xset; then + if ${glibcxx_cv_func_finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitef_use=yes +else + glibcxx_cv_func_finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitef_use" >&5 +$as_echo "$glibcxx_cv_func_finitef_use" >&6; } + + if test x$glibcxx_cv_func_finitef_use = x"yes"; then + for ac_func in finitef +do : + ac_fn_c_check_func "$LINENO" "finitef" "ac_cv_func_finitef" +if test "x$ac_cv_func_finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitef declaration" >&5 +$as_echo_n "checking for _finitef declaration... " >&6; } + if test x${glibcxx_cv_func__finitef_use+set} != xset; then + if ${glibcxx_cv_func__finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitef_use=yes +else + glibcxx_cv_func__finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitef_use" >&5 +$as_echo "$glibcxx_cv_func__finitef_use" >&6; } + + if test x$glibcxx_cv_func__finitef_use = x"yes"; then + for ac_func in _finitef +do : + ac_fn_c_check_func "$LINENO" "_finitef" "ac_cv_func__finitef" +if test "x$ac_cv_func__finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double trig functions" >&5 +$as_echo_n "checking for long double trig functions... " >&6; } + if ${glibcxx_cv_func_long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosl (0); asinl (0); atanl (0); cosl (0); sinl (0); tanl (0); coshl (0); sinhl (0); tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_trig_use=yes +else + glibcxx_cv_func_long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_trig_use" >&6; } + if test x$glibcxx_cv_func_long_double_trig_use = x"yes"; then + for ac_func in acosl asinl atanl cosl sinl tanl coshl sinhl tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double trig functions" >&5 +$as_echo_n "checking for _long double trig functions... " >&6; } + if ${glibcxx_cv_func__long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosl (0); _asinl (0); _atanl (0); _cosl (0); _sinl (0); _tanl (0); _coshl (0); _sinhl (0); _tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_trig_use=yes +else + glibcxx_cv_func__long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_trig_use" >&6; } + if test x$glibcxx_cv_func__long_double_trig_use = x"yes"; then + for ac_func in _acosl _asinl _atanl _cosl _sinl _tanl _coshl _sinhl _tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double round functions" >&5 +$as_echo_n "checking for long double round functions... " >&6; } + if ${glibcxx_cv_func_long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceill (0); floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_round_use=yes +else + glibcxx_cv_func_long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_round_use" >&6; } + if test x$glibcxx_cv_func_long_double_round_use = x"yes"; then + for ac_func in ceill floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double round functions" >&5 +$as_echo_n "checking for _long double round functions... " >&6; } + if ${glibcxx_cv_func__long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceill (0); _floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_round_use=yes +else + glibcxx_cv_func__long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_round_use" >&6; } + if test x$glibcxx_cv_func__long_double_round_use = x"yes"; then + for ac_func in _ceill _floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanl declaration" >&5 +$as_echo_n "checking for isnanl declaration... " >&6; } + if test x${glibcxx_cv_func_isnanl_use+set} != xset; then + if ${glibcxx_cv_func_isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanl_use=yes +else + glibcxx_cv_func_isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanl_use" >&5 +$as_echo "$glibcxx_cv_func_isnanl_use" >&6; } + + if test x$glibcxx_cv_func_isnanl_use = x"yes"; then + for ac_func in isnanl +do : + ac_fn_c_check_func "$LINENO" "isnanl" "ac_cv_func_isnanl" +if test "x$ac_cv_func_isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanl declaration" >&5 +$as_echo_n "checking for _isnanl declaration... " >&6; } + if test x${glibcxx_cv_func__isnanl_use+set} != xset; then + if ${glibcxx_cv_func__isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanl_use=yes +else + glibcxx_cv_func__isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanl_use" >&5 +$as_echo "$glibcxx_cv_func__isnanl_use" >&6; } + + if test x$glibcxx_cv_func__isnanl_use = x"yes"; then + for ac_func in _isnanl +do : + ac_fn_c_check_func "$LINENO" "_isnanl" "ac_cv_func__isnanl" +if test "x$ac_cv_func__isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinfl declaration" >&5 +$as_echo_n "checking for isinfl declaration... " >&6; } + if test x${glibcxx_cv_func_isinfl_use+set} != xset; then + if ${glibcxx_cv_func_isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinfl_use=yes +else + glibcxx_cv_func_isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinfl_use" >&5 +$as_echo "$glibcxx_cv_func_isinfl_use" >&6; } + + if test x$glibcxx_cv_func_isinfl_use = x"yes"; then + for ac_func in isinfl +do : + ac_fn_c_check_func "$LINENO" "isinfl" "ac_cv_func_isinfl" +if test "x$ac_cv_func_isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinfl declaration" >&5 +$as_echo_n "checking for _isinfl declaration... " >&6; } + if test x${glibcxx_cv_func__isinfl_use+set} != xset; then + if ${glibcxx_cv_func__isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinfl_use=yes +else + glibcxx_cv_func__isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinfl_use" >&5 +$as_echo "$glibcxx_cv_func__isinfl_use" >&6; } + + if test x$glibcxx_cv_func__isinfl_use = x"yes"; then + for ac_func in _isinfl +do : + ac_fn_c_check_func "$LINENO" "_isinfl" "ac_cv_func__isinfl" +if test "x$ac_cv_func__isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } + if test x${glibcxx_cv_func_atan2l_use+set} != xset; then + if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + + if test x$glibcxx_cv_func_atan2l_use = x"yes"; then + for ac_func in atan2l +do : + ac_fn_c_check_func "$LINENO" "atan2l" "ac_cv_func_atan2l" +if test "x$ac_cv_func_atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2l declaration" >&5 +$as_echo_n "checking for _atan2l declaration... " >&6; } + if test x${glibcxx_cv_func__atan2l_use+set} != xset; then + if ${glibcxx_cv_func__atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2l_use=yes +else + glibcxx_cv_func__atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2l_use" >&5 +$as_echo "$glibcxx_cv_func__atan2l_use" >&6; } + + if test x$glibcxx_cv_func__atan2l_use = x"yes"; then + for ac_func in _atan2l +do : + ac_fn_c_check_func "$LINENO" "_atan2l" "ac_cv_func__atan2l" +if test "x$ac_cv_func__atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } + if test x${glibcxx_cv_func_expl_use+set} != xset; then + if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + + if test x$glibcxx_cv_func_expl_use = x"yes"; then + for ac_func in expl +do : + ac_fn_c_check_func "$LINENO" "expl" "ac_cv_func_expl" +if test "x$ac_cv_func_expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expl declaration" >&5 +$as_echo_n "checking for _expl declaration... " >&6; } + if test x${glibcxx_cv_func__expl_use+set} != xset; then + if ${glibcxx_cv_func__expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expl_use=yes +else + glibcxx_cv_func__expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expl_use" >&5 +$as_echo "$glibcxx_cv_func__expl_use" >&6; } + + if test x$glibcxx_cv_func__expl_use = x"yes"; then + for ac_func in _expl +do : + ac_fn_c_check_func "$LINENO" "_expl" "ac_cv_func__expl" +if test "x$ac_cv_func__expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } + if test x${glibcxx_cv_func_fabsl_use+set} != xset; then + if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + + if test x$glibcxx_cv_func_fabsl_use = x"yes"; then + for ac_func in fabsl +do : + ac_fn_c_check_func "$LINENO" "fabsl" "ac_cv_func_fabsl" +if test "x$ac_cv_func_fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsl declaration" >&5 +$as_echo_n "checking for _fabsl declaration... " >&6; } + if test x${glibcxx_cv_func__fabsl_use+set} != xset; then + if ${glibcxx_cv_func__fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsl_use=yes +else + glibcxx_cv_func__fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsl_use" >&5 +$as_echo "$glibcxx_cv_func__fabsl_use" >&6; } + + if test x$glibcxx_cv_func__fabsl_use = x"yes"; then + for ac_func in _fabsl +do : + ac_fn_c_check_func "$LINENO" "_fabsl" "ac_cv_func__fabsl" +if test "x$ac_cv_func__fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } + if test x${glibcxx_cv_func_fmodl_use+set} != xset; then + if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + + if test x$glibcxx_cv_func_fmodl_use = x"yes"; then + for ac_func in fmodl +do : + ac_fn_c_check_func "$LINENO" "fmodl" "ac_cv_func_fmodl" +if test "x$ac_cv_func_fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodl declaration" >&5 +$as_echo_n "checking for _fmodl declaration... " >&6; } + if test x${glibcxx_cv_func__fmodl_use+set} != xset; then + if ${glibcxx_cv_func__fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodl_use=yes +else + glibcxx_cv_func__fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodl_use" >&5 +$as_echo "$glibcxx_cv_func__fmodl_use" >&6; } + + if test x$glibcxx_cv_func__fmodl_use = x"yes"; then + for ac_func in _fmodl +do : + ac_fn_c_check_func "$LINENO" "_fmodl" "ac_cv_func__fmodl" +if test "x$ac_cv_func__fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } + if test x${glibcxx_cv_func_frexpl_use+set} != xset; then + if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + + if test x$glibcxx_cv_func_frexpl_use = x"yes"; then + for ac_func in frexpl +do : + ac_fn_c_check_func "$LINENO" "frexpl" "ac_cv_func_frexpl" +if test "x$ac_cv_func_frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpl declaration" >&5 +$as_echo_n "checking for _frexpl declaration... " >&6; } + if test x${glibcxx_cv_func__frexpl_use+set} != xset; then + if ${glibcxx_cv_func__frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpl_use=yes +else + glibcxx_cv_func__frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpl_use" >&5 +$as_echo "$glibcxx_cv_func__frexpl_use" >&6; } + + if test x$glibcxx_cv_func__frexpl_use = x"yes"; then + for ac_func in _frexpl +do : + ac_fn_c_check_func "$LINENO" "_frexpl" "ac_cv_func__frexpl" +if test "x$ac_cv_func__frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } + if test x${glibcxx_cv_func_hypotl_use+set} != xset; then + if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + + if test x$glibcxx_cv_func_hypotl_use = x"yes"; then + for ac_func in hypotl +do : + ac_fn_c_check_func "$LINENO" "hypotl" "ac_cv_func_hypotl" +if test "x$ac_cv_func_hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotl declaration" >&5 +$as_echo_n "checking for _hypotl declaration... " >&6; } + if test x${glibcxx_cv_func__hypotl_use+set} != xset; then + if ${glibcxx_cv_func__hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotl_use=yes +else + glibcxx_cv_func__hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotl_use" >&5 +$as_echo "$glibcxx_cv_func__hypotl_use" >&6; } + + if test x$glibcxx_cv_func__hypotl_use = x"yes"; then + for ac_func in _hypotl +do : + ac_fn_c_check_func "$LINENO" "_hypotl" "ac_cv_func__hypotl" +if test "x$ac_cv_func__hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpl_use+set} != xset; then + if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + + if test x$glibcxx_cv_func_ldexpl_use = x"yes"; then + for ac_func in ldexpl +do : + ac_fn_c_check_func "$LINENO" "ldexpl" "ac_cv_func_ldexpl" +if test "x$ac_cv_func_ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpl declaration" >&5 +$as_echo_n "checking for _ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpl_use+set} != xset; then + if ${glibcxx_cv_func__ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpl_use=yes +else + glibcxx_cv_func__ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpl_use" >&6; } + + if test x$glibcxx_cv_func__ldexpl_use = x"yes"; then + for ac_func in _ldexpl +do : + ac_fn_c_check_func "$LINENO" "_ldexpl" "ac_cv_func__ldexpl" +if test "x$ac_cv_func__ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } + if test x${glibcxx_cv_func_logl_use+set} != xset; then + if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + + if test x$glibcxx_cv_func_logl_use = x"yes"; then + for ac_func in logl +do : + ac_fn_c_check_func "$LINENO" "logl" "ac_cv_func_logl" +if test "x$ac_cv_func_logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logl declaration" >&5 +$as_echo_n "checking for _logl declaration... " >&6; } + if test x${glibcxx_cv_func__logl_use+set} != xset; then + if ${glibcxx_cv_func__logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logl_use=yes +else + glibcxx_cv_func__logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logl_use" >&5 +$as_echo "$glibcxx_cv_func__logl_use" >&6; } + + if test x$glibcxx_cv_func__logl_use = x"yes"; then + for ac_func in _logl +do : + ac_fn_c_check_func "$LINENO" "_logl" "ac_cv_func__logl" +if test "x$ac_cv_func__logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } + if test x${glibcxx_cv_func_log10l_use+set} != xset; then + if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + + if test x$glibcxx_cv_func_log10l_use = x"yes"; then + for ac_func in log10l +do : + ac_fn_c_check_func "$LINENO" "log10l" "ac_cv_func_log10l" +if test "x$ac_cv_func_log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10l declaration" >&5 +$as_echo_n "checking for _log10l declaration... " >&6; } + if test x${glibcxx_cv_func__log10l_use+set} != xset; then + if ${glibcxx_cv_func__log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10l_use=yes +else + glibcxx_cv_func__log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10l_use" >&5 +$as_echo "$glibcxx_cv_func__log10l_use" >&6; } + + if test x$glibcxx_cv_func__log10l_use = x"yes"; then + for ac_func in _log10l +do : + ac_fn_c_check_func "$LINENO" "_log10l" "ac_cv_func__log10l" +if test "x$ac_cv_func__log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } + if test x${glibcxx_cv_func_modfl_use+set} != xset; then + if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + + if test x$glibcxx_cv_func_modfl_use = x"yes"; then + for ac_func in modfl +do : + ac_fn_c_check_func "$LINENO" "modfl" "ac_cv_func_modfl" +if test "x$ac_cv_func_modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modfl declaration" >&5 +$as_echo_n "checking for _modfl declaration... " >&6; } + if test x${glibcxx_cv_func__modfl_use+set} != xset; then + if ${glibcxx_cv_func__modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modfl_use=yes +else + glibcxx_cv_func__modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modfl_use" >&5 +$as_echo "$glibcxx_cv_func__modfl_use" >&6; } + + if test x$glibcxx_cv_func__modfl_use = x"yes"; then + for ac_func in _modfl +do : + ac_fn_c_check_func "$LINENO" "_modfl" "ac_cv_func__modfl" +if test "x$ac_cv_func__modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } + if test x${glibcxx_cv_func_powl_use+set} != xset; then + if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + + if test x$glibcxx_cv_func_powl_use = x"yes"; then + for ac_func in powl +do : + ac_fn_c_check_func "$LINENO" "powl" "ac_cv_func_powl" +if test "x$ac_cv_func_powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powl declaration" >&5 +$as_echo_n "checking for _powl declaration... " >&6; } + if test x${glibcxx_cv_func__powl_use+set} != xset; then + if ${glibcxx_cv_func__powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powl_use=yes +else + glibcxx_cv_func__powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powl_use" >&5 +$as_echo "$glibcxx_cv_func__powl_use" >&6; } + + if test x$glibcxx_cv_func__powl_use = x"yes"; then + for ac_func in _powl +do : + ac_fn_c_check_func "$LINENO" "_powl" "ac_cv_func__powl" +if test "x$ac_cv_func__powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtl_use+set} != xset; then + if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + + if test x$glibcxx_cv_func_sqrtl_use = x"yes"; then + for ac_func in sqrtl +do : + ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl" +if test "x$ac_cv_func_sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtl declaration" >&5 +$as_echo_n "checking for _sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtl_use+set} != xset; then + if ${glibcxx_cv_func__sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtl_use=yes +else + glibcxx_cv_func__sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtl_use" >&6; } + + if test x$glibcxx_cv_func__sqrtl_use = x"yes"; then + for ac_func in _sqrtl +do : + ac_fn_c_check_func "$LINENO" "_sqrtl" "ac_cv_func__sqrtl" +if test "x$ac_cv_func__sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosl declaration" >&5 +$as_echo_n "checking for sincosl declaration... " >&6; } + if test x${glibcxx_cv_func_sincosl_use+set} != xset; then + if ${glibcxx_cv_func_sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosl_use=yes +else + glibcxx_cv_func_sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosl_use" >&5 +$as_echo "$glibcxx_cv_func_sincosl_use" >&6; } + + if test x$glibcxx_cv_func_sincosl_use = x"yes"; then + for ac_func in sincosl +do : + ac_fn_c_check_func "$LINENO" "sincosl" "ac_cv_func_sincosl" +if test "x$ac_cv_func_sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosl declaration" >&5 +$as_echo_n "checking for _sincosl declaration... " >&6; } + if test x${glibcxx_cv_func__sincosl_use+set} != xset; then + if ${glibcxx_cv_func__sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosl_use=yes +else + glibcxx_cv_func__sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosl_use" >&5 +$as_echo "$glibcxx_cv_func__sincosl_use" >&6; } + + if test x$glibcxx_cv_func__sincosl_use = x"yes"; then + for ac_func in _sincosl +do : + ac_fn_c_check_func "$LINENO" "_sincosl" "ac_cv_func__sincosl" +if test "x$ac_cv_func__sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitel declaration" >&5 +$as_echo_n "checking for finitel declaration... " >&6; } + if test x${glibcxx_cv_func_finitel_use+set} != xset; then + if ${glibcxx_cv_func_finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitel_use=yes +else + glibcxx_cv_func_finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitel_use" >&5 +$as_echo "$glibcxx_cv_func_finitel_use" >&6; } + + if test x$glibcxx_cv_func_finitel_use = x"yes"; then + for ac_func in finitel +do : + ac_fn_c_check_func "$LINENO" "finitel" "ac_cv_func_finitel" +if test "x$ac_cv_func_finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitel declaration" >&5 +$as_echo_n "checking for _finitel declaration... " >&6; } + if test x${glibcxx_cv_func__finitel_use+set} != xset; then + if ${glibcxx_cv_func__finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitel_use=yes +else + glibcxx_cv_func__finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitel_use" >&5 +$as_echo "$glibcxx_cv_func__finitel_use" >&6; } + + if test x$glibcxx_cv_func__finitel_use = x"yes"; then + for ac_func in _finitel +do : + ac_fn_c_check_func "$LINENO" "_finitel" "ac_cv_func__finitel" +if test "x$ac_cv_func__finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEL 1 +_ACEOF + +fi +done + + fi + fi + + + + + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for at_quick_exit declaration" >&5 +$as_echo_n "checking for at_quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_at_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_at_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + at_quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_at_quick_exit_use=yes +else + glibcxx_cv_func_at_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_at_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_at_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_at_quick_exit_use = x"yes"; then + for ac_func in at_quick_exit +do : + ac_fn_c_check_func "$LINENO" "at_quick_exit" "ac_cv_func_at_quick_exit" +if test "x$ac_cv_func_at_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AT_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for quick_exit declaration" >&5 +$as_echo_n "checking for quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_quick_exit_use=yes +else + glibcxx_cv_func_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_quick_exit_use = x"yes"; then + for ac_func in quick_exit +do : + ac_fn_c_check_func "$LINENO" "quick_exit" "ac_cv_func_quick_exit" +if test "x$ac_cv_func_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtold declaration" >&5 +$as_echo_n "checking for strtold declaration... " >&6; } + if test x${glibcxx_cv_func_strtold_use+set} != xset; then + if ${glibcxx_cv_func_strtold_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtold(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtold_use=yes +else + glibcxx_cv_func_strtold_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtold_use" >&5 +$as_echo "$glibcxx_cv_func_strtold_use" >&6; } + if test x$glibcxx_cv_func_strtold_use = x"yes"; then + for ac_func in strtold +do : + ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold" +if test "x$ac_cv_func_strtold" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOLD 1 +_ACEOF + +fi +done + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtof declaration" >&5 +$as_echo_n "checking for strtof declaration... " >&6; } + if test x${glibcxx_cv_func_strtof_use+set} != xset; then + if ${glibcxx_cv_func_strtof_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtof(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtof_use=yes +else + glibcxx_cv_func_strtof_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtof_use" >&5 +$as_echo "$glibcxx_cv_func_strtof_use" >&6; } + if test x$glibcxx_cv_func_strtof_use = x"yes"; then + for ac_func in strtof +do : + ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof" +if test "x$ac_cv_func_strtof" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOF 1 +_ACEOF + +fi +done + + fi + + + + + CXXFLAGS="$ac_save_CXXFLAGS" + + for ac_func in aligned_alloc posix_memalign memalign _aligned_malloc +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + for ac_func in _wfopen +do : + ac_fn_c_check_func "$LINENO" "_wfopen" "ac_cv_func__wfopen" +if test "x$ac_cv_func__wfopen" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__WFOPEN 1 +_ACEOF + +fi +done + + ;; + *-netbsd* | *-openbsd*) + SECTION_FLAGS='-ffunction-sections -fdata-sections' + + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + $as_echo "#define HAVE_FINITEF 1" >>confdefs.h + + $as_echo "#define HAVE_FINITE 1" >>confdefs.h + + $as_echo "#define HAVE_FREXPF 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOTF 1" >>confdefs.h + + $as_echo "#define HAVE_ISINF 1" >>confdefs.h + + $as_echo "#define HAVE_ISINFF 1" >>confdefs.h + + $as_echo "#define HAVE_ISNAN 1" >>confdefs.h + + $as_echo "#define HAVE_ISNANF 1" >>confdefs.h + + if test x"long_double_math_on_this_cpu" = x"yes"; then + $as_echo "#define HAVE_FINITEL 1" >>confdefs.h + + $as_echo "#define HAVE_ISINFL 1" >>confdefs.h + + $as_echo "#define HAVE_ISNANL 1" >>confdefs.h + + fi + for ac_func in aligned_alloc posix_memalign memalign _aligned_malloc +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + for ac_func in timespec_get +do : + ac_fn_c_check_func "$LINENO" "timespec_get" "ac_cv_func_timespec_get" +if test "x$ac_cv_func_timespec_get" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_TIMESPEC_GET 1 +_ACEOF + +fi +done + + for ac_func in sockatmark +do : + ac_fn_c_check_func "$LINENO" "sockatmark" "ac_cv_func_sockatmark" +if test "x$ac_cv_func_sockatmark" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKATMARK 1 +_ACEOF + +fi +done + + ;; + *-qnx6.1* | *-qnx6.2*) + SECTION_FLAGS='-ffunction-sections -fdata-sections' + + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + $as_echo "#define HAVE_COSF 1" >>confdefs.h + + $as_echo "#define HAVE_COSL 1" >>confdefs.h + + $as_echo "#define HAVE_COSHF 1" >>confdefs.h + + $as_echo "#define HAVE_COSHL 1" >>confdefs.h + + $as_echo "#define HAVE_LOGF 1" >>confdefs.h + + $as_echo "#define HAVE_LOGL 1" >>confdefs.h + + $as_echo "#define HAVE_LOG10F 1" >>confdefs.h + + $as_echo "#define HAVE_LOG10L 1" >>confdefs.h + + $as_echo "#define HAVE_SINF 1" >>confdefs.h + + $as_echo "#define HAVE_SINL 1" >>confdefs.h + + $as_echo "#define HAVE_SINHF 1" >>confdefs.h + + $as_echo "#define HAVE_SINHL 1" >>confdefs.h + + ;; + *-rtems*) + + # All these tests are for C++; save the language and the compiler flags. + # The CXXFLAGS thing is suspicious, but based on similar bits previously + # found in GLIBCXX_CONFIGURE. + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + + # Check for -ffunction-sections -fdata-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for g++ that supports -ffunction-sections -fdata-sections" >&5 +$as_echo_n "checking for g++ that supports -ffunction-sections -fdata-sections... " >&6; } + CXXFLAGS='-g -Werror -ffunction-sections -fdata-sections' + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo; void bar() { }; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_fdsections=yes +else + ac_fdsections=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" + else + # this is the suspicious part + CXXFLAGS='' + fi + if test x"$ac_fdsections" = x"yes"; then + SECTION_FLAGS='-ffunction-sections -fdata-sections' + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_fdsections" >&5 +$as_echo "$ac_fdsections" >&6; } + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + + + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + glibcxx_ld_is_gold=no + if test x"$with_gnu_ld" = x"yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 +$as_echo_n "checking for ld version... " >&6; } + + if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then + glibcxx_ld_is_gold=yes + fi + ldver=`$LD --version 2>/dev/null | + sed -e 's/[. ][0-9]\{8\}$//;s/.* \([^ ]\{1,\}\)$/\1/; q'` + + glibcxx_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 +$as_echo "$glibcxx_gnu_ld_version" >&6; } + fi + + # Set --gc-sections. + glibcxx_have_gc_sections=no + if test "$glibcxx_ld_is_gold" = "yes"; then + if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then + glibcxx_have_gc_sections=yes + fi + else + glibcxx_gcsections_min_ld=21602 + if test x"$with_gnu_ld" = x"yes" && + test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then + glibcxx_have_gc_sections=yes + fi + fi + if test "$glibcxx_have_gc_sections" = "yes"; then + # Sufficiently young GNU ld it is! Joy and bunny rabbits! + # NB: This flag only works reliably after 2.16.1. Configure tests + # for this are difficult, so hard wire a value that should work. + + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-Wl,--gc-sections' + + # Check for -Wl,--gc-sections + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 +$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_gcsections=yes +else + ac_gcsections=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$ac_gcsections" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + if $LD --gc-sections -o conftest conftest.o 2>&1 | \ + grep "Warning: gc-sections option ignored" > /dev/null; then + ac_gcsections=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + if test "$ac_gcsections" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + fi + + # Set -z,relro. + # Note this is only for shared objects. + ac_ld_relro=no + if test x"$with_gnu_ld" = x"yes"; then + # cygwin and mingw uses PE, which has no ELF relro support, + # multi target ld may confuse configure machinery + case "$host" in + *-*-cygwin*) + ;; + *-*-mingw*) + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 +$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } + cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` + if test -n "$cxx_z_relo"; then + OPT_LDFLAGS="-Wl,-z,relro" + ac_ld_relro=yes + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 +$as_echo "$ac_ld_relro" >&6; } + esac + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + + + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + libm="-lm" +fi + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $libm" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf declaration" >&5 +$as_echo_n "checking for isinf declaration... " >&6; } + if test x${glibcxx_cv_func_isinf_use+set} != xset; then + if ${glibcxx_cv_func_isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinf_use=yes +else + glibcxx_cv_func_isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinf_use" >&5 +$as_echo "$glibcxx_cv_func_isinf_use" >&6; } + + if test x$glibcxx_cv_func_isinf_use = x"yes"; then + for ac_func in isinf +do : + ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinf declaration" >&5 +$as_echo_n "checking for _isinf declaration... " >&6; } + if test x${glibcxx_cv_func__isinf_use+set} != xset; then + if ${glibcxx_cv_func__isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinf_use=yes +else + glibcxx_cv_func__isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinf_use" >&5 +$as_echo "$glibcxx_cv_func__isinf_use" >&6; } + + if test x$glibcxx_cv_func__isinf_use = x"yes"; then + for ac_func in _isinf +do : + ac_fn_c_check_func "$LINENO" "_isinf" "ac_cv_func__isinf" +if test "x$ac_cv_func__isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan declaration" >&5 +$as_echo_n "checking for isnan declaration... " >&6; } + if test x${glibcxx_cv_func_isnan_use+set} != xset; then + if ${glibcxx_cv_func_isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnan_use=yes +else + glibcxx_cv_func_isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnan_use" >&5 +$as_echo "$glibcxx_cv_func_isnan_use" >&6; } + + if test x$glibcxx_cv_func_isnan_use = x"yes"; then + for ac_func in isnan +do : + ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNAN 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnan declaration" >&5 +$as_echo_n "checking for _isnan declaration... " >&6; } + if test x${glibcxx_cv_func__isnan_use+set} != xset; then + if ${glibcxx_cv_func__isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnan_use=yes +else + glibcxx_cv_func__isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnan_use" >&5 +$as_echo "$glibcxx_cv_func__isnan_use" >&6; } + + if test x$glibcxx_cv_func__isnan_use = x"yes"; then + for ac_func in _isnan +do : + ac_fn_c_check_func "$LINENO" "_isnan" "ac_cv_func__isnan" +if test "x$ac_cv_func__isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNAN 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finite declaration" >&5 +$as_echo_n "checking for finite declaration... " >&6; } + if test x${glibcxx_cv_func_finite_use+set} != xset; then + if ${glibcxx_cv_func_finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finite_use=yes +else + glibcxx_cv_func_finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finite_use" >&5 +$as_echo "$glibcxx_cv_func_finite_use" >&6; } + + if test x$glibcxx_cv_func_finite_use = x"yes"; then + for ac_func in finite +do : + ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITE 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finite declaration" >&5 +$as_echo_n "checking for _finite declaration... " >&6; } + if test x${glibcxx_cv_func__finite_use+set} != xset; then + if ${glibcxx_cv_func__finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finite_use=yes +else + glibcxx_cv_func__finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finite_use" >&5 +$as_echo "$glibcxx_cv_func__finite_use" >&6; } + + if test x$glibcxx_cv_func__finite_use = x"yes"; then + for ac_func in _finite +do : + ac_fn_c_check_func "$LINENO" "_finite" "ac_cv_func__finite" +if test "x$ac_cv_func__finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITE 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincos declaration" >&5 +$as_echo_n "checking for sincos declaration... " >&6; } + if test x${glibcxx_cv_func_sincos_use+set} != xset; then + if ${glibcxx_cv_func_sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincos_use=yes +else + glibcxx_cv_func_sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincos_use" >&5 +$as_echo "$glibcxx_cv_func_sincos_use" >&6; } + + if test x$glibcxx_cv_func_sincos_use = x"yes"; then + for ac_func in sincos +do : + ac_fn_c_check_func "$LINENO" "sincos" "ac_cv_func_sincos" +if test "x$ac_cv_func_sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincos declaration" >&5 +$as_echo_n "checking for _sincos declaration... " >&6; } + if test x${glibcxx_cv_func__sincos_use+set} != xset; then + if ${glibcxx_cv_func__sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincos_use=yes +else + glibcxx_cv_func__sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincos_use" >&5 +$as_echo "$glibcxx_cv_func__sincos_use" >&6; } + + if test x$glibcxx_cv_func__sincos_use = x"yes"; then + for ac_func in _sincos +do : + ac_fn_c_check_func "$LINENO" "_sincos" "ac_cv_func__sincos" +if test "x$ac_cv_func__sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpclass declaration" >&5 +$as_echo_n "checking for fpclass declaration... " >&6; } + if test x${glibcxx_cv_func_fpclass_use+set} != xset; then + if ${glibcxx_cv_func_fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fpclass_use=yes +else + glibcxx_cv_func_fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fpclass_use" >&5 +$as_echo "$glibcxx_cv_func_fpclass_use" >&6; } + + if test x$glibcxx_cv_func_fpclass_use = x"yes"; then + for ac_func in fpclass +do : + ac_fn_c_check_func "$LINENO" "fpclass" "ac_cv_func_fpclass" +if test "x$ac_cv_func_fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fpclass declaration" >&5 +$as_echo_n "checking for _fpclass declaration... " >&6; } + if test x${glibcxx_cv_func__fpclass_use+set} != xset; then + if ${glibcxx_cv_func__fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fpclass_use=yes +else + glibcxx_cv_func__fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fpclass_use" >&5 +$as_echo "$glibcxx_cv_func__fpclass_use" >&6; } + + if test x$glibcxx_cv_func__fpclass_use = x"yes"; then + for ac_func in _fpclass +do : + ac_fn_c_check_func "$LINENO" "_fpclass" "ac_cv_func__fpclass" +if test "x$ac_cv_func__fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for qfpclass declaration" >&5 +$as_echo_n "checking for qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func_qfpclass_use+set} != xset; then + if ${glibcxx_cv_func_qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_qfpclass_use=yes +else + glibcxx_cv_func_qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func_qfpclass_use" >&6; } + + if test x$glibcxx_cv_func_qfpclass_use = x"yes"; then + for ac_func in qfpclass +do : + ac_fn_c_check_func "$LINENO" "qfpclass" "ac_cv_func_qfpclass" +if test "x$ac_cv_func_qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QFPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _qfpclass declaration" >&5 +$as_echo_n "checking for _qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func__qfpclass_use+set} != xset; then + if ${glibcxx_cv_func__qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__qfpclass_use=yes +else + glibcxx_cv_func__qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func__qfpclass_use" >&6; } + + if test x$glibcxx_cv_func__qfpclass_use = x"yes"; then + for ac_func in _qfpclass +do : + ac_fn_c_check_func "$LINENO" "_qfpclass" "ac_cv_func__qfpclass" +if test "x$ac_cv_func__qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__QFPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypot declaration" >&5 +$as_echo_n "checking for hypot declaration... " >&6; } + if test x${glibcxx_cv_func_hypot_use+set} != xset; then + if ${glibcxx_cv_func_hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypot_use=yes +else + glibcxx_cv_func_hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypot_use" >&5 +$as_echo "$glibcxx_cv_func_hypot_use" >&6; } + + if test x$glibcxx_cv_func_hypot_use = x"yes"; then + for ac_func in hypot +do : + ac_fn_c_check_func "$LINENO" "hypot" "ac_cv_func_hypot" +if test "x$ac_cv_func_hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOT 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypot declaration" >&5 +$as_echo_n "checking for _hypot declaration... " >&6; } + if test x${glibcxx_cv_func__hypot_use+set} != xset; then + if ${glibcxx_cv_func__hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypot_use=yes +else + glibcxx_cv_func__hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypot_use" >&5 +$as_echo "$glibcxx_cv_func__hypot_use" >&6; } + + if test x$glibcxx_cv_func__hypot_use = x"yes"; then + for ac_func in _hypot +do : + ac_fn_c_check_func "$LINENO" "_hypot" "ac_cv_func__hypot" +if test "x$ac_cv_func__hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOT 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float trig functions" >&5 +$as_echo_n "checking for float trig functions... " >&6; } + if ${glibcxx_cv_func_float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosf (0); asinf (0); atanf (0); cosf (0); sinf (0); tanf (0); coshf (0); sinhf (0); tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_trig_use=yes +else + glibcxx_cv_func_float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_trig_use" >&5 +$as_echo "$glibcxx_cv_func_float_trig_use" >&6; } + if test x$glibcxx_cv_func_float_trig_use = x"yes"; then + for ac_func in acosf asinf atanf cosf sinf tanf coshf sinhf tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float trig functions" >&5 +$as_echo_n "checking for _float trig functions... " >&6; } + if ${glibcxx_cv_func__float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosf (0); _asinf (0); _atanf (0); _cosf (0); _sinf (0); _tanf (0); _coshf (0); _sinhf (0); _tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_trig_use=yes +else + glibcxx_cv_func__float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_trig_use" >&5 +$as_echo "$glibcxx_cv_func__float_trig_use" >&6; } + if test x$glibcxx_cv_func__float_trig_use = x"yes"; then + for ac_func in _acosf _asinf _atanf _cosf _sinf _tanf _coshf _sinhf _tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float round functions" >&5 +$as_echo_n "checking for float round functions... " >&6; } + if ${glibcxx_cv_func_float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceilf (0); floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_round_use=yes +else + glibcxx_cv_func_float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_round_use" >&5 +$as_echo "$glibcxx_cv_func_float_round_use" >&6; } + if test x$glibcxx_cv_func_float_round_use = x"yes"; then + for ac_func in ceilf floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float round functions" >&5 +$as_echo_n "checking for _float round functions... " >&6; } + if ${glibcxx_cv_func__float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceilf (0); _floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_round_use=yes +else + glibcxx_cv_func__float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_round_use" >&5 +$as_echo "$glibcxx_cv_func__float_round_use" >&6; } + if test x$glibcxx_cv_func__float_round_use = x"yes"; then + for ac_func in _ceilf _floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expf declaration" >&5 +$as_echo_n "checking for expf declaration... " >&6; } + if test x${glibcxx_cv_func_expf_use+set} != xset; then + if ${glibcxx_cv_func_expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expf_use=yes +else + glibcxx_cv_func_expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expf_use" >&5 +$as_echo "$glibcxx_cv_func_expf_use" >&6; } + + if test x$glibcxx_cv_func_expf_use = x"yes"; then + for ac_func in expf +do : + ac_fn_c_check_func "$LINENO" "expf" "ac_cv_func_expf" +if test "x$ac_cv_func_expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expf declaration" >&5 +$as_echo_n "checking for _expf declaration... " >&6; } + if test x${glibcxx_cv_func__expf_use+set} != xset; then + if ${glibcxx_cv_func__expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expf_use=yes +else + glibcxx_cv_func__expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expf_use" >&5 +$as_echo "$glibcxx_cv_func__expf_use" >&6; } + + if test x$glibcxx_cv_func__expf_use = x"yes"; then + for ac_func in _expf +do : + ac_fn_c_check_func "$LINENO" "_expf" "ac_cv_func__expf" +if test "x$ac_cv_func__expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanf declaration" >&5 +$as_echo_n "checking for isnanf declaration... " >&6; } + if test x${glibcxx_cv_func_isnanf_use+set} != xset; then + if ${glibcxx_cv_func_isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanf_use=yes +else + glibcxx_cv_func_isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanf_use" >&5 +$as_echo "$glibcxx_cv_func_isnanf_use" >&6; } + + if test x$glibcxx_cv_func_isnanf_use = x"yes"; then + for ac_func in isnanf +do : + ac_fn_c_check_func "$LINENO" "isnanf" "ac_cv_func_isnanf" +if test "x$ac_cv_func_isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanf declaration" >&5 +$as_echo_n "checking for _isnanf declaration... " >&6; } + if test x${glibcxx_cv_func__isnanf_use+set} != xset; then + if ${glibcxx_cv_func__isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanf_use=yes +else + glibcxx_cv_func__isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanf_use" >&5 +$as_echo "$glibcxx_cv_func__isnanf_use" >&6; } + + if test x$glibcxx_cv_func__isnanf_use = x"yes"; then + for ac_func in _isnanf +do : + ac_fn_c_check_func "$LINENO" "_isnanf" "ac_cv_func__isnanf" +if test "x$ac_cv_func__isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinff declaration" >&5 +$as_echo_n "checking for isinff declaration... " >&6; } + if test x${glibcxx_cv_func_isinff_use+set} != xset; then + if ${glibcxx_cv_func_isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinff_use=yes +else + glibcxx_cv_func_isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinff_use" >&5 +$as_echo "$glibcxx_cv_func_isinff_use" >&6; } + + if test x$glibcxx_cv_func_isinff_use = x"yes"; then + for ac_func in isinff +do : + ac_fn_c_check_func "$LINENO" "isinff" "ac_cv_func_isinff" +if test "x$ac_cv_func_isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinff declaration" >&5 +$as_echo_n "checking for _isinff declaration... " >&6; } + if test x${glibcxx_cv_func__isinff_use+set} != xset; then + if ${glibcxx_cv_func__isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinff_use=yes +else + glibcxx_cv_func__isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinff_use" >&5 +$as_echo "$glibcxx_cv_func__isinff_use" >&6; } + + if test x$glibcxx_cv_func__isinff_use = x"yes"; then + for ac_func in _isinff +do : + ac_fn_c_check_func "$LINENO" "_isinff" "ac_cv_func__isinff" +if test "x$ac_cv_func__isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f declaration" >&5 +$as_echo_n "checking for atan2f declaration... " >&6; } + if test x${glibcxx_cv_func_atan2f_use+set} != xset; then + if ${glibcxx_cv_func_atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2f_use=yes +else + glibcxx_cv_func_atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2f_use" >&5 +$as_echo "$glibcxx_cv_func_atan2f_use" >&6; } + + if test x$glibcxx_cv_func_atan2f_use = x"yes"; then + for ac_func in atan2f +do : + ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2f declaration" >&5 +$as_echo_n "checking for _atan2f declaration... " >&6; } + if test x${glibcxx_cv_func__atan2f_use+set} != xset; then + if ${glibcxx_cv_func__atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2f_use=yes +else + glibcxx_cv_func__atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2f_use" >&5 +$as_echo "$glibcxx_cv_func__atan2f_use" >&6; } + + if test x$glibcxx_cv_func__atan2f_use = x"yes"; then + for ac_func in _atan2f +do : + ac_fn_c_check_func "$LINENO" "_atan2f" "ac_cv_func__atan2f" +if test "x$ac_cv_func__atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsf declaration" >&5 +$as_echo_n "checking for fabsf declaration... " >&6; } + if test x${glibcxx_cv_func_fabsf_use+set} != xset; then + if ${glibcxx_cv_func_fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsf_use=yes +else + glibcxx_cv_func_fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsf_use" >&5 +$as_echo "$glibcxx_cv_func_fabsf_use" >&6; } + + if test x$glibcxx_cv_func_fabsf_use = x"yes"; then + for ac_func in fabsf +do : + ac_fn_c_check_func "$LINENO" "fabsf" "ac_cv_func_fabsf" +if test "x$ac_cv_func_fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsf declaration" >&5 +$as_echo_n "checking for _fabsf declaration... " >&6; } + if test x${glibcxx_cv_func__fabsf_use+set} != xset; then + if ${glibcxx_cv_func__fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsf_use=yes +else + glibcxx_cv_func__fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsf_use" >&5 +$as_echo "$glibcxx_cv_func__fabsf_use" >&6; } + + if test x$glibcxx_cv_func__fabsf_use = x"yes"; then + for ac_func in _fabsf +do : + ac_fn_c_check_func "$LINENO" "_fabsf" "ac_cv_func__fabsf" +if test "x$ac_cv_func__fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf declaration" >&5 +$as_echo_n "checking for fmodf declaration... " >&6; } + if test x${glibcxx_cv_func_fmodf_use+set} != xset; then + if ${glibcxx_cv_func_fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodf_use=yes +else + glibcxx_cv_func_fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodf_use" >&5 +$as_echo "$glibcxx_cv_func_fmodf_use" >&6; } + + if test x$glibcxx_cv_func_fmodf_use = x"yes"; then + for ac_func in fmodf +do : + ac_fn_c_check_func "$LINENO" "fmodf" "ac_cv_func_fmodf" +if test "x$ac_cv_func_fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodf declaration" >&5 +$as_echo_n "checking for _fmodf declaration... " >&6; } + if test x${glibcxx_cv_func__fmodf_use+set} != xset; then + if ${glibcxx_cv_func__fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodf_use=yes +else + glibcxx_cv_func__fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodf_use" >&5 +$as_echo "$glibcxx_cv_func__fmodf_use" >&6; } + + if test x$glibcxx_cv_func__fmodf_use = x"yes"; then + for ac_func in _fmodf +do : + ac_fn_c_check_func "$LINENO" "_fmodf" "ac_cv_func__fmodf" +if test "x$ac_cv_func__fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } + if test x${glibcxx_cv_func_frexpf_use+set} != xset; then + if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + + if test x$glibcxx_cv_func_frexpf_use = x"yes"; then + for ac_func in frexpf +do : + ac_fn_c_check_func "$LINENO" "frexpf" "ac_cv_func_frexpf" +if test "x$ac_cv_func_frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpf declaration" >&5 +$as_echo_n "checking for _frexpf declaration... " >&6; } + if test x${glibcxx_cv_func__frexpf_use+set} != xset; then + if ${glibcxx_cv_func__frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpf_use=yes +else + glibcxx_cv_func__frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpf_use" >&5 +$as_echo "$glibcxx_cv_func__frexpf_use" >&6; } + + if test x$glibcxx_cv_func__frexpf_use = x"yes"; then + for ac_func in _frexpf +do : + ac_fn_c_check_func "$LINENO" "_frexpf" "ac_cv_func__frexpf" +if test "x$ac_cv_func__frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } + if test x${glibcxx_cv_func_hypotf_use+set} != xset; then + if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + + if test x$glibcxx_cv_func_hypotf_use = x"yes"; then + for ac_func in hypotf +do : + ac_fn_c_check_func "$LINENO" "hypotf" "ac_cv_func_hypotf" +if test "x$ac_cv_func_hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotf declaration" >&5 +$as_echo_n "checking for _hypotf declaration... " >&6; } + if test x${glibcxx_cv_func__hypotf_use+set} != xset; then + if ${glibcxx_cv_func__hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotf_use=yes +else + glibcxx_cv_func__hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotf_use" >&5 +$as_echo "$glibcxx_cv_func__hypotf_use" >&6; } + + if test x$glibcxx_cv_func__hypotf_use = x"yes"; then + for ac_func in _hypotf +do : + ac_fn_c_check_func "$LINENO" "_hypotf" "ac_cv_func__hypotf" +if test "x$ac_cv_func__hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpf_use+set} != xset; then + if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + + if test x$glibcxx_cv_func_ldexpf_use = x"yes"; then + for ac_func in ldexpf +do : + ac_fn_c_check_func "$LINENO" "ldexpf" "ac_cv_func_ldexpf" +if test "x$ac_cv_func_ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpf declaration" >&5 +$as_echo_n "checking for _ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpf_use+set} != xset; then + if ${glibcxx_cv_func__ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpf_use=yes +else + glibcxx_cv_func__ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpf_use" >&6; } + + if test x$glibcxx_cv_func__ldexpf_use = x"yes"; then + for ac_func in _ldexpf +do : + ac_fn_c_check_func "$LINENO" "_ldexpf" "ac_cv_func__ldexpf" +if test "x$ac_cv_func__ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logf declaration" >&5 +$as_echo_n "checking for logf declaration... " >&6; } + if test x${glibcxx_cv_func_logf_use+set} != xset; then + if ${glibcxx_cv_func_logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logf_use=yes +else + glibcxx_cv_func_logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logf_use" >&5 +$as_echo "$glibcxx_cv_func_logf_use" >&6; } + + if test x$glibcxx_cv_func_logf_use = x"yes"; then + for ac_func in logf +do : + ac_fn_c_check_func "$LINENO" "logf" "ac_cv_func_logf" +if test "x$ac_cv_func_logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logf declaration" >&5 +$as_echo_n "checking for _logf declaration... " >&6; } + if test x${glibcxx_cv_func__logf_use+set} != xset; then + if ${glibcxx_cv_func__logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logf_use=yes +else + glibcxx_cv_func__logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logf_use" >&5 +$as_echo "$glibcxx_cv_func__logf_use" >&6; } + + if test x$glibcxx_cv_func__logf_use = x"yes"; then + for ac_func in _logf +do : + ac_fn_c_check_func "$LINENO" "_logf" "ac_cv_func__logf" +if test "x$ac_cv_func__logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10f declaration" >&5 +$as_echo_n "checking for log10f declaration... " >&6; } + if test x${glibcxx_cv_func_log10f_use+set} != xset; then + if ${glibcxx_cv_func_log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10f_use=yes +else + glibcxx_cv_func_log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10f_use" >&5 +$as_echo "$glibcxx_cv_func_log10f_use" >&6; } + + if test x$glibcxx_cv_func_log10f_use = x"yes"; then + for ac_func in log10f +do : + ac_fn_c_check_func "$LINENO" "log10f" "ac_cv_func_log10f" +if test "x$ac_cv_func_log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10f declaration" >&5 +$as_echo_n "checking for _log10f declaration... " >&6; } + if test x${glibcxx_cv_func__log10f_use+set} != xset; then + if ${glibcxx_cv_func__log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10f_use=yes +else + glibcxx_cv_func__log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10f_use" >&5 +$as_echo "$glibcxx_cv_func__log10f_use" >&6; } + + if test x$glibcxx_cv_func__log10f_use = x"yes"; then + for ac_func in _log10f +do : + ac_fn_c_check_func "$LINENO" "_log10f" "ac_cv_func__log10f" +if test "x$ac_cv_func__log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } + if test x${glibcxx_cv_func_modff_use+set} != xset; then + if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + + if test x$glibcxx_cv_func_modff_use = x"yes"; then + for ac_func in modff +do : + ac_fn_c_check_func "$LINENO" "modff" "ac_cv_func_modff" +if test "x$ac_cv_func_modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modff declaration" >&5 +$as_echo_n "checking for _modff declaration... " >&6; } + if test x${glibcxx_cv_func__modff_use+set} != xset; then + if ${glibcxx_cv_func__modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modff_use=yes +else + glibcxx_cv_func__modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modff_use" >&5 +$as_echo "$glibcxx_cv_func__modff_use" >&6; } + + if test x$glibcxx_cv_func__modff_use = x"yes"; then + for ac_func in _modff +do : + ac_fn_c_check_func "$LINENO" "_modff" "ac_cv_func__modff" +if test "x$ac_cv_func__modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modf declaration" >&5 +$as_echo_n "checking for modf declaration... " >&6; } + if test x${glibcxx_cv_func_modf_use+set} != xset; then + if ${glibcxx_cv_func_modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modf_use=yes +else + glibcxx_cv_func_modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modf_use" >&5 +$as_echo "$glibcxx_cv_func_modf_use" >&6; } + + if test x$glibcxx_cv_func_modf_use = x"yes"; then + for ac_func in modf +do : + ac_fn_c_check_func "$LINENO" "modf" "ac_cv_func_modf" +if test "x$ac_cv_func_modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modf declaration" >&5 +$as_echo_n "checking for _modf declaration... " >&6; } + if test x${glibcxx_cv_func__modf_use+set} != xset; then + if ${glibcxx_cv_func__modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modf_use=yes +else + glibcxx_cv_func__modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modf_use" >&5 +$as_echo "$glibcxx_cv_func__modf_use" >&6; } + + if test x$glibcxx_cv_func__modf_use = x"yes"; then + for ac_func in _modf +do : + ac_fn_c_check_func "$LINENO" "_modf" "ac_cv_func__modf" +if test "x$ac_cv_func__modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powf declaration" >&5 +$as_echo_n "checking for powf declaration... " >&6; } + if test x${glibcxx_cv_func_powf_use+set} != xset; then + if ${glibcxx_cv_func_powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powf_use=yes +else + glibcxx_cv_func_powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powf_use" >&5 +$as_echo "$glibcxx_cv_func_powf_use" >&6; } + + if test x$glibcxx_cv_func_powf_use = x"yes"; then + for ac_func in powf +do : + ac_fn_c_check_func "$LINENO" "powf" "ac_cv_func_powf" +if test "x$ac_cv_func_powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powf declaration" >&5 +$as_echo_n "checking for _powf declaration... " >&6; } + if test x${glibcxx_cv_func__powf_use+set} != xset; then + if ${glibcxx_cv_func__powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powf_use=yes +else + glibcxx_cv_func__powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powf_use" >&5 +$as_echo "$glibcxx_cv_func__powf_use" >&6; } + + if test x$glibcxx_cv_func__powf_use = x"yes"; then + for ac_func in _powf +do : + ac_fn_c_check_func "$LINENO" "_powf" "ac_cv_func__powf" +if test "x$ac_cv_func__powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtf declaration" >&5 +$as_echo_n "checking for sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtf_use+set} != xset; then + if ${glibcxx_cv_func_sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtf_use=yes +else + glibcxx_cv_func_sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtf_use" >&6; } + + if test x$glibcxx_cv_func_sqrtf_use = x"yes"; then + for ac_func in sqrtf +do : + ac_fn_c_check_func "$LINENO" "sqrtf" "ac_cv_func_sqrtf" +if test "x$ac_cv_func_sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtf declaration" >&5 +$as_echo_n "checking for _sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtf_use+set} != xset; then + if ${glibcxx_cv_func__sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtf_use=yes +else + glibcxx_cv_func__sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtf_use" >&6; } + + if test x$glibcxx_cv_func__sqrtf_use = x"yes"; then + for ac_func in _sqrtf +do : + ac_fn_c_check_func "$LINENO" "_sqrtf" "ac_cv_func__sqrtf" +if test "x$ac_cv_func__sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosf declaration" >&5 +$as_echo_n "checking for sincosf declaration... " >&6; } + if test x${glibcxx_cv_func_sincosf_use+set} != xset; then + if ${glibcxx_cv_func_sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosf_use=yes +else + glibcxx_cv_func_sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosf_use" >&5 +$as_echo "$glibcxx_cv_func_sincosf_use" >&6; } + + if test x$glibcxx_cv_func_sincosf_use = x"yes"; then + for ac_func in sincosf +do : + ac_fn_c_check_func "$LINENO" "sincosf" "ac_cv_func_sincosf" +if test "x$ac_cv_func_sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosf declaration" >&5 +$as_echo_n "checking for _sincosf declaration... " >&6; } + if test x${glibcxx_cv_func__sincosf_use+set} != xset; then + if ${glibcxx_cv_func__sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosf_use=yes +else + glibcxx_cv_func__sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosf_use" >&5 +$as_echo "$glibcxx_cv_func__sincosf_use" >&6; } + + if test x$glibcxx_cv_func__sincosf_use = x"yes"; then + for ac_func in _sincosf +do : + ac_fn_c_check_func "$LINENO" "_sincosf" "ac_cv_func__sincosf" +if test "x$ac_cv_func__sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitef declaration" >&5 +$as_echo_n "checking for finitef declaration... " >&6; } + if test x${glibcxx_cv_func_finitef_use+set} != xset; then + if ${glibcxx_cv_func_finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitef_use=yes +else + glibcxx_cv_func_finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitef_use" >&5 +$as_echo "$glibcxx_cv_func_finitef_use" >&6; } + + if test x$glibcxx_cv_func_finitef_use = x"yes"; then + for ac_func in finitef +do : + ac_fn_c_check_func "$LINENO" "finitef" "ac_cv_func_finitef" +if test "x$ac_cv_func_finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitef declaration" >&5 +$as_echo_n "checking for _finitef declaration... " >&6; } + if test x${glibcxx_cv_func__finitef_use+set} != xset; then + if ${glibcxx_cv_func__finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitef_use=yes +else + glibcxx_cv_func__finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitef_use" >&5 +$as_echo "$glibcxx_cv_func__finitef_use" >&6; } + + if test x$glibcxx_cv_func__finitef_use = x"yes"; then + for ac_func in _finitef +do : + ac_fn_c_check_func "$LINENO" "_finitef" "ac_cv_func__finitef" +if test "x$ac_cv_func__finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double trig functions" >&5 +$as_echo_n "checking for long double trig functions... " >&6; } + if ${glibcxx_cv_func_long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosl (0); asinl (0); atanl (0); cosl (0); sinl (0); tanl (0); coshl (0); sinhl (0); tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_trig_use=yes +else + glibcxx_cv_func_long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_trig_use" >&6; } + if test x$glibcxx_cv_func_long_double_trig_use = x"yes"; then + for ac_func in acosl asinl atanl cosl sinl tanl coshl sinhl tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double trig functions" >&5 +$as_echo_n "checking for _long double trig functions... " >&6; } + if ${glibcxx_cv_func__long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosl (0); _asinl (0); _atanl (0); _cosl (0); _sinl (0); _tanl (0); _coshl (0); _sinhl (0); _tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_trig_use=yes +else + glibcxx_cv_func__long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_trig_use" >&6; } + if test x$glibcxx_cv_func__long_double_trig_use = x"yes"; then + for ac_func in _acosl _asinl _atanl _cosl _sinl _tanl _coshl _sinhl _tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double round functions" >&5 +$as_echo_n "checking for long double round functions... " >&6; } + if ${glibcxx_cv_func_long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceill (0); floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_round_use=yes +else + glibcxx_cv_func_long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_round_use" >&6; } + if test x$glibcxx_cv_func_long_double_round_use = x"yes"; then + for ac_func in ceill floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double round functions" >&5 +$as_echo_n "checking for _long double round functions... " >&6; } + if ${glibcxx_cv_func__long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceill (0); _floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_round_use=yes +else + glibcxx_cv_func__long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_round_use" >&6; } + if test x$glibcxx_cv_func__long_double_round_use = x"yes"; then + for ac_func in _ceill _floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanl declaration" >&5 +$as_echo_n "checking for isnanl declaration... " >&6; } + if test x${glibcxx_cv_func_isnanl_use+set} != xset; then + if ${glibcxx_cv_func_isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanl_use=yes +else + glibcxx_cv_func_isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanl_use" >&5 +$as_echo "$glibcxx_cv_func_isnanl_use" >&6; } + + if test x$glibcxx_cv_func_isnanl_use = x"yes"; then + for ac_func in isnanl +do : + ac_fn_c_check_func "$LINENO" "isnanl" "ac_cv_func_isnanl" +if test "x$ac_cv_func_isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanl declaration" >&5 +$as_echo_n "checking for _isnanl declaration... " >&6; } + if test x${glibcxx_cv_func__isnanl_use+set} != xset; then + if ${glibcxx_cv_func__isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanl_use=yes +else + glibcxx_cv_func__isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanl_use" >&5 +$as_echo "$glibcxx_cv_func__isnanl_use" >&6; } + + if test x$glibcxx_cv_func__isnanl_use = x"yes"; then + for ac_func in _isnanl +do : + ac_fn_c_check_func "$LINENO" "_isnanl" "ac_cv_func__isnanl" +if test "x$ac_cv_func__isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinfl declaration" >&5 +$as_echo_n "checking for isinfl declaration... " >&6; } + if test x${glibcxx_cv_func_isinfl_use+set} != xset; then + if ${glibcxx_cv_func_isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinfl_use=yes +else + glibcxx_cv_func_isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinfl_use" >&5 +$as_echo "$glibcxx_cv_func_isinfl_use" >&6; } + + if test x$glibcxx_cv_func_isinfl_use = x"yes"; then + for ac_func in isinfl +do : + ac_fn_c_check_func "$LINENO" "isinfl" "ac_cv_func_isinfl" +if test "x$ac_cv_func_isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinfl declaration" >&5 +$as_echo_n "checking for _isinfl declaration... " >&6; } + if test x${glibcxx_cv_func__isinfl_use+set} != xset; then + if ${glibcxx_cv_func__isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinfl_use=yes +else + glibcxx_cv_func__isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinfl_use" >&5 +$as_echo "$glibcxx_cv_func__isinfl_use" >&6; } + + if test x$glibcxx_cv_func__isinfl_use = x"yes"; then + for ac_func in _isinfl +do : + ac_fn_c_check_func "$LINENO" "_isinfl" "ac_cv_func__isinfl" +if test "x$ac_cv_func__isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } + if test x${glibcxx_cv_func_atan2l_use+set} != xset; then + if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + + if test x$glibcxx_cv_func_atan2l_use = x"yes"; then + for ac_func in atan2l +do : + ac_fn_c_check_func "$LINENO" "atan2l" "ac_cv_func_atan2l" +if test "x$ac_cv_func_atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2l declaration" >&5 +$as_echo_n "checking for _atan2l declaration... " >&6; } + if test x${glibcxx_cv_func__atan2l_use+set} != xset; then + if ${glibcxx_cv_func__atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2l_use=yes +else + glibcxx_cv_func__atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2l_use" >&5 +$as_echo "$glibcxx_cv_func__atan2l_use" >&6; } + + if test x$glibcxx_cv_func__atan2l_use = x"yes"; then + for ac_func in _atan2l +do : + ac_fn_c_check_func "$LINENO" "_atan2l" "ac_cv_func__atan2l" +if test "x$ac_cv_func__atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } + if test x${glibcxx_cv_func_expl_use+set} != xset; then + if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + + if test x$glibcxx_cv_func_expl_use = x"yes"; then + for ac_func in expl +do : + ac_fn_c_check_func "$LINENO" "expl" "ac_cv_func_expl" +if test "x$ac_cv_func_expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expl declaration" >&5 +$as_echo_n "checking for _expl declaration... " >&6; } + if test x${glibcxx_cv_func__expl_use+set} != xset; then + if ${glibcxx_cv_func__expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expl_use=yes +else + glibcxx_cv_func__expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expl_use" >&5 +$as_echo "$glibcxx_cv_func__expl_use" >&6; } + + if test x$glibcxx_cv_func__expl_use = x"yes"; then + for ac_func in _expl +do : + ac_fn_c_check_func "$LINENO" "_expl" "ac_cv_func__expl" +if test "x$ac_cv_func__expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } + if test x${glibcxx_cv_func_fabsl_use+set} != xset; then + if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + + if test x$glibcxx_cv_func_fabsl_use = x"yes"; then + for ac_func in fabsl +do : + ac_fn_c_check_func "$LINENO" "fabsl" "ac_cv_func_fabsl" +if test "x$ac_cv_func_fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsl declaration" >&5 +$as_echo_n "checking for _fabsl declaration... " >&6; } + if test x${glibcxx_cv_func__fabsl_use+set} != xset; then + if ${glibcxx_cv_func__fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsl_use=yes +else + glibcxx_cv_func__fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsl_use" >&5 +$as_echo "$glibcxx_cv_func__fabsl_use" >&6; } + + if test x$glibcxx_cv_func__fabsl_use = x"yes"; then + for ac_func in _fabsl +do : + ac_fn_c_check_func "$LINENO" "_fabsl" "ac_cv_func__fabsl" +if test "x$ac_cv_func__fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } + if test x${glibcxx_cv_func_fmodl_use+set} != xset; then + if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + + if test x$glibcxx_cv_func_fmodl_use = x"yes"; then + for ac_func in fmodl +do : + ac_fn_c_check_func "$LINENO" "fmodl" "ac_cv_func_fmodl" +if test "x$ac_cv_func_fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodl declaration" >&5 +$as_echo_n "checking for _fmodl declaration... " >&6; } + if test x${glibcxx_cv_func__fmodl_use+set} != xset; then + if ${glibcxx_cv_func__fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodl_use=yes +else + glibcxx_cv_func__fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodl_use" >&5 +$as_echo "$glibcxx_cv_func__fmodl_use" >&6; } + + if test x$glibcxx_cv_func__fmodl_use = x"yes"; then + for ac_func in _fmodl +do : + ac_fn_c_check_func "$LINENO" "_fmodl" "ac_cv_func__fmodl" +if test "x$ac_cv_func__fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } + if test x${glibcxx_cv_func_frexpl_use+set} != xset; then + if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + + if test x$glibcxx_cv_func_frexpl_use = x"yes"; then + for ac_func in frexpl +do : + ac_fn_c_check_func "$LINENO" "frexpl" "ac_cv_func_frexpl" +if test "x$ac_cv_func_frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpl declaration" >&5 +$as_echo_n "checking for _frexpl declaration... " >&6; } + if test x${glibcxx_cv_func__frexpl_use+set} != xset; then + if ${glibcxx_cv_func__frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpl_use=yes +else + glibcxx_cv_func__frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpl_use" >&5 +$as_echo "$glibcxx_cv_func__frexpl_use" >&6; } + + if test x$glibcxx_cv_func__frexpl_use = x"yes"; then + for ac_func in _frexpl +do : + ac_fn_c_check_func "$LINENO" "_frexpl" "ac_cv_func__frexpl" +if test "x$ac_cv_func__frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } + if test x${glibcxx_cv_func_hypotl_use+set} != xset; then + if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + + if test x$glibcxx_cv_func_hypotl_use = x"yes"; then + for ac_func in hypotl +do : + ac_fn_c_check_func "$LINENO" "hypotl" "ac_cv_func_hypotl" +if test "x$ac_cv_func_hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotl declaration" >&5 +$as_echo_n "checking for _hypotl declaration... " >&6; } + if test x${glibcxx_cv_func__hypotl_use+set} != xset; then + if ${glibcxx_cv_func__hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotl_use=yes +else + glibcxx_cv_func__hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotl_use" >&5 +$as_echo "$glibcxx_cv_func__hypotl_use" >&6; } + + if test x$glibcxx_cv_func__hypotl_use = x"yes"; then + for ac_func in _hypotl +do : + ac_fn_c_check_func "$LINENO" "_hypotl" "ac_cv_func__hypotl" +if test "x$ac_cv_func__hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpl_use+set} != xset; then + if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + + if test x$glibcxx_cv_func_ldexpl_use = x"yes"; then + for ac_func in ldexpl +do : + ac_fn_c_check_func "$LINENO" "ldexpl" "ac_cv_func_ldexpl" +if test "x$ac_cv_func_ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpl declaration" >&5 +$as_echo_n "checking for _ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpl_use+set} != xset; then + if ${glibcxx_cv_func__ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpl_use=yes +else + glibcxx_cv_func__ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpl_use" >&6; } + + if test x$glibcxx_cv_func__ldexpl_use = x"yes"; then + for ac_func in _ldexpl +do : + ac_fn_c_check_func "$LINENO" "_ldexpl" "ac_cv_func__ldexpl" +if test "x$ac_cv_func__ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } + if test x${glibcxx_cv_func_logl_use+set} != xset; then + if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + + if test x$glibcxx_cv_func_logl_use = x"yes"; then + for ac_func in logl +do : + ac_fn_c_check_func "$LINENO" "logl" "ac_cv_func_logl" +if test "x$ac_cv_func_logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logl declaration" >&5 +$as_echo_n "checking for _logl declaration... " >&6; } + if test x${glibcxx_cv_func__logl_use+set} != xset; then + if ${glibcxx_cv_func__logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logl_use=yes +else + glibcxx_cv_func__logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logl_use" >&5 +$as_echo "$glibcxx_cv_func__logl_use" >&6; } + + if test x$glibcxx_cv_func__logl_use = x"yes"; then + for ac_func in _logl +do : + ac_fn_c_check_func "$LINENO" "_logl" "ac_cv_func__logl" +if test "x$ac_cv_func__logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } + if test x${glibcxx_cv_func_log10l_use+set} != xset; then + if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + + if test x$glibcxx_cv_func_log10l_use = x"yes"; then + for ac_func in log10l +do : + ac_fn_c_check_func "$LINENO" "log10l" "ac_cv_func_log10l" +if test "x$ac_cv_func_log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10l declaration" >&5 +$as_echo_n "checking for _log10l declaration... " >&6; } + if test x${glibcxx_cv_func__log10l_use+set} != xset; then + if ${glibcxx_cv_func__log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10l_use=yes +else + glibcxx_cv_func__log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10l_use" >&5 +$as_echo "$glibcxx_cv_func__log10l_use" >&6; } + + if test x$glibcxx_cv_func__log10l_use = x"yes"; then + for ac_func in _log10l +do : + ac_fn_c_check_func "$LINENO" "_log10l" "ac_cv_func__log10l" +if test "x$ac_cv_func__log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } + if test x${glibcxx_cv_func_modfl_use+set} != xset; then + if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + + if test x$glibcxx_cv_func_modfl_use = x"yes"; then + for ac_func in modfl +do : + ac_fn_c_check_func "$LINENO" "modfl" "ac_cv_func_modfl" +if test "x$ac_cv_func_modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modfl declaration" >&5 +$as_echo_n "checking for _modfl declaration... " >&6; } + if test x${glibcxx_cv_func__modfl_use+set} != xset; then + if ${glibcxx_cv_func__modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modfl_use=yes +else + glibcxx_cv_func__modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modfl_use" >&5 +$as_echo "$glibcxx_cv_func__modfl_use" >&6; } + + if test x$glibcxx_cv_func__modfl_use = x"yes"; then + for ac_func in _modfl +do : + ac_fn_c_check_func "$LINENO" "_modfl" "ac_cv_func__modfl" +if test "x$ac_cv_func__modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } + if test x${glibcxx_cv_func_powl_use+set} != xset; then + if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + + if test x$glibcxx_cv_func_powl_use = x"yes"; then + for ac_func in powl +do : + ac_fn_c_check_func "$LINENO" "powl" "ac_cv_func_powl" +if test "x$ac_cv_func_powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powl declaration" >&5 +$as_echo_n "checking for _powl declaration... " >&6; } + if test x${glibcxx_cv_func__powl_use+set} != xset; then + if ${glibcxx_cv_func__powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powl_use=yes +else + glibcxx_cv_func__powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powl_use" >&5 +$as_echo "$glibcxx_cv_func__powl_use" >&6; } + + if test x$glibcxx_cv_func__powl_use = x"yes"; then + for ac_func in _powl +do : + ac_fn_c_check_func "$LINENO" "_powl" "ac_cv_func__powl" +if test "x$ac_cv_func__powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtl_use+set} != xset; then + if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + + if test x$glibcxx_cv_func_sqrtl_use = x"yes"; then + for ac_func in sqrtl +do : + ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl" +if test "x$ac_cv_func_sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtl declaration" >&5 +$as_echo_n "checking for _sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtl_use+set} != xset; then + if ${glibcxx_cv_func__sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtl_use=yes +else + glibcxx_cv_func__sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtl_use" >&6; } + + if test x$glibcxx_cv_func__sqrtl_use = x"yes"; then + for ac_func in _sqrtl +do : + ac_fn_c_check_func "$LINENO" "_sqrtl" "ac_cv_func__sqrtl" +if test "x$ac_cv_func__sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosl declaration" >&5 +$as_echo_n "checking for sincosl declaration... " >&6; } + if test x${glibcxx_cv_func_sincosl_use+set} != xset; then + if ${glibcxx_cv_func_sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosl_use=yes +else + glibcxx_cv_func_sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosl_use" >&5 +$as_echo "$glibcxx_cv_func_sincosl_use" >&6; } + + if test x$glibcxx_cv_func_sincosl_use = x"yes"; then + for ac_func in sincosl +do : + ac_fn_c_check_func "$LINENO" "sincosl" "ac_cv_func_sincosl" +if test "x$ac_cv_func_sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosl declaration" >&5 +$as_echo_n "checking for _sincosl declaration... " >&6; } + if test x${glibcxx_cv_func__sincosl_use+set} != xset; then + if ${glibcxx_cv_func__sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosl_use=yes +else + glibcxx_cv_func__sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosl_use" >&5 +$as_echo "$glibcxx_cv_func__sincosl_use" >&6; } + + if test x$glibcxx_cv_func__sincosl_use = x"yes"; then + for ac_func in _sincosl +do : + ac_fn_c_check_func "$LINENO" "_sincosl" "ac_cv_func__sincosl" +if test "x$ac_cv_func__sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitel declaration" >&5 +$as_echo_n "checking for finitel declaration... " >&6; } + if test x${glibcxx_cv_func_finitel_use+set} != xset; then + if ${glibcxx_cv_func_finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitel_use=yes +else + glibcxx_cv_func_finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitel_use" >&5 +$as_echo "$glibcxx_cv_func_finitel_use" >&6; } + + if test x$glibcxx_cv_func_finitel_use = x"yes"; then + for ac_func in finitel +do : + ac_fn_c_check_func "$LINENO" "finitel" "ac_cv_func_finitel" +if test "x$ac_cv_func_finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitel declaration" >&5 +$as_echo_n "checking for _finitel declaration... " >&6; } + if test x${glibcxx_cv_func__finitel_use+set} != xset; then + if ${glibcxx_cv_func__finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitel_use=yes +else + glibcxx_cv_func__finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitel_use" >&5 +$as_echo "$glibcxx_cv_func__finitel_use" >&6; } + + if test x$glibcxx_cv_func__finitel_use = x"yes"; then + for ac_func in _finitel +do : + ac_fn_c_check_func "$LINENO" "_finitel" "ac_cv_func__finitel" +if test "x$ac_cv_func__finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEL 1 +_ACEOF + +fi +done + + fi + fi + + + + + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for at_quick_exit declaration" >&5 +$as_echo_n "checking for at_quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_at_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_at_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + at_quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_at_quick_exit_use=yes +else + glibcxx_cv_func_at_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_at_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_at_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_at_quick_exit_use = x"yes"; then + for ac_func in at_quick_exit +do : + ac_fn_c_check_func "$LINENO" "at_quick_exit" "ac_cv_func_at_quick_exit" +if test "x$ac_cv_func_at_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AT_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for quick_exit declaration" >&5 +$as_echo_n "checking for quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_quick_exit_use=yes +else + glibcxx_cv_func_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_quick_exit_use = x"yes"; then + for ac_func in quick_exit +do : + ac_fn_c_check_func "$LINENO" "quick_exit" "ac_cv_func_quick_exit" +if test "x$ac_cv_func_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtold declaration" >&5 +$as_echo_n "checking for strtold declaration... " >&6; } + if test x${glibcxx_cv_func_strtold_use+set} != xset; then + if ${glibcxx_cv_func_strtold_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtold(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtold_use=yes +else + glibcxx_cv_func_strtold_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtold_use" >&5 +$as_echo "$glibcxx_cv_func_strtold_use" >&6; } + if test x$glibcxx_cv_func_strtold_use = x"yes"; then + for ac_func in strtold +do : + ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold" +if test "x$ac_cv_func_strtold" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOLD 1 +_ACEOF + +fi +done + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtof declaration" >&5 +$as_echo_n "checking for strtof declaration... " >&6; } + if test x${glibcxx_cv_func_strtof_use+set} != xset; then + if ${glibcxx_cv_func_strtof_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtof(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtof_use=yes +else + glibcxx_cv_func_strtof_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtof_use" >&5 +$as_echo "$glibcxx_cv_func_strtof_use" >&6; } + if test x$glibcxx_cv_func_strtof_use = x"yes"; then + for ac_func in strtof +do : + ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof" +if test "x$ac_cv_func_strtof" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOF 1 +_ACEOF + +fi +done + + fi + + + + + CXXFLAGS="$ac_save_CXXFLAGS" + + ;; + *-tpf) + SECTION_FLAGS='-ffunction-sections -fdata-sections' + SECTION_LDFLAGS='-Wl,--gc-sections $SECTION_LDFLAGS' + + $as_echo "#define HAVE_FINITE 1" >>confdefs.h + + $as_echo "#define HAVE_FINITEF 1" >>confdefs.h + + $as_echo "#define HAVE_FREXPF 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOTF 1" >>confdefs.h + + $as_echo "#define HAVE_ISINF 1" >>confdefs.h + + $as_echo "#define HAVE_ISINFF 1" >>confdefs.h + + $as_echo "#define HAVE_ISNAN 1" >>confdefs.h + + $as_echo "#define HAVE_ISNANF 1" >>confdefs.h + + $as_echo "#define HAVE_SINCOS 1" >>confdefs.h + + $as_echo "#define HAVE_SINCOSF 1" >>confdefs.h + + if test x"long_double_math_on_this_cpu" = x"yes"; then + $as_echo "#define HAVE_FINITEL 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOTL 1" >>confdefs.h + + $as_echo "#define HAVE_ISINFL 1" >>confdefs.h + + $as_echo "#define HAVE_ISNANL 1" >>confdefs.h + + fi + ;; + *-*vms*) + # Check for available headers. + # Don't call GLIBCXX_CHECK_LINKER_FEATURES, VMS doesn't have a GNU ld + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +$as_echo_n "checking for sin in -lm... " >&6; } +if ${ac_cv_lib_m_sin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sin (); +int +main () +{ +return sin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sin=yes +else + ac_cv_lib_m_sin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +$as_echo "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes; then : + libm="-lm" +fi + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $libm" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf declaration" >&5 +$as_echo_n "checking for isinf declaration... " >&6; } + if test x${glibcxx_cv_func_isinf_use+set} != xset; then + if ${glibcxx_cv_func_isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinf_use=yes +else + glibcxx_cv_func_isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinf_use" >&5 +$as_echo "$glibcxx_cv_func_isinf_use" >&6; } + + if test x$glibcxx_cv_func_isinf_use = x"yes"; then + for ac_func in isinf +do : + ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinf declaration" >&5 +$as_echo_n "checking for _isinf declaration... " >&6; } + if test x${glibcxx_cv_func__isinf_use+set} != xset; then + if ${glibcxx_cv_func__isinf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinf_use=yes +else + glibcxx_cv_func__isinf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinf_use" >&5 +$as_echo "$glibcxx_cv_func__isinf_use" >&6; } + + if test x$glibcxx_cv_func__isinf_use = x"yes"; then + for ac_func in _isinf +do : + ac_fn_c_check_func "$LINENO" "_isinf" "ac_cv_func__isinf" +if test "x$ac_cv_func__isinf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan declaration" >&5 +$as_echo_n "checking for isnan declaration... " >&6; } + if test x${glibcxx_cv_func_isnan_use+set} != xset; then + if ${glibcxx_cv_func_isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnan_use=yes +else + glibcxx_cv_func_isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnan_use" >&5 +$as_echo "$glibcxx_cv_func_isnan_use" >&6; } + + if test x$glibcxx_cv_func_isnan_use = x"yes"; then + for ac_func in isnan +do : + ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNAN 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnan declaration" >&5 +$as_echo_n "checking for _isnan declaration... " >&6; } + if test x${glibcxx_cv_func__isnan_use+set} != xset; then + if ${glibcxx_cv_func__isnan_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnan(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnan_use=yes +else + glibcxx_cv_func__isnan_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnan_use" >&5 +$as_echo "$glibcxx_cv_func__isnan_use" >&6; } + + if test x$glibcxx_cv_func__isnan_use = x"yes"; then + for ac_func in _isnan +do : + ac_fn_c_check_func "$LINENO" "_isnan" "ac_cv_func__isnan" +if test "x$ac_cv_func__isnan" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNAN 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finite declaration" >&5 +$as_echo_n "checking for finite declaration... " >&6; } + if test x${glibcxx_cv_func_finite_use+set} != xset; then + if ${glibcxx_cv_func_finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finite_use=yes +else + glibcxx_cv_func_finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finite_use" >&5 +$as_echo "$glibcxx_cv_func_finite_use" >&6; } + + if test x$glibcxx_cv_func_finite_use = x"yes"; then + for ac_func in finite +do : + ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITE 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finite declaration" >&5 +$as_echo_n "checking for _finite declaration... " >&6; } + if test x${glibcxx_cv_func__finite_use+set} != xset; then + if ${glibcxx_cv_func__finite_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finite(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finite_use=yes +else + glibcxx_cv_func__finite_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finite_use" >&5 +$as_echo "$glibcxx_cv_func__finite_use" >&6; } + + if test x$glibcxx_cv_func__finite_use = x"yes"; then + for ac_func in _finite +do : + ac_fn_c_check_func "$LINENO" "_finite" "ac_cv_func__finite" +if test "x$ac_cv_func__finite" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITE 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincos declaration" >&5 +$as_echo_n "checking for sincos declaration... " >&6; } + if test x${glibcxx_cv_func_sincos_use+set} != xset; then + if ${glibcxx_cv_func_sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincos_use=yes +else + glibcxx_cv_func_sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincos_use" >&5 +$as_echo "$glibcxx_cv_func_sincos_use" >&6; } + + if test x$glibcxx_cv_func_sincos_use = x"yes"; then + for ac_func in sincos +do : + ac_fn_c_check_func "$LINENO" "sincos" "ac_cv_func_sincos" +if test "x$ac_cv_func_sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincos declaration" >&5 +$as_echo_n "checking for _sincos declaration... " >&6; } + if test x${glibcxx_cv_func__sincos_use+set} != xset; then + if ${glibcxx_cv_func__sincos_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincos(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincos_use=yes +else + glibcxx_cv_func__sincos_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincos_use" >&5 +$as_echo "$glibcxx_cv_func__sincos_use" >&6; } + + if test x$glibcxx_cv_func__sincos_use = x"yes"; then + for ac_func in _sincos +do : + ac_fn_c_check_func "$LINENO" "_sincos" "ac_cv_func__sincos" +if test "x$ac_cv_func__sincos" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpclass declaration" >&5 +$as_echo_n "checking for fpclass declaration... " >&6; } + if test x${glibcxx_cv_func_fpclass_use+set} != xset; then + if ${glibcxx_cv_func_fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fpclass_use=yes +else + glibcxx_cv_func_fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fpclass_use" >&5 +$as_echo "$glibcxx_cv_func_fpclass_use" >&6; } + + if test x$glibcxx_cv_func_fpclass_use = x"yes"; then + for ac_func in fpclass +do : + ac_fn_c_check_func "$LINENO" "fpclass" "ac_cv_func_fpclass" +if test "x$ac_cv_func_fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fpclass declaration" >&5 +$as_echo_n "checking for _fpclass declaration... " >&6; } + if test x${glibcxx_cv_func__fpclass_use+set} != xset; then + if ${glibcxx_cv_func__fpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fpclass_use=yes +else + glibcxx_cv_func__fpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fpclass_use" >&5 +$as_echo "$glibcxx_cv_func__fpclass_use" >&6; } + + if test x$glibcxx_cv_func__fpclass_use = x"yes"; then + for ac_func in _fpclass +do : + ac_fn_c_check_func "$LINENO" "_fpclass" "ac_cv_func__fpclass" +if test "x$ac_cv_func__fpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for qfpclass declaration" >&5 +$as_echo_n "checking for qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func_qfpclass_use+set} != xset; then + if ${glibcxx_cv_func_qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_qfpclass_use=yes +else + glibcxx_cv_func_qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func_qfpclass_use" >&6; } + + if test x$glibcxx_cv_func_qfpclass_use = x"yes"; then + for ac_func in qfpclass +do : + ac_fn_c_check_func "$LINENO" "qfpclass" "ac_cv_func_qfpclass" +if test "x$ac_cv_func_qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QFPCLASS 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _qfpclass declaration" >&5 +$as_echo_n "checking for _qfpclass declaration... " >&6; } + if test x${glibcxx_cv_func__qfpclass_use+set} != xset; then + if ${glibcxx_cv_func__qfpclass_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _qfpclass(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__qfpclass_use=yes +else + glibcxx_cv_func__qfpclass_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__qfpclass_use" >&5 +$as_echo "$glibcxx_cv_func__qfpclass_use" >&6; } + + if test x$glibcxx_cv_func__qfpclass_use = x"yes"; then + for ac_func in _qfpclass +do : + ac_fn_c_check_func "$LINENO" "_qfpclass" "ac_cv_func__qfpclass" +if test "x$ac_cv_func__qfpclass" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__QFPCLASS 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypot declaration" >&5 +$as_echo_n "checking for hypot declaration... " >&6; } + if test x${glibcxx_cv_func_hypot_use+set} != xset; then + if ${glibcxx_cv_func_hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypot_use=yes +else + glibcxx_cv_func_hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypot_use" >&5 +$as_echo "$glibcxx_cv_func_hypot_use" >&6; } + + if test x$glibcxx_cv_func_hypot_use = x"yes"; then + for ac_func in hypot +do : + ac_fn_c_check_func "$LINENO" "hypot" "ac_cv_func_hypot" +if test "x$ac_cv_func_hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOT 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypot declaration" >&5 +$as_echo_n "checking for _hypot declaration... " >&6; } + if test x${glibcxx_cv_func__hypot_use+set} != xset; then + if ${glibcxx_cv_func__hypot_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypot(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypot_use=yes +else + glibcxx_cv_func__hypot_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypot_use" >&5 +$as_echo "$glibcxx_cv_func__hypot_use" >&6; } + + if test x$glibcxx_cv_func__hypot_use = x"yes"; then + for ac_func in _hypot +do : + ac_fn_c_check_func "$LINENO" "_hypot" "ac_cv_func__hypot" +if test "x$ac_cv_func__hypot" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOT 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float trig functions" >&5 +$as_echo_n "checking for float trig functions... " >&6; } + if ${glibcxx_cv_func_float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosf (0); asinf (0); atanf (0); cosf (0); sinf (0); tanf (0); coshf (0); sinhf (0); tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_trig_use=yes +else + glibcxx_cv_func_float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_trig_use" >&5 +$as_echo "$glibcxx_cv_func_float_trig_use" >&6; } + if test x$glibcxx_cv_func_float_trig_use = x"yes"; then + for ac_func in acosf asinf atanf cosf sinf tanf coshf sinhf tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float trig functions" >&5 +$as_echo_n "checking for _float trig functions... " >&6; } + if ${glibcxx_cv_func__float_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosf (0); _asinf (0); _atanf (0); _cosf (0); _sinf (0); _tanf (0); _coshf (0); _sinhf (0); _tanhf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_trig_use=yes +else + glibcxx_cv_func__float_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_trig_use" >&5 +$as_echo "$glibcxx_cv_func__float_trig_use" >&6; } + if test x$glibcxx_cv_func__float_trig_use = x"yes"; then + for ac_func in _acosf _asinf _atanf _cosf _sinf _tanf _coshf _sinhf _tanhf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for float round functions" >&5 +$as_echo_n "checking for float round functions... " >&6; } + if ${glibcxx_cv_func_float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceilf (0); floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_float_round_use=yes +else + glibcxx_cv_func_float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_float_round_use" >&5 +$as_echo "$glibcxx_cv_func_float_round_use" >&6; } + if test x$glibcxx_cv_func_float_round_use = x"yes"; then + for ac_func in ceilf floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _float round functions" >&5 +$as_echo_n "checking for _float round functions... " >&6; } + if ${glibcxx_cv_func__float_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceilf (0); _floorf (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__float_round_use=yes +else + glibcxx_cv_func__float_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__float_round_use" >&5 +$as_echo "$glibcxx_cv_func__float_round_use" >&6; } + if test x$glibcxx_cv_func__float_round_use = x"yes"; then + for ac_func in _ceilf _floorf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expf declaration" >&5 +$as_echo_n "checking for expf declaration... " >&6; } + if test x${glibcxx_cv_func_expf_use+set} != xset; then + if ${glibcxx_cv_func_expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expf_use=yes +else + glibcxx_cv_func_expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expf_use" >&5 +$as_echo "$glibcxx_cv_func_expf_use" >&6; } + + if test x$glibcxx_cv_func_expf_use = x"yes"; then + for ac_func in expf +do : + ac_fn_c_check_func "$LINENO" "expf" "ac_cv_func_expf" +if test "x$ac_cv_func_expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expf declaration" >&5 +$as_echo_n "checking for _expf declaration... " >&6; } + if test x${glibcxx_cv_func__expf_use+set} != xset; then + if ${glibcxx_cv_func__expf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expf_use=yes +else + glibcxx_cv_func__expf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expf_use" >&5 +$as_echo "$glibcxx_cv_func__expf_use" >&6; } + + if test x$glibcxx_cv_func__expf_use = x"yes"; then + for ac_func in _expf +do : + ac_fn_c_check_func "$LINENO" "_expf" "ac_cv_func__expf" +if test "x$ac_cv_func__expf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanf declaration" >&5 +$as_echo_n "checking for isnanf declaration... " >&6; } + if test x${glibcxx_cv_func_isnanf_use+set} != xset; then + if ${glibcxx_cv_func_isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanf_use=yes +else + glibcxx_cv_func_isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanf_use" >&5 +$as_echo "$glibcxx_cv_func_isnanf_use" >&6; } + + if test x$glibcxx_cv_func_isnanf_use = x"yes"; then + for ac_func in isnanf +do : + ac_fn_c_check_func "$LINENO" "isnanf" "ac_cv_func_isnanf" +if test "x$ac_cv_func_isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanf declaration" >&5 +$as_echo_n "checking for _isnanf declaration... " >&6; } + if test x${glibcxx_cv_func__isnanf_use+set} != xset; then + if ${glibcxx_cv_func__isnanf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanf_use=yes +else + glibcxx_cv_func__isnanf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanf_use" >&5 +$as_echo "$glibcxx_cv_func__isnanf_use" >&6; } + + if test x$glibcxx_cv_func__isnanf_use = x"yes"; then + for ac_func in _isnanf +do : + ac_fn_c_check_func "$LINENO" "_isnanf" "ac_cv_func__isnanf" +if test "x$ac_cv_func__isnanf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinff declaration" >&5 +$as_echo_n "checking for isinff declaration... " >&6; } + if test x${glibcxx_cv_func_isinff_use+set} != xset; then + if ${glibcxx_cv_func_isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinff_use=yes +else + glibcxx_cv_func_isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinff_use" >&5 +$as_echo "$glibcxx_cv_func_isinff_use" >&6; } + + if test x$glibcxx_cv_func_isinff_use = x"yes"; then + for ac_func in isinff +do : + ac_fn_c_check_func "$LINENO" "isinff" "ac_cv_func_isinff" +if test "x$ac_cv_func_isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinff declaration" >&5 +$as_echo_n "checking for _isinff declaration... " >&6; } + if test x${glibcxx_cv_func__isinff_use+set} != xset; then + if ${glibcxx_cv_func__isinff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinff(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinff_use=yes +else + glibcxx_cv_func__isinff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinff_use" >&5 +$as_echo "$glibcxx_cv_func__isinff_use" >&6; } + + if test x$glibcxx_cv_func__isinff_use = x"yes"; then + for ac_func in _isinff +do : + ac_fn_c_check_func "$LINENO" "_isinff" "ac_cv_func__isinff" +if test "x$ac_cv_func__isinff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f declaration" >&5 +$as_echo_n "checking for atan2f declaration... " >&6; } + if test x${glibcxx_cv_func_atan2f_use+set} != xset; then + if ${glibcxx_cv_func_atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2f_use=yes +else + glibcxx_cv_func_atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2f_use" >&5 +$as_echo "$glibcxx_cv_func_atan2f_use" >&6; } + + if test x$glibcxx_cv_func_atan2f_use = x"yes"; then + for ac_func in atan2f +do : + ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2f declaration" >&5 +$as_echo_n "checking for _atan2f declaration... " >&6; } + if test x${glibcxx_cv_func__atan2f_use+set} != xset; then + if ${glibcxx_cv_func__atan2f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2f(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2f_use=yes +else + glibcxx_cv_func__atan2f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2f_use" >&5 +$as_echo "$glibcxx_cv_func__atan2f_use" >&6; } + + if test x$glibcxx_cv_func__atan2f_use = x"yes"; then + for ac_func in _atan2f +do : + ac_fn_c_check_func "$LINENO" "_atan2f" "ac_cv_func__atan2f" +if test "x$ac_cv_func__atan2f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsf declaration" >&5 +$as_echo_n "checking for fabsf declaration... " >&6; } + if test x${glibcxx_cv_func_fabsf_use+set} != xset; then + if ${glibcxx_cv_func_fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsf_use=yes +else + glibcxx_cv_func_fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsf_use" >&5 +$as_echo "$glibcxx_cv_func_fabsf_use" >&6; } + + if test x$glibcxx_cv_func_fabsf_use = x"yes"; then + for ac_func in fabsf +do : + ac_fn_c_check_func "$LINENO" "fabsf" "ac_cv_func_fabsf" +if test "x$ac_cv_func_fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsf declaration" >&5 +$as_echo_n "checking for _fabsf declaration... " >&6; } + if test x${glibcxx_cv_func__fabsf_use+set} != xset; then + if ${glibcxx_cv_func__fabsf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsf_use=yes +else + glibcxx_cv_func__fabsf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsf_use" >&5 +$as_echo "$glibcxx_cv_func__fabsf_use" >&6; } + + if test x$glibcxx_cv_func__fabsf_use = x"yes"; then + for ac_func in _fabsf +do : + ac_fn_c_check_func "$LINENO" "_fabsf" "ac_cv_func__fabsf" +if test "x$ac_cv_func__fabsf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf declaration" >&5 +$as_echo_n "checking for fmodf declaration... " >&6; } + if test x${glibcxx_cv_func_fmodf_use+set} != xset; then + if ${glibcxx_cv_func_fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodf_use=yes +else + glibcxx_cv_func_fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodf_use" >&5 +$as_echo "$glibcxx_cv_func_fmodf_use" >&6; } + + if test x$glibcxx_cv_func_fmodf_use = x"yes"; then + for ac_func in fmodf +do : + ac_fn_c_check_func "$LINENO" "fmodf" "ac_cv_func_fmodf" +if test "x$ac_cv_func_fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodf declaration" >&5 +$as_echo_n "checking for _fmodf declaration... " >&6; } + if test x${glibcxx_cv_func__fmodf_use+set} != xset; then + if ${glibcxx_cv_func__fmodf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodf_use=yes +else + glibcxx_cv_func__fmodf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodf_use" >&5 +$as_echo "$glibcxx_cv_func__fmodf_use" >&6; } + + if test x$glibcxx_cv_func__fmodf_use = x"yes"; then + for ac_func in _fmodf +do : + ac_fn_c_check_func "$LINENO" "_fmodf" "ac_cv_func__fmodf" +if test "x$ac_cv_func__fmodf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } + if test x${glibcxx_cv_func_frexpf_use+set} != xset; then + if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + + if test x$glibcxx_cv_func_frexpf_use = x"yes"; then + for ac_func in frexpf +do : + ac_fn_c_check_func "$LINENO" "frexpf" "ac_cv_func_frexpf" +if test "x$ac_cv_func_frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpf declaration" >&5 +$as_echo_n "checking for _frexpf declaration... " >&6; } + if test x${glibcxx_cv_func__frexpf_use+set} != xset; then + if ${glibcxx_cv_func__frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpf_use=yes +else + glibcxx_cv_func__frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpf_use" >&5 +$as_echo "$glibcxx_cv_func__frexpf_use" >&6; } + + if test x$glibcxx_cv_func__frexpf_use = x"yes"; then + for ac_func in _frexpf +do : + ac_fn_c_check_func "$LINENO" "_frexpf" "ac_cv_func__frexpf" +if test "x$ac_cv_func__frexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } + if test x${glibcxx_cv_func_hypotf_use+set} != xset; then + if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + + if test x$glibcxx_cv_func_hypotf_use = x"yes"; then + for ac_func in hypotf +do : + ac_fn_c_check_func "$LINENO" "hypotf" "ac_cv_func_hypotf" +if test "x$ac_cv_func_hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotf declaration" >&5 +$as_echo_n "checking for _hypotf declaration... " >&6; } + if test x${glibcxx_cv_func__hypotf_use+set} != xset; then + if ${glibcxx_cv_func__hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotf_use=yes +else + glibcxx_cv_func__hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotf_use" >&5 +$as_echo "$glibcxx_cv_func__hypotf_use" >&6; } + + if test x$glibcxx_cv_func__hypotf_use = x"yes"; then + for ac_func in _hypotf +do : + ac_fn_c_check_func "$LINENO" "_hypotf" "ac_cv_func__hypotf" +if test "x$ac_cv_func__hypotf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpf_use+set} != xset; then + if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + + if test x$glibcxx_cv_func_ldexpf_use = x"yes"; then + for ac_func in ldexpf +do : + ac_fn_c_check_func "$LINENO" "ldexpf" "ac_cv_func_ldexpf" +if test "x$ac_cv_func_ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpf declaration" >&5 +$as_echo_n "checking for _ldexpf declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpf_use+set} != xset; then + if ${glibcxx_cv_func__ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpf_use=yes +else + glibcxx_cv_func__ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpf_use" >&6; } + + if test x$glibcxx_cv_func__ldexpf_use = x"yes"; then + for ac_func in _ldexpf +do : + ac_fn_c_check_func "$LINENO" "_ldexpf" "ac_cv_func__ldexpf" +if test "x$ac_cv_func__ldexpf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logf declaration" >&5 +$as_echo_n "checking for logf declaration... " >&6; } + if test x${glibcxx_cv_func_logf_use+set} != xset; then + if ${glibcxx_cv_func_logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logf_use=yes +else + glibcxx_cv_func_logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logf_use" >&5 +$as_echo "$glibcxx_cv_func_logf_use" >&6; } + + if test x$glibcxx_cv_func_logf_use = x"yes"; then + for ac_func in logf +do : + ac_fn_c_check_func "$LINENO" "logf" "ac_cv_func_logf" +if test "x$ac_cv_func_logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logf declaration" >&5 +$as_echo_n "checking for _logf declaration... " >&6; } + if test x${glibcxx_cv_func__logf_use+set} != xset; then + if ${glibcxx_cv_func__logf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logf_use=yes +else + glibcxx_cv_func__logf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logf_use" >&5 +$as_echo "$glibcxx_cv_func__logf_use" >&6; } + + if test x$glibcxx_cv_func__logf_use = x"yes"; then + for ac_func in _logf +do : + ac_fn_c_check_func "$LINENO" "_logf" "ac_cv_func__logf" +if test "x$ac_cv_func__logf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10f declaration" >&5 +$as_echo_n "checking for log10f declaration... " >&6; } + if test x${glibcxx_cv_func_log10f_use+set} != xset; then + if ${glibcxx_cv_func_log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10f_use=yes +else + glibcxx_cv_func_log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10f_use" >&5 +$as_echo "$glibcxx_cv_func_log10f_use" >&6; } + + if test x$glibcxx_cv_func_log10f_use = x"yes"; then + for ac_func in log10f +do : + ac_fn_c_check_func "$LINENO" "log10f" "ac_cv_func_log10f" +if test "x$ac_cv_func_log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10F 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10f declaration" >&5 +$as_echo_n "checking for _log10f declaration... " >&6; } + if test x${glibcxx_cv_func__log10f_use+set} != xset; then + if ${glibcxx_cv_func__log10f_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10f(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10f_use=yes +else + glibcxx_cv_func__log10f_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10f_use" >&5 +$as_echo "$glibcxx_cv_func__log10f_use" >&6; } + + if test x$glibcxx_cv_func__log10f_use = x"yes"; then + for ac_func in _log10f +do : + ac_fn_c_check_func "$LINENO" "_log10f" "ac_cv_func__log10f" +if test "x$ac_cv_func__log10f" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10F 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } + if test x${glibcxx_cv_func_modff_use+set} != xset; then + if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + + if test x$glibcxx_cv_func_modff_use = x"yes"; then + for ac_func in modff +do : + ac_fn_c_check_func "$LINENO" "modff" "ac_cv_func_modff" +if test "x$ac_cv_func_modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modff declaration" >&5 +$as_echo_n "checking for _modff declaration... " >&6; } + if test x${glibcxx_cv_func__modff_use+set} != xset; then + if ${glibcxx_cv_func__modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modff(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modff_use=yes +else + glibcxx_cv_func__modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modff_use" >&5 +$as_echo "$glibcxx_cv_func__modff_use" >&6; } + + if test x$glibcxx_cv_func__modff_use = x"yes"; then + for ac_func in _modff +do : + ac_fn_c_check_func "$LINENO" "_modff" "ac_cv_func__modff" +if test "x$ac_cv_func__modff" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modf declaration" >&5 +$as_echo_n "checking for modf declaration... " >&6; } + if test x${glibcxx_cv_func_modf_use+set} != xset; then + if ${glibcxx_cv_func_modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modf_use=yes +else + glibcxx_cv_func_modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modf_use" >&5 +$as_echo "$glibcxx_cv_func_modf_use" >&6; } + + if test x$glibcxx_cv_func_modf_use = x"yes"; then + for ac_func in modf +do : + ac_fn_c_check_func "$LINENO" "modf" "ac_cv_func_modf" +if test "x$ac_cv_func_modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modf declaration" >&5 +$as_echo_n "checking for _modf declaration... " >&6; } + if test x${glibcxx_cv_func__modf_use+set} != xset; then + if ${glibcxx_cv_func__modf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modf_use=yes +else + glibcxx_cv_func__modf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modf_use" >&5 +$as_echo "$glibcxx_cv_func__modf_use" >&6; } + + if test x$glibcxx_cv_func__modf_use = x"yes"; then + for ac_func in _modf +do : + ac_fn_c_check_func "$LINENO" "_modf" "ac_cv_func__modf" +if test "x$ac_cv_func__modf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powf declaration" >&5 +$as_echo_n "checking for powf declaration... " >&6; } + if test x${glibcxx_cv_func_powf_use+set} != xset; then + if ${glibcxx_cv_func_powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powf_use=yes +else + glibcxx_cv_func_powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powf_use" >&5 +$as_echo "$glibcxx_cv_func_powf_use" >&6; } + + if test x$glibcxx_cv_func_powf_use = x"yes"; then + for ac_func in powf +do : + ac_fn_c_check_func "$LINENO" "powf" "ac_cv_func_powf" +if test "x$ac_cv_func_powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powf declaration" >&5 +$as_echo_n "checking for _powf declaration... " >&6; } + if test x${glibcxx_cv_func__powf_use+set} != xset; then + if ${glibcxx_cv_func__powf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powf(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powf_use=yes +else + glibcxx_cv_func__powf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powf_use" >&5 +$as_echo "$glibcxx_cv_func__powf_use" >&6; } + + if test x$glibcxx_cv_func__powf_use = x"yes"; then + for ac_func in _powf +do : + ac_fn_c_check_func "$LINENO" "_powf" "ac_cv_func__powf" +if test "x$ac_cv_func__powf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtf declaration" >&5 +$as_echo_n "checking for sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtf_use+set} != xset; then + if ${glibcxx_cv_func_sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtf_use=yes +else + glibcxx_cv_func_sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtf_use" >&6; } + + if test x$glibcxx_cv_func_sqrtf_use = x"yes"; then + for ac_func in sqrtf +do : + ac_fn_c_check_func "$LINENO" "sqrtf" "ac_cv_func_sqrtf" +if test "x$ac_cv_func_sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtf declaration" >&5 +$as_echo_n "checking for _sqrtf declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtf_use+set} != xset; then + if ${glibcxx_cv_func__sqrtf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtf(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtf_use=yes +else + glibcxx_cv_func__sqrtf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtf_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtf_use" >&6; } + + if test x$glibcxx_cv_func__sqrtf_use = x"yes"; then + for ac_func in _sqrtf +do : + ac_fn_c_check_func "$LINENO" "_sqrtf" "ac_cv_func__sqrtf" +if test "x$ac_cv_func__sqrtf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosf declaration" >&5 +$as_echo_n "checking for sincosf declaration... " >&6; } + if test x${glibcxx_cv_func_sincosf_use+set} != xset; then + if ${glibcxx_cv_func_sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosf_use=yes +else + glibcxx_cv_func_sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosf_use" >&5 +$as_echo "$glibcxx_cv_func_sincosf_use" >&6; } + + if test x$glibcxx_cv_func_sincosf_use = x"yes"; then + for ac_func in sincosf +do : + ac_fn_c_check_func "$LINENO" "sincosf" "ac_cv_func_sincosf" +if test "x$ac_cv_func_sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosf declaration" >&5 +$as_echo_n "checking for _sincosf declaration... " >&6; } + if test x${glibcxx_cv_func__sincosf_use+set} != xset; then + if ${glibcxx_cv_func__sincosf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosf(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosf_use=yes +else + glibcxx_cv_func__sincosf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosf_use" >&5 +$as_echo "$glibcxx_cv_func__sincosf_use" >&6; } + + if test x$glibcxx_cv_func__sincosf_use = x"yes"; then + for ac_func in _sincosf +do : + ac_fn_c_check_func "$LINENO" "_sincosf" "ac_cv_func__sincosf" +if test "x$ac_cv_func__sincosf" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitef declaration" >&5 +$as_echo_n "checking for finitef declaration... " >&6; } + if test x${glibcxx_cv_func_finitef_use+set} != xset; then + if ${glibcxx_cv_func_finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitef_use=yes +else + glibcxx_cv_func_finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitef_use" >&5 +$as_echo "$glibcxx_cv_func_finitef_use" >&6; } + + if test x$glibcxx_cv_func_finitef_use = x"yes"; then + for ac_func in finitef +do : + ac_fn_c_check_func "$LINENO" "finitef" "ac_cv_func_finitef" +if test "x$ac_cv_func_finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEF 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitef declaration" >&5 +$as_echo_n "checking for _finitef declaration... " >&6; } + if test x${glibcxx_cv_func__finitef_use+set} != xset; then + if ${glibcxx_cv_func__finitef_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitef(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitef_use=yes +else + glibcxx_cv_func__finitef_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitef_use" >&5 +$as_echo "$glibcxx_cv_func__finitef_use" >&6; } + + if test x$glibcxx_cv_func__finitef_use = x"yes"; then + for ac_func in _finitef +do : + ac_fn_c_check_func "$LINENO" "_finitef" "ac_cv_func__finitef" +if test "x$ac_cv_func__finitef" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEF 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double trig functions" >&5 +$as_echo_n "checking for long double trig functions... " >&6; } + if ${glibcxx_cv_func_long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +acosl (0); asinl (0); atanl (0); cosl (0); sinl (0); tanl (0); coshl (0); sinhl (0); tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_trig_use=yes +else + glibcxx_cv_func_long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_trig_use" >&6; } + if test x$glibcxx_cv_func_long_double_trig_use = x"yes"; then + for ac_func in acosl asinl atanl cosl sinl tanl coshl sinhl tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double trig functions" >&5 +$as_echo_n "checking for _long double trig functions... " >&6; } + if ${glibcxx_cv_func__long_double_trig_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_acosl (0); _asinl (0); _atanl (0); _cosl (0); _sinl (0); _tanl (0); _coshl (0); _sinhl (0); _tanhl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_trig_use=yes +else + glibcxx_cv_func__long_double_trig_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_trig_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_trig_use" >&6; } + if test x$glibcxx_cv_func__long_double_trig_use = x"yes"; then + for ac_func in _acosl _asinl _atanl _cosl _sinl _tanl _coshl _sinhl _tanhl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double round functions" >&5 +$as_echo_n "checking for long double round functions... " >&6; } + if ${glibcxx_cv_func_long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +ceill (0); floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_long_double_round_use=yes +else + glibcxx_cv_func_long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func_long_double_round_use" >&6; } + if test x$glibcxx_cv_func_long_double_round_use = x"yes"; then + for ac_func in ceill floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _long double round functions" >&5 +$as_echo_n "checking for _long double round functions... " >&6; } + if ${glibcxx_cv_func__long_double_round_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +_ceill (0); _floorl (0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__long_double_round_use=yes +else + glibcxx_cv_func__long_double_round_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__long_double_round_use" >&5 +$as_echo "$glibcxx_cv_func__long_double_round_use" >&6; } + if test x$glibcxx_cv_func__long_double_round_use = x"yes"; then + for ac_func in _ceill _floorl +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + fi + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnanl declaration" >&5 +$as_echo_n "checking for isnanl declaration... " >&6; } + if test x${glibcxx_cv_func_isnanl_use+set} != xset; then + if ${glibcxx_cv_func_isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isnanl_use=yes +else + glibcxx_cv_func_isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isnanl_use" >&5 +$as_echo "$glibcxx_cv_func_isnanl_use" >&6; } + + if test x$glibcxx_cv_func_isnanl_use = x"yes"; then + for ac_func in isnanl +do : + ac_fn_c_check_func "$LINENO" "isnanl" "ac_cv_func_isnanl" +if test "x$ac_cv_func_isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISNANL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isnanl declaration" >&5 +$as_echo_n "checking for _isnanl declaration... " >&6; } + if test x${glibcxx_cv_func__isnanl_use+set} != xset; then + if ${glibcxx_cv_func__isnanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isnanl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isnanl_use=yes +else + glibcxx_cv_func__isnanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isnanl_use" >&5 +$as_echo "$glibcxx_cv_func__isnanl_use" >&6; } + + if test x$glibcxx_cv_func__isnanl_use = x"yes"; then + for ac_func in _isnanl +do : + ac_fn_c_check_func "$LINENO" "_isnanl" "ac_cv_func__isnanl" +if test "x$ac_cv_func__isnanl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISNANL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinfl declaration" >&5 +$as_echo_n "checking for isinfl declaration... " >&6; } + if test x${glibcxx_cv_func_isinfl_use+set} != xset; then + if ${glibcxx_cv_func_isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_isinfl_use=yes +else + glibcxx_cv_func_isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_isinfl_use" >&5 +$as_echo "$glibcxx_cv_func_isinfl_use" >&6; } + + if test x$glibcxx_cv_func_isinfl_use = x"yes"; then + for ac_func in isinfl +do : + ac_fn_c_check_func "$LINENO" "isinfl" "ac_cv_func_isinfl" +if test "x$ac_cv_func_isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ISINFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _isinfl declaration" >&5 +$as_echo_n "checking for _isinfl declaration... " >&6; } + if test x${glibcxx_cv_func__isinfl_use+set} != xset; then + if ${glibcxx_cv_func__isinfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _isinfl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__isinfl_use=yes +else + glibcxx_cv_func__isinfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__isinfl_use" >&5 +$as_echo "$glibcxx_cv_func__isinfl_use" >&6; } + + if test x$glibcxx_cv_func__isinfl_use = x"yes"; then + for ac_func in _isinfl +do : + ac_fn_c_check_func "$LINENO" "_isinfl" "ac_cv_func__isinfl" +if test "x$ac_cv_func__isinfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ISINFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } + if test x${glibcxx_cv_func_atan2l_use+set} != xset; then + if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + + if test x$glibcxx_cv_func_atan2l_use = x"yes"; then + for ac_func in atan2l +do : + ac_fn_c_check_func "$LINENO" "atan2l" "ac_cv_func_atan2l" +if test "x$ac_cv_func_atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _atan2l declaration" >&5 +$as_echo_n "checking for _atan2l declaration... " >&6; } + if test x${glibcxx_cv_func__atan2l_use+set} != xset; then + if ${glibcxx_cv_func__atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _atan2l(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__atan2l_use=yes +else + glibcxx_cv_func__atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__atan2l_use" >&5 +$as_echo "$glibcxx_cv_func__atan2l_use" >&6; } + + if test x$glibcxx_cv_func__atan2l_use = x"yes"; then + for ac_func in _atan2l +do : + ac_fn_c_check_func "$LINENO" "_atan2l" "ac_cv_func__atan2l" +if test "x$ac_cv_func__atan2l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__ATAN2L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } + if test x${glibcxx_cv_func_expl_use+set} != xset; then + if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + + if test x$glibcxx_cv_func_expl_use = x"yes"; then + for ac_func in expl +do : + ac_fn_c_check_func "$LINENO" "expl" "ac_cv_func_expl" +if test "x$ac_cv_func_expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _expl declaration" >&5 +$as_echo_n "checking for _expl declaration... " >&6; } + if test x${glibcxx_cv_func__expl_use+set} != xset; then + if ${glibcxx_cv_func__expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _expl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__expl_use=yes +else + glibcxx_cv_func__expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__expl_use" >&5 +$as_echo "$glibcxx_cv_func__expl_use" >&6; } + + if test x$glibcxx_cv_func__expl_use = x"yes"; then + for ac_func in _expl +do : + ac_fn_c_check_func "$LINENO" "_expl" "ac_cv_func__expl" +if test "x$ac_cv_func__expl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__EXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } + if test x${glibcxx_cv_func_fabsl_use+set} != xset; then + if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + + if test x$glibcxx_cv_func_fabsl_use = x"yes"; then + for ac_func in fabsl +do : + ac_fn_c_check_func "$LINENO" "fabsl" "ac_cv_func_fabsl" +if test "x$ac_cv_func_fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fabsl declaration" >&5 +$as_echo_n "checking for _fabsl declaration... " >&6; } + if test x${glibcxx_cv_func__fabsl_use+set} != xset; then + if ${glibcxx_cv_func__fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _fabsl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fabsl_use=yes +else + glibcxx_cv_func__fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fabsl_use" >&5 +$as_echo "$glibcxx_cv_func__fabsl_use" >&6; } + + if test x$glibcxx_cv_func__fabsl_use = x"yes"; then + for ac_func in _fabsl +do : + ac_fn_c_check_func "$LINENO" "_fabsl" "ac_cv_func__fabsl" +if test "x$ac_cv_func__fabsl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FABSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } + if test x${glibcxx_cv_func_fmodl_use+set} != xset; then + if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + + if test x$glibcxx_cv_func_fmodl_use = x"yes"; then + for ac_func in fmodl +do : + ac_fn_c_check_func "$LINENO" "fmodl" "ac_cv_func_fmodl" +if test "x$ac_cv_func_fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _fmodl declaration" >&5 +$as_echo_n "checking for _fmodl declaration... " >&6; } + if test x${glibcxx_cv_func__fmodl_use+set} != xset; then + if ${glibcxx_cv_func__fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _fmodl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__fmodl_use=yes +else + glibcxx_cv_func__fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__fmodl_use" >&5 +$as_echo "$glibcxx_cv_func__fmodl_use" >&6; } + + if test x$glibcxx_cv_func__fmodl_use = x"yes"; then + for ac_func in _fmodl +do : + ac_fn_c_check_func "$LINENO" "_fmodl" "ac_cv_func__fmodl" +if test "x$ac_cv_func__fmodl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FMODL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } + if test x${glibcxx_cv_func_frexpl_use+set} != xset; then + if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + + if test x$glibcxx_cv_func_frexpl_use = x"yes"; then + for ac_func in frexpl +do : + ac_fn_c_check_func "$LINENO" "frexpl" "ac_cv_func_frexpl" +if test "x$ac_cv_func_frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _frexpl declaration" >&5 +$as_echo_n "checking for _frexpl declaration... " >&6; } + if test x${glibcxx_cv_func__frexpl_use+set} != xset; then + if ${glibcxx_cv_func__frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _frexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__frexpl_use=yes +else + glibcxx_cv_func__frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__frexpl_use" >&5 +$as_echo "$glibcxx_cv_func__frexpl_use" >&6; } + + if test x$glibcxx_cv_func__frexpl_use = x"yes"; then + for ac_func in _frexpl +do : + ac_fn_c_check_func "$LINENO" "_frexpl" "ac_cv_func__frexpl" +if test "x$ac_cv_func__frexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FREXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } + if test x${glibcxx_cv_func_hypotl_use+set} != xset; then + if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + + if test x$glibcxx_cv_func_hypotl_use = x"yes"; then + for ac_func in hypotl +do : + ac_fn_c_check_func "$LINENO" "hypotl" "ac_cv_func_hypotl" +if test "x$ac_cv_func_hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _hypotl declaration" >&5 +$as_echo_n "checking for _hypotl declaration... " >&6; } + if test x${glibcxx_cv_func__hypotl_use+set} != xset; then + if ${glibcxx_cv_func__hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _hypotl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__hypotl_use=yes +else + glibcxx_cv_func__hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__hypotl_use" >&5 +$as_echo "$glibcxx_cv_func__hypotl_use" >&6; } + + if test x$glibcxx_cv_func__hypotl_use = x"yes"; then + for ac_func in _hypotl +do : + ac_fn_c_check_func "$LINENO" "_hypotl" "ac_cv_func__hypotl" +if test "x$ac_cv_func__hypotl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__HYPOTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func_ldexpl_use+set} != xset; then + if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + + if test x$glibcxx_cv_func_ldexpl_use = x"yes"; then + for ac_func in ldexpl +do : + ac_fn_c_check_func "$LINENO" "ldexpl" "ac_cv_func_ldexpl" +if test "x$ac_cv_func_ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ldexpl declaration" >&5 +$as_echo_n "checking for _ldexpl declaration... " >&6; } + if test x${glibcxx_cv_func__ldexpl_use+set} != xset; then + if ${glibcxx_cv_func__ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _ldexpl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__ldexpl_use=yes +else + glibcxx_cv_func__ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func__ldexpl_use" >&6; } + + if test x$glibcxx_cv_func__ldexpl_use = x"yes"; then + for ac_func in _ldexpl +do : + ac_fn_c_check_func "$LINENO" "_ldexpl" "ac_cv_func__ldexpl" +if test "x$ac_cv_func__ldexpl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LDEXPL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } + if test x${glibcxx_cv_func_logl_use+set} != xset; then + if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + + if test x$glibcxx_cv_func_logl_use = x"yes"; then + for ac_func in logl +do : + ac_fn_c_check_func "$LINENO" "logl" "ac_cv_func_logl" +if test "x$ac_cv_func_logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _logl declaration" >&5 +$as_echo_n "checking for _logl declaration... " >&6; } + if test x${glibcxx_cv_func__logl_use+set} != xset; then + if ${glibcxx_cv_func__logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _logl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__logl_use=yes +else + glibcxx_cv_func__logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__logl_use" >&5 +$as_echo "$glibcxx_cv_func__logl_use" >&6; } + + if test x$glibcxx_cv_func__logl_use = x"yes"; then + for ac_func in _logl +do : + ac_fn_c_check_func "$LINENO" "_logl" "ac_cv_func__logl" +if test "x$ac_cv_func__logl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOGL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } + if test x${glibcxx_cv_func_log10l_use+set} != xset; then + if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + + if test x$glibcxx_cv_func_log10l_use = x"yes"; then + for ac_func in log10l +do : + ac_fn_c_check_func "$LINENO" "log10l" "ac_cv_func_log10l" +if test "x$ac_cv_func_log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _log10l declaration" >&5 +$as_echo_n "checking for _log10l declaration... " >&6; } + if test x${glibcxx_cv_func__log10l_use+set} != xset; then + if ${glibcxx_cv_func__log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _log10l(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__log10l_use=yes +else + glibcxx_cv_func__log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__log10l_use" >&5 +$as_echo "$glibcxx_cv_func__log10l_use" >&6; } + + if test x$glibcxx_cv_func__log10l_use = x"yes"; then + for ac_func in _log10l +do : + ac_fn_c_check_func "$LINENO" "_log10l" "ac_cv_func__log10l" +if test "x$ac_cv_func__log10l" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__LOG10L 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } + if test x${glibcxx_cv_func_modfl_use+set} != xset; then + if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + + if test x$glibcxx_cv_func_modfl_use = x"yes"; then + for ac_func in modfl +do : + ac_fn_c_check_func "$LINENO" "modfl" "ac_cv_func_modfl" +if test "x$ac_cv_func_modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _modfl declaration" >&5 +$as_echo_n "checking for _modfl declaration... " >&6; } + if test x${glibcxx_cv_func__modfl_use+set} != xset; then + if ${glibcxx_cv_func__modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _modfl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__modfl_use=yes +else + glibcxx_cv_func__modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__modfl_use" >&5 +$as_echo "$glibcxx_cv_func__modfl_use" >&6; } + + if test x$glibcxx_cv_func__modfl_use = x"yes"; then + for ac_func in _modfl +do : + ac_fn_c_check_func "$LINENO" "_modfl" "ac_cv_func__modfl" +if test "x$ac_cv_func__modfl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__MODFL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } + if test x${glibcxx_cv_func_powl_use+set} != xset; then + if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + + if test x$glibcxx_cv_func_powl_use = x"yes"; then + for ac_func in powl +do : + ac_fn_c_check_func "$LINENO" "powl" "ac_cv_func_powl" +if test "x$ac_cv_func_powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _powl declaration" >&5 +$as_echo_n "checking for _powl declaration... " >&6; } + if test x${glibcxx_cv_func__powl_use+set} != xset; then + if ${glibcxx_cv_func__powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _powl(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__powl_use=yes +else + glibcxx_cv_func__powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__powl_use" >&5 +$as_echo "$glibcxx_cv_func__powl_use" >&6; } + + if test x$glibcxx_cv_func__powl_use = x"yes"; then + for ac_func in _powl +do : + ac_fn_c_check_func "$LINENO" "_powl" "ac_cv_func__powl" +if test "x$ac_cv_func__powl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__POWL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func_sqrtl_use+set} != xset; then + if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + + if test x$glibcxx_cv_func_sqrtl_use = x"yes"; then + for ac_func in sqrtl +do : + ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl" +if test "x$ac_cv_func_sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sqrtl declaration" >&5 +$as_echo_n "checking for _sqrtl declaration... " >&6; } + if test x${glibcxx_cv_func__sqrtl_use+set} != xset; then + if ${glibcxx_cv_func__sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _sqrtl(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sqrtl_use=yes +else + glibcxx_cv_func__sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func__sqrtl_use" >&6; } + + if test x$glibcxx_cv_func__sqrtl_use = x"yes"; then + for ac_func in _sqrtl +do : + ac_fn_c_check_func "$LINENO" "_sqrtl" "ac_cv_func__sqrtl" +if test "x$ac_cv_func__sqrtl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SQRTL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sincosl declaration" >&5 +$as_echo_n "checking for sincosl declaration... " >&6; } + if test x${glibcxx_cv_func_sincosl_use+set} != xset; then + if ${glibcxx_cv_func_sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_sincosl_use=yes +else + glibcxx_cv_func_sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sincosl_use" >&5 +$as_echo "$glibcxx_cv_func_sincosl_use" >&6; } + + if test x$glibcxx_cv_func_sincosl_use = x"yes"; then + for ac_func in sincosl +do : + ac_fn_c_check_func "$LINENO" "sincosl" "ac_cv_func_sincosl" +if test "x$ac_cv_func_sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SINCOSL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sincosl declaration" >&5 +$as_echo_n "checking for _sincosl declaration... " >&6; } + if test x${glibcxx_cv_func__sincosl_use+set} != xset; then + if ${glibcxx_cv_func__sincosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + _sincosl(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__sincosl_use=yes +else + glibcxx_cv_func__sincosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__sincosl_use" >&5 +$as_echo "$glibcxx_cv_func__sincosl_use" >&6; } + + if test x$glibcxx_cv_func__sincosl_use = x"yes"; then + for ac_func in _sincosl +do : + ac_fn_c_check_func "$LINENO" "_sincosl" "ac_cv_func__sincosl" +if test "x$ac_cv_func__sincosl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__SINCOSL 1 +_ACEOF + +fi +done + + fi + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for finitel declaration" >&5 +$as_echo_n "checking for finitel declaration... " >&6; } + if test x${glibcxx_cv_func_finitel_use+set} != xset; then + if ${glibcxx_cv_func_finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_finitel_use=yes +else + glibcxx_cv_func_finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_finitel_use" >&5 +$as_echo "$glibcxx_cv_func_finitel_use" >&6; } + + if test x$glibcxx_cv_func_finitel_use = x"yes"; then + for ac_func in finitel +do : + ac_fn_c_check_func "$LINENO" "finitel" "ac_cv_func_finitel" +if test "x$ac_cv_func_finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FINITEL 1 +_ACEOF + +fi +done + + else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _finitel declaration" >&5 +$as_echo_n "checking for _finitel declaration... " >&6; } + if test x${glibcxx_cv_func__finitel_use+set} != xset; then + if ${glibcxx_cv_func__finitel_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifdef HAVE_IEEEFP_H + #include + #endif + +int +main () +{ + _finitel(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func__finitel_use=yes +else + glibcxx_cv_func__finitel_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func__finitel_use" >&5 +$as_echo "$glibcxx_cv_func__finitel_use" >&6; } + + if test x$glibcxx_cv_func__finitel_use = x"yes"; then + for ac_func in _finitel +do : + ac_fn_c_check_func "$LINENO" "_finitel" "ac_cv_func__finitel" +if test "x$ac_cv_func__finitel" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__FINITEL 1 +_ACEOF + +fi +done + + fi + fi + + + + + LIBS="$ac_save_LIBS" + CXXFLAGS="$ac_save_CXXFLAGS" + + + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS='-fno-builtin -D_GNU_SOURCE' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for at_quick_exit declaration" >&5 +$as_echo_n "checking for at_quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_at_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_at_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + at_quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_at_quick_exit_use=yes +else + glibcxx_cv_func_at_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_at_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_at_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_at_quick_exit_use = x"yes"; then + for ac_func in at_quick_exit +do : + ac_fn_c_check_func "$LINENO" "at_quick_exit" "ac_cv_func_at_quick_exit" +if test "x$ac_cv_func_at_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_AT_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for quick_exit declaration" >&5 +$as_echo_n "checking for quick_exit declaration... " >&6; } + if test x${glibcxx_cv_func_quick_exit_use+set} != xset; then + if ${glibcxx_cv_func_quick_exit_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + quick_exit(0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_quick_exit_use=yes +else + glibcxx_cv_func_quick_exit_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_quick_exit_use" >&5 +$as_echo "$glibcxx_cv_func_quick_exit_use" >&6; } + if test x$glibcxx_cv_func_quick_exit_use = x"yes"; then + for ac_func in quick_exit +do : + ac_fn_c_check_func "$LINENO" "quick_exit" "ac_cv_func_quick_exit" +if test "x$ac_cv_func_quick_exit" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_QUICK_EXIT 1 +_ACEOF + +fi +done + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtold declaration" >&5 +$as_echo_n "checking for strtold declaration... " >&6; } + if test x${glibcxx_cv_func_strtold_use+set} != xset; then + if ${glibcxx_cv_func_strtold_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtold(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtold_use=yes +else + glibcxx_cv_func_strtold_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtold_use" >&5 +$as_echo "$glibcxx_cv_func_strtold_use" >&6; } + if test x$glibcxx_cv_func_strtold_use = x"yes"; then + for ac_func in strtold +do : + ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold" +if test "x$ac_cv_func_strtold" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOLD 1 +_ACEOF + +fi +done + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtof declaration" >&5 +$as_echo_n "checking for strtof declaration... " >&6; } + if test x${glibcxx_cv_func_strtof_use+set} != xset; then + if ${glibcxx_cv_func_strtof_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + strtof(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_strtof_use=yes +else + glibcxx_cv_func_strtof_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_strtof_use" >&5 +$as_echo "$glibcxx_cv_func_strtof_use" >&6; } + if test x$glibcxx_cv_func_strtof_use = x"yes"; then + for ac_func in strtof +do : + ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof" +if test "x$ac_cv_func_strtof" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTOF 1 +_ACEOF + +fi +done + + fi + + + + + CXXFLAGS="$ac_save_CXXFLAGS" + + ;; + *-vxworks*) + $as_echo "#define HAVE_ACOSF 1" >>confdefs.h + + $as_echo "#define HAVE_ASINF 1" >>confdefs.h + + $as_echo "#define HAVE_ATAN2F 1" >>confdefs.h + + $as_echo "#define HAVE_ATANF 1" >>confdefs.h + + $as_echo "#define HAVE_CEILF 1" >>confdefs.h + + $as_echo "#define HAVE_COSF 1" >>confdefs.h + + $as_echo "#define HAVE_COSHF 1" >>confdefs.h + + $as_echo "#define HAVE_EXPF 1" >>confdefs.h + + $as_echo "#define HAVE_FABSF 1" >>confdefs.h + + $as_echo "#define HAVE_FLOORF 1" >>confdefs.h + + $as_echo "#define HAVE_FMODF 1" >>confdefs.h + + $as_echo "#define HAVE_HYPOT 1" >>confdefs.h + + $as_echo "#define HAVE_LOG10F 1" >>confdefs.h + + $as_echo "#define HAVE_LOGF 1" >>confdefs.h + + $as_echo "#define HAVE_POWF 1" >>confdefs.h + + $as_echo "#define HAVE_SINF 1" >>confdefs.h + + $as_echo "#define HAVE_SINHF 1" >>confdefs.h + + $as_echo "#define HAVE_SQRTF 1" >>confdefs.h + + $as_echo "#define HAVE_TANF 1" >>confdefs.h + + $as_echo "#define HAVE_TANHF 1" >>confdefs.h + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acosl declaration" >&5 +$as_echo_n "checking for acosl declaration... " >&6; } +if ${glibcxx_cv_func_acosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef acosl + +int +main () +{ + + void (*f)(void) = (void (*)(void))acosl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_acosl_use=yes + +else + glibcxx_cv_func_acosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_acosl_use" >&5 +$as_echo "$glibcxx_cv_func_acosl_use" >&6; } + if test "x$glibcxx_cv_func_acosl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_ACOSL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for asinl declaration" >&5 +$as_echo_n "checking for asinl declaration... " >&6; } +if ${glibcxx_cv_func_asinl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef asinl + +int +main () +{ + + void (*f)(void) = (void (*)(void))asinl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_asinl_use=yes + +else + glibcxx_cv_func_asinl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_asinl_use" >&5 +$as_echo "$glibcxx_cv_func_asinl_use" >&6; } + if test "x$glibcxx_cv_func_asinl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_ASINL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l declaration" >&5 +$as_echo_n "checking for atan2l declaration... " >&6; } +if ${glibcxx_cv_func_atan2l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef atan2l + +int +main () +{ + + void (*f)(void) = (void (*)(void))atan2l; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_atan2l_use=yes + +else + glibcxx_cv_func_atan2l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atan2l_use" >&5 +$as_echo "$glibcxx_cv_func_atan2l_use" >&6; } + if test "x$glibcxx_cv_func_atan2l_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_ATAN2L 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atanl declaration" >&5 +$as_echo_n "checking for atanl declaration... " >&6; } +if ${glibcxx_cv_func_atanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef atanl + +int +main () +{ + + void (*f)(void) = (void (*)(void))atanl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_atanl_use=yes + +else + glibcxx_cv_func_atanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_atanl_use" >&5 +$as_echo "$glibcxx_cv_func_atanl_use" >&6; } + if test "x$glibcxx_cv_func_atanl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_ATANL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ceill declaration" >&5 +$as_echo_n "checking for ceill declaration... " >&6; } +if ${glibcxx_cv_func_ceill_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef ceill + +int +main () +{ + + void (*f)(void) = (void (*)(void))ceill; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_ceill_use=yes + +else + glibcxx_cv_func_ceill_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ceill_use" >&5 +$as_echo "$glibcxx_cv_func_ceill_use" >&6; } + if test "x$glibcxx_cv_func_ceill_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_CEILL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cosl declaration" >&5 +$as_echo_n "checking for cosl declaration... " >&6; } +if ${glibcxx_cv_func_cosl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef cosl + +int +main () +{ + + void (*f)(void) = (void (*)(void))cosl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_cosl_use=yes + +else + glibcxx_cv_func_cosl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_cosl_use" >&5 +$as_echo "$glibcxx_cv_func_cosl_use" >&6; } + if test "x$glibcxx_cv_func_cosl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_COSL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for coshl declaration" >&5 +$as_echo_n "checking for coshl declaration... " >&6; } +if ${glibcxx_cv_func_coshl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef coshl + +int +main () +{ + + void (*f)(void) = (void (*)(void))coshl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_coshl_use=yes + +else + glibcxx_cv_func_coshl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_coshl_use" >&5 +$as_echo "$glibcxx_cv_func_coshl_use" >&6; } + if test "x$glibcxx_cv_func_coshl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_COSHL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl declaration" >&5 +$as_echo_n "checking for expl declaration... " >&6; } +if ${glibcxx_cv_func_expl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef expl + +int +main () +{ + + void (*f)(void) = (void (*)(void))expl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_expl_use=yes + +else + glibcxx_cv_func_expl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_expl_use" >&5 +$as_echo "$glibcxx_cv_func_expl_use" >&6; } + if test "x$glibcxx_cv_func_expl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fabsl declaration" >&5 +$as_echo_n "checking for fabsl declaration... " >&6; } +if ${glibcxx_cv_func_fabsl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef fabsl + +int +main () +{ + + void (*f)(void) = (void (*)(void))fabsl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_fabsl_use=yes + +else + glibcxx_cv_func_fabsl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fabsl_use" >&5 +$as_echo "$glibcxx_cv_func_fabsl_use" >&6; } + if test "x$glibcxx_cv_func_fabsl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_FABSL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for floorl declaration" >&5 +$as_echo_n "checking for floorl declaration... " >&6; } +if ${glibcxx_cv_func_floorl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef floorl + +int +main () +{ + + void (*f)(void) = (void (*)(void))floorl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_floorl_use=yes + +else + glibcxx_cv_func_floorl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_floorl_use" >&5 +$as_echo "$glibcxx_cv_func_floorl_use" >&6; } + if test "x$glibcxx_cv_func_floorl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_FLOORL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl declaration" >&5 +$as_echo_n "checking for fmodl declaration... " >&6; } +if ${glibcxx_cv_func_fmodl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef fmodl + +int +main () +{ + + void (*f)(void) = (void (*)(void))fmodl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_fmodl_use=yes + +else + glibcxx_cv_func_fmodl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_fmodl_use" >&5 +$as_echo "$glibcxx_cv_func_fmodl_use" >&6; } + if test "x$glibcxx_cv_func_fmodl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_FMODL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpl declaration" >&5 +$as_echo_n "checking for frexpl declaration... " >&6; } +if ${glibcxx_cv_func_frexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef frexpl + +int +main () +{ + + void (*f)(void) = (void (*)(void))frexpl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpl_use=yes + +else + glibcxx_cv_func_frexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpl_use" >&5 +$as_echo "$glibcxx_cv_func_frexpl_use" >&6; } + if test "x$glibcxx_cv_func_frexpl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpl declaration" >&5 +$as_echo_n "checking for ldexpl declaration... " >&6; } +if ${glibcxx_cv_func_ldexpl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef ldexpl + +int +main () +{ + + void (*f)(void) = (void (*)(void))ldexpl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpl_use=yes + +else + glibcxx_cv_func_ldexpl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpl_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpl_use" >&6; } + if test "x$glibcxx_cv_func_ldexpl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log10l declaration" >&5 +$as_echo_n "checking for log10l declaration... " >&6; } +if ${glibcxx_cv_func_log10l_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef log10l + +int +main () +{ + + void (*f)(void) = (void (*)(void))log10l; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_log10l_use=yes + +else + glibcxx_cv_func_log10l_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_log10l_use" >&5 +$as_echo "$glibcxx_cv_func_log10l_use" >&6; } + if test "x$glibcxx_cv_func_log10l_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LOG10L 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl declaration" >&5 +$as_echo_n "checking for logl declaration... " >&6; } +if ${glibcxx_cv_func_logl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef logl + +int +main () +{ + + void (*f)(void) = (void (*)(void))logl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_logl_use=yes + +else + glibcxx_cv_func_logl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_logl_use" >&5 +$as_echo "$glibcxx_cv_func_logl_use" >&6; } + if test "x$glibcxx_cv_func_logl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modfl declaration" >&5 +$as_echo_n "checking for modfl declaration... " >&6; } +if ${glibcxx_cv_func_modfl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef modfl + +int +main () +{ + + void (*f)(void) = (void (*)(void))modfl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_modfl_use=yes + +else + glibcxx_cv_func_modfl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modfl_use" >&5 +$as_echo "$glibcxx_cv_func_modfl_use" >&6; } + if test "x$glibcxx_cv_func_modfl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl declaration" >&5 +$as_echo_n "checking for powl declaration... " >&6; } +if ${glibcxx_cv_func_powl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef powl + +int +main () +{ + + void (*f)(void) = (void (*)(void))powl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_powl_use=yes + +else + glibcxx_cv_func_powl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_powl_use" >&5 +$as_echo "$glibcxx_cv_func_powl_use" >&6; } + if test "x$glibcxx_cv_func_powl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sinl declaration" >&5 +$as_echo_n "checking for sinl declaration... " >&6; } +if ${glibcxx_cv_func_sinl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef sinl + +int +main () +{ + + void (*f)(void) = (void (*)(void))sinl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_sinl_use=yes + +else + glibcxx_cv_func_sinl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sinl_use" >&5 +$as_echo "$glibcxx_cv_func_sinl_use" >&6; } + if test "x$glibcxx_cv_func_sinl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_SINL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sinhl declaration" >&5 +$as_echo_n "checking for sinhl declaration... " >&6; } +if ${glibcxx_cv_func_sinhl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef sinhl + +int +main () +{ + + void (*f)(void) = (void (*)(void))sinhl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_sinhl_use=yes + +else + glibcxx_cv_func_sinhl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sinhl_use" >&5 +$as_echo "$glibcxx_cv_func_sinhl_use" >&6; } + if test "x$glibcxx_cv_func_sinhl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_SINHL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl declaration" >&5 +$as_echo_n "checking for sqrtl declaration... " >&6; } +if ${glibcxx_cv_func_sqrtl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef sqrtl + +int +main () +{ + + void (*f)(void) = (void (*)(void))sqrtl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_sqrtl_use=yes + +else + glibcxx_cv_func_sqrtl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_sqrtl_use" >&5 +$as_echo "$glibcxx_cv_func_sqrtl_use" >&6; } + if test "x$glibcxx_cv_func_sqrtl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_SQRTL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tanl declaration" >&5 +$as_echo_n "checking for tanl declaration... " >&6; } +if ${glibcxx_cv_func_tanl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef tanl + +int +main () +{ + + void (*f)(void) = (void (*)(void))tanl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_tanl_use=yes + +else + glibcxx_cv_func_tanl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_tanl_use" >&5 +$as_echo "$glibcxx_cv_func_tanl_use" >&6; } + if test "x$glibcxx_cv_func_tanl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_TANL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tanhl declaration" >&5 +$as_echo_n "checking for tanhl declaration... " >&6; } +if ${glibcxx_cv_func_tanhl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef tanhl + +int +main () +{ + + void (*f)(void) = (void (*)(void))tanhl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_tanhl_use=yes + +else + glibcxx_cv_func_tanhl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_tanhl_use" >&5 +$as_echo "$glibcxx_cv_func_tanhl_use" >&6; } + if test "x$glibcxx_cv_func_tanhl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_TANHL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotl declaration" >&5 +$as_echo_n "checking for hypotl declaration... " >&6; } +if ${glibcxx_cv_func_hypotl_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef hypotl + +int +main () +{ + + void (*f)(void) = (void (*)(void))hypotl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotl_use=yes + +else + glibcxx_cv_func_hypotl_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotl_use" >&5 +$as_echo "$glibcxx_cv_func_hypotl_use" >&6; } + if test "x$glibcxx_cv_func_hypotl_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldexpf declaration" >&5 +$as_echo_n "checking for ldexpf declaration... " >&6; } +if ${glibcxx_cv_func_ldexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef ldexpf + +int +main () +{ + + void (*f)(void) = (void (*)(void))ldexpf; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_ldexpf_use=yes + +else + glibcxx_cv_func_ldexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_ldexpf_use" >&5 +$as_echo "$glibcxx_cv_func_ldexpf_use" >&6; } + if test "x$glibcxx_cv_func_ldexpf_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LDEXPF 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modff declaration" >&5 +$as_echo_n "checking for modff declaration... " >&6; } +if ${glibcxx_cv_func_modff_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef modff + +int +main () +{ + + void (*f)(void) = (void (*)(void))modff; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_modff_use=yes + +else + glibcxx_cv_func_modff_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_modff_use" >&5 +$as_echo "$glibcxx_cv_func_modff_use" >&6; } + if test "x$glibcxx_cv_func_modff_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_MODFF 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hypotf declaration" >&5 +$as_echo_n "checking for hypotf declaration... " >&6; } +if ${glibcxx_cv_func_hypotf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef hypotf + +int +main () +{ + + void (*f)(void) = (void (*)(void))hypotf; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_hypotf_use=yes + +else + glibcxx_cv_func_hypotf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_hypotf_use" >&5 +$as_echo "$glibcxx_cv_func_hypotf_use" >&6; } + if test "x$glibcxx_cv_func_hypotf_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_HYPOTF 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexpf declaration" >&5 +$as_echo_n "checking for frexpf declaration... " >&6; } +if ${glibcxx_cv_func_frexpf_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifdef HAVE_IEEEFP_H +# include +#endif +#undef frexpf + +int +main () +{ + + void (*f)(void) = (void (*)(void))frexpf; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_func_frexpf_use=yes + +else + glibcxx_cv_func_frexpf_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_frexpf_use" >&5 +$as_echo "$glibcxx_cv_func_frexpf_use" >&6; } + if test "x$glibcxx_cv_func_frexpf_use" = xyes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_FREXPF 1 +_ACEOF + + fi + + + + ;; + *) + as_fn_error $? "No support for this host/target combination." "$LINENO" 5 + ;; +esac + + fi + + # At some point, we should differentiate between architectures + # like x86, which have long double versions, and alpha/powerpc/etc., + # which don't. For the time being, punt. + if test x"long_double_math_on_this_cpu" = x"yes"; then + $as_echo "#define HAVE_ACOSL 1" >>confdefs.h + + $as_echo "#define HAVE_ASINL 1" >>confdefs.h + + $as_echo "#define HAVE_ATAN2L 1" >>confdefs.h + + $as_echo "#define HAVE_ATANL 1" >>confdefs.h + + $as_echo "#define HAVE_CEILL 1" >>confdefs.h + + $as_echo "#define HAVE_COSL 1" >>confdefs.h + + $as_echo "#define HAVE_COSHL 1" >>confdefs.h + + $as_echo "#define HAVE_EXPL 1" >>confdefs.h + + $as_echo "#define HAVE_FABSL 1" >>confdefs.h + + $as_echo "#define HAVE_FLOORL 1" >>confdefs.h + + $as_echo "#define HAVE_FMODL 1" >>confdefs.h + + $as_echo "#define HAVE_FREXPL 1" >>confdefs.h + + $as_echo "#define HAVE_LDEXPL 1" >>confdefs.h + + $as_echo "#define HAVE_LOG10L 1" >>confdefs.h + + $as_echo "#define HAVE_LOGL 1" >>confdefs.h + + $as_echo "#define HAVE_MODFL 1" >>confdefs.h + + $as_echo "#define HAVE_POWL 1" >>confdefs.h + + $as_echo "#define HAVE_SINCOSL 1" >>confdefs.h + + $as_echo "#define HAVE_SINL 1" >>confdefs.h + + $as_echo "#define HAVE_SINHL 1" >>confdefs.h + + $as_echo "#define HAVE_SQRTL 1" >>confdefs.h + + $as_echo "#define HAVE_TANL 1" >>confdefs.h + + $as_echo "#define HAVE_TANHL 1" >>confdefs.h + + fi +fi + +# Check for _Unwind_GetIPInfo. + + +# Check whether --with-system-libunwind was given. +if test "${with_system_libunwind+set}" = set; then : + withval=$with_system_libunwind; +fi + + # If system-libunwind was not specifically set, pick a default setting. + if test x$with_system_libunwind = x; then + case ${target} in + ia64-*-hpux*) with_system_libunwind=yes ;; + *) with_system_libunwind=no ;; + esac + fi + # Based on system-libunwind and target, do we have ipinfo? + if test x$with_system_libunwind = xyes; then + case ${target} in + ia64-*-*) have_unwind_getipinfo=no ;; + *) have_unwind_getipinfo=yes ;; + esac + else + # Darwin before version 9 does not have _Unwind_GetIPInfo. + + case ${target} in + *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;; + *) have_unwind_getipinfo=yes ;; + esac + + fi + + if test x$have_unwind_getipinfo = xyes; then + +$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h + + fi + + + # Check whether --enable-linux-futex was given. +if test "${enable_linux_futex+set}" = set; then : + enableval=$enable_linux_futex; + case "$enableval" in + yes|no|default) ;; + *) as_fn_error $? "Unknown argument to enable/disable linux-futex" "$LINENO" 5 ;; + esac + +else + enable_linux_futex=default +fi + + +case "$target" in + *-linux* | *-uclinux*) + case "$enable_linux_futex" in + default) + # If headers don't have gettid/futex syscalls definition, then + # default to no, otherwise there will be compile time failures. + # Otherwise, default to yes. If we don't detect we are + # compiled/linked against NPTL and not cross-compiling, check + # if programs are run by default against NPTL and if not, issue + # a warning. + enable_linux_futex=no + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + int lk; +int +main () +{ +syscall (SYS_gettid); syscall (SYS_futex, &lk, 0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + save_LIBS="$LIBS" + LIBS="-lpthread $LIBS" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef _GNU_SOURCE + #define _GNU_SOURCE 1 + #endif + #include + pthread_t th; void *status; +int +main () +{ +pthread_tryjoin_np (th, &status); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + enable_linux_futex=yes +else + if test x$cross_compiling = xno; then + if getconf GNU_LIBPTHREAD_VERSION 2>/dev/null \ + | LC_ALL=C grep -i NPTL > /dev/null 2>/dev/null; then :; else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: The kernel might not support futex or gettid syscalls. +If so, please configure with --disable-linux-futex" >&5 +$as_echo "$as_me: WARNING: The kernel might not support futex or gettid syscalls. +If so, please configure with --disable-linux-futex" >&2;} + fi + fi + enable_linux_futex=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$save_LIBS" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ;; + yes) + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + int lk; +int +main () +{ +syscall (SYS_gettid); syscall (SYS_futex, &lk, 0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +else + as_fn_error $? "SYS_gettid and SYS_futex required for --enable-linux-futex" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ;; + esac + ;; + *) + enable_linux_futex=no + ;; +esac +if test x$enable_linux_futex = xyes; then + +$as_echo "#define HAVE_LINUX_FUTEX 1" >>confdefs.h + +fi + + + + +inttype_headers=`echo inttypes.h sys/inttypes.h | sed -e 's/,/ /g'` + +acx_cv_header_stdint=stddef.h +acx_cv_header_stdint_kind="(already complete)" +for i in stdint.h $inttype_headers; do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uintmax_t + unset ac_cv_type_int_least32_t + unset ac_cv_type_int_fast32_t + unset ac_cv_type_uint64_t + $as_echo_n "looking for a compliant stdint.h in $i, " >&6 + ac_fn_c_check_type "$LINENO" "uintmax_t" "ac_cv_type_uintmax_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uintmax_t" = xyes; then : + acx_cv_header_stdint=$i +else + continue +fi + + ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uintptr_t" = xyes; then : + +else + acx_cv_header_stdint_kind="(mostly complete)" +fi + + ac_fn_c_check_type "$LINENO" "int_least32_t" "ac_cv_type_int_least32_t" "#include +#include <$i> +" +if test "x$ac_cv_type_int_least32_t" = xyes; then : + +else + acx_cv_header_stdint_kind="(mostly complete)" +fi + + ac_fn_c_check_type "$LINENO" "int_fast32_t" "ac_cv_type_int_fast32_t" "#include +#include <$i> +" +if test "x$ac_cv_type_int_fast32_t" = xyes; then : + +else + acx_cv_header_stdint_kind="(mostly complete)" +fi + + ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uint64_t" = xyes; then : + +else + acx_cv_header_stdint_kind="(lacks uint64_t)" +fi + + break +done +if test "$acx_cv_header_stdint" = stddef.h; then + acx_cv_header_stdint_kind="(lacks uintmax_t)" + for i in stdint.h $inttype_headers; do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uint32_t + unset ac_cv_type_uint64_t + $as_echo_n "looking for an incomplete stdint.h in $i, " >&6 + ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uint32_t" = xyes; then : + acx_cv_header_stdint=$i +else + continue +fi + + ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uint64_t" = xyes; then : + +fi + + ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uintptr_t" = xyes; then : + +fi + + break + done +fi +if test "$acx_cv_header_stdint" = stddef.h; then + acx_cv_header_stdint_kind="(u_intXX_t style)" + for i in sys/types.h $inttype_headers; do + unset ac_cv_type_u_int32_t + unset ac_cv_type_u_int64_t + $as_echo_n "looking for u_intXX_t types in $i, " >&6 + ac_fn_c_check_type "$LINENO" "u_int32_t" "ac_cv_type_u_int32_t" "#include +#include <$i> +" +if test "x$ac_cv_type_u_int32_t" = xyes; then : + acx_cv_header_stdint=$i +else + continue +fi + + ac_fn_c_check_type "$LINENO" "u_int64_t" "ac_cv_type_u_int64_t" "#include +#include <$i> +" +if test "x$ac_cv_type_u_int64_t" = xyes; then : + +fi + + break + done +fi +if test "$acx_cv_header_stdint" = stddef.h; then + acx_cv_header_stdint_kind="(using manual detection)" +fi + +test -z "$ac_cv_type_uintptr_t" && ac_cv_type_uintptr_t=no +test -z "$ac_cv_type_uint64_t" && ac_cv_type_uint64_t=no +test -z "$ac_cv_type_u_int64_t" && ac_cv_type_u_int64_t=no +test -z "$ac_cv_type_int_least32_t" && ac_cv_type_int_least32_t=no +test -z "$ac_cv_type_int_fast32_t" && ac_cv_type_int_fast32_t=no + +# ----------------- Summarize what we found so far + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what to include in include/gstdint.h" >&5 +$as_echo_n "checking what to include in include/gstdint.h... " >&6; } + +case `$as_basename -- include/gstdint.h || +$as_expr X/include/gstdint.h : '.*/\([^/][^/]*\)/*$' \| \ + Xinclude/gstdint.h : 'X\(//\)$' \| \ + Xinclude/gstdint.h : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/include/gstdint.h | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` in + stdint.h) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: are you sure you want it there?" >&5 +$as_echo "$as_me: WARNING: are you sure you want it there?" >&2;} ;; + inttypes.h) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: are you sure you want it there?" >&5 +$as_echo "$as_me: WARNING: are you sure you want it there?" >&2;} ;; + *) ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_header_stdint $acx_cv_header_stdint_kind" >&5 +$as_echo "$acx_cv_header_stdint $acx_cv_header_stdint_kind" >&6; } + +# ----------------- done included file, check C basic types -------- + +# Lacking an uintptr_t? Test size of void * +case "$acx_cv_header_stdint:$ac_cv_type_uintptr_t" in + stddef.h:* | *:no) # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +$as_echo_n "checking size of void *... " >&6; } +if ${ac_cv_sizeof_void_p+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_void_p" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_void_p=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +$as_echo "$ac_cv_sizeof_void_p" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_VOID_P $ac_cv_sizeof_void_p +_ACEOF + + ;; +esac + +# Lacking an uint64_t? Test size of long +case "$acx_cv_header_stdint:$ac_cv_type_uint64_t:$ac_cv_type_u_int64_t" in + stddef.h:*:* | *:no:no) # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +$as_echo_n "checking size of long... " >&6; } +if ${ac_cv_sizeof_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (long) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +$as_echo "$ac_cv_sizeof_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + ;; +esac + +if test $acx_cv_header_stdint = stddef.h; then + # Lacking a good header? Test size of everything and deduce all types. + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +$as_echo_n "checking size of int... " >&6; } +if ${ac_cv_sizeof_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_int" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (int) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_int=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +$as_echo "$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 +$as_echo_n "checking size of short... " >&6; } +if ${ac_cv_sizeof_short+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_short" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (short) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_short=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 +$as_echo "$ac_cv_sizeof_short" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +_ACEOF + + + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 +$as_echo_n "checking size of char... " >&6; } +if ${ac_cv_sizeof_char+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_char" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (char) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_char=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 +$as_echo "$ac_cv_sizeof_char" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_CHAR $ac_cv_sizeof_char +_ACEOF + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int8_t" >&5 +$as_echo_n "checking for type equivalent to int8_t... " >&6; } + case "$ac_cv_sizeof_char" in + 1) acx_cv_type_int8_t=char ;; + *) as_fn_error $? "no 8-bit type, please report a bug" "$LINENO" 5 + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int8_t" >&5 +$as_echo "$acx_cv_type_int8_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int16_t" >&5 +$as_echo_n "checking for type equivalent to int16_t... " >&6; } + case "$ac_cv_sizeof_int:$ac_cv_sizeof_short" in + 2:*) acx_cv_type_int16_t=int ;; + *:2) acx_cv_type_int16_t=short ;; + *) as_fn_error $? "no 16-bit type, please report a bug" "$LINENO" 5 + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int16_t" >&5 +$as_echo "$acx_cv_type_int16_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int32_t" >&5 +$as_echo_n "checking for type equivalent to int32_t... " >&6; } + case "$ac_cv_sizeof_int:$ac_cv_sizeof_long" in + 4:*) acx_cv_type_int32_t=int ;; + *:4) acx_cv_type_int32_t=long ;; + *) as_fn_error $? "no 32-bit type, please report a bug" "$LINENO" 5 + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int32_t" >&5 +$as_echo "$acx_cv_type_int32_t" >&6; } +fi + +# These tests are here to make the output prettier + +if test "$ac_cv_type_uint64_t" != yes && test "$ac_cv_type_u_int64_t" != yes; then + case "$ac_cv_sizeof_long" in + 8) acx_cv_type_int64_t=long ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int64_t" >&5 +$as_echo_n "checking for type equivalent to int64_t... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${acx_cv_type_int64_t-'using preprocessor symbols'}" >&5 +$as_echo "${acx_cv_type_int64_t-'using preprocessor symbols'}" >&6; } +fi + +# Now we can use the above types + +if test "$ac_cv_type_uintptr_t" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to intptr_t" >&5 +$as_echo_n "checking for type equivalent to intptr_t... " >&6; } + case $ac_cv_sizeof_void_p in + 2) acx_cv_type_intptr_t=int16_t ;; + 4) acx_cv_type_intptr_t=int32_t ;; + 8) acx_cv_type_intptr_t=int64_t ;; + *) as_fn_error $? "no equivalent for intptr_t, please report a bug" "$LINENO" 5 + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_intptr_t" >&5 +$as_echo "$acx_cv_type_intptr_t" >&6; } +fi + +# ----------------- done all checks, emit header ------------- +ac_config_commands="$ac_config_commands include/gstdint.h" + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU c++filt" >&5 +$as_echo_n "checking for GNU c++filt... " >&6; } +if ${ac_cv_path_CXXFILT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$CXXFILT"; then + ac_path_CXXFILT_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in c++filt gc++filt; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_CXXFILT="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_CXXFILT" || continue +# Check for GNU $ac_path_CXXFILT +case `"$ac_path_CXXFILT" --version 2>&1` in +*GNU*) + ac_cv_path_CXXFILT=$ac_path_CXXFILT && ac_path_CXXFILT_found=:;; +esac + + $ac_path_CXXFILT_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_CXXFILT"; then + : + fi +else + ac_cv_path_CXXFILT=$CXXFILT +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_CXXFILT" >&5 +$as_echo "$ac_cv_path_CXXFILT" >&6; } + CXXFILT=$ac_cv_path_CXXFILT + + + + # Check whether --enable-symvers was given. +if test "${enable_symvers+set}" = set; then : + enableval=$enable_symvers; + case "$enableval" in + yes|no|gnu|gnu-versioned-namespace|darwin|darwin-export|sun) ;; + *) as_fn_error $? "Unknown argument to enable/disable symvers" "$LINENO" 5 ;; + esac + +else + enable_symvers=yes +fi + + + +# If we never went through the GLIBCXX_CHECK_LINKER_FEATURES macro, then we +# don't know enough about $LD to do tricks... + +# Sun style symbol versions needs GNU c++filt for make_sunver.pl to work +# with extern "C++" in version scripts. + + +# Turn a 'yes' into a suitable default. +if test x$enable_symvers = xyes ; then + if test $enable_shared = no || test "x$LD" = x || test x$gcc_no_link = xyes; then + enable_symvers=no + else + if test $with_gnu_ld = yes ; then + case ${target_os} in + hpux*) + enable_symvers=no ;; + *) + enable_symvers=gnu ;; + esac + else + case ${target_os} in + darwin*) + enable_symvers=darwin ;; + # Sun symbol versioning exists since Solaris 2.5. + solaris2.[5-9]* | solaris2.1[0-9]*) + # make_sunver.pl needs GNU c++filt to support extern "C++" in + # version scripts, so disable symbol versioning if none can be + # found. + if test -z "$ac_cv_path_CXXFILT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === You have requested Sun symbol versioning, but" >&5 +$as_echo "$as_me: WARNING: === You have requested Sun symbol versioning, but" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === no GNU c++filt could be found." >&5 +$as_echo "$as_me: WARNING: === no GNU c++filt could be found." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === Symbol versioning will be disabled." >&5 +$as_echo "$as_me: WARNING: === Symbol versioning will be disabled." >&2;} + enable_symvers=no + else + enable_symvers=sun + fi + ;; + *) + enable_symvers=no ;; + esac + fi + fi +fi + +# Check to see if 'darwin' or 'darwin-export' can win. +if test x$enable_symvers = xdarwin-export ; then + enable_symvers=darwin +fi + +# Check if 'sun' was requested on non-Solaris 2 platforms. +if test x$enable_symvers = xsun ; then + case ${target_os} in + solaris2*) + # All fine. + ;; + *) + # Unlikely to work. + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === You have requested Sun symbol versioning, but" >&5 +$as_echo "$as_me: WARNING: === You have requested Sun symbol versioning, but" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === you are not targetting Solaris 2." >&5 +$as_echo "$as_me: WARNING: === you are not targetting Solaris 2." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === Symbol versioning will be disabled." >&5 +$as_echo "$as_me: WARNING: === Symbol versioning will be disabled." >&2;} + enable_symvers=no + ;; + esac +fi + +# Check to see if 'gnu' can win. +if test $enable_symvers = gnu || + test $enable_symvers = gnu-versioned-namespace || + test $enable_symvers = sun; then + # Check to see if libgcc_s exists, indicating that shared libgcc is possible. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared libgcc" >&5 +$as_echo_n "checking for shared libgcc... " >&6; } + ac_save_CFLAGS="$CFLAGS" + CFLAGS=' -lgcc_s' + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + glibcxx_shared_libgcc=yes +else + glibcxx_shared_libgcc=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$ac_save_CFLAGS" + if test $glibcxx_shared_libgcc = no; then + cat > conftest.c <&1 >/dev/null \ + | sed -n 's/^.* -lgcc_s\([^ ]*\) .*$/\1/p'` + rm -f conftest.c conftest.so + if test x${glibcxx_libgcc_s_suffix+set} = xset; then + CFLAGS=" -lgcc_s$glibcxx_libgcc_s_suffix" + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + glibcxx_shared_libgcc=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$ac_save_CFLAGS" + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_shared_libgcc" >&5 +$as_echo "$glibcxx_shared_libgcc" >&6; } + + # For GNU ld, we need at least this version. The format is described in + # GLIBCXX_CHECK_LINKER_FEATURES above. + glibcxx_min_gnu_ld_version=21400 + + # If no shared libgcc, can't win. + if test $glibcxx_shared_libgcc != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === You have requested GNU symbol versioning, but" >&5 +$as_echo "$as_me: WARNING: === You have requested GNU symbol versioning, but" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === you are not building a shared libgcc_s." >&5 +$as_echo "$as_me: WARNING: === you are not building a shared libgcc_s." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === Symbol versioning will be disabled." >&5 +$as_echo "$as_me: WARNING: === Symbol versioning will be disabled." >&2;} + enable_symvers=no + elif test $with_gnu_ld != yes && test $enable_symvers = sun; then + : All interesting versions of Sun ld support sun style symbol versioning. + elif test $with_gnu_ld != yes ; then + # just fail for now + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === You have requested GNU symbol versioning, but" >&5 +$as_echo "$as_me: WARNING: === You have requested GNU symbol versioning, but" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === you are not using the GNU linker." >&5 +$as_echo "$as_me: WARNING: === you are not using the GNU linker." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === Symbol versioning will be disabled." >&5 +$as_echo "$as_me: WARNING: === Symbol versioning will be disabled." >&2;} + enable_symvers=no + elif test $glibcxx_ld_is_gold = yes ; then + : All versions of gold support symbol versioning. + elif test $glibcxx_gnu_ld_version -lt $glibcxx_min_gnu_ld_version ; then + # The right tools, the right setup, but too old. Fallbacks? + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === Linker version $glibcxx_gnu_ld_version is too old for" >&5 +$as_echo "$as_me: WARNING: === Linker version $glibcxx_gnu_ld_version is too old for" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === full symbol versioning support in this release of GCC." >&5 +$as_echo "$as_me: WARNING: === full symbol versioning support in this release of GCC." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === You would need to upgrade your binutils to version" >&5 +$as_echo "$as_me: WARNING: === You would need to upgrade your binutils to version" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === $glibcxx_min_gnu_ld_version or later and rebuild GCC." >&5 +$as_echo "$as_me: WARNING: === $glibcxx_min_gnu_ld_version or later and rebuild GCC." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: === Symbol versioning will be disabled." >&5 +$as_echo "$as_me: WARNING: === Symbol versioning will be disabled." >&2;} + enable_symvers=no + fi +fi + +# For libtool versioning info, format is CURRENT:REVISION:AGE +libtool_VERSION=6:29:0 + +# Everything parsed; figure out what files and settings to use. +case $enable_symvers in + no) + SYMVER_FILE=config/abi/pre/none.ver + ;; + gnu) + SYMVER_FILE=config/abi/pre/gnu.ver + +$as_echo "#define _GLIBCXX_SYMVER_GNU 1" >>confdefs.h + + ;; + gnu-versioned-namespace) + libtool_VERSION=8:0:0 + SYMVER_FILE=config/abi/pre/gnu-versioned-namespace.ver + +$as_echo "#define _GLIBCXX_SYMVER_GNU_NAMESPACE 1" >>confdefs.h + + ;; + darwin) + SYMVER_FILE=config/abi/pre/gnu.ver + +$as_echo "#define _GLIBCXX_SYMVER_DARWIN 1" >>confdefs.h + + ;; + sun) + SYMVER_FILE=config/abi/pre/gnu.ver + +$as_echo "#define _GLIBCXX_SYMVER_SUN 1" >>confdefs.h + + ;; +esac + +if test x$enable_symvers != xno ; then + +$as_echo "#define _GLIBCXX_SYMVER 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports .symver directive" >&5 +$as_echo_n "checking whether the target supports .symver directive... " >&6; } +if ${glibcxx_cv_have_as_symver_directive+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +void foo (void); __asm (".symver foo, bar@SYMVER"); +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_have_as_symver_directive=yes +else + glibcxx_cv_have_as_symver_directive=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_have_as_symver_directive" >&5 +$as_echo "$glibcxx_cv_have_as_symver_directive" >&6; } +if test $glibcxx_cv_have_as_symver_directive = yes; then + +$as_echo "#define HAVE_AS_SYMVER_DIRECTIVE 1" >>confdefs.h + +fi + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: versioning on shared library symbols is $enable_symvers" >&5 +$as_echo "$as_me: versioning on shared library symbols is $enable_symvers" >&6;} + +if test $enable_symvers != no ; then + case ${target_os} in + # The Solaris 2 runtime linker doesn't support the GNU extension of + # binding the same symbol to different versions + solaris2*) + ;; + # Other platforms with GNU symbol versioning (GNU/Linux, more?) do. + *) + +$as_echo "#define HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT 1" >>confdefs.h + + ;; + esac +fi + +# Now, set up compatibility support, if any. +# In addition, need this to deal with std::size_t mangling in +# src/compatibility.cc. In a perfect world, could use +# typeid(std::size_t).name()[0] to do direct substitution. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for size_t as unsigned int" >&5 +$as_echo_n "checking for size_t as unsigned int... " >&6; } +ac_save_CFLAGS="$CFLAGS" +CFLAGS="-Werror" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__SIZE_TYPE__* stp; unsigned int* uip; stp = uip; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_size_t_is_i=yes +else + glibcxx_size_t_is_i=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS=$ac_save_CFLAGS +if test "$glibcxx_size_t_is_i" = yes; then + +$as_echo "#define _GLIBCXX_SIZE_T_IS_UINT 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_size_t_is_i" >&5 +$as_echo "$glibcxx_size_t_is_i" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ptrdiff_t as int" >&5 +$as_echo_n "checking for ptrdiff_t as int... " >&6; } +ac_save_CFLAGS="$CFLAGS" +CFLAGS="-Werror" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__PTRDIFF_TYPE__* ptp; int* ip; ptp = ip; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_ptrdiff_t_is_i=yes +else + glibcxx_ptrdiff_t_is_i=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS=$ac_save_CFLAGS +if test "$glibcxx_ptrdiff_t_is_i" = yes; then + +$as_echo "#define _GLIBCXX_PTRDIFF_T_IS_INT 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_ptrdiff_t_is_i" >&5 +$as_echo "$glibcxx_ptrdiff_t_is_i" >&6; } + + + + + # Check whether --enable-libstdcxx-visibility was given. +if test "${enable_libstdcxx_visibility+set}" = set; then : + enableval=$enable_libstdcxx_visibility; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable libstdcxx-visibility must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_libstdcxx_visibility=yes +fi + + + +if test x$enable_libstdcxx_visibility = xyes ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports hidden visibility" >&5 +$as_echo_n "checking whether the target supports hidden visibility... " >&6; } +if ${glibcxx_cv_have_attribute_visibility+:} false; then : + $as_echo_n "(cached) " >&6 +else + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +void __attribute__((visibility("hidden"))) foo(void) { } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_have_attribute_visibility=yes +else + glibcxx_cv_have_attribute_visibility=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_have_attribute_visibility" >&5 +$as_echo "$glibcxx_cv_have_attribute_visibility" >&6; } + if test $glibcxx_cv_have_attribute_visibility = no; then + enable_libstdcxx_visibility=no + fi +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: visibility supported: $enable_libstdcxx_visibility" >&5 +$as_echo "$as_me: visibility supported: $enable_libstdcxx_visibility" >&6;} + + + + # Check whether --enable-libstdcxx-dual-abi was given. +if test "${enable_libstdcxx_dual_abi+set}" = set; then : + enableval=$enable_libstdcxx_dual_abi; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable libstdcxx-dual-abi must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_libstdcxx_dual_abi=yes +fi + + + if test x$enable_symvers = xgnu-versioned-namespace; then + # gnu-versioned-namespace is incompatible with the dual ABI. + enable_libstdcxx_dual_abi="no" + fi + if test x"$enable_libstdcxx_dual_abi" != xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: dual ABI is disabled" >&5 +$as_echo "$as_me: dual ABI is disabled" >&6;} + default_libstdcxx_abi="gcc4-compatible" + fi + + + + if test x$enable_libstdcxx_dual_abi = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for default std::string ABI to use" >&5 +$as_echo_n "checking for default std::string ABI to use... " >&6; } + +# Check whether --with-default-libstdcxx-abi was given. +if test "${with_default_libstdcxx_abi+set}" = set; then : + withval=$with_default_libstdcxx_abi; case "$withval" in + gcc4-compatible) default_libstdcxx_abi="gcc4-compatible" ;; + new|cxx11) default_libstdcxx_abi="new" ;; + c++*|gnu++*) as_fn_error $? "Supported arguments for --with-default-libstdcxx-abi have changed, use \"new\" or \"gcc4-compatible\"" "$LINENO" 5 ;; + *) as_fn_error $? "Invalid argument for --with-default-libstdcxx-abi" "$LINENO" 5 ;; + esac + +else + default_libstdcxx_abi="new" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${default_libstdcxx_abi}" >&5 +$as_echo "${default_libstdcxx_abi}" >&6; } + fi + if test $default_libstdcxx_abi = "new"; then + glibcxx_cxx11_abi=1 + glibcxx_cxx98_abi=0 + else + glibcxx_cxx11_abi=0 + glibcxx_cxx98_abi=1 + fi + + + + +ac_ldbl_compat=no +ac_ldbl_alt128_compat=no +ac_ldbl_ieee128_default=no +LONG_DOUBLE_COMPAT_FLAGS="-mlong-double-64" +LONG_DOUBLE_128_FLAGS= +LONG_DOUBLE_ALT128_COMPAT_FLAGS= +case "$target" in + powerpc*-*-linux* | \ + sparc*-*-linux* | \ + s390*-*-linux* | \ + alpha*-*-linux*) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +#if !defined __LONG_DOUBLE_128__ || (defined(__sparc__) && defined(__arch64__)) +#error no need for long double compatibility +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_ldbl_compat=yes +else + ac_ldbl_compat=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$ac_ldbl_compat" = yes; then + +$as_echo "#define _GLIBCXX_LONG_DOUBLE_COMPAT 1" >>confdefs.h + + port_specific_symbol_files="\$(top_srcdir)/config/os/gnu-linux/ldbl-extra.ver" + case "$target" in + powerpc*-*-linux*) + LONG_DOUBLE_COMPAT_FLAGS="$LONG_DOUBLE_COMPAT_FLAGS -mno-gnu-attribute" + # Check for IEEE128 support in libm: + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __frexpieee128 in -lm" >&5 +$as_echo_n "checking for __frexpieee128 in -lm... " >&6; } +if ${ac_cv_lib_m___frexpieee128+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __frexpieee128 (); +int +main () +{ +return __frexpieee128 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m___frexpieee128=yes +else + ac_cv_lib_m___frexpieee128=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m___frexpieee128" >&5 +$as_echo "$ac_cv_lib_m___frexpieee128" >&6; } +if test "x$ac_cv_lib_m___frexpieee128" = xyes; then : + ac_ldbl_ieee128_in_libc=yes +else + ac_ldbl_ieee128_in_libc=no +fi + + if test $ac_ldbl_ieee128_in_libc = yes; then + # Determine which long double format is the compiler's default: + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + #ifndef __LONG_DOUBLE_IEEE128__ + #error compiler defaults to ibm128 + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_ldbl_ieee128_default=yes +else + ac_ldbl_ieee128_default=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + # Library objects should use default long double format. + if test "$ac_ldbl_ieee128_default" = yes; then + LONG_DOUBLE_128_FLAGS="-mno-gnu-attribute" + # Except for the ones that explicitly use these flags: + LONG_DOUBLE_ALT128_COMPAT_FLAGS="-mabi=ibmlongdouble -mno-gnu-attribute -Wno-psabi" + else + LONG_DOUBLE_128_FLAGS="-mno-gnu-attribute" + LONG_DOUBLE_ALT128_COMPAT_FLAGS="-mabi=ieeelongdouble -mno-gnu-attribute -Wno-psabi" + fi + +$as_echo "#define _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT 1" >>confdefs.h + + port_specific_symbol_files="$port_specific_symbol_files \$(top_srcdir)/config/os/gnu-linux/ldbl-ieee128-extra.ver" + ac_ldbl_alt128_compat=yes + else + ac_ldbl_alt128_compat=no + fi + ;; + esac + fi +esac + + + + + + +# Check if assembler supports disabling hardware capability support. + + test -z "$HWCAP_CFLAGS" && HWCAP_CFLAGS='' + + # Restrict the test to Solaris, other assemblers (e.g. AIX as) have -nH + # with a different meaning. + case ${target_os} in + solaris2*) + ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wa,-nH" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for as that supports -Wa,-nH" >&5 +$as_echo_n "checking for as that supports -Wa,-nH... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hwcap_flags=yes +else + ac_hwcap_flags=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$ac_hwcap_flags" = "yes"; then + HWCAP_CFLAGS="-Wa,-nH $HWCAP_CFLAGS" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_hwcap_flags" >&5 +$as_echo "$ac_hwcap_flags" >&6; } + + CFLAGS="$ac_save_CFLAGS" + ;; + esac + + + + +# Check if assembler supports rdrand opcode. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rdrand support in assembler" >&5 +$as_echo_n "checking for rdrand support in assembler... " >&6; } + if ${ac_cv_x86_rdrand+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_cv_x86_rdrand=no + case "$target" in + i?86-*-* | \ + x86_64-*-*) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +asm("rdrand %eax"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_x86_rdrand=yes +else + ac_cv_x86_rdrand=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + esac + +fi + + if test $ac_cv_x86_rdrand = yes; then + +$as_echo "#define _GLIBCXX_X86_RDRAND 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_x86_rdrand" >&5 +$as_echo "$ac_cv_x86_rdrand" >&6; } + +# Check if assembler supports rdseed opcode. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rdseed support in assembler" >&5 +$as_echo_n "checking for rdseed support in assembler... " >&6; } + if ${ac_cv_x86_rdseed+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_cv_x86_rdseed=no + case "$target" in + i?86-*-* | \ + x86_64-*-*) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +asm("rdseed %eax"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_x86_rdseed=yes +else + ac_cv_x86_rdseed=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + esac + +fi + + if test $ac_cv_x86_rdseed = yes; then + +$as_echo "#define _GLIBCXX_X86_RDSEED 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_x86_rdseed" >&5 +$as_echo "$ac_cv_x86_rdseed" >&6; } + + +# This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE. + + # Do checks for resource limit functions. + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + setrlimit_have_headers=yes + for ac_header in unistd.h sys/time.h sys/resource.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else + setrlimit_have_headers=no +fi + +done + + # If don't have the headers, then we can't run the tests now, and we + # won't be seeing any of these during testsuite compilation. + if test $setrlimit_have_headers = yes; then + # Can't do these in a loop, else the resulting syntax is wrong. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RLIMIT_DATA" >&5 +$as_echo_n "checking for RLIMIT_DATA... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ + int f = RLIMIT_DATA ; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_mresult=1 +else + glibcxx_mresult=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat >>confdefs.h <<_ACEOF +#define HAVE_LIMIT_DATA $glibcxx_mresult +_ACEOF + + if test $glibcxx_mresult = 1 ; then res=yes ; else res=no ; fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $res" >&5 +$as_echo "$res" >&6; } + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RLIMIT_RSS" >&5 +$as_echo_n "checking for RLIMIT_RSS... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ + int f = RLIMIT_RSS ; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_mresult=1 +else + glibcxx_mresult=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat >>confdefs.h <<_ACEOF +#define HAVE_LIMIT_RSS $glibcxx_mresult +_ACEOF + + if test $glibcxx_mresult = 1 ; then res=yes ; else res=no ; fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $res" >&5 +$as_echo "$res" >&6; } + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RLIMIT_VMEM" >&5 +$as_echo_n "checking for RLIMIT_VMEM... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ + int f = RLIMIT_VMEM ; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_mresult=1 +else + glibcxx_mresult=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat >>confdefs.h <<_ACEOF +#define HAVE_LIMIT_VMEM $glibcxx_mresult +_ACEOF + + if test $glibcxx_mresult = 1 ; then res=yes ; else res=no ; fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $res" >&5 +$as_echo "$res" >&6; } + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RLIMIT_AS" >&5 +$as_echo_n "checking for RLIMIT_AS... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ + int f = RLIMIT_AS ; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_mresult=1 +else + glibcxx_mresult=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat >>confdefs.h <<_ACEOF +#define HAVE_LIMIT_AS $glibcxx_mresult +_ACEOF + + if test $glibcxx_mresult = 1 ; then res=yes ; else res=no ; fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $res" >&5 +$as_echo "$res" >&6; } + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RLIMIT_FSIZE" >&5 +$as_echo_n "checking for RLIMIT_FSIZE... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ + int f = RLIMIT_FSIZE ; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_mresult=1 +else + glibcxx_mresult=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat >>confdefs.h <<_ACEOF +#define HAVE_LIMIT_FSIZE $glibcxx_mresult +_ACEOF + + if test $glibcxx_mresult = 1 ; then res=yes ; else res=no ; fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $res" >&5 +$as_echo "$res" >&6; } + + + # Check for rlimit, setrlimit. + if ${glibcxx_cv_setrlimit+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + +int +main () +{ +struct rlimit r; + setrlimit(0, &r); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_setrlimit=yes +else + glibcxx_cv_setrlimit=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for testsuite resource limits support" >&5 +$as_echo_n "checking for testsuite resource limits support... " >&6; } + if test $setrlimit_have_headers = yes && test $glibcxx_cv_setrlimit = yes; then + ac_res_limits=yes + +$as_echo "#define _GLIBCXX_RES_LIMITS 1" >>confdefs.h + + else + ac_res_limits=no + fi + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res_limits" >&5 +$as_echo "$ac_res_limits" >&6; } + + + if $GLIBCXX_IS_NATIVE ; then + # Look for setenv, so that extended locale tests can be performed. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setenv declaration" >&5 +$as_echo_n "checking for setenv declaration... " >&6; } + if test x${glibcxx_cv_func_setenv_use+set} != xset; then + if ${glibcxx_cv_func_setenv_use+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + setenv(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_func_setenv_use=yes +else + glibcxx_cv_func_setenv_use=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_func_setenv_use" >&5 +$as_echo "$glibcxx_cv_func_setenv_use" >&6; } + if test x$glibcxx_cv_func_setenv_use = x"yes"; then + for ac_func in setenv +do : + ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv" +if test "x$ac_cv_func_setenv" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SETENV 1 +_ACEOF + +fi +done + + fi + + fi + + if $GLIBCXX_IS_NATIVE && test $is_hosted = yes && + test $enable_symvers != no; then + case "$host" in + *-*-cygwin*) + enable_abi_check=no ;; + *) + enable_abi_check=yes ;; + esac + else + # Only build this as native, since automake does not understand + # CXX_FOR_BUILD. + enable_abi_check=no + fi + + # Export file names for ABI checking. + baseline_dir="$glibcxx_srcdir/config/abi/post/${abi_baseline_pair}" + + baseline_subdir_switch="$abi_baseline_subdir_switch" + + + +# For gthread support. Depends on GLIBCXX_ENABLE_SYMVERS. + + # Check whether --enable-libstdcxx-threads was given. +if test "${enable_libstdcxx_threads+set}" = set; then : + enableval=$enable_libstdcxx_threads; + case "$enableval" in + yes|no) ;; + *) as_fn_error $? "Argument to enable/disable libstdcxx-threads must be yes or no" "$LINENO" 5 ;; + esac + +else + enable_libstdcxx_threads=auto +fi + + + + if test x$enable_libstdcxx_threads = xauto || + test x$enable_libstdcxx_threads = xyes; then + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions \ + -I${toplevel_srcdir}/libgcc -I${toplevel_builddir}/libgcc" + + target_thread_file=`$CXX -v 2>&1 | sed -n 's/^Thread model: //p'` + case $target_thread_file in + posix) + CXXFLAGS="$CXXFLAGS -DSUPPORTS_WEAK -DGTHREAD_USE_WEAK -D_PTHREADS" + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it can be safely assumed that mutex_timedlock is available" >&5 +$as_echo_n "checking whether it can be safely assumed that mutex_timedlock is available... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + // In case of POSIX threads check _POSIX_TIMEOUTS. + #if (defined(_PTHREADS) \ + && (!defined(_POSIX_TIMEOUTS) || _POSIX_TIMEOUTS <= 0)) + #error + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_gthread_use_mutex_timedlock=1 +else + ac_gthread_use_mutex_timedlock=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + +cat >>confdefs.h <<_ACEOF +#define _GTHREAD_USE_MUTEX_TIMEDLOCK $ac_gthread_use_mutex_timedlock +_ACEOF + + + if test $ac_gthread_use_mutex_timedlock = 1 ; then res_mutex_timedlock=yes ; + else res_mutex_timedlock=no ; fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $res_mutex_timedlock" >&5 +$as_echo "$res_mutex_timedlock" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gthreads library" >&5 +$as_echo_n "checking for gthreads library... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include "gthr.h" +int +main () +{ + + #ifndef __GTHREADS_CXX0X + #error + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_has_gthreads=yes +else + ac_has_gthreads=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + else + ac_has_gthreads=no + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_gthreads" >&5 +$as_echo "$ac_has_gthreads" >&6; } + + if test x"$ac_has_gthreads" = x"yes"; then + +$as_echo "#define _GLIBCXX_HAS_GTHREADS 1" >>confdefs.h + + + # Also check for pthread_rwlock_t for std::shared_timed_mutex in C++14 + # but only do so if we're using pthread in the gthread library. + # On VxWorks for example, pthread_rwlock_t is defined in sys/types.h + # but the pthread library is not there by default and the gthread library + # does not use it. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include "gthr.h" +int +main () +{ + + #if (!defined(_PTHREADS)) + #error + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_gthread_use_pthreads=yes +else + ac_gthread_use_pthreads=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test x"$ac_gthread_use_pthreads" = x"yes"; then + ac_fn_cxx_check_type "$LINENO" "pthread_rwlock_t" "ac_cv_type_pthread_rwlock_t" "#include \"gthr.h\" +" +if test "x$ac_cv_type_pthread_rwlock_t" = xyes; then : + +$as_echo "#define _GLIBCXX_USE_PTHREAD_RWLOCK_T 1" >>confdefs.h + +fi + + fi + fi + + ac_fn_cxx_check_header_mongrel "$LINENO" "semaphore.h" "ac_cv_header_semaphore_h" "$ac_includes_default" +if test "x$ac_cv_header_semaphore_h" = xyes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for POSIX Semaphores and sem_timedwait" >&5 +$as_echo_n "checking for POSIX Semaphores and sem_timedwait... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + +int +main () +{ + + #if !defined _POSIX_TIMEOUTS || _POSIX_TIMEOUTS <= 0 + # error "POSIX Timeouts option not supported" + #elif !defined _POSIX_SEMAPHORES || _POSIX_SEMAPHORES <= 0 + # error "POSIX Semaphores option not supported" + #else + #if defined SEM_VALUE_MAX + constexpr int sem_value_max = SEM_VALUE_MAX; + #elif defined _POSIX_SEM_VALUE_MAX + constexpr int sem_value_max = _POSIX_SEM_VALUE_MAX; + #else + # error "SEM_VALUE_MAX not available" + #endif + sem_t sem; + sem_init(&sem, 0, sem_value_max); + struct timespec ts = { 0 }; + sem_timedwait(&sem, &ts); + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_have_posix_semaphore=yes +else + ac_have_posix_semaphore=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + ac_have_posix_semaphore=no +fi + + + + if test $ac_have_posix_semaphore = yes ; then + +$as_echo "#define HAVE_POSIX_SEMAPHORE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_have_posix_semaphore" >&5 +$as_echo "$ac_have_posix_semaphore" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For Filesystem TS. +for ac_header in fcntl.h dirent.h sys/statvfs.h utime.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + # Check whether --enable-libstdcxx-filesystem-ts was given. +if test "${enable_libstdcxx_filesystem_ts+set}" = set; then : + enableval=$enable_libstdcxx_filesystem_ts; + case "$enableval" in + yes|no|auto) ;; + *) as_fn_error $? "Unknown argument to enable/disable libstdcxx-filesystem-ts" "$LINENO" 5 ;; + esac + +else + enable_libstdcxx_filesystem_ts=auto +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Filesystem TS support" >&5 +$as_echo_n "checking whether to build Filesystem TS support... " >&6; } + if test x"$ac_cv_header_dirent_h" != x"yes"; then + enable_libstdcxx_filesystem_ts=no + fi + if test x"$enable_libstdcxx_filesystem_ts" = x"auto"; then + case "${target_os}" in + freebsd*|netbsd*|openbsd*|dragonfly*|darwin*) + enable_libstdcxx_filesystem_ts=yes + ;; + gnu* | linux* | kfreebsd*-gnu | knetbsd*-gnu | uclinux*) + enable_libstdcxx_filesystem_ts=yes + ;; + rtems*) + enable_libstdcxx_filesystem_ts=yes + ;; + solaris*) + enable_libstdcxx_filesystem_ts=yes + ;; + mingw*) + enable_libstdcxx_filesystem_ts=yes + ;; + *) + enable_libstdcxx_filesystem_ts=no + ;; + esac + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libstdcxx_filesystem_ts" >&5 +$as_echo "$enable_libstdcxx_filesystem_ts" >&6; } + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct dirent.d_type" >&5 +$as_echo_n "checking for struct dirent.d_type... " >&6; } + if ${glibcxx_cv_dirent_d_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + struct dirent d; + if (sizeof d.d_type) return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_dirent_d_type=yes +else + glibcxx_cv_dirent_d_type=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + struct dirent d; + if (sizeof d.d_type) return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_dirent_d_type=yes +else + glibcxx_cv_dirent_d_type=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_dirent_d_type = yes; then + +$as_echo "#define HAVE_STRUCT_DIRENT_D_TYPE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_dirent_d_type" >&5 +$as_echo "$glibcxx_cv_dirent_d_type" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for realpath" >&5 +$as_echo_n "checking for realpath... " >&6; } + if ${glibcxx_cv_realpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + +int +main () +{ + + #if _XOPEN_VERSION < 500 + #error + #elif _XOPEN_VERSION >= 700 || defined(PATH_MAX) + char *tmp = realpath((const char*)NULL, (char*)NULL); + #else + #error + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_realpath=yes +else + glibcxx_cv_realpath=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + +int +main () +{ + + #if _XOPEN_VERSION < 500 + #error + #elif _XOPEN_VERSION >= 700 || defined(PATH_MAX) + char *tmp = realpath((const char*)NULL, (char*)NULL); + #else + #error + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_realpath=yes +else + glibcxx_cv_realpath=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_realpath = yes; then + +$as_echo "#define _GLIBCXX_USE_REALPATH 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_realpath" >&5 +$as_echo "$glibcxx_cv_realpath" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for utimensat" >&5 +$as_echo_n "checking for utimensat... " >&6; } + if ${glibcxx_cv_utimensat+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + struct timespec ts[2] = { { 0, UTIME_OMIT }, { 1, 1 } }; + int i = utimensat(AT_FDCWD, "path", ts, 0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_utimensat=yes +else + glibcxx_cv_utimensat=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + struct timespec ts[2] = { { 0, UTIME_OMIT }, { 1, 1 } }; + int i = utimensat(AT_FDCWD, "path", ts, 0); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_utimensat=yes +else + glibcxx_cv_utimensat=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_utimensat = yes; then + +$as_echo "#define _GLIBCXX_USE_UTIMENSAT 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_utimensat" >&5 +$as_echo "$glibcxx_cv_utimensat" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for utime" >&5 +$as_echo_n "checking for utime... " >&6; } + if ${glibcxx_cv_utime+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main () +{ + + struct utimbuf t = { 1, 1 }; + int i = utime("path", &t); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_utime=yes +else + glibcxx_cv_utime=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main () +{ + + struct utimbuf t = { 1, 1 }; + int i = utime("path", &t); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_utime=yes +else + glibcxx_cv_utime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_utime = yes; then + +$as_echo "#define _GLIBCXX_USE_UTIME 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_utime" >&5 +$as_echo "$glibcxx_cv_utime" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lstat" >&5 +$as_echo_n "checking for lstat... " >&6; } + if ${glibcxx_cv_lstat+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ + + struct stat st; + int i = lstat("path", &st); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_lstat=yes +else + glibcxx_cv_lstat=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ + + struct stat st; + int i = lstat("path", &st); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_lstat=yes +else + glibcxx_cv_lstat=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_lstat = yes; then + +$as_echo "#define _GLIBCXX_USE_LSTAT 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_lstat" >&5 +$as_echo "$glibcxx_cv_lstat" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat.st_mtim.tv_nsec" >&5 +$as_echo_n "checking for struct stat.st_mtim.tv_nsec... " >&6; } + if ${glibcxx_cv_st_mtim+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ + + struct stat st; + return st.st_mtim.tv_nsec; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_st_mtim=yes +else + glibcxx_cv_st_mtim=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ + + struct stat st; + return st.st_mtim.tv_nsec; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_st_mtim=yes +else + glibcxx_cv_st_mtim=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_st_mtim = yes; then + +$as_echo "#define _GLIBCXX_USE_ST_MTIM 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_st_mtim" >&5 +$as_echo "$glibcxx_cv_st_mtim" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fchmod" >&5 +$as_echo_n "checking for fchmod... " >&6; } + if ${glibcxx_cv_fchmod+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +fchmod(1, S_IWUSR); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_fchmod=yes +else + glibcxx_cv_fchmod=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +fchmod(1, S_IWUSR); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_fchmod=yes +else + glibcxx_cv_fchmod=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_fchmod = yes; then + +$as_echo "#define _GLIBCXX_USE_FCHMOD 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_fchmod" >&5 +$as_echo "$glibcxx_cv_fchmod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fchmodat" >&5 +$as_echo_n "checking for fchmodat... " >&6; } + if ${glibcxx_cv_fchmodat+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ +fchmodat(AT_FDCWD, "", 0, AT_SYMLINK_NOFOLLOW); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_fchmodat=yes +else + glibcxx_cv_fchmodat=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ +fchmodat(AT_FDCWD, "", 0, AT_SYMLINK_NOFOLLOW); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_fchmodat=yes +else + glibcxx_cv_fchmodat=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_fchmodat = yes; then + +$as_echo "#define _GLIBCXX_USE_FCHMODAT 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_fchmodat" >&5 +$as_echo "$glibcxx_cv_fchmodat" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile that can copy files" >&5 +$as_echo_n "checking for sendfile that can copy files... " >&6; } + if ${glibcxx_cv_sendfile+:} false; then : + $as_echo_n "(cached) " >&6 +else + case "${target_os}" in + gnu* | linux* | solaris* | uclinux*) + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +sendfile(1, 2, (off_t*)0, sizeof 1); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_sendfile=yes +else + glibcxx_cv_sendfile=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +sendfile(1, 2, (off_t*)0, sizeof 1); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_sendfile=yes +else + glibcxx_cv_sendfile=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + ;; + *) + glibcxx_cv_sendfile=no + ;; + esac + +fi + + if test $glibcxx_cv_sendfile = yes; then + +$as_echo "#define _GLIBCXX_USE_SENDFILE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_sendfile" >&5 +$as_echo "$glibcxx_cv_sendfile" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for link" >&5 +$as_echo_n "checking for link... " >&6; } + if ${glibcxx_cv_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +link("", ""); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_link=yes +else + glibcxx_cv_link=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +link("", ""); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_link=yes +else + glibcxx_cv_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_link = yes; then + +$as_echo "#define HAVE_LINK 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_link" >&5 +$as_echo "$glibcxx_cv_link" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readlink" >&5 +$as_echo_n "checking for readlink... " >&6; } + if ${glibcxx_cv_readlink+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char buf[32]; readlink("", buf, sizeof(buf)); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_readlink=yes +else + glibcxx_cv_readlink=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char buf[32]; readlink("", buf, sizeof(buf)); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_readlink=yes +else + glibcxx_cv_readlink=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_readlink = yes; then + +$as_echo "#define HAVE_READLINK 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_readlink" >&5 +$as_echo "$glibcxx_cv_readlink" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for symlink" >&5 +$as_echo_n "checking for symlink... " >&6; } + if ${glibcxx_cv_symlink+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +symlink("", ""); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_symlink=yes +else + glibcxx_cv_symlink=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +symlink("", ""); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_symlink=yes +else + glibcxx_cv_symlink=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_symlink = yes; then + +$as_echo "#define HAVE_SYMLINK 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_symlink" >&5 +$as_echo "$glibcxx_cv_symlink" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for truncate" >&5 +$as_echo_n "checking for truncate... " >&6; } + if ${glibcxx_cv_truncate+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +truncate("", 99); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_truncate=yes +else + glibcxx_cv_truncate=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +truncate("", 99); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_truncate=yes +else + glibcxx_cv_truncate=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_truncate = yes; then + +$as_echo "#define HAVE_TRUNCATE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_truncate" >&5 +$as_echo "$glibcxx_cv_truncate" >&6; } + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# For Networking TS. +for ac_header in fcntl.h sys/ioctl.h sys/socket.h sys/uio.h poll.h netdb.h arpa/inet.h netinet/in.h netinet/tcp.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# For Transactional Memory TS + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how size_t is mangled" >&5 +$as_echo_n "checking how size_t is mangled... " >&6; } +if ${glibcxx_cv_size_t_mangling+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +extern __SIZE_TYPE__ x; extern unsigned long x; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_size_t_mangling=m +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +extern __SIZE_TYPE__ x; extern unsigned int x; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_size_t_mangling=j +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +extern __SIZE_TYPE__ x; extern unsigned long long x; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_size_t_mangling=y +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +extern __SIZE_TYPE__ x; extern unsigned short x; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_size_t_mangling=t +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +extern __SIZE_TYPE__ x; extern __int20 unsigned x; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + glibcxx_cv_size_t_mangling=u6uint20 +else + glibcxx_cv_size_t_mangling=x +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_size_t_mangling" >&5 +$as_echo "$glibcxx_cv_size_t_mangling" >&6; } + if test $glibcxx_cv_size_t_mangling = x; then + as_fn_error $? "Unknown underlying type for size_t" "$LINENO" 5 + fi + +cat >>confdefs.h <<_ACEOF +#define _GLIBCXX_MANGLE_SIZE_T $glibcxx_cv_size_t_mangling +_ACEOF + + + +# Check which release added std::exception_ptr for the target + + if test $enable_symvers != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for first version to support std::exception_ptr" >&5 +$as_echo_n "checking for first version to support std::exception_ptr... " >&6; } + case ${target} in + aarch64-*-* | alpha-*-* | hppa*-*-* | i?86-*-* | x86_64-*-* | \ + m68k-*-* | powerpc*-*-* | s390*-*-* | *-*-solaris* ) + ac_exception_ptr_since_gcc46=yes + ;; + *) + # If the value of this macro changes then we will need to hardcode + # yes/no here for additional targets based on the original value. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + #if __GCC_ATOMIC_INT_LOCK_FREE <= 1 + # error atomic int not always lock free + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_exception_ptr_since_gcc46=yes +else + ac_exception_ptr_since_gcc46=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + esac + if test x"$ac_exception_ptr_since_gcc46" = x"yes" ; then + +$as_echo "#define HAVE_EXCEPTION_PTR_SINCE_GCC46 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: 4.6.0" >&5 +$as_echo "4.6.0" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: 7.1.0" >&5 +$as_echo "7.1.0" >&6; } + fi + fi + + +# Define documentation rules conditionally. + +# See if makeinfo has been installed and is modern enough +# that we can use it. + + # Extract the first word of "makeinfo", so it can be a program name with args. +set dummy makeinfo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MAKEINFO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MAKEINFO"; then + ac_cv_prog_MAKEINFO="$MAKEINFO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MAKEINFO="makeinfo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MAKEINFO=$ac_cv_prog_MAKEINFO +if test -n "$MAKEINFO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKEINFO" >&5 +$as_echo "$MAKEINFO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -n "$MAKEINFO"; then + # Found it, now check the version. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modern makeinfo" >&5 +$as_echo_n "checking for modern makeinfo... " >&6; } +if ${gcc_cv_prog_makeinfo_modern+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_prog_version=`eval $MAKEINFO --version 2>&1 | + sed -n 's/^.*GNU texinfo.* \([0-9][0-9.]*\).*$/\1/p'` + + case $ac_prog_version in + '') gcc_cv_prog_makeinfo_modern=no;; + 4.[4-9]*|4.[1-9][0-9]*|[5-9]*|[1-9][0-9]*) gcc_cv_prog_makeinfo_modern=yes;; + *) gcc_cv_prog_makeinfo_modern=no;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_prog_makeinfo_modern" >&5 +$as_echo "$gcc_cv_prog_makeinfo_modern" >&6; } + else + gcc_cv_prog_makeinfo_modern=no + fi + if test $gcc_cv_prog_makeinfo_modern = no; then + MAKEINFO="${CONFIG_SHELL-/bin/sh} $ac_aux_dir/missing makeinfo" + fi + + if test $gcc_cv_prog_makeinfo_modern = "yes"; then + BUILD_INFO_TRUE= + BUILD_INFO_FALSE='#' +else + BUILD_INFO_TRUE='#' + BUILD_INFO_FALSE= +fi + + +# Check for doxygen +# Extract the first word of "doxygen", so it can be a program name with args. +set dummy doxygen; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DOXYGEN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DOXYGEN"; then + ac_cv_prog_DOXYGEN="$DOXYGEN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DOXYGEN="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_DOXYGEN" && ac_cv_prog_DOXYGEN="no" +fi +fi +DOXYGEN=$ac_cv_prog_DOXYGEN +if test -n "$DOXYGEN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5 +$as_echo "$DOXYGEN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "dot", so it can be a program name with args. +set dummy dot; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DOT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DOT"; then + ac_cv_prog_DOT="$DOT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DOT="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_DOT" && ac_cv_prog_DOT="no" +fi +fi +DOT=$ac_cv_prog_DOT +if test -n "$DOT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOT" >&5 +$as_echo "$DOT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +# Check for docbook +# Extract the first word of "xmlcatalog", so it can be a program name with args. +set dummy xmlcatalog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_XMLCATALOG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$XMLCATALOG"; then + ac_cv_prog_XMLCATALOG="$XMLCATALOG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_XMLCATALOG="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_XMLCATALOG" && ac_cv_prog_XMLCATALOG="no" +fi +fi +XMLCATALOG=$ac_cv_prog_XMLCATALOG +if test -n "$XMLCATALOG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XMLCATALOG" >&5 +$as_echo "$XMLCATALOG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "xsltproc", so it can be a program name with args. +set dummy xsltproc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_XSLTPROC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$XSLTPROC"; then + ac_cv_prog_XSLTPROC="$XSLTPROC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_XSLTPROC="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_XSLTPROC" && ac_cv_prog_XSLTPROC="no" +fi +fi +XSLTPROC=$ac_cv_prog_XSLTPROC +if test -n "$XSLTPROC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 +$as_echo "$XSLTPROC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "xmllint", so it can be a program name with args. +set dummy xmllint; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_XMLLINT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$XMLLINT"; then + ac_cv_prog_XMLLINT="$XMLLINT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_XMLLINT="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_XMLLINT" && ac_cv_prog_XMLLINT="no" +fi +fi +XMLLINT=$ac_cv_prog_XMLLINT +if test -n "$XMLLINT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XMLLINT" >&5 +$as_echo "$XMLLINT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + +glibcxx_docbook_url=http://docbook.sourceforge.net/release/xsl-ns/current/ + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for local stylesheet directory" >&5 +$as_echo_n "checking for local stylesheet directory... " >&6; } +glibcxx_local_stylesheets=no +if test x${XMLCATALOG} = xyes && xsl_style_dir=`xmlcatalog "" $glibcxx_docbook_url 2>/dev/null` +then + XSL_STYLE_DIR=`echo $xsl_style_dir | sed -n 's;^file://;;p'` + glibcxx_local_stylesheets=yes +else + for dir in \ + /usr/share/sgml/docbook/xsl-ns-stylesheets \ + /usr/share/xml/docbook/stylesheet/docbook-xsl-ns \ + /usr/share/xml/docbook/stylesheet/nwalsh5/current \ + /usr/share/xml/docbook/stylesheet/nwalsh/current + do + if test -d $dir; then + glibcxx_local_stylesheets=yes + XSL_STYLE_DIR=$dir + break + fi + done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_local_stylesheets" >&5 +$as_echo "$glibcxx_local_stylesheets" >&6; } + +if test x"$glibcxx_local_stylesheets" = x"yes"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: $XSL_STYLE_DIR" >&5 +$as_echo "$as_me: $XSL_STYLE_DIR" >&6;} + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for docbook stylesheets for documentation creation" >&5 +$as_echo_n "checking for docbook stylesheets for documentation creation... " >&6; } + glibcxx_stylesheets=no + if test x${XMLCATALOG} = xno || xmlcatalog "" $glibcxx_docbook_url/xhtml/docbook.xsl >/dev/null 2>&1; then + if test x${XSLTPROC} = xyes && echo '' | xsltproc --noout --nonet --xinclude $glibcxx_docbook_url/xhtml/docbook.xsl - 2>/dev/null; then + glibcxx_stylesheets=yes + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_stylesheets" >&5 +$as_echo "$glibcxx_stylesheets" >&6; } + +else + glibcxx_stylesheets=no +fi + +# Check for epub3 dependencies. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for epub3 stylesheets for documentation creation" >&5 +$as_echo_n "checking for epub3 stylesheets for documentation creation... " >&6; } +glibcxx_epub_stylesheets=no +if test x"$glibcxx_local_stylesheets" = x"yes"; then + if test -f "$XSL_STYLE_DIR/epub3/chunk.xsl"; then + glibcxx_epub_stylesheets=yes + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_epub_stylesheets" >&5 +$as_echo "$glibcxx_epub_stylesheets" >&6; } + if test x"$glibcxx_epub_stylesheets" = x"yes"; then + BUILD_EPUB_TRUE= + BUILD_EPUB_FALSE='#' +else + BUILD_EPUB_TRUE='#' + BUILD_EPUB_FALSE= +fi + + + + +# Check for xml/html dependencies. + if test $ac_cv_prog_DOXYGEN = "yes" && + test $ac_cv_prog_DOT = "yes" && + test $ac_cv_prog_XSLTPROC = "yes" && + test $ac_cv_prog_XMLLINT = "yes" && + test $glibcxx_stylesheets = "yes"; then + BUILD_XML_TRUE= + BUILD_XML_FALSE='#' +else + BUILD_XML_TRUE='#' + BUILD_XML_FALSE= +fi + + + if test $ac_cv_prog_DOXYGEN = "yes" && + test $ac_cv_prog_DOT = "yes" && + test $ac_cv_prog_XSLTPROC = "yes" && + test $ac_cv_prog_XMLLINT = "yes" && + test $glibcxx_stylesheets = "yes"; then + BUILD_HTML_TRUE= + BUILD_HTML_FALSE='#' +else + BUILD_HTML_TRUE='#' + BUILD_HTML_FALSE= +fi + + +# Check for man dependencies. + if test $ac_cv_prog_DOXYGEN = "yes" && + test $ac_cv_prog_DOT = "yes"; then + BUILD_MAN_TRUE= + BUILD_MAN_FALSE='#' +else + BUILD_MAN_TRUE='#' + BUILD_MAN_FALSE= +fi + + +# Check for pdf dependencies. +# Extract the first word of "dblatex", so it can be a program name with args. +set dummy dblatex; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DBLATEX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DBLATEX"; then + ac_cv_prog_DBLATEX="$DBLATEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DBLATEX="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_DBLATEX" && ac_cv_prog_DBLATEX="no" +fi +fi +DBLATEX=$ac_cv_prog_DBLATEX +if test -n "$DBLATEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DBLATEX" >&5 +$as_echo "$DBLATEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "pdflatex", so it can be a program name with args. +set dummy pdflatex; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PDFLATEX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PDFLATEX"; then + ac_cv_prog_PDFLATEX="$PDFLATEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PDFLATEX="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_PDFLATEX" && ac_cv_prog_PDFLATEX="no" +fi +fi +PDFLATEX=$ac_cv_prog_PDFLATEX +if test -n "$PDFLATEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5 +$as_echo "$PDFLATEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test $ac_cv_prog_DOXYGEN = "yes" && + test $ac_cv_prog_DOT = "yes" && + test $ac_cv_prog_XSLTPROC = "yes" && + test $ac_cv_prog_XMLLINT = "yes" && + test $ac_cv_prog_DBLATEX = "yes" && + test $ac_cv_prog_PDFLATEX = "yes"; then + BUILD_PDF_TRUE= + BUILD_PDF_FALSE='#' +else + BUILD_PDF_TRUE='#' + BUILD_PDF_FALSE= +fi + + +case "$build" in + *-*-darwin* ) glibcxx_include_dir_notparallel=yes ;; + * ) glibcxx_include_dir_notparallel=no ;; +esac + if test $glibcxx_include_dir_notparallel = "yes"; then + INCLUDE_DIR_NOTPARALLEL_TRUE= + INCLUDE_DIR_NOTPARALLEL_FALSE='#' +else + INCLUDE_DIR_NOTPARALLEL_TRUE='#' + INCLUDE_DIR_NOTPARALLEL_FALSE= +fi + + +# Propagate the target-specific source directories through the build chain. +ATOMICITY_SRCDIR=config/${atomicity_dir} +ATOMIC_WORD_SRCDIR=config/${atomic_word_dir} +ATOMIC_FLAGS=${atomic_flags} +CPU_DEFINES_SRCDIR=config/${cpu_defines_dir} +OS_INC_SRCDIR=config/${os_include_dir} +ERROR_CONSTANTS_SRCDIR=config/${error_constants_dir} +ABI_TWEAKS_SRCDIR=config/${abi_tweaks_dir} +CPU_OPT_EXT_RANDOM=config/${cpu_opt_ext_random} +CPU_OPT_BITS_RANDOM=config/${cpu_opt_bits_random} + + + + + + + + + + +# Conditionalize the makefile for this target machine. +tmake_file_= +for f in ${tmake_file} +do + if test -f ${srcdir}/config/$f + then + tmake_file_="${tmake_file_} \$(srcdir)/config/$f" + fi +done +tmake_file="${tmake_file_}" + + +# Add CET specific flags if Intel CET is enabled. + # Check whether --enable-cet was given. +if test "${enable_cet+set}" = set; then : + enableval=$enable_cet; + case "$enableval" in + yes|no|auto) ;; + *) as_fn_error $? "Unknown argument to enable/disable cet" "$LINENO" 5 ;; + esac + +else + enable_cet=auto +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CET support" >&5 +$as_echo_n "checking for CET support... " >&6; } + +# NB: Avoid nested save_CFLAGS and save_LDFLAGS. +case "$host" in + i[34567]86-*-linux* | x86_64-*-linux*) + case "$enable_cet" in + auto) + # Check if target supports multi-byte NOPs + # and if compiler and assembler support CET insn. + cet_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fcf-protection" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +#if !defined(__SSE2__) +#error target does not support multi-byte NOPs +#else +asm ("setssbsy"); +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + enable_cet=yes +else + enable_cet=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$cet_save_CFLAGS" + ;; + yes) + # Check if assembler supports CET. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +asm ("setssbsy"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + as_fn_error $? "assembler with CET support is required for --enable-cet" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + esac + ;; + *) + enable_cet=no + ;; +esac +if test x$enable_cet = xyes; then + CET_FLAGS="-fcf-protection -mshstk" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +EXTRA_CXX_FLAGS="$EXTRA_CXX_FLAGS $CET_FLAGS" +EXTRA_CFLAGS="$EXTRA_CFLAGS $CET_FLAGS" + + + +# Determine cross-compile flags and AM_CONDITIONALs. +#AC_SUBST(GLIBCXX_IS_NATIVE) +#AM_CONDITIONAL(CANADIAN, test $CANADIAN = yes) + if test $is_hosted = yes; then + GLIBCXX_HOSTED_TRUE= + GLIBCXX_HOSTED_FALSE='#' +else + GLIBCXX_HOSTED_TRUE='#' + GLIBCXX_HOSTED_FALSE= +fi + + + if test $enable_libstdcxx_pch = yes; then + GLIBCXX_BUILD_PCH_TRUE= + GLIBCXX_BUILD_PCH_FALSE='#' +else + GLIBCXX_BUILD_PCH_TRUE='#' + GLIBCXX_BUILD_PCH_FALSE= +fi + + + if test $enable_float128 = yes; then + ENABLE_FLOAT128_TRUE= + ENABLE_FLOAT128_FALSE='#' +else + ENABLE_FLOAT128_TRUE='#' + ENABLE_FLOAT128_FALSE= +fi + + + if test $enable_libstdcxx_allocator_flag = new; then + ENABLE_ALLOCATOR_NEW_TRUE= + ENABLE_ALLOCATOR_NEW_FALSE='#' +else + ENABLE_ALLOCATOR_NEW_TRUE='#' + ENABLE_ALLOCATOR_NEW_FALSE= +fi + + + if test $enable_cheaders = c; then + GLIBCXX_C_HEADERS_C_TRUE= + GLIBCXX_C_HEADERS_C_FALSE='#' +else + GLIBCXX_C_HEADERS_C_TRUE='#' + GLIBCXX_C_HEADERS_C_FALSE= +fi + + + if test $enable_cheaders = c_std; then + GLIBCXX_C_HEADERS_C_STD_TRUE= + GLIBCXX_C_HEADERS_C_STD_FALSE='#' +else + GLIBCXX_C_HEADERS_C_STD_TRUE='#' + GLIBCXX_C_HEADERS_C_STD_FALSE= +fi + + + if test $enable_cheaders = c_global; then + GLIBCXX_C_HEADERS_C_GLOBAL_TRUE= + GLIBCXX_C_HEADERS_C_GLOBAL_FALSE='#' +else + GLIBCXX_C_HEADERS_C_GLOBAL_TRUE='#' + GLIBCXX_C_HEADERS_C_GLOBAL_FALSE= +fi + + + if test $c_compatibility = yes; then + GLIBCXX_C_HEADERS_COMPATIBILITY_TRUE= + GLIBCXX_C_HEADERS_COMPATIBILITY_FALSE='#' +else + GLIBCXX_C_HEADERS_COMPATIBILITY_TRUE='#' + GLIBCXX_C_HEADERS_COMPATIBILITY_FALSE= +fi + + + if test $enable_libstdcxx_debug = yes; then + GLIBCXX_BUILD_DEBUG_TRUE= + GLIBCXX_BUILD_DEBUG_FALSE='#' +else + GLIBCXX_BUILD_DEBUG_TRUE='#' + GLIBCXX_BUILD_DEBUG_FALSE= +fi + + + if test $enable_extern_template = yes; then + ENABLE_EXTERN_TEMPLATE_TRUE= + ENABLE_EXTERN_TEMPLATE_FALSE='#' +else + ENABLE_EXTERN_TEMPLATE_TRUE='#' + ENABLE_EXTERN_TEMPLATE_FALSE= +fi + + + if test $python_mod_dir != no; then + ENABLE_PYTHONDIR_TRUE= + ENABLE_PYTHONDIR_FALSE='#' +else + ENABLE_PYTHONDIR_TRUE='#' + ENABLE_PYTHONDIR_FALSE= +fi + + + if test $enable_werror = yes; then + ENABLE_WERROR_TRUE= + ENABLE_WERROR_FALSE='#' +else + ENABLE_WERROR_TRUE='#' + ENABLE_WERROR_FALSE= +fi + + + if test $enable_vtable_verify = yes; then + ENABLE_VTABLE_VERIFY_TRUE= + ENABLE_VTABLE_VERIFY_FALSE='#' +else + ENABLE_VTABLE_VERIFY_TRUE='#' + ENABLE_VTABLE_VERIFY_FALSE= +fi + + + if test $enable_symvers != no; then + ENABLE_SYMVERS_TRUE= + ENABLE_SYMVERS_FALSE='#' +else + ENABLE_SYMVERS_TRUE='#' + ENABLE_SYMVERS_FALSE= +fi + + + if test $enable_symvers = gnu; then + ENABLE_SYMVERS_GNU_TRUE= + ENABLE_SYMVERS_GNU_FALSE='#' +else + ENABLE_SYMVERS_GNU_TRUE='#' + ENABLE_SYMVERS_GNU_FALSE= +fi + + + if test $enable_symvers = gnu-versioned-namespace; then + ENABLE_SYMVERS_GNU_NAMESPACE_TRUE= + ENABLE_SYMVERS_GNU_NAMESPACE_FALSE='#' +else + ENABLE_SYMVERS_GNU_NAMESPACE_TRUE='#' + ENABLE_SYMVERS_GNU_NAMESPACE_FALSE= +fi + + + if test $enable_symvers = darwin; then + ENABLE_SYMVERS_DARWIN_TRUE= + ENABLE_SYMVERS_DARWIN_FALSE='#' +else + ENABLE_SYMVERS_DARWIN_TRUE='#' + ENABLE_SYMVERS_DARWIN_FALSE= +fi + + + if test $enable_symvers = sun; then + ENABLE_SYMVERS_SUN_TRUE= + ENABLE_SYMVERS_SUN_FALSE='#' +else + ENABLE_SYMVERS_SUN_TRUE='#' + ENABLE_SYMVERS_SUN_FALSE= +fi + + + if test $enable_libstdcxx_visibility = yes; then + ENABLE_VISIBILITY_TRUE= + ENABLE_VISIBILITY_FALSE='#' +else + ENABLE_VISIBILITY_TRUE='#' + ENABLE_VISIBILITY_FALSE= +fi + + + if test $enable_libstdcxx_dual_abi = yes; then + ENABLE_DUAL_ABI_TRUE= + ENABLE_DUAL_ABI_FALSE='#' +else + ENABLE_DUAL_ABI_TRUE='#' + ENABLE_DUAL_ABI_FALSE= +fi + + + if test $glibcxx_cxx11_abi = 1; then + ENABLE_CXX11_ABI_TRUE= + ENABLE_CXX11_ABI_FALSE='#' +else + ENABLE_CXX11_ABI_TRUE='#' + ENABLE_CXX11_ABI_FALSE= +fi + + + if test $ac_ldbl_compat = yes; then + GLIBCXX_LDBL_COMPAT_TRUE= + GLIBCXX_LDBL_COMPAT_FALSE='#' +else + GLIBCXX_LDBL_COMPAT_TRUE='#' + GLIBCXX_LDBL_COMPAT_FALSE= +fi + + + if test $ac_ldbl_alt128_compat = yes; then + GLIBCXX_LDBL_ALT128_COMPAT_TRUE= + GLIBCXX_LDBL_ALT128_COMPAT_FALSE='#' +else + GLIBCXX_LDBL_ALT128_COMPAT_TRUE='#' + GLIBCXX_LDBL_ALT128_COMPAT_FALSE= +fi + + + if test $enable_libstdcxx_filesystem_ts = yes; then + ENABLE_FILESYSTEM_TS_TRUE= + ENABLE_FILESYSTEM_TS_FALSE='#' +else + ENABLE_FILESYSTEM_TS_TRUE='#' + ENABLE_FILESYSTEM_TS_FALSE= +fi + + + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +if test ${multilib} = yes; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +# Export all the install information. + + glibcxx_toolexecdir=no + glibcxx_toolexeclibdir=no + glibcxx_prefixdir=$prefix + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gxx-include-dir" >&5 +$as_echo_n "checking for gxx-include-dir... " >&6; } + +# Check whether --with-gxx-include-dir was given. +if test "${with_gxx_include_dir+set}" = set; then : + withval=$with_gxx_include_dir; case "$withval" in + yes) as_fn_error $? "Missing directory for --with-gxx-include-dir" "$LINENO" 5 ;; + no) gxx_include_dir=no ;; + *) gxx_include_dir=$withval ;; + esac +else + gxx_include_dir=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gxx_include_dir" >&5 +$as_echo "$gxx_include_dir" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-version-specific-runtime-libs" >&5 +$as_echo_n "checking for --enable-version-specific-runtime-libs... " >&6; } + # Check whether --enable-version-specific-runtime-libs was given. +if test "${enable_version_specific_runtime_libs+set}" = set; then : + enableval=$enable_version_specific_runtime_libs; case "$enableval" in + yes) version_specific_libs=yes ;; + no) version_specific_libs=no ;; + *) as_fn_error $? "Unknown argument to enable/disable version-specific libs" "$LINENO" 5;; + esac +else + version_specific_libs=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $version_specific_libs" >&5 +$as_echo "$version_specific_libs" >&6; } + + +# Check whether --with-toolexeclibdir was given. +if test "${with_toolexeclibdir+set}" = set; then : + withval=$with_toolexeclibdir; case ${with_toolexeclibdir} in + /) + ;; + */) + with_toolexeclibdir=`echo $with_toolexeclibdir | sed 's,/$,,'` + ;; +esac +else + with_toolexeclibdir=no +fi + + + + # Default case for install directory for include files. + if test $version_specific_libs = no && test $gxx_include_dir = no; then + gxx_include_dir='include/c++/${gcc_version}' + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + gxx_include_dir='${prefix}/${target_alias}/'"$gxx_include_dir" + else + gxx_include_dir='${prefix}/'"$gxx_include_dir" + fi + fi + + # Version-specific runtime libs processing. + if test $version_specific_libs = yes; then + # Need the gcc compiler version to know where to install libraries + # and header files if --enable-version-specific-runtime-libs option + # is selected. FIXME: these variables are misnamed, there are + # no executables installed in _toolexecdir or _toolexeclibdir. + if test x"$gxx_include_dir" = x"no"; then + gxx_include_dir='${libdir}/gcc/${host_alias}/${gcc_version}/include/c++' + fi + glibcxx_toolexecdir='${libdir}/gcc/${host_alias}' + glibcxx_toolexeclibdir='${toolexecdir}/${gcc_version}$(MULTISUBDIR)' + fi + + # Calculate glibcxx_toolexecdir, glibcxx_toolexeclibdir + # Install a library built with a cross compiler in tooldir, not libdir. + if test x"$glibcxx_toolexecdir" = x"no"; then + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + glibcxx_toolexecdir='${exec_prefix}/${host_alias}' + case ${with_toolexeclibdir} in + no) + glibcxx_toolexeclibdir='${toolexecdir}/lib' + ;; + *) + glibcxx_toolexeclibdir=${with_toolexeclibdir} + ;; + esac + else + glibcxx_toolexecdir='${libdir}/gcc/${host_alias}' + glibcxx_toolexeclibdir='${libdir}' + fi + multi_os_directory=`$CXX -print-multi-os-directory` + case $multi_os_directory in + .) ;; # Avoid trailing /. + *) glibcxx_toolexeclibdir=$glibcxx_toolexeclibdir/$multi_os_directory ;; + esac + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for install location" >&5 +$as_echo_n "checking for install location... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gxx_include_dir" >&5 +$as_echo "$gxx_include_dir" >&6; } + + + + + + + +# Export all the include and flag information to Makefiles. + + # Used for every C++ compile we perform. + GLIBCXX_INCLUDES="\ +-I$glibcxx_builddir/include/$host_alias \ +-I$glibcxx_builddir/include \ +-I$glibcxx_srcdir/libsupc++" + + # For Canadian crosses, pick this up too. + if test $CANADIAN = yes; then + GLIBCXX_INCLUDES="$GLIBCXX_INCLUDES -I\${includedir}" + fi + + # Stuff in the actual top level. Currently only used by libsupc++ to + # get unwind* headers from the libgcc dir. + #TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/libgcc -I$(toplevel_srcdir)/include' + TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/libgcc' + + # Now, export this to all the little Makefiles.... + + + + + # Optimization flags that are probably a good idea for thrill-seekers. Just + # uncomment the lines below and make, everything else is ready to go... + # Alternatively OPTIMIZE_CXXFLAGS can be set in configure.host. + # OPTIMIZE_CXXFLAGS = -O3 -fstrict-aliasing -fvtable-gc + + + WARN_FLAGS="-Wall -Wextra -Wwrite-strings -Wcast-qual -Wabi=2" + + + +# Determine what GCC version number to use in filesystem paths. + + get_gcc_base_ver="cat" + +# Check whether --with-gcc-major-version-only was given. +if test "${with_gcc_major_version_only+set}" = set; then : + withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then + get_gcc_base_ver="sed -e 's/^\([0-9]*\).*/\1/'" + fi + +fi + + + + +ac_config_files="$ac_config_files Makefile" + +ac_config_files="$ac_config_files scripts/testsuite_flags" + +ac_config_files="$ac_config_files scripts/extract_symvers" + +ac_config_files="$ac_config_files doc/xsl/customization.xsl" + + +# Multilibs need MULTISUBDIR defined correctly in certain makefiles so +# that multilib installs will end up installed in the correct place. +# The testsuite needs it for multilib-aware ABI baseline files. +# To work around this not being passed down from config-ml.in -> +# srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually +# append it here. Only modify Makefiles that have just been created. +# +# Also, get rid of this simulated-VPATH thing that automake does. +ac_config_files="$ac_config_files include/Makefile libsupc++/Makefile src/Makefile src/c++98/Makefile src/c++11/Makefile src/c++17/Makefile src/c++20/Makefile src/filesystem/Makefile doc/Makefile po/Makefile testsuite/Makefile python/Makefile" + + +ac_config_commands="$ac_config_commands generate-headers" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_HOSTED_TRUE}" && test -z "${GLIBCXX_HOSTED_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_HOSTED\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_BUILD_PCH_TRUE}" && test -z "${GLIBCXX_BUILD_PCH_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_BUILD_PCH\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_FLOAT128_TRUE}" && test -z "${ENABLE_FLOAT128_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_FLOAT128\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_ALLOCATOR_NEW_TRUE}" && test -z "${ENABLE_ALLOCATOR_NEW_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_ALLOCATOR_NEW\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_C_HEADERS_C_TRUE}" && test -z "${GLIBCXX_C_HEADERS_C_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_C_HEADERS_C\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_C_HEADERS_C_STD_TRUE}" && test -z "${GLIBCXX_C_HEADERS_C_STD_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_C_HEADERS_C_STD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_C_HEADERS_C_GLOBAL_TRUE}" && test -z "${GLIBCXX_C_HEADERS_C_GLOBAL_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_C_HEADERS_C_GLOBAL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_C_HEADERS_COMPATIBILITY_TRUE}" && test -z "${GLIBCXX_C_HEADERS_COMPATIBILITY_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_C_HEADERS_COMPATIBILITY\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_BUILD_DEBUG_TRUE}" && test -z "${GLIBCXX_BUILD_DEBUG_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_BUILD_DEBUG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_EXTERN_TEMPLATE_TRUE}" && test -z "${ENABLE_EXTERN_TEMPLATE_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_EXTERN_TEMPLATE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_PYTHONDIR_TRUE}" && test -z "${ENABLE_PYTHONDIR_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_PYTHONDIR\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_WERROR_TRUE}" && test -z "${ENABLE_WERROR_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_WERROR\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${VTV_CYGMIN_TRUE}" && test -z "${VTV_CYGMIN_FALSE}"; then + as_fn_error $? "conditional \"VTV_CYGMIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_VTABLE_VERIFY_TRUE}" && test -z "${ENABLE_VTABLE_VERIFY_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_VTABLE_VERIFY\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_SYMVERS_TRUE}" && test -z "${ENABLE_SYMVERS_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_SYMVERS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_SYMVERS_GNU_TRUE}" && test -z "${ENABLE_SYMVERS_GNU_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_SYMVERS_GNU\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_SYMVERS_GNU_NAMESPACE_TRUE}" && test -z "${ENABLE_SYMVERS_GNU_NAMESPACE_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_SYMVERS_GNU_NAMESPACE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_SYMVERS_DARWIN_TRUE}" && test -z "${ENABLE_SYMVERS_DARWIN_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_SYMVERS_DARWIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_SYMVERS_SUN_TRUE}" && test -z "${ENABLE_SYMVERS_SUN_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_SYMVERS_SUN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_VISIBILITY_TRUE}" && test -z "${ENABLE_VISIBILITY_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_VISIBILITY\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_DUAL_ABI_TRUE}" && test -z "${ENABLE_DUAL_ABI_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_DUAL_ABI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_CXX11_ABI_TRUE}" && test -z "${ENABLE_CXX11_ABI_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_CXX11_ABI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_LDBL_COMPAT_TRUE}" && test -z "${GLIBCXX_LDBL_COMPAT_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_LDBL_COMPAT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GLIBCXX_LDBL_ALT128_COMPAT_TRUE}" && test -z "${GLIBCXX_LDBL_ALT128_COMPAT_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_LDBL_ALT128_COMPAT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_FILESYSTEM_TS_TRUE}" && test -z "${ENABLE_FILESYSTEM_TS_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_FILESYSTEM_TS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_INFO_TRUE}" && test -z "${BUILD_INFO_FALSE}"; then + as_fn_error $? "conditional \"BUILD_INFO\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_EPUB_TRUE}" && test -z "${BUILD_EPUB_FALSE}"; then + as_fn_error $? "conditional \"BUILD_EPUB\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_XML_TRUE}" && test -z "${BUILD_XML_FALSE}"; then + as_fn_error $? "conditional \"BUILD_XML\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_HTML_TRUE}" && test -z "${BUILD_HTML_FALSE}"; then + as_fn_error $? "conditional \"BUILD_HTML\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_MAN_TRUE}" && test -z "${BUILD_MAN_FALSE}"; then + as_fn_error $? "conditional \"BUILD_MAN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PDF_TRUE}" && test -z "${BUILD_PDF_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PDF\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${INCLUDE_DIR_NOTPARALLEL_TRUE}" && test -z "${INCLUDE_DIR_NOTPARALLEL_FALSE}"; then + as_fn_error $? "conditional \"INCLUDE_DIR_NOTPARALLEL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by package-unused $as_me version-unused, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +package-unused config.status version-unused +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# + +srcdir="$srcdir" +host="$host" +target="$target" +with_multisubdir="$with_multisubdir" +with_multisrctop="$with_multisrctop" +with_target_subdir="$with_target_subdir" +ac_configure_args="${multilib_arg} ${ac_configure_args}" +multi_basedir="$multi_basedir" +CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} +CC="$CC" +CXX="$CXX" +GFORTRAN="$GFORTRAN" +GDC="$GDC" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_flag_spec_ld_CXX \ +hardcode_libdir_separator_CXX \ +fix_srcfile_path_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + + +GCC="$GCC" +CC="$CC" +acx_cv_header_stdint="$acx_cv_header_stdint" +acx_cv_type_int8_t="$acx_cv_type_int8_t" +acx_cv_type_int16_t="$acx_cv_type_int16_t" +acx_cv_type_int32_t="$acx_cv_type_int32_t" +acx_cv_type_int64_t="$acx_cv_type_int64_t" +acx_cv_type_intptr_t="$acx_cv_type_intptr_t" +ac_cv_type_uintmax_t="$ac_cv_type_uintmax_t" +ac_cv_type_uintptr_t="$ac_cv_type_uintptr_t" +ac_cv_type_uint64_t="$ac_cv_type_uint64_t" +ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" +ac_cv_type_u_int32_t="$ac_cv_type_u_int32_t" +ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" +ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" +ac_cv_sizeof_void_p="$ac_cv_sizeof_void_p" + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "include/gstdint.h") CONFIG_COMMANDS="$CONFIG_COMMANDS include/gstdint.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "scripts/testsuite_flags") CONFIG_FILES="$CONFIG_FILES scripts/testsuite_flags" ;; + "scripts/extract_symvers") CONFIG_FILES="$CONFIG_FILES scripts/extract_symvers" ;; + "doc/xsl/customization.xsl") CONFIG_FILES="$CONFIG_FILES doc/xsl/customization.xsl" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "libsupc++/Makefile") CONFIG_FILES="$CONFIG_FILES libsupc++/Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "src/c++98/Makefile") CONFIG_FILES="$CONFIG_FILES src/c++98/Makefile" ;; + "src/c++11/Makefile") CONFIG_FILES="$CONFIG_FILES src/c++11/Makefile" ;; + "src/c++17/Makefile") CONFIG_FILES="$CONFIG_FILES src/c++17/Makefile" ;; + "src/c++20/Makefile") CONFIG_FILES="$CONFIG_FILES src/c++20/Makefile" ;; + "src/filesystem/Makefile") CONFIG_FILES="$CONFIG_FILES src/filesystem/Makefile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "po/Makefile") CONFIG_FILES="$CONFIG_FILES po/Makefile" ;; + "testsuite/Makefile") CONFIG_FILES="$CONFIG_FILES testsuite/Makefile" ;; + "python/Makefile") CONFIG_FILES="$CONFIG_FILES python/Makefile" ;; + "generate-headers") CONFIG_COMMANDS="$CONFIG_COMMANDS generate-headers" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "default-1":C) +# Only add multilib support code if we just rebuilt the top-level +# Makefile. +case " $CONFIG_FILES " in + *" Makefile "*) + ac_file=Makefile . ${multi_basedir}/config-ml.in + ;; +esac ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + "include/gstdint.h":C) +if test "$GCC" = yes; then + echo "/* generated for " `$CC --version | sed 1q` "*/" > tmp-stdint.h +else + echo "/* generated for $CC */" > tmp-stdint.h +fi + +sed 's/^ *//' >> tmp-stdint.h <<EOF + + #ifndef GCC_GENERATED_STDINT_H + #define GCC_GENERATED_STDINT_H 1 + + #include <sys/types.h> +EOF + +if test "$acx_cv_header_stdint" != stdint.h; then + echo "#include <stddef.h>" >> tmp-stdint.h +fi +if test "$acx_cv_header_stdint" != stddef.h; then + echo "#include <$acx_cv_header_stdint>" >> tmp-stdint.h +fi + +sed 's/^ *//' >> tmp-stdint.h <<EOF + /* glibc uses these symbols as guards to prevent redefinitions. */ + #ifdef __int8_t_defined + #define _INT8_T + #define _INT16_T + #define _INT32_T + #endif + #ifdef __uint32_t_defined + #define _UINT32_T + #endif + +EOF + +# ----------------- done header, emit basic int types ------------- +if test "$acx_cv_header_stdint" = stddef.h; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + #ifndef _UINT8_T + #define _UINT8_T + #ifndef __uint8_t_defined + #define __uint8_t_defined + #ifndef uint8_t + typedef unsigned $acx_cv_type_int8_t uint8_t; + #endif + #endif + #endif + + #ifndef _UINT16_T + #define _UINT16_T + #ifndef __uint16_t_defined + #define __uint16_t_defined + #ifndef uint16_t + typedef unsigned $acx_cv_type_int16_t uint16_t; + #endif + #endif + #endif + + #ifndef _UINT32_T + #define _UINT32_T + #ifndef __uint32_t_defined + #define __uint32_t_defined + #ifndef uint32_t + typedef unsigned $acx_cv_type_int32_t uint32_t; + #endif + #endif + #endif + + #ifndef _INT8_T + #define _INT8_T + #ifndef __int8_t_defined + #define __int8_t_defined + #ifndef int8_t + typedef $acx_cv_type_int8_t int8_t; + #endif + #endif + #endif + + #ifndef _INT16_T + #define _INT16_T + #ifndef __int16_t_defined + #define __int16_t_defined + #ifndef int16_t + typedef $acx_cv_type_int16_t int16_t; + #endif + #endif + #endif + + #ifndef _INT32_T + #define _INT32_T + #ifndef __int32_t_defined + #define __int32_t_defined + #ifndef int32_t + typedef $acx_cv_type_int32_t int32_t; + #endif + #endif + #endif +EOF +elif test "$ac_cv_type_u_int32_t" = yes; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* int8_t int16_t int32_t defined by inet code, we do the u_intXX types */ + #ifndef _INT8_T + #define _INT8_T + #endif + #ifndef _INT16_T + #define _INT16_T + #endif + #ifndef _INT32_T + #define _INT32_T + #endif + + #ifndef _UINT8_T + #define _UINT8_T + #ifndef __uint8_t_defined + #define __uint8_t_defined + #ifndef uint8_t + typedef u_int8_t uint8_t; + #endif + #endif + #endif + + #ifndef _UINT16_T + #define _UINT16_T + #ifndef __uint16_t_defined + #define __uint16_t_defined + #ifndef uint16_t + typedef u_int16_t uint16_t; + #endif + #endif + #endif + + #ifndef _UINT32_T + #define _UINT32_T + #ifndef __uint32_t_defined + #define __uint32_t_defined + #ifndef uint32_t + typedef u_int32_t uint32_t; + #endif + #endif + #endif +EOF +else + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* Some systems have guard macros to prevent redefinitions, define them. */ + #ifndef _INT8_T + #define _INT8_T + #endif + #ifndef _INT16_T + #define _INT16_T + #endif + #ifndef _INT32_T + #define _INT32_T + #endif + #ifndef _UINT8_T + #define _UINT8_T + #endif + #ifndef _UINT16_T + #define _UINT16_T + #endif + #ifndef _UINT32_T + #define _UINT32_T + #endif +EOF +fi + +# ------------- done basic int types, emit int64_t types ------------ +if test "$ac_cv_type_uint64_t" = yes; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* system headers have good uint64_t and int64_t */ + #ifndef _INT64_T + #define _INT64_T + #endif + #ifndef _UINT64_T + #define _UINT64_T + #endif +EOF +elif test "$ac_cv_type_u_int64_t" = yes; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* system headers have an u_int64_t (and int64_t) */ + #ifndef _INT64_T + #define _INT64_T + #endif + #ifndef _UINT64_T + #define _UINT64_T + #ifndef __uint64_t_defined + #define __uint64_t_defined + #ifndef uint64_t + typedef u_int64_t uint64_t; + #endif + #endif + #endif +EOF +elif test -n "$acx_cv_type_int64_t"; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* architecture has a 64-bit type, $acx_cv_type_int64_t */ + #ifndef _INT64_T + #define _INT64_T + #ifndef int64_t + typedef $acx_cv_type_int64_t int64_t; + #endif + #endif + #ifndef _UINT64_T + #define _UINT64_T + #ifndef __uint64_t_defined + #define __uint64_t_defined + #ifndef uint64_t + typedef unsigned $acx_cv_type_int64_t uint64_t; + #endif + #endif + #endif +EOF +else + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* some common heuristics for int64_t, using compiler-specific tests */ + #if defined __STDC_VERSION__ && (__STDC_VERSION__-0) >= 199901L + #ifndef _INT64_T + #define _INT64_T + #ifndef __int64_t_defined + #ifndef int64_t + typedef long long int64_t; + #endif + #endif + #endif + #ifndef _UINT64_T + #define _UINT64_T + #ifndef uint64_t + typedef unsigned long long uint64_t; + #endif + #endif + + #elif defined __GNUC__ && defined (__STDC__) && __STDC__-0 + /* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and + does not implement __extension__. But that compiler doesn't define + __GNUC_MINOR__. */ + # if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) + # define __extension__ + # endif + + # ifndef _INT64_T + # define _INT64_T + # ifndef int64_t + __extension__ typedef long long int64_t; + # endif + # endif + # ifndef _UINT64_T + # define _UINT64_T + # ifndef uint64_t + __extension__ typedef unsigned long long uint64_t; + # endif + # endif + + #elif !defined __STRICT_ANSI__ + # if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ + + # ifndef _INT64_T + # define _INT64_T + # ifndef int64_t + typedef __int64 int64_t; + # endif + # endif + # ifndef _UINT64_T + # define _UINT64_T + # ifndef uint64_t + typedef unsigned __int64 uint64_t; + # endif + # endif + # endif /* compiler */ + + #endif /* ANSI version */ +EOF +fi + +# ------------- done int64_t types, emit intptr types ------------ +if test "$ac_cv_type_uintptr_t" != yes; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* Define intptr_t based on sizeof(void*) = $ac_cv_sizeof_void_p */ + #ifndef __uintptr_t_defined + #ifndef uintptr_t + typedef u$acx_cv_type_intptr_t uintptr_t; + #endif + #endif + #ifndef __intptr_t_defined + #ifndef intptr_t + typedef $acx_cv_type_intptr_t intptr_t; + #endif + #endif +EOF +fi + +# ------------- done intptr types, emit int_least types ------------ +if test "$ac_cv_type_int_least32_t" != yes; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* Define int_least types */ + typedef int8_t int_least8_t; + typedef int16_t int_least16_t; + typedef int32_t int_least32_t; + #ifdef _INT64_T + typedef int64_t int_least64_t; + #endif + + typedef uint8_t uint_least8_t; + typedef uint16_t uint_least16_t; + typedef uint32_t uint_least32_t; + #ifdef _UINT64_T + typedef uint64_t uint_least64_t; + #endif +EOF +fi + +# ------------- done intptr types, emit int_fast types ------------ +if test "$ac_cv_type_int_fast32_t" != yes; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* Define int_fast types. short is often slow */ + typedef int8_t int_fast8_t; + typedef int int_fast16_t; + typedef int32_t int_fast32_t; + #ifdef _INT64_T + typedef int64_t int_fast64_t; + #endif + + typedef uint8_t uint_fast8_t; + typedef unsigned int uint_fast16_t; + typedef uint32_t uint_fast32_t; + #ifdef _UINT64_T + typedef uint64_t uint_fast64_t; + #endif +EOF +fi + +if test "$ac_cv_type_uintmax_t" != yes; then + sed 's/^ *//' >> tmp-stdint.h <<EOF + + /* Define intmax based on what we found */ + #ifndef intmax_t + #ifdef _INT64_T + typedef int64_t intmax_t; + #else + typedef long intmax_t; + #endif + #endif + #ifndef uintmax_t + #ifdef _UINT64_T + typedef uint64_t uintmax_t; + #else + typedef unsigned long uintmax_t; + #endif + #endif +EOF +fi + +sed 's/^ *//' >> tmp-stdint.h <<EOF + + #endif /* GCC_GENERATED_STDINT_H */ +EOF + +if test -r include/gstdint.h && cmp -s tmp-stdint.h include/gstdint.h; then + rm -f tmp-stdint.h +else + mv -f tmp-stdint.h include/gstdint.h +fi + + ;; + "scripts/testsuite_flags":F) chmod +x scripts/testsuite_flags ;; + "scripts/extract_symvers":F) chmod +x scripts/extract_symvers ;; + "include/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "libsupc++/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "src/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "src/c++98/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "src/c++11/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "src/c++17/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "src/c++20/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "src/filesystem/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "doc/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "po/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "testsuite/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "python/Makefile":F) cat > vpsed$$ << \_EOF +s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + sed -f vpsed$$ $ac_file > tmp$$ + mv tmp$$ $ac_file + rm vpsed$$ + echo 'MULTISUBDIR =' >> $ac_file + ml_norecursion=yes + . ${multi_basedir}/config-ml.in + { ml_norecursion=; unset ml_norecursion;} + ;; + "generate-headers":C) (cd include && ${MAKE-make} pch_build= ) ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/ports/gcc/hello.c b/ports/gcc/hello.c new file mode 100644 index 0000000..8f411ec --- /dev/null +++ b/ports/gcc/hello.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <essence.h> + +int main(int argc, char **argv) { + printf("Hello, world!\n"); + return 0; +} diff --git a/ports/gcc/notes.txt b/ports/gcc/notes.txt new file mode 100644 index 0000000..f9374df --- /dev/null +++ b/ports/gcc/notes.txt @@ -0,0 +1,92 @@ +binutils-2.31.1/config.sub + replace line 1379 with + " | midnightbsd* | essence*)" + +binutils-2.31.1/bfd/config.bfd + replace line 665 with + " x86_64-*-elf* | x86_64-*-rtems* | x86_64-*-fuchsia | x86_64-*-essence)" + +binutils-2.31.1/gas/configure.tgt + insert after line 215 + " i386-*-essence*) fmt=elf ;;" + +binutils-2.31.1/ld/configure.tgt + replace line 308 with + "x86_64-*-elf* | x86_64-*-rtems* | x86_64-*-fuchsia* | x86_64-*-essence*)" + insert after line 780 + "*-*-essence*)" + " NATIVE_LIB_DIRS='/Programs/POSIX/lib'" + " ;;" + "" + +gcc-8.2.0/config.sub + replace line 1419 with + " | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* | -essence*)" + +gcc-8.2.0/gcc/config.gcc + insert after line 698 + "*-*-essence*)" + " gas=yes" + " gnu_ld=yes" + " native_system_header_dir=/Programs/POSIX/include" + " ;;" + insert after line 1504 + "x86_64-*-essence*)" + " tmake_file="${tmake_file} i386/t-x86_64-essence"" + " tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h essence.h"" + " ;;" + +gcc-8.2.0/gcc/config/i386/t-x86_64-essence + create new file +*** +MULTILIB_OPTIONS += mno-red-zone +MULTILIB_DIRNAMES += no-red-zone +*** + +gcc-8.2.0/gcc/config/essence.h + create new file +*** +#undef TARGET_ESSENCE +#define TARGET_ESSENCE 1 +/* Default arguments to ld */ +#undef LIB_SPEC +#define LIB_SPEC "-lapi --start-group -lglue -lc --end-group -z max-page-size=0x1000" +/* Files that are linked before user code. The %s tells GCC to look for these files in the library directory. */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crti.o%s crtbegin.o%s" +/* Files that are linked after user code. */ +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" +/* Additional predefined macros. */ +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + do { \ + builtin_define ("ARCH_64"); \ + builtin_define ("ARCH_X86_64"); \ + builtin_define ("ARCH_X86_COMMON"); \ + builtin_define ("OS_ESSENCE"); \ + } while(0) +*** + +gcc-8.2.0/libgcc/config.host + insert after line 617 + "x86_64-*-essence)" + " extra_parts="$extra_parts crti.o crtbegin.o crtend.o crtn.o"" + " tmake_file="$tmake_file i386/t-crtstuff t-crt-stuff-pic -t-libgcc-pic"" + " ;;" + +gcc-8.2.0/fixincludes/mkfixinc.sh + insert after line 13 + " *-essence* | \" + +gcc-8.2.0/libstdc++-v3/configure + " *-essence*)" + "" + " ;;" + and + essence*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + +(then build according to https://wiki.osdev.org/Hosted_GCC_Cross-Compiler) diff --git a/ports/gcc/port.sh b/ports/gcc/port.sh new file mode 100755 index 0000000..2db5efc --- /dev/null +++ b/ports/gcc/port.sh @@ -0,0 +1,214 @@ +set -e + +SYSROOT=`realpath root` + +BINUTILS_VERSION=2.36.1 +GCC_VERSION=11.1.0 +GMP_VERSION=6.2.1 +MPFR_VERSION=4.1.0 +MPC_VERSION=1.2.1 + +if [ ! -f "bin/binutils-$BINUTILS_VERSION.tar.xz" ]; then + curl ftp://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS_VERSION.tar.xz > bin/binutils-$BINUTILS_VERSION.tar.xz +fi + +if [ ! -f "bin/gcc-$GCC_VERSION.tar.xz" ]; then + curl ftp://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.xz > bin/gcc-$GCC_VERSION.tar.xz +fi + +if [ ! -f "bin/gmp-$GMP_VERSION.tar.xz" ]; then + curl ftp://ftp.gnu.org/gnu/gmp/gmp-$GMP_VERSION.tar.xz > bin/gmp-$GMP_VERSION.tar.xz +fi + +if [ ! -f "bin/mpfr-$MPFR_VERSION.tar.xz" ]; then + curl ftp://ftp.gnu.org/gnu/mpfr/mpfr-$MPFR_VERSION.tar.xz > bin/mpfr-$MPFR_VERSION.tar.xz +fi + +if [ ! -f "bin/mpc-$MPC_VERSION.tar.gz" ]; then + curl ftp://ftp.gnu.org/gnu/mpc/mpc-$MPC_VERSION.tar.gz > bin/mpc-$MPC_VERSION.tar.gz +fi + +tar -xJf bin/binutils-$BINUTILS_VERSION.tar.xz +tar -xJf bin/gcc-$GCC_VERSION.tar.xz +tar -xJf bin/gmp-$GMP_VERSION.tar.xz +tar -xJf bin/mpfr-$MPFR_VERSION.tar.xz +tar -xzf bin/mpc-$MPC_VERSION.tar.gz + +mv binutils-$BINUTILS_VERSION bin/binutils-src +mv gcc-$GCC_VERSION bin/gcc-src +mv gmp-$GMP_VERSION bin/gmp-src +mv mpfr-$MPFR_VERSION bin/mpfr-src +mv mpc-$MPC_VERSION bin/mpc-src + +cp ports/gcc/changes/binutils_bfd_config.bfd bin/binutils-src/bfd/config.bfd +cp ports/gcc/changes/binutils_config.sub bin/binutils-src/config.sub +cp ports/gcc/changes/binutils_gas_configure.tgt bin/binutils-src/gas/configure.tgt +cp ports/gcc/changes/binutils_ld_configure.tgt bin/binutils-src/ld/configure.tgt + +cp ports/gcc/changes/gcc_config.sub bin/gcc-src/config.sub +cp ports/gcc/changes/gcc_fixincludes_mkfixinc.sh bin/gcc-src/fixincludes/mkfixinc.sh +cp ports/gcc/changes/gcc_gcc_config_essence.h bin/gcc-src/gcc/config/essence.h +cp ports/gcc/changes/gcc_gcc_config_i386_t-x86_64-essence bin/gcc-src/gcc/config/i386/t-x86_64-essence +cp ports/gcc/changes/gcc_gcc_config.gcc bin/gcc-src/gcc/config.gcc +cp ports/gcc/changes/gcc_libgcc_config.host bin/gcc-src/libgcc/config.host +cp ports/gcc/changes/gcc_libstdc++-v3_configure bin/gcc-src/libstdc++-v3/configure + +export ac_cv_func_calloc_0_nonnull="yes" +export ac_cv_func_chown_works="yes" +export ac_cv_func_getgroups_works="yes" +export ac_cv_func_malloc_0_nonnull="yes" +export gl_cv_func_cbrtl_ieee="yes" +export gl_cv_func_ceil_ieee="yes" +export gl_cv_func_ceilf_ieee="yes" +export gl_cv_func_ceill_ieee="yes" +export gl_cv_func_chown_ctime_works="yes" +export gl_cv_func_chown_slash_works="yes" +export gl_cv_func_exp2l_ieee="yes" +export gl_cv_func_expm1_ieee="yes" +export gl_cv_func_fcntl_f_dupfd_works="yes" +export gl_cv_func_fdopendir_works="yes" +export gl_cv_func_floorf_ieee="yes" +export gl_cv_func_fma_works="yes" +export gl_cv_func_fmaf_works="yes" +export gl_cv_func_fmal_works="yes" +export gl_cv_func_fmod_ieee="yes" +export gl_cv_func_fmodf_ieee="yes" +export gl_cv_func_fmodl_ieee="yes" +export gl_cv_func_fpurge_works="yes" +export gl_cv_func_futimens_works="yes" +export gl_cv_func_futimesat_works="yes" +export gl_cv_func_getgroups_works="yes" +export gl_cv_func_gettimeofday_clobber="yes" +export gl_cv_func_hypot_ieee="yes" +export gl_cv_func_hypotf_ieee="yes" +export gl_cv_func_hypotl_ieee="yes" +export gl_cv_func_isfinitel_works="yes" +export gl_cv_func_isnanl_works="yes" +export gl_cv_func_link_works="yes" +export gl_cv_func_linkat_slash="yes" +export gl_cv_func_log10_ieee="yes" +export gl_cv_func_log10f_ieee="yes" +export gl_cv_func_log1p_ieee="yes" +export gl_cv_func_log1pf_ieee="yes" +export gl_cv_func_log1pl_ieee="yes" +export gl_cv_func_log2_ieee="yes" +export gl_cv_func_log2f_ieee="yes" +export gl_cv_func_log_ieee="yes" +export gl_cv_func_logf_ieee="yes" +export gl_cv_func_lstat_dereferences_slashed_symlink="yes" +export gl_cv_func_mbrlen_empty_input="yes" +export gl_cv_func_mbrtowc_empty_input="yes" +export gl_cv_func_memchr_works="yes" +export gl_cv_func_memmem_works_fast="yes" +export gl_cv_func_mkdir_trailing_dot_works="yes" +export gl_cv_func_mkdir_trailing_slash_works="yes" +export gl_cv_func_mkfifo_works="yes" +export gl_cv_func_mknod_works="yes" +export gl_cv_func_modf_ieee="yes" +export gl_cv_func_modff_ieee="yes" +export gl_cv_func_modfl_ieee="yes" +export gl_cv_func_nanosleep="yes" +export gl_cv_func_open_directory_works="yes" +export gl_cv_func_perror_works="yes" +export gl_cv_func_printf_directive_a="yes" +export gl_cv_func_printf_directive_f="yes" +export gl_cv_func_printf_directive_n="yes" +export gl_cv_func_printf_enomem="yes" +export gl_cv_func_printf_flag_zero="yes" +export gl_cv_func_printf_infinite="yes" +export gl_cv_func_printf_infinite_long_double="yes" +export gl_cv_func_printf_sizes_c99="yes" +export gl_cv_func_pselect_detects_ebadf="yes" +export gl_cv_func_ptsname_sets_errno="yes" +export gl_cv_func_readlink_works="yes" +export gl_cv_func_realpath_works="yes" +export gl_cv_func_remainder_ieee="yes" +export gl_cv_func_remainderf_ieee="yes" +export gl_cv_func_remainderl_iee="yes" +export gl_cv_func_rename_dest_works="yes" +export gl_cv_func_rename_link_works="yes" +export gl_cv_func_rename_slash_dst_works="yes" +export gl_cv_func_rename_slash_src_works="yes" +export gl_cv_func_rmdir_works="yes" +export gl_cv_func_round_ieee="yes" +export gl_cv_func_roundf_ieee="yes" +export gl_cv_func_select_detects_ebadf="yes" +export gl_cv_func_setenv_works="yes" +export gl_cv_func_signbit="yes" +export gl_cv_func_signbit_gcc="yes" +export gl_cv_func_sleep_works="yes" +export gl_cv_func_snprintf_directive_n="yes" +export gl_cv_func_snprintf_retval_c99="yes" +export gl_cv_func_snprintf_truncation_c99="yes" +export gl_cv_func_stat_dir_slash="yes" +export gl_cv_func_stat_file_slash="yes" +export gl_cv_func_stpncpy="yes" +export gl_cv_func_strcasestr_linear="yes" +export gl_cv_func_strchrnul_works="yes" +export gl_cv_func_strerror_0_works="yes" +export gl_cv_func_strstr_linear="yes" +export gl_cv_func_strtod_works="yes" +export gl_cv_func_svid_putenv="yes" +export gl_cv_func_symlink_works="yes" +export gl_cv_func_tdelete_works="yes" +export gl_cv_func_trunc_ieee="yes" +export gl_cv_func_truncf_ieee="yes" +export gl_cv_func_truncl_iee="yes" +export gl_cv_func_tzset_clobber="yes" +export gl_cv_func_ungetc_works="yes" +export gl_cv_func_unlink_honors_slashes="yes" +export gl_cv_func_unsetenv_works="yes" +export gl_cv_func_usleep_works="yes" +export gl_cv_func_utimensat_works="yes" +export gl_cv_func_vsnprintf_posix="yes" +export gl_cv_func_vsnprintf_zerosize_c99="yes" +export gl_cv_func_vsprintf_posix="yes" +export gl_cv_func_wcwidth_works="yes" +export gl_cv_func_working_getdelim="yes" +export gl_cv_func_working_mkstemp="yes" +export gl_cv_func_working_mktime="yes" +export gl_cv_func_working_strerror="yes" + +mkdir bin/build-gmp +cd bin/build-gmp +../gmp-src/configure --host=x86_64-essence --prefix=/Applications/POSIX --without-readline CC=x86_64-essence-gcc CXX=x86_64-essence-g++ +make +make DESTDIR=$SYSROOT install +cd ../.. +rm -rf bin/build-gmp + +mkdir bin/build-mpfr +cd bin/build-mpfr +../mpfr-src/configure --host=x86_64-essence --prefix=/Applications/POSIX CC=x86_64-essence-gcc CXX=x86_64-essence-g++ +make +make DESTDIR=$SYSROOT install +cd ../.. +rm -rf bin/build-mpfr + +mkdir bin/build-mpc +cd bin/build-mpc +../mpc-src/configure --host=x86_64-essence --prefix=/Applications/POSIX CC=x86_64-essence-gcc CXX=x86_64-essence-g++ +make +make DESTDIR=$SYSROOT install +cd ../.. +rm -rf bin/build-mpc + +mkdir bin/build-binutils +cd bin/build-binutils +../binutils-src/configure --host=x86_64-essence --target=x86_64-essence --prefix=/Applications/POSIX --with-local-prefix=/Applications/POSIX/local --with-build-sysroot=$SYSROOT --without-isl --disable-nls --disable-werror --without-target-bdw-gc CC=x86_64-essence-gcc CXX=x86_64-essence-g++ +make -j4 +make DESTDIR=$SYSROOT install +cd ../.. +rm -rf bin/build-binutils + +mkdir bin/build-gcc +cd bin/build-gcc +../gcc-src/configure --host=x86_64-essence --target=x86_64-essence --prefix=/Applications/POSIX --with-local-prefix=/Applications/POSIX/local --with-build-sysroot=$SYSROOT --without-isl --disable-nls --disable-werror --without-target-bdw-gc --enable-languages=c,c++ CC=x86_64-essence-gcc CXX=x86_64-essence-g++ LD=x86_64-essence-ld +make all-gcc -j4 +make all-target-libgcc +make DESTDIR=$SYSROOT install-strip-gcc +make DESTDIR=$SYSROOT install-target-libgcc +cd ../.. +rm -rf bin/build-gcc + +rm -rf bin/gcc-src bin/binutils-src bin/mpc-src bin/gmp-src bin/mpfr-src diff --git a/ports/harfbuzz/LICENSE b/ports/harfbuzz/LICENSE new file mode 100644 index 0000000..0278e60 --- /dev/null +++ b/ports/harfbuzz/LICENSE @@ -0,0 +1,37 @@ +HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. +For parts of HarfBuzz that are licensed under different licenses see individual +files names COPYING in subdirectories where applicable. + +Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Google, Inc. +Copyright © 2019 Facebook, Inc. +Copyright © 2012 Mozilla Foundation +Copyright © 2011 Codethink Limited +Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) +Copyright © 2009 Keith Stribley +Copyright © 2009 Martin Hosken and SIL International +Copyright © 2007 Chris Wilson +Copyright © 2006 Behdad Esfahbod +Copyright © 2005 David Turner +Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc. +Copyright © 1998-2004 David Turner and Werner Lemberg + +For full copyright notices consult the individual files in the package. + + +Permission is hereby granted, without written agreement and without +license or royalty fees, to use, copy, modify, and distribute this +software and its documentation for any purpose, provided that the +above copyright notice and the following two paragraphs appear in +all copies of this software. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN +IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/ports/harfbuzz/build.sh b/ports/harfbuzz/build.sh new file mode 100755 index 0000000..59e62bc --- /dev/null +++ b/ports/harfbuzz/build.sh @@ -0,0 +1,90 @@ +if [ ! -d "bin/harfbuzz" ]; then + echo " Downloading and building Harfbuzz..." + + if [ ! -f "bin/harfbuzz-2.6.4.tar" ]; then + curl https://www.freedesktop.org/software/harfbuzz/release/harfbuzz-2.6.4.tar.xz > bin/harfbuzz-2.6.4.tar.xz 2> bin/harfbuzz_dl.txt + xz -d bin/harfbuzz-2.6.4.tar.xz + fi + + tar -xf bin/harfbuzz-2.6.4.tar + mv harfbuzz-2.6.4 bin/harfbuzz + + cd bin/harfbuzz + ./configure --with-glib=no --with-icu=no --with-freetype=no --with-cairo=no --with-fontconfig=no --enable-shared \ + CFLAGS="-g -O2 -DHB_TINY" CXXFLAGS="-g -O2 -DHB_TINY" > ../harfbuzz_configure.txt + cd ../.. + + cp ports/harfbuzz/essence-config.h bin/harfbuzz/config.h + + cd bin/harfbuzz/src + + find . -type f -exec sed -i 's/#include <assert.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <atomic.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <builtins.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <float.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <locale.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <math.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <stdio.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <stdlib.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <string.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <unistd.h>/#include <essence.h>/g' {} \; + find . -type f -exec sed -i 's/#include <xlocale.h>/#include <essence.h>/g' {} \; + + CC="x86_64-essence-g++ -DHAVE_CONFIG_H -I. -I.. -ffreestanding -fno-rtti -g -O2 -DHB_TINY -fno-exceptions -fno-threadsafe-statics -fvisibility-inlines-hidden" + + $CC -c hb-aat-layout.cc -o hb-aat-layout.o + $CC -c hb-aat-map.cc -o hb-aat-map.o + $CC -c hb-blob.cc -o hb-blob.o + $CC -c hb-buffer-serialize.cc -o hb-buffer-serialize.o + $CC -c hb-buffer.cc -o hb-buffer.o + $CC -c hb-common.cc -o hb-common.o + $CC -c hb-face.cc -o hb-face.o + $CC -c hb-fallback-shape.cc -o hb-fallback-shape.o + $CC -c hb-font.cc -o hb-font.o + $CC -c hb-map.cc -o hb-map.o + $CC -c hb-number.cc -o hb-number.o + $CC -c hb-ot-cff1-table.cc -o hb-ot-cff1-table.o + $CC -c hb-ot-cff2-table.cc -o hb-ot-cff2-table.o + $CC -c hb-ot-color.cc -o hb-ot-color.o + $CC -c hb-ot-face.cc -o hb-ot-face.o + $CC -c hb-ot-font.cc -o hb-ot-font.o + $CC -c hb-ot-layout.cc -o hb-ot-layout.o + $CC -c hb-ot-map.cc -o hb-ot-map.o + $CC -c hb-ot-math.cc -o hb-ot-math.o + $CC -c hb-ot-meta.cc -o hb-ot-meta.o + $CC -c hb-ot-metrics.cc -o hb-ot-metrics.o + $CC -c hb-ot-name.cc -o hb-ot-name.o + $CC -c hb-ot-shape-complex-arabic.cc -o hb-ot-shape-complex-arabic.o + $CC -c hb-ot-shape-complex-default.cc -o hb-ot-shape-complex-default.o + $CC -c hb-ot-shape-complex-hangul.cc -o hb-ot-shape-complex-hangul.o + $CC -c hb-ot-shape-complex-hebrew.cc -o hb-ot-shape-complex-hebrew.o + $CC -c hb-ot-shape-complex-indic-table.cc -o hb-ot-shape-complex-indic-table.o + $CC -c hb-ot-shape-complex-indic.cc -o hb-ot-shape-complex-indic.o + $CC -c hb-ot-shape-complex-khmer.cc -o hb-ot-shape-complex-khmer.o + $CC -c hb-ot-shape-complex-myanmar.cc -o hb-ot-shape-complex-myanmar.o + $CC -c hb-ot-shape-complex-thai.cc -o hb-ot-shape-complex-thai.o + $CC -c hb-ot-shape-complex-use-table.cc -o hb-ot-shape-complex-use-table.o + $CC -c hb-ot-shape-complex-use.cc -o hb-ot-shape-complex-use.o + $CC -c hb-ot-shape-complex-vowel-constraints.cc -o hb-ot-shape-complex-vowel-constraints.o + $CC -c hb-ot-shape-fallback.cc -o hb-ot-shape-fallback.o + $CC -c hb-ot-shape-normalize.cc -o hb-ot-shape-normalize.o + $CC -c hb-ot-shape.cc -o hb-ot-shape.o + $CC -c hb-ot-tag.cc -o hb-ot-tag.o + $CC -c hb-ot-var.cc -o hb-ot-var.o + $CC -c hb-set.cc -o hb-set.o + $CC -c hb-shape-plan.cc -o hb-shape-plan.o + $CC -c hb-shape.cc -o hb-shape.o + $CC -c hb-shaper.cc -o hb-shaper.o + $CC -c hb-static.cc -o hb-static.o + $CC -c hb-ucd.cc -o hb-ucd.o + $CC -c hb-unicode.cc -o hb-unicode.o + $CC -c hb-ft.cc -o hb-ft.o + + ar cr libharfbuzz.a hb-aat-layout.o hb-aat-map.o hb-blob.o hb-buffer-serialize.o hb-buffer.o hb-common.o hb-face.o hb-fallback-shape.o hb-font.o hb-map.o hb-number.o hb-ot-cff1-table.o hb-ot-cff2-table.o hb-ot-color.o hb-ot-face.o hb-ot-font.o hb-ot-layout.o hb-ot-map.o hb-ot-math.o hb-ot-meta.o hb-ot-metrics.o hb-ot-name.o hb-ot-shape-complex-arabic.o hb-ot-shape-complex-default.o hb-ot-shape-complex-hangul.o hb-ot-shape-complex-hebrew.o hb-ot-shape-complex-indic-table.o hb-ot-shape-complex-indic.o hb-ot-shape-complex-khmer.o hb-ot-shape-complex-myanmar.o hb-ot-shape-complex-thai.o hb-ot-shape-complex-use-table.o hb-ot-shape-complex-use.o hb-ot-shape-complex-vowel-constraints.o hb-ot-shape-fallback.o hb-ot-shape-normalize.o hb-ot-shape.o hb-ot-tag.o hb-ot-var.o hb-set.o hb-shape-plan.o hb-shape.o hb-shaper.o hb-static.o hb-ucd.o hb-unicode.o hb-ft.o + + cd ../../.. +fi + +cp -p bin/harfbuzz/src/libharfbuzz.a root/Applications/POSIX/lib +mkdir -p root/Applications/POSIX/include/harfbuzz +cp -p bin/harfbuzz/src/*.h root/Applications/POSIX/include/harfbuzz diff --git a/ports/harfbuzz/essence-config.h b/ports/harfbuzz/essence-config.h new file mode 100644 index 0000000..b67aa84 --- /dev/null +++ b/ports/harfbuzz/essence-config.h @@ -0,0 +1,74 @@ +#define ALIGNOF_STRUCT_CHAR__ 1 +#define HAVE_ATEXIT 1 +#define HAVE_CXX11 1 +#define HAVE_DLFCN_H 1 +#define HAVE_INTEL_ATOMIC_PRIMITIVES 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_ISATTY 1 +#define HAVE_MEMORY_H 1 +#define HAVE_MMAP 1 +#define HAVE_MPROTECT 1 +#define HAVE_PTHREAD 1 +#define HAVE_PTHREAD_PRIO_INHERIT 1 +#define HAVE_STDBOOL_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_STRTOD_L 1 +#define HAVE_SYS_MMAN_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_UNISTD_H 1 +#define LT_OBJDIR ".libs/" +#define PACKAGE_BUGREPORT "https://github.com/harfbuzz/harfbuzz/issues/new" +#define PACKAGE_NAME "HarfBuzz" +#define PACKAGE_STRING "HarfBuzz 2.6.4" +#define PACKAGE_TARNAME "harfbuzz" +#define PACKAGE_URL "http://harfbuzz.org/" +#define PACKAGE_VERSION "2.6.4" +#define STDC_HEADERS 1 +#define HAVE_FREETYPE 1 + +#define ES_API +#define ES_FORWARD(x) x +#define ES_EXTERN_FORWARD extern "C" +#define ES_DIRECT_API + +#define abs EsCRTabs +#define assert EsCRTassert +#define calloc EsCRTcalloc +#define ceil EsCRTceil +#define fabs EsCRTfabs +#define floor EsCRTfloor +#define free EsCRTfree +#define malloc EsCRTmalloc +#define memcmp EsCRTmemcmp +#define memcpy EsCRTmemcpy +#define memmove EsCRTmemmove +#define memset EsCRTmemset +#define qsort EsCRTqsort +#define realloc EsCRTrealloc +#define snprintf EsCRTsnprintf +#define strchr EsCRTstrchr +#define strcmp EsCRTstrcmp +#define strerror EsCRTstrerror +#define strlen EsCRTstrlen +#define strncmp EsCRTstrncmp +#define strncpy EsCRTstrncpy +#define strstr EsCRTstrstr +#define strtol EsCRTstrtol +#define strtoul EsCRTstrtoul + +#include <stdarg.h> + +#define FLT_MIN 1.17549435082228750797e-38F +#define FLT_MAX 3.40282346638528859812e+38F +#define DBL_MIN 2.22507385850720138309e-308 +#define DBL_MAX 1.79769313486231570815e+308 + +// These are never used in the release build. +struct FILE; +int fprintf(FILE *stream, const char *format, ...); +int vfprintf(FILE *stream, const char *format, va_list ap); +#define stderr ((FILE *) NULL) diff --git a/ports/md4c/LICENSE.md b/ports/md4c/LICENSE.md new file mode 100644 index 0000000..2088ba4 --- /dev/null +++ b/ports/md4c/LICENSE.md @@ -0,0 +1,22 @@ + +# The MIT License (MIT) + +Copyright © 2016-2020 Martin Mitáš + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the “Software”), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/ports/md4c/md4c.c b/ports/md4c/md4c.c new file mode 100644 index 0000000..a263059 --- /dev/null +++ b/ports/md4c/md4c.c @@ -0,0 +1,6395 @@ +/* + * MD4C: Markdown parser for C + * (http://github.com/mity/md4c) + * + * Copyright (c) 2016-2020 Martin Mitas + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "md4c.h" + +#ifdef OS_ESSENCE +#define bsearch EsCRTbsearch +#define free EsCRTfree +#define malloc EsCRTmalloc +#define memcmp EsCRTmemcmp +#define memcpy EsCRTmemcpy +#define memmove EsCRTmemmove +#define memset EsCRTmemset +#define qsort EsCRTqsort +#define realloc EsCRTrealloc +#define strchr EsCRTstrchr +#else +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> +#endif + +/***************************** + *** Miscellaneous Stuff *** + *****************************/ + +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199409L + /* C89/90 or old compilers in general may not understand "inline". */ + #if defined __GNUC__ + #define inline __inline__ + #elif defined _MSC_VER + #define inline __inline + #else + #define inline + #endif +#endif + +/* Make the UTF-8 support the default. */ +#if !defined MD4C_USE_ASCII && !defined MD4C_USE_UTF8 && !defined MD4C_USE_UTF16 + #define MD4C_USE_UTF8 +#endif + +/* Magic for making wide literals with MD4C_USE_UTF16. */ +#ifdef _T + #undef _T +#endif +#if defined MD4C_USE_UTF16 + #define _T(x) L##x +#else + #define _T(x) x +#endif + +/* Misc. macros. */ +#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0])) + +#define STRINGIZE_(x) #x +#define STRINGIZE(x) STRINGIZE_(x) + +#ifndef TRUE + #define TRUE 1 + #define FALSE 0 +#endif + +#define MD_LOG(msg) \ + do { \ + if(ctx->parser.debug_log != NULL) \ + ctx->parser.debug_log((msg), ctx->userdata); \ + } while(0) + +#ifdef DEBUG + #define MD_ASSERT(cond) \ + do { \ + if(!(cond)) { \ + MD_LOG(__FILE__ ":" STRINGIZE(__LINE__) ": " \ + "Assertion '" STRINGIZE(cond) "' failed."); \ + exit(1); \ + } \ + } while(0) + + #define MD_UNREACHABLE() MD_ASSERT(1 == 0) +#else + #ifdef __GNUC__ + #define MD_ASSERT(cond) do { if(!(cond)) __builtin_unreachable(); } while(0) + #define MD_UNREACHABLE() do { __builtin_unreachable(); } while(0) + #elif defined _MSC_VER && _MSC_VER > 120 + #define MD_ASSERT(cond) do { __assume(cond); } while(0) + #define MD_UNREACHABLE() do { __assume(0); } while(0) + #else + #define MD_ASSERT(cond) do {} while(0) + #define MD_UNREACHABLE() do {} while(0) + #endif +#endif + +/* For falling through case labels in switch statements. */ +#if defined __clang__ && __clang_major__ >= 12 + #define MD_FALLTHROUGH() __attribute__((fallthrough)) +#elif defined __GNUC__ && __GNUC__ >= 7 + #define MD_FALLTHROUGH() __attribute__((fallthrough)) +#else + #define MD_FALLTHROUGH() ((void)0) +#endif + +/* Suppress "unused parameter" warnings. */ +#define MD_UNUSED(x) ((void)x) + + +/************************ + *** Internal Types *** + ************************/ + +/* These are omnipresent so lets save some typing. */ +#define CHAR MD_CHAR +#define SZ MD_SIZE +#define OFF MD_OFFSET + +typedef struct MD_MARK_tag MD_MARK; +typedef struct MD_BLOCK_tag MD_BLOCK; +typedef struct MD_CONTAINER_tag MD_CONTAINER; +typedef struct MD_REF_DEF_tag MD_REF_DEF; + + +/* During analyzes of inline marks, we need to manage some "mark chains", + * of (yet unresolved) openers. This structure holds start/end of the chain. + * The chain internals are then realized through MD_MARK::prev and ::next. + */ +typedef struct MD_MARKCHAIN_tag MD_MARKCHAIN; +struct MD_MARKCHAIN_tag { + int head; /* Index of first mark in the chain, or -1 if empty. */ + int tail; /* Index of last mark in the chain, or -1 if empty. */ +}; + +/* Context propagated through all the parsing. */ +typedef struct MD_CTX_tag MD_CTX; +struct MD_CTX_tag { + /* Immutable stuff (parameters of md_parse()). */ + const CHAR* text; + SZ size; + MD_PARSER parser; + void* userdata; + + /* When this is true, it allows some optimizations. */ + int doc_ends_with_newline; + + /* Helper temporary growing buffer. */ + CHAR* buffer; + unsigned alloc_buffer; + + /* Reference definitions. */ + MD_REF_DEF* ref_defs; + int n_ref_defs; + int alloc_ref_defs; + void** ref_def_hashtable; + int ref_def_hashtable_size; + + /* Stack of inline/span markers. + * This is only used for parsing a single block contents but by storing it + * here we may reuse the stack for subsequent blocks; i.e. we have fewer + * (re)allocations. */ + MD_MARK* marks; + int n_marks; + int alloc_marks; + +#if defined MD4C_USE_UTF16 + char mark_char_map[128]; +#else + char mark_char_map[256]; +#endif + + /* For resolving of inline spans. */ + MD_MARKCHAIN mark_chains[13]; +#define PTR_CHAIN (ctx->mark_chains[0]) +#define TABLECELLBOUNDARIES (ctx->mark_chains[1]) +#define ASTERISK_OPENERS_extraword_mod3_0 (ctx->mark_chains[2]) +#define ASTERISK_OPENERS_extraword_mod3_1 (ctx->mark_chains[3]) +#define ASTERISK_OPENERS_extraword_mod3_2 (ctx->mark_chains[4]) +#define ASTERISK_OPENERS_intraword_mod3_0 (ctx->mark_chains[5]) +#define ASTERISK_OPENERS_intraword_mod3_1 (ctx->mark_chains[6]) +#define ASTERISK_OPENERS_intraword_mod3_2 (ctx->mark_chains[7]) +#define UNDERSCORE_OPENERS (ctx->mark_chains[8]) +#define TILDE_OPENERS_1 (ctx->mark_chains[9]) +#define TILDE_OPENERS_2 (ctx->mark_chains[10]) +#define BRACKET_OPENERS (ctx->mark_chains[11]) +#define DOLLAR_OPENERS (ctx->mark_chains[12]) +#define OPENERS_CHAIN_FIRST 2 +#define OPENERS_CHAIN_LAST 12 + + int n_table_cell_boundaries; + + /* For resolving links. */ + int unresolved_link_head; + int unresolved_link_tail; + + /* For resolving raw HTML. */ + OFF html_comment_horizon; + OFF html_proc_instr_horizon; + OFF html_decl_horizon; + OFF html_cdata_horizon; + + /* For block analysis. + * Notes: + * -- It holds MD_BLOCK as well as MD_LINE structures. After each + * MD_BLOCK, its (multiple) MD_LINE(s) follow. + * -- For MD_BLOCK_HTML and MD_BLOCK_CODE, MD_VERBATIMLINE(s) are used + * instead of MD_LINE(s). + */ + void* block_bytes; + MD_BLOCK* current_block; + int n_block_bytes; + int alloc_block_bytes; + + /* For container block analysis. */ + MD_CONTAINER* containers; + int n_containers; + int alloc_containers; + + /* Minimal indentation to call the block "indented code block". */ + unsigned code_indent_offset; + + /* Contextual info for line analysis. */ + SZ code_fence_length; /* For checking closing fence length. */ + int html_block_type; /* For checking closing raw HTML condition. */ + int last_line_has_list_loosening_effect; + int last_list_item_starts_with_two_blank_lines; +}; + +enum MD_LINETYPE_tag { + MD_LINE_BLANK, + MD_LINE_HR, + MD_LINE_ATXHEADER, + MD_LINE_SETEXTHEADER, + MD_LINE_SETEXTUNDERLINE, + MD_LINE_INDENTEDCODE, + MD_LINE_FENCEDCODE, + MD_LINE_HTML, + MD_LINE_TEXT, + MD_LINE_TABLE, + MD_LINE_TABLEUNDERLINE +}; +typedef enum MD_LINETYPE_tag MD_LINETYPE; + +typedef struct MD_LINE_ANALYSIS_tag MD_LINE_ANALYSIS; +struct MD_LINE_ANALYSIS_tag { + MD_LINETYPE type : 16; + unsigned data : 16; + OFF beg; + OFF end; + unsigned indent; /* Indentation level. */ +}; + +typedef struct MD_LINE_tag MD_LINE; +struct MD_LINE_tag { + OFF beg; + OFF end; +}; + +typedef struct MD_VERBATIMLINE_tag MD_VERBATIMLINE; +struct MD_VERBATIMLINE_tag { + OFF beg; + OFF end; + OFF indent; +}; + + +/***************** + *** Helpers *** + *****************/ + +/* Character accessors. */ +#define CH(off) (ctx->text[(off)]) +#define STR(off) (ctx->text + (off)) + +/* Character classification. + * Note we assume ASCII compatibility of code points < 128 here. */ +#define ISIN_(ch, ch_min, ch_max) ((ch_min) <= (unsigned)(ch) && (unsigned)(ch) <= (ch_max)) +#define ISANYOF_(ch, palette) ((ch) != _T('\0') && md_strchr((palette), (ch)) != NULL) +#define ISANYOF2_(ch, ch1, ch2) ((ch) == (ch1) || (ch) == (ch2)) +#define ISANYOF3_(ch, ch1, ch2, ch3) ((ch) == (ch1) || (ch) == (ch2) || (ch) == (ch3)) +#define ISASCII_(ch) ((unsigned)(ch) <= 127) +#define ISBLANK_(ch) (ISANYOF2_((ch), _T(' '), _T('\t'))) +#define ISNEWLINE_(ch) (ISANYOF2_((ch), _T('\r'), _T('\n'))) +#define ISWHITESPACE_(ch) (ISBLANK_(ch) || ISANYOF2_((ch), _T('\v'), _T('\f'))) +#define ISCNTRL_(ch) ((unsigned)(ch) <= 31 || (unsigned)(ch) == 127) +#define ISPUNCT_(ch) (ISIN_(ch, 33, 47) || ISIN_(ch, 58, 64) || ISIN_(ch, 91, 96) || ISIN_(ch, 123, 126)) +#define ISUPPER_(ch) (ISIN_(ch, _T('A'), _T('Z'))) +#define ISLOWER_(ch) (ISIN_(ch, _T('a'), _T('z'))) +#define ISALPHA_(ch) (ISUPPER_(ch) || ISLOWER_(ch)) +#define ISDIGIT_(ch) (ISIN_(ch, _T('0'), _T('9'))) +#define ISXDIGIT_(ch) (ISDIGIT_(ch) || ISIN_(ch, _T('A'), _T('F')) || ISIN_(ch, _T('a'), _T('f'))) +#define ISALNUM_(ch) (ISALPHA_(ch) || ISDIGIT_(ch)) + +#define ISANYOF(off, palette) ISANYOF_(CH(off), (palette)) +#define ISANYOF2(off, ch1, ch2) ISANYOF2_(CH(off), (ch1), (ch2)) +#define ISANYOF3(off, ch1, ch2, ch3) ISANYOF3_(CH(off), (ch1), (ch2), (ch3)) +#define ISASCII(off) ISASCII_(CH(off)) +#define ISBLANK(off) ISBLANK_(CH(off)) +#define ISNEWLINE(off) ISNEWLINE_(CH(off)) +#define ISWHITESPACE(off) ISWHITESPACE_(CH(off)) +#define ISCNTRL(off) ISCNTRL_(CH(off)) +#define ISPUNCT(off) ISPUNCT_(CH(off)) +#define ISUPPER(off) ISUPPER_(CH(off)) +#define ISLOWER(off) ISLOWER_(CH(off)) +#define ISALPHA(off) ISALPHA_(CH(off)) +#define ISDIGIT(off) ISDIGIT_(CH(off)) +#define ISXDIGIT(off) ISXDIGIT_(CH(off)) +#define ISALNUM(off) ISALNUM_(CH(off)) + + +#if defined MD4C_USE_UTF16 + #define md_strchr wcschr +#else + #define md_strchr strchr +#endif + + +/* Case insensitive check of string equality. */ +static inline int +md_ascii_case_eq(const CHAR* s1, const CHAR* s2, SZ n) +{ + OFF i; + for(i = 0; i < n; i++) { + CHAR ch1 = s1[i]; + CHAR ch2 = s2[i]; + + if(ISLOWER_(ch1)) + ch1 += ('A'-'a'); + if(ISLOWER_(ch2)) + ch2 += ('A'-'a'); + if(ch1 != ch2) + return FALSE; + } + return TRUE; +} + +static inline int +md_ascii_eq(const CHAR* s1, const CHAR* s2, SZ n) +{ + return memcmp(s1, s2, n * sizeof(CHAR)) == 0; +} + +static int +md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ size) +{ + OFF off = 0; + int ret = 0; + + while(1) { + while(off < size && str[off] != _T('\0')) + off++; + + if(off > 0) { + ret = ctx->parser.text(type, str, off, ctx->userdata); + if(ret != 0) + return ret; + + str += off; + size -= off; + off = 0; + } + + if(off >= size) + return 0; + + ret = ctx->parser.text(MD_TEXT_NULLCHAR, _T(""), 1, ctx->userdata); + if(ret != 0) + return ret; + off++; + } +} + + +#define MD_CHECK(func) \ + do { \ + ret = (func); \ + if(ret < 0) \ + goto abort; \ + } while(0) + + +#define MD_TEMP_BUFFER(sz) \ + do { \ + if(sz > ctx->alloc_buffer) { \ + CHAR* new_buffer; \ + SZ new_size = ((sz) + (sz) / 2 + 128) & ~127; \ + \ + new_buffer = (MD_CHAR *) realloc(ctx->buffer, new_size); \ + if(new_buffer == NULL) { \ + MD_LOG("realloc() failed."); \ + ret = -1; \ + goto abort; \ + } \ + \ + ctx->buffer = new_buffer; \ + ctx->alloc_buffer = new_size; \ + } \ + } while(0) + + +#define MD_ENTER_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.enter_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_block() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_LEAVE_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.leave_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_block() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_ENTER_SPAN(type, arg) \ + do { \ + ret = ctx->parser.enter_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_span() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_LEAVE_SPAN(type, arg) \ + do { \ + ret = ctx->parser.leave_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_span() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_TEXT(type, str, size) \ + do { \ + if(size > 0) { \ + ret = ctx->parser.text((type), (str), (size), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ + } while(0) + +#define MD_TEXT_INSECURE(type, str, size) \ + do { \ + if(size > 0) { \ + ret = md_text_with_null_replacement(ctx, type, str, size); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ + } while(0) + + + +/************************* + *** Unicode Support *** + *************************/ + +typedef struct MD_UNICODE_FOLD_INFO_tag MD_UNICODE_FOLD_INFO; +struct MD_UNICODE_FOLD_INFO_tag { + unsigned codepoints[3]; + unsigned n_codepoints; +}; + + +#if defined MD4C_USE_UTF16 || defined MD4C_USE_UTF8 + /* Binary search over sorted "map" of codepoints. Consecutive sequences + * of codepoints may be encoded in the map by just using the + * (MIN_CODEPOINT | 0x40000000) and (MAX_CODEPOINT | 0x80000000). + * + * Returns index of the found record in the map (in the case of ranges, + * the minimal value is used); or -1 on failure. */ + static int + md_unicode_bsearch__(unsigned codepoint, const unsigned* map, size_t map_size) + { + int beg, end; + int pivot_beg, pivot_end; + + beg = 0; + end = (int) map_size-1; + while(beg <= end) { + /* Pivot may be a range, not just a single value. */ + pivot_beg = pivot_end = (beg + end) / 2; + if(map[pivot_end] & 0x40000000) + pivot_end++; + if(map[pivot_beg] & 0x80000000) + pivot_beg--; + + if(codepoint < (map[pivot_beg] & 0x00ffffff)) + end = pivot_beg - 1; + else if(codepoint > (map[pivot_end] & 0x00ffffff)) + beg = pivot_end + 1; + else + return pivot_beg; + } + + return -1; + } + + static int + md_is_unicode_whitespace__(unsigned codepoint) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Zs" category. + * (generated by scripts/build_whitespace_map.py) */ + static const unsigned WHITESPACE_MAP[] = { + S(0x0020), S(0x00a0), S(0x1680), R(0x2000,0x200a), S(0x202f), S(0x205f), S(0x3000) + }; +#undef R +#undef S + + /* The ASCII ones are the most frequently used ones, also CommonMark + * specification requests few more in this range. */ + if(codepoint <= 0x7f) + return ISWHITESPACE_(codepoint); + + return (md_unicode_bsearch__(codepoint, WHITESPACE_MAP, SIZEOF_ARRAY(WHITESPACE_MAP)) >= 0); + } + + static int + md_is_unicode_punct__(unsigned codepoint) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories. + * (generated by scripts/build_punct_map.py) */ + static const unsigned PUNCT_MAP[] = { + R(0x0021,0x0023), R(0x0025,0x002a), R(0x002c,0x002f), R(0x003a,0x003b), R(0x003f,0x0040), + R(0x005b,0x005d), S(0x005f), S(0x007b), S(0x007d), S(0x00a1), S(0x00a7), S(0x00ab), R(0x00b6,0x00b7), + S(0x00bb), S(0x00bf), S(0x037e), S(0x0387), R(0x055a,0x055f), R(0x0589,0x058a), S(0x05be), S(0x05c0), + S(0x05c3), S(0x05c6), R(0x05f3,0x05f4), R(0x0609,0x060a), R(0x060c,0x060d), S(0x061b), R(0x061e,0x061f), + R(0x066a,0x066d), S(0x06d4), R(0x0700,0x070d), R(0x07f7,0x07f9), R(0x0830,0x083e), S(0x085e), + R(0x0964,0x0965), S(0x0970), S(0x09fd), S(0x0a76), S(0x0af0), S(0x0c77), S(0x0c84), S(0x0df4), S(0x0e4f), + R(0x0e5a,0x0e5b), R(0x0f04,0x0f12), S(0x0f14), R(0x0f3a,0x0f3d), S(0x0f85), R(0x0fd0,0x0fd4), + R(0x0fd9,0x0fda), R(0x104a,0x104f), S(0x10fb), R(0x1360,0x1368), S(0x1400), S(0x166e), R(0x169b,0x169c), + R(0x16eb,0x16ed), R(0x1735,0x1736), R(0x17d4,0x17d6), R(0x17d8,0x17da), R(0x1800,0x180a), + R(0x1944,0x1945), R(0x1a1e,0x1a1f), R(0x1aa0,0x1aa6), R(0x1aa8,0x1aad), R(0x1b5a,0x1b60), + R(0x1bfc,0x1bff), R(0x1c3b,0x1c3f), R(0x1c7e,0x1c7f), R(0x1cc0,0x1cc7), S(0x1cd3), R(0x2010,0x2027), + R(0x2030,0x2043), R(0x2045,0x2051), R(0x2053,0x205e), R(0x207d,0x207e), R(0x208d,0x208e), + R(0x2308,0x230b), R(0x2329,0x232a), R(0x2768,0x2775), R(0x27c5,0x27c6), R(0x27e6,0x27ef), + R(0x2983,0x2998), R(0x29d8,0x29db), R(0x29fc,0x29fd), R(0x2cf9,0x2cfc), R(0x2cfe,0x2cff), S(0x2d70), + R(0x2e00,0x2e2e), R(0x2e30,0x2e4f), S(0x2e52), R(0x3001,0x3003), R(0x3008,0x3011), R(0x3014,0x301f), + S(0x3030), S(0x303d), S(0x30a0), S(0x30fb), R(0xa4fe,0xa4ff), R(0xa60d,0xa60f), S(0xa673), S(0xa67e), + R(0xa6f2,0xa6f7), R(0xa874,0xa877), R(0xa8ce,0xa8cf), R(0xa8f8,0xa8fa), S(0xa8fc), R(0xa92e,0xa92f), + S(0xa95f), R(0xa9c1,0xa9cd), R(0xa9de,0xa9df), R(0xaa5c,0xaa5f), R(0xaade,0xaadf), R(0xaaf0,0xaaf1), + S(0xabeb), R(0xfd3e,0xfd3f), R(0xfe10,0xfe19), R(0xfe30,0xfe52), R(0xfe54,0xfe61), S(0xfe63), S(0xfe68), + R(0xfe6a,0xfe6b), R(0xff01,0xff03), R(0xff05,0xff0a), R(0xff0c,0xff0f), R(0xff1a,0xff1b), + R(0xff1f,0xff20), R(0xff3b,0xff3d), S(0xff3f), S(0xff5b), S(0xff5d), R(0xff5f,0xff65), R(0x10100,0x10102), + S(0x1039f), S(0x103d0), S(0x1056f), S(0x10857), S(0x1091f), S(0x1093f), R(0x10a50,0x10a58), S(0x10a7f), + R(0x10af0,0x10af6), R(0x10b39,0x10b3f), R(0x10b99,0x10b9c), S(0x10ead), R(0x10f55,0x10f59), + R(0x11047,0x1104d), R(0x110bb,0x110bc), R(0x110be,0x110c1), R(0x11140,0x11143), R(0x11174,0x11175), + R(0x111c5,0x111c8), S(0x111cd), S(0x111db), R(0x111dd,0x111df), R(0x11238,0x1123d), S(0x112a9), + R(0x1144b,0x1144f), R(0x1145a,0x1145b), S(0x1145d), S(0x114c6), R(0x115c1,0x115d7), R(0x11641,0x11643), + R(0x11660,0x1166c), R(0x1173c,0x1173e), S(0x1183b), R(0x11944,0x11946), S(0x119e2), R(0x11a3f,0x11a46), + R(0x11a9a,0x11a9c), R(0x11a9e,0x11aa2), R(0x11c41,0x11c45), R(0x11c70,0x11c71), R(0x11ef7,0x11ef8), + S(0x11fff), R(0x12470,0x12474), R(0x16a6e,0x16a6f), S(0x16af5), R(0x16b37,0x16b3b), S(0x16b44), + R(0x16e97,0x16e9a), S(0x16fe2), S(0x1bc9f), R(0x1da87,0x1da8b), R(0x1e95e,0x1e95f) + }; +#undef R +#undef S + + /* The ASCII ones are the most frequently used ones, also CommonMark + * specification requests few more in this range. */ + if(codepoint <= 0x7f) + return ISPUNCT_(codepoint); + + return (md_unicode_bsearch__(codepoint, PUNCT_MAP, SIZEOF_ARRAY(PUNCT_MAP)) >= 0); + } + + static void + md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories. + * (generated by scripts/build_folding_map.py) */ + static const unsigned FOLD_MAP_1[] = { + R(0x0041,0x005a), S(0x00b5), R(0x00c0,0x00d6), R(0x00d8,0x00de), R(0x0100,0x012e), R(0x0132,0x0136), + R(0x0139,0x0147), R(0x014a,0x0176), S(0x0178), R(0x0179,0x017d), S(0x017f), S(0x0181), S(0x0182), + S(0x0184), S(0x0186), S(0x0187), S(0x0189), S(0x018a), S(0x018b), S(0x018e), S(0x018f), S(0x0190), + S(0x0191), S(0x0193), S(0x0194), S(0x0196), S(0x0197), S(0x0198), S(0x019c), S(0x019d), S(0x019f), + R(0x01a0,0x01a4), S(0x01a6), S(0x01a7), S(0x01a9), S(0x01ac), S(0x01ae), S(0x01af), S(0x01b1), S(0x01b2), + S(0x01b3), S(0x01b5), S(0x01b7), S(0x01b8), S(0x01bc), S(0x01c4), S(0x01c5), S(0x01c7), S(0x01c8), + S(0x01ca), R(0x01cb,0x01db), R(0x01de,0x01ee), S(0x01f1), S(0x01f2), S(0x01f4), S(0x01f6), S(0x01f7), + R(0x01f8,0x021e), S(0x0220), R(0x0222,0x0232), S(0x023a), S(0x023b), S(0x023d), S(0x023e), S(0x0241), + S(0x0243), S(0x0244), S(0x0245), R(0x0246,0x024e), S(0x0345), S(0x0370), S(0x0372), S(0x0376), S(0x037f), + S(0x0386), R(0x0388,0x038a), S(0x038c), S(0x038e), S(0x038f), R(0x0391,0x03a1), R(0x03a3,0x03ab), + S(0x03c2), S(0x03cf), S(0x03d0), S(0x03d1), S(0x03d5), S(0x03d6), R(0x03d8,0x03ee), S(0x03f0), S(0x03f1), + S(0x03f4), S(0x03f5), S(0x03f7), S(0x03f9), S(0x03fa), R(0x03fd,0x03ff), R(0x0400,0x040f), + R(0x0410,0x042f), R(0x0460,0x0480), R(0x048a,0x04be), S(0x04c0), R(0x04c1,0x04cd), R(0x04d0,0x052e), + R(0x0531,0x0556), R(0x10a0,0x10c5), S(0x10c7), S(0x10cd), R(0x13f8,0x13fd), S(0x1c80), S(0x1c81), + S(0x1c82), S(0x1c83), S(0x1c84), S(0x1c85), S(0x1c86), S(0x1c87), S(0x1c88), R(0x1c90,0x1cba), + R(0x1cbd,0x1cbf), R(0x1e00,0x1e94), S(0x1e9b), R(0x1ea0,0x1efe), R(0x1f08,0x1f0f), R(0x1f18,0x1f1d), + R(0x1f28,0x1f2f), R(0x1f38,0x1f3f), R(0x1f48,0x1f4d), S(0x1f59), S(0x1f5b), S(0x1f5d), S(0x1f5f), + R(0x1f68,0x1f6f), S(0x1fb8), S(0x1fb9), S(0x1fba), S(0x1fbb), S(0x1fbe), R(0x1fc8,0x1fcb), S(0x1fd8), + S(0x1fd9), S(0x1fda), S(0x1fdb), S(0x1fe8), S(0x1fe9), S(0x1fea), S(0x1feb), S(0x1fec), S(0x1ff8), + S(0x1ff9), S(0x1ffa), S(0x1ffb), S(0x2126), S(0x212a), S(0x212b), S(0x2132), R(0x2160,0x216f), S(0x2183), + R(0x24b6,0x24cf), R(0x2c00,0x2c2e), S(0x2c60), S(0x2c62), S(0x2c63), S(0x2c64), R(0x2c67,0x2c6b), + S(0x2c6d), S(0x2c6e), S(0x2c6f), S(0x2c70), S(0x2c72), S(0x2c75), S(0x2c7e), S(0x2c7f), R(0x2c80,0x2ce2), + S(0x2ceb), S(0x2ced), S(0x2cf2), R(0xa640,0xa66c), R(0xa680,0xa69a), R(0xa722,0xa72e), R(0xa732,0xa76e), + S(0xa779), S(0xa77b), S(0xa77d), R(0xa77e,0xa786), S(0xa78b), S(0xa78d), S(0xa790), S(0xa792), + R(0xa796,0xa7a8), S(0xa7aa), S(0xa7ab), S(0xa7ac), S(0xa7ad), S(0xa7ae), S(0xa7b0), S(0xa7b1), S(0xa7b2), + S(0xa7b3), R(0xa7b4,0xa7be), S(0xa7c2), S(0xa7c4), S(0xa7c5), S(0xa7c6), S(0xa7c7), S(0xa7c9), S(0xa7f5), + R(0xab70,0xabbf), R(0xff21,0xff3a), R(0x10400,0x10427), R(0x104b0,0x104d3), R(0x10c80,0x10cb2), + R(0x118a0,0x118bf), R(0x16e40,0x16e5f), R(0x1e900,0x1e921) + }; + static const unsigned FOLD_MAP_1_DATA[] = { + 0x0061, 0x007a, 0x03bc, 0x00e0, 0x00f6, 0x00f8, 0x00fe, 0x0101, 0x012f, 0x0133, 0x0137, 0x013a, 0x0148, + 0x014b, 0x0177, 0x00ff, 0x017a, 0x017e, 0x0073, 0x0253, 0x0183, 0x0185, 0x0254, 0x0188, 0x0256, 0x0257, + 0x018c, 0x01dd, 0x0259, 0x025b, 0x0192, 0x0260, 0x0263, 0x0269, 0x0268, 0x0199, 0x026f, 0x0272, 0x0275, + 0x01a1, 0x01a5, 0x0280, 0x01a8, 0x0283, 0x01ad, 0x0288, 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b6, 0x0292, + 0x01b9, 0x01bd, 0x01c6, 0x01c6, 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01dc, 0x01df, 0x01ef, 0x01f3, 0x01f3, + 0x01f5, 0x0195, 0x01bf, 0x01f9, 0x021f, 0x019e, 0x0223, 0x0233, 0x2c65, 0x023c, 0x019a, 0x2c66, 0x0242, + 0x0180, 0x0289, 0x028c, 0x0247, 0x024f, 0x03b9, 0x0371, 0x0373, 0x0377, 0x03f3, 0x03ac, 0x03ad, 0x03af, + 0x03cc, 0x03cd, 0x03ce, 0x03b1, 0x03c1, 0x03c3, 0x03cb, 0x03c3, 0x03d7, 0x03b2, 0x03b8, 0x03c6, 0x03c0, + 0x03d9, 0x03ef, 0x03ba, 0x03c1, 0x03b8, 0x03b5, 0x03f8, 0x03f2, 0x03fb, 0x037b, 0x037d, 0x0450, 0x045f, + 0x0430, 0x044f, 0x0461, 0x0481, 0x048b, 0x04bf, 0x04cf, 0x04c2, 0x04ce, 0x04d1, 0x052f, 0x0561, 0x0586, + 0x2d00, 0x2d25, 0x2d27, 0x2d2d, 0x13f0, 0x13f5, 0x0432, 0x0434, 0x043e, 0x0441, 0x0442, 0x0442, 0x044a, + 0x0463, 0xa64b, 0x10d0, 0x10fa, 0x10fd, 0x10ff, 0x1e01, 0x1e95, 0x1e61, 0x1ea1, 0x1eff, 0x1f00, 0x1f07, + 0x1f10, 0x1f15, 0x1f20, 0x1f27, 0x1f30, 0x1f37, 0x1f40, 0x1f45, 0x1f51, 0x1f53, 0x1f55, 0x1f57, 0x1f60, + 0x1f67, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x03b9, 0x1f72, 0x1f75, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fe0, + 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x03c9, 0x006b, 0x00e5, 0x214e, 0x2170, + 0x217f, 0x2184, 0x24d0, 0x24e9, 0x2c30, 0x2c5e, 0x2c61, 0x026b, 0x1d7d, 0x027d, 0x2c68, 0x2c6c, 0x0251, + 0x0271, 0x0250, 0x0252, 0x2c73, 0x2c76, 0x023f, 0x0240, 0x2c81, 0x2ce3, 0x2cec, 0x2cee, 0x2cf3, 0xa641, + 0xa66d, 0xa681, 0xa69b, 0xa723, 0xa72f, 0xa733, 0xa76f, 0xa77a, 0xa77c, 0x1d79, 0xa77f, 0xa787, 0xa78c, + 0x0265, 0xa791, 0xa793, 0xa797, 0xa7a9, 0x0266, 0x025c, 0x0261, 0x026c, 0x026a, 0x029e, 0x0287, 0x029d, + 0xab53, 0xa7b5, 0xa7bf, 0xa7c3, 0xa794, 0x0282, 0x1d8e, 0xa7c8, 0xa7ca, 0xa7f6, 0x13a0, 0x13ef, 0xff41, + 0xff5a, 0x10428, 0x1044f, 0x104d8, 0x104fb, 0x10cc0, 0x10cf2, 0x118c0, 0x118df, 0x16e60, 0x16e7f, 0x1e922, + 0x1e943 + }; + static const unsigned FOLD_MAP_2[] = { + S(0x00df), S(0x0130), S(0x0149), S(0x01f0), S(0x0587), S(0x1e96), S(0x1e97), S(0x1e98), S(0x1e99), + S(0x1e9a), S(0x1e9e), S(0x1f50), R(0x1f80,0x1f87), R(0x1f88,0x1f8f), R(0x1f90,0x1f97), R(0x1f98,0x1f9f), + R(0x1fa0,0x1fa7), R(0x1fa8,0x1faf), S(0x1fb2), S(0x1fb3), S(0x1fb4), S(0x1fb6), S(0x1fbc), S(0x1fc2), + S(0x1fc3), S(0x1fc4), S(0x1fc6), S(0x1fcc), S(0x1fd6), S(0x1fe4), S(0x1fe6), S(0x1ff2), S(0x1ff3), + S(0x1ff4), S(0x1ff6), S(0x1ffc), S(0xfb00), S(0xfb01), S(0xfb02), S(0xfb05), S(0xfb06), S(0xfb13), + S(0xfb14), S(0xfb15), S(0xfb16), S(0xfb17) + }; + static const unsigned FOLD_MAP_2_DATA[] = { + 0x0073,0x0073, 0x0069,0x0307, 0x02bc,0x006e, 0x006a,0x030c, 0x0565,0x0582, 0x0068,0x0331, 0x0074,0x0308, + 0x0077,0x030a, 0x0079,0x030a, 0x0061,0x02be, 0x0073,0x0073, 0x03c5,0x0313, 0x1f00,0x03b9, 0x1f07,0x03b9, + 0x1f00,0x03b9, 0x1f07,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f60,0x03b9, + 0x1f67,0x03b9, 0x1f60,0x03b9, 0x1f67,0x03b9, 0x1f70,0x03b9, 0x03b1,0x03b9, 0x03ac,0x03b9, 0x03b1,0x0342, + 0x03b1,0x03b9, 0x1f74,0x03b9, 0x03b7,0x03b9, 0x03ae,0x03b9, 0x03b7,0x0342, 0x03b7,0x03b9, 0x03b9,0x0342, + 0x03c1,0x0313, 0x03c5,0x0342, 0x1f7c,0x03b9, 0x03c9,0x03b9, 0x03ce,0x03b9, 0x03c9,0x0342, 0x03c9,0x03b9, + 0x0066,0x0066, 0x0066,0x0069, 0x0066,0x006c, 0x0073,0x0074, 0x0073,0x0074, 0x0574,0x0576, 0x0574,0x0565, + 0x0574,0x056b, 0x057e,0x0576, 0x0574,0x056d + }; + static const unsigned FOLD_MAP_3[] = { + S(0x0390), S(0x03b0), S(0x1f52), S(0x1f54), S(0x1f56), S(0x1fb7), S(0x1fc7), S(0x1fd2), S(0x1fd3), + S(0x1fd7), S(0x1fe2), S(0x1fe3), S(0x1fe7), S(0x1ff7), S(0xfb03), S(0xfb04) + }; + static const unsigned FOLD_MAP_3_DATA[] = { + 0x03b9,0x0308,0x0301, 0x03c5,0x0308,0x0301, 0x03c5,0x0313,0x0300, 0x03c5,0x0313,0x0301, + 0x03c5,0x0313,0x0342, 0x03b1,0x0342,0x03b9, 0x03b7,0x0342,0x03b9, 0x03b9,0x0308,0x0300, + 0x03b9,0x0308,0x0301, 0x03b9,0x0308,0x0342, 0x03c5,0x0308,0x0300, 0x03c5,0x0308,0x0301, + 0x03c5,0x0308,0x0342, 0x03c9,0x0342,0x03b9, 0x0066,0x0066,0x0069, 0x0066,0x0066,0x006c + }; +#undef R +#undef S + static const struct { + const unsigned* map; + const unsigned* data; + size_t map_size; + unsigned n_codepoints; + } FOLD_MAP_LIST[] = { + { FOLD_MAP_1, FOLD_MAP_1_DATA, SIZEOF_ARRAY(FOLD_MAP_1), 1 }, + { FOLD_MAP_2, FOLD_MAP_2_DATA, SIZEOF_ARRAY(FOLD_MAP_2), 2 }, + { FOLD_MAP_3, FOLD_MAP_3_DATA, SIZEOF_ARRAY(FOLD_MAP_3), 3 } + }; + + int i; + + /* Fast path for ASCII characters. */ + if(codepoint <= 0x7f) { + info->codepoints[0] = codepoint; + if(ISUPPER_(codepoint)) + info->codepoints[0] += 'a' - 'A'; + info->n_codepoints = 1; + return; + } + + /* Try to locate the codepoint in any of the maps. */ + for(i = 0; i < (int) SIZEOF_ARRAY(FOLD_MAP_LIST); i++) { + int index; + + index = md_unicode_bsearch__(codepoint, FOLD_MAP_LIST[i].map, FOLD_MAP_LIST[i].map_size); + if(index >= 0) { + /* Found the mapping. */ + unsigned n_codepoints = FOLD_MAP_LIST[i].n_codepoints; + const unsigned* map = FOLD_MAP_LIST[i].map; + const unsigned* codepoints = FOLD_MAP_LIST[i].data + (index * n_codepoints); + + memcpy(info->codepoints, codepoints, sizeof(unsigned) * n_codepoints); + info->n_codepoints = n_codepoints; + + if(FOLD_MAP_LIST[i].map[index] != codepoint) { + /* The found mapping maps whole range of codepoints, + * i.e. we have to offset info->codepoints[0] accordingly. */ + if((map[index] & 0x00ffffff)+1 == codepoints[0]) { + /* Alternating type of the range. */ + info->codepoints[0] = codepoint + ((codepoint & 0x1) == (map[index] & 0x1) ? 1 : 0); + } else { + /* Range to range kind of mapping. */ + info->codepoints[0] += (codepoint - (map[index] & 0x00ffffff)); + } + } + + return; + } + } + + /* No mapping found. Map the codepoint to itself. */ + info->codepoints[0] = codepoint; + info->n_codepoints = 1; + } +#endif + + +#if defined MD4C_USE_UTF16 + #define IS_UTF16_SURROGATE_HI(word) (((WORD)(word) & 0xfc00) == 0xd800) + #define IS_UTF16_SURROGATE_LO(word) (((WORD)(word) & 0xfc00) == 0xdc00) + #define UTF16_DECODE_SURROGATE(hi, lo) (0x10000 + ((((unsigned)(hi) & 0x3ff) << 10) | (((unsigned)(lo) & 0x3ff) << 0))) + + static unsigned + md_decode_utf16le__(const CHAR* str, SZ str_size, SZ* p_size) + { + if(IS_UTF16_SURROGATE_HI(str[0])) { + if(1 < str_size && IS_UTF16_SURROGATE_LO(str[1])) { + if(p_size != NULL) + *p_size = 2; + return UTF16_DECODE_SURROGATE(str[0], str[1]); + } + } + + if(p_size != NULL) + *p_size = 1; + return str[0]; + } + + static unsigned + md_decode_utf16le_before__(MD_CTX* ctx, OFF off) + { + if(off > 2 && IS_UTF16_SURROGATE_HI(CH(off-2)) && IS_UTF16_SURROGATE_LO(CH(off-1))) + return UTF16_DECODE_SURROGATE(CH(off-2), CH(off-1)); + + return CH(off); + } + + /* No whitespace uses surrogates, so no decoding needed here. */ + #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint) + #define ISUNICODEWHITESPACE(off) md_is_unicode_whitespace__(CH(off)) + #define ISUNICODEWHITESPACEBEFORE(off) md_is_unicode_whitespace__(CH((off)-1)) + + #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf16le__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf16le_before__(ctx, off)) + + static inline int + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) + { + return md_decode_utf16le__(str+off, str_size-off, p_char_size); + } +#elif defined MD4C_USE_UTF8 + #define IS_UTF8_LEAD1(byte) ((unsigned char)(byte) <= 0x7f) + #define IS_UTF8_LEAD2(byte) (((unsigned char)(byte) & 0xe0) == 0xc0) + #define IS_UTF8_LEAD3(byte) (((unsigned char)(byte) & 0xf0) == 0xe0) + #define IS_UTF8_LEAD4(byte) (((unsigned char)(byte) & 0xf8) == 0xf0) + #define IS_UTF8_TAIL(byte) (((unsigned char)(byte) & 0xc0) == 0x80) + + static unsigned + md_decode_utf8__(const CHAR* str, SZ str_size, SZ* p_size) + { + if(!IS_UTF8_LEAD1(str[0])) { + if(IS_UTF8_LEAD2(str[0])) { + if(1 < str_size && IS_UTF8_TAIL(str[1])) { + if(p_size != NULL) + *p_size = 2; + + return (((unsigned int)str[0] & 0x1f) << 6) | + (((unsigned int)str[1] & 0x3f) << 0); + } + } else if(IS_UTF8_LEAD3(str[0])) { + if(2 < str_size && IS_UTF8_TAIL(str[1]) && IS_UTF8_TAIL(str[2])) { + if(p_size != NULL) + *p_size = 3; + + return (((unsigned int)str[0] & 0x0f) << 12) | + (((unsigned int)str[1] & 0x3f) << 6) | + (((unsigned int)str[2] & 0x3f) << 0); + } + } else if(IS_UTF8_LEAD4(str[0])) { + if(3 < str_size && IS_UTF8_TAIL(str[1]) && IS_UTF8_TAIL(str[2]) && IS_UTF8_TAIL(str[3])) { + if(p_size != NULL) + *p_size = 4; + + return (((unsigned int)str[0] & 0x07) << 18) | + (((unsigned int)str[1] & 0x3f) << 12) | + (((unsigned int)str[2] & 0x3f) << 6) | + (((unsigned int)str[3] & 0x3f) << 0); + } + } + } + + if(p_size != NULL) + *p_size = 1; + return (unsigned) str[0]; + } + + static unsigned + md_decode_utf8_before__(MD_CTX* ctx, OFF off) + { + if(!IS_UTF8_LEAD1(CH(off-1))) { + if(off > 1 && IS_UTF8_LEAD2(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-2) & 0x1f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + + if(off > 2 && IS_UTF8_LEAD3(CH(off-3)) && IS_UTF8_TAIL(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-3) & 0x0f) << 12) | + (((unsigned int)CH(off-2) & 0x3f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + + if(off > 3 && IS_UTF8_LEAD4(CH(off-4)) && IS_UTF8_TAIL(CH(off-3)) && IS_UTF8_TAIL(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-4) & 0x07) << 18) | + (((unsigned int)CH(off-3) & 0x3f) << 12) | + (((unsigned int)CH(off-2) & 0x3f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + } + + return (unsigned) CH(off-1); + } + + #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint) + #define ISUNICODEWHITESPACE(off) md_is_unicode_whitespace__(md_decode_utf8__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEWHITESPACEBEFORE(off) md_is_unicode_whitespace__(md_decode_utf8_before__(ctx, off)) + + #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf8__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf8_before__(ctx, off)) + + static inline unsigned + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) + { + return md_decode_utf8__(str+off, str_size-off, p_char_size); + } +#else + #define ISUNICODEWHITESPACE_(codepoint) ISWHITESPACE_(codepoint) + #define ISUNICODEWHITESPACE(off) ISWHITESPACE(off) + #define ISUNICODEWHITESPACEBEFORE(off) ISWHITESPACE((off)-1) + + #define ISUNICODEPUNCT(off) ISPUNCT(off) + #define ISUNICODEPUNCTBEFORE(off) ISPUNCT((off)-1) + + static inline void + md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) + { + info->codepoints[0] = codepoint; + if(ISUPPER_(codepoint)) + info->codepoints[0] += 'a' - 'A'; + info->n_codepoints = 1; + } + + static inline unsigned + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_size) + { + *p_size = 1; + return (unsigned) str[off]; + } +#endif + + +/************************************* + *** Helper string manipulations *** + *************************************/ + +/* Fill buffer with copy of the string between 'beg' and 'end' but replace any + * line breaks with given replacement character. + * + * NOTE: Caller is responsible to make sure the buffer is large enough. + * (Given the output is always shorter then input, (end - beg) is good idea + * what the caller should allocate.) + */ +static void +md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n_lines, + CHAR line_break_replacement_char, CHAR* buffer, SZ* p_size) +{ + CHAR* ptr = buffer; + int line_index = 0; + OFF off = beg; + + MD_UNUSED(n_lines); + + while(1) { + const MD_LINE* line = &lines[line_index]; + OFF line_end = line->end; + if(end < line_end) + line_end = end; + + while(off < line_end) { + *ptr = CH(off); + ptr++; + off++; + } + + if(off >= end) { + *p_size = (MD_SIZE)(ptr - buffer); + return; + } + + *ptr = line_break_replacement_char; + ptr++; + + line_index++; + off = lines[line_index].beg; + } +} + +/* Wrapper of md_merge_lines() which allocates new buffer for the output string. + */ +static int +md_merge_lines_alloc(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n_lines, + CHAR line_break_replacement_char, CHAR** p_str, SZ* p_size) +{ + CHAR* buffer; + + buffer = (CHAR*) malloc(sizeof(CHAR) * (end - beg)); + if(buffer == NULL) { + MD_LOG("malloc() failed."); + return -1; + } + + md_merge_lines(ctx, beg, end, lines, n_lines, + line_break_replacement_char, buffer, p_size); + + *p_str = buffer; + return 0; +} + +static OFF +md_skip_unicode_whitespace(const CHAR* label, OFF off, SZ size) +{ + SZ char_size; + unsigned codepoint; + + while(off < size) { + codepoint = md_decode_unicode(label, off, size, &char_size); + if(!ISUNICODEWHITESPACE_(codepoint) && !ISNEWLINE_(label[off])) + break; + off += char_size; + } + + return off; +} + + +/****************************** + *** Recognizing raw HTML *** + ******************************/ + +/* md_is_html_tag() may be called when processing inlines (inline raw HTML) + * or when breaking document to blocks (checking for start of HTML block type 7). + * + * When breaking document to blocks, we do not yet know line boundaries, but + * in that case the whole tag has to live on a single line. We distinguish this + * by n_lines == 0. + */ +static int +md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + int attr_state; + OFF off = beg; + OFF line_end = (n_lines > 0) ? lines[0].end : ctx->size; + int i = 0; + + MD_ASSERT(CH(beg) == _T('<')); + + if(off + 1 >= line_end) + return FALSE; + off++; + + /* For parsing attributes, we need a little state automaton below. + * State -1: no attributes are allowed. + * State 0: attribute could follow after some whitespace. + * State 1: after a whitespace (attribute name may follow). + * State 2: after attribute name ('=' MAY follow). + * State 3: after '=' (value specification MUST follow). + * State 41: in middle of unquoted attribute value. + * State 42: in middle of single-quoted attribute value. + * State 43: in middle of double-quoted attribute value. + */ + attr_state = 0; + + if(CH(off) == _T('/')) { + /* Closer tag "</ ... >". No attributes may be present. */ + attr_state = -1; + off++; + } + + /* Tag name */ + if(off >= line_end || !ISALPHA(off)) + return FALSE; + off++; + while(off < line_end && (ISALNUM(off) || CH(off) == _T('-'))) + off++; + + /* (Optional) attributes (if not closer), (optional) '/' (if not closer) + * and final '>'. */ + while(1) { + while(off < line_end && !ISNEWLINE(off)) { + if(attr_state > 40) { + if(attr_state == 41 && (ISBLANK(off) || ISANYOF(off, _T("\"'=<>`")))) { + attr_state = 0; + off--; /* Put the char back for re-inspection in the new state. */ + } else if(attr_state == 42 && CH(off) == _T('\'')) { + attr_state = 0; + } else if(attr_state == 43 && CH(off) == _T('"')) { + attr_state = 0; + } + off++; + } else if(ISWHITESPACE(off)) { + if(attr_state == 0) + attr_state = 1; + off++; + } else if(attr_state <= 2 && CH(off) == _T('>')) { + /* End. */ + goto done; + } else if(attr_state <= 2 && CH(off) == _T('/') && off+1 < line_end && CH(off+1) == _T('>')) { + /* End with digraph '/>' */ + off++; + goto done; + } else if((attr_state == 1 || attr_state == 2) && (ISALPHA(off) || CH(off) == _T('_') || CH(off) == _T(':'))) { + off++; + /* Attribute name */ + while(off < line_end && (ISALNUM(off) || ISANYOF(off, _T("_.:-")))) + off++; + attr_state = 2; + } else if(attr_state == 2 && CH(off) == _T('=')) { + /* Attribute assignment sign */ + off++; + attr_state = 3; + } else if(attr_state == 3) { + /* Expecting start of attribute value. */ + if(CH(off) == _T('"')) + attr_state = 43; + else if(CH(off) == _T('\'')) + attr_state = 42; + else if(!ISANYOF(off, _T("\"'=<>`")) && !ISNEWLINE(off)) + attr_state = 41; + else + return FALSE; + off++; + } else { + /* Anything unexpected. */ + return FALSE; + } + } + + /* We have to be on a single line. See definition of start condition + * of HTML block, type 7. */ + if(n_lines == 0) + return FALSE; + + i++; + if(i >= n_lines) + return FALSE; + + off = lines[i].beg; + line_end = lines[i].end; + + if(attr_state == 0 || attr_state == 41) + attr_state = 1; + + if(off >= max_end) + return FALSE; + } + +done: + if(off >= max_end) + return FALSE; + + *p_end = off+1; + return TRUE; +} + +static int +md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len, + const MD_LINE* lines, int n_lines, + OFF beg, OFF max_end, OFF* p_end, + OFF* p_scan_horizon) +{ + OFF off = beg; + int i = 0; + + if(off < *p_scan_horizon && *p_scan_horizon >= max_end - len) { + /* We have already scanned the range up to the max_end so we know + * there is nothing to see. */ + return FALSE; + } + + while(TRUE) { + while(off + len <= lines[i].end && off + len <= max_end) { + if(md_ascii_eq(STR(off), str, len)) { + /* Success. */ + *p_end = off + len; + return TRUE; + } + off++; + } + + i++; + if(off >= max_end || i >= n_lines) { + /* Failure. */ + *p_scan_horizon = off; + return FALSE; + } + + off = lines[i].beg; + } +} + +static int +md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + MD_ASSERT(CH(beg) == _T('<')); + + if(off + 4 >= lines[0].end) + return FALSE; + if(CH(off+1) != _T('!') || CH(off+2) != _T('-') || CH(off+3) != _T('-')) + return FALSE; + off += 4; + + /* ">" and "->" must not follow the opening. */ + if(off < lines[0].end && CH(off) == _T('>')) + return FALSE; + if(off+1 < lines[0].end && CH(off) == _T('-') && CH(off+1) == _T('>')) + return FALSE; + + /* HTML comment must not contain "--", so we scan just for "--" instead + * of "-->" and verify manually that '>' follows. */ + if(md_scan_for_html_closer(ctx, _T("--"), 2, + lines, n_lines, off, max_end, p_end, &ctx->html_comment_horizon)) + { + if(*p_end < max_end && CH(*p_end) == _T('>')) { + *p_end = *p_end + 1; + return TRUE; + } + } + + return FALSE; +} + +static int +md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + if(off + 2 >= lines[0].end) + return FALSE; + if(CH(off+1) != _T('?')) + return FALSE; + off += 2; + + return md_scan_for_html_closer(ctx, _T("?>"), 2, + lines, n_lines, off, max_end, p_end, &ctx->html_proc_instr_horizon); +} + +static int +md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + if(off + 2 >= lines[0].end) + return FALSE; + if(CH(off+1) != _T('!')) + return FALSE; + off += 2; + + /* Declaration name. */ + if(off >= lines[0].end || !ISALPHA(off)) + return FALSE; + off++; + while(off < lines[0].end && ISALPHA(off)) + off++; + if(off < lines[0].end && !ISWHITESPACE(off)) + return FALSE; + + return md_scan_for_html_closer(ctx, _T(">"), 1, + lines, n_lines, off, max_end, p_end, &ctx->html_decl_horizon); +} + +static int +md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + static const CHAR open_str[] = _T("<![CDATA["); + static const SZ open_size = SIZEOF_ARRAY(open_str) - 1; + + OFF off = beg; + + if(off + open_size >= lines[0].end) + return FALSE; + if(memcmp(STR(off), open_str, open_size) != 0) + return FALSE; + off += open_size; + + if(lines[n_lines-1].end < max_end) + max_end = lines[n_lines-1].end - 2; + + return md_scan_for_html_closer(ctx, _T("]]>"), 3, + lines, n_lines, off, max_end, p_end, &ctx->html_cdata_horizon); +} + +static int +md_is_html_any(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + MD_ASSERT(CH(beg) == _T('<')); + return (md_is_html_tag(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_comment(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_processing_instruction(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_declaration(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_cdata(ctx, lines, n_lines, beg, max_end, p_end)); +} + + +/**************************** + *** Recognizing Entity *** + ****************************/ + +static int +md_is_hex_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + while(off < max_end && ISXDIGIT_(text[off]) && off - beg <= 8) + off++; + + if(1 <= off - beg && off - beg <= 6) { + *p_end = off; + return TRUE; + } else { + return FALSE; + } +} + +static int +md_is_dec_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + while(off < max_end && ISDIGIT_(text[off]) && off - beg <= 8) + off++; + + if(1 <= off - beg && off - beg <= 7) { + *p_end = off; + return TRUE; + } else { + return FALSE; + } +} + +static int +md_is_named_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + if(off < max_end && ISALPHA_(text[off])) + off++; + else + return FALSE; + + while(off < max_end && ISALNUM_(text[off]) && off - beg <= 48) + off++; + + if(2 <= off - beg && off - beg <= 48) { + *p_end = off; + return TRUE; + } else { + return FALSE; + } +} + +static int +md_is_entity_str(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + int is_contents; + OFF off = beg; + + MD_ASSERT(text[off] == _T('&')); + off++; + + if(off+2 < max_end && text[off] == _T('#') && (text[off+1] == _T('x') || text[off+1] == _T('X'))) + is_contents = md_is_hex_entity_contents(ctx, text, off+2, max_end, &off); + else if(off+1 < max_end && text[off] == _T('#')) + is_contents = md_is_dec_entity_contents(ctx, text, off+1, max_end, &off); + else + is_contents = md_is_named_entity_contents(ctx, text, off, max_end, &off); + + if(is_contents && off < max_end && text[off] == _T(';')) { + *p_end = off+1; + return TRUE; + } else { + return FALSE; + } +} + +static inline int +md_is_entity(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + return md_is_entity_str(ctx, ctx->text, beg, max_end, p_end); +} + + +/****************************** + *** Attribute Management *** + ******************************/ + +typedef struct MD_ATTRIBUTE_BUILD_tag MD_ATTRIBUTE_BUILD; +struct MD_ATTRIBUTE_BUILD_tag { + CHAR* text; + MD_TEXTTYPE* substr_types; + OFF* substr_offsets; + int substr_count; + int substr_alloc; + MD_TEXTTYPE trivial_types[1]; + OFF trivial_offsets[2]; +}; + + +#define MD_BUILD_ATTR_NO_ESCAPES 0x0001 + +static int +md_build_attr_append_substr(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build, + MD_TEXTTYPE type, OFF off) +{ + if(build->substr_count >= build->substr_alloc) { + MD_TEXTTYPE* new_substr_types; + OFF* new_substr_offsets; + + build->substr_alloc = (build->substr_alloc > 0 + ? build->substr_alloc + build->substr_alloc / 2 + : 8); + new_substr_types = (MD_TEXTTYPE*) realloc(build->substr_types, + build->substr_alloc * sizeof(MD_TEXTTYPE)); + if(new_substr_types == NULL) { + MD_LOG("realloc() failed."); + return -1; + } + /* Note +1 to reserve space for final offset (== raw_size). */ + new_substr_offsets = (OFF*) realloc(build->substr_offsets, + (build->substr_alloc+1) * sizeof(OFF)); + if(new_substr_offsets == NULL) { + MD_LOG("realloc() failed."); + free(new_substr_types); + return -1; + } + + build->substr_types = new_substr_types; + build->substr_offsets = new_substr_offsets; + } + + build->substr_types[build->substr_count] = type; + build->substr_offsets[build->substr_count] = off; + build->substr_count++; + return 0; +} + +static void +md_free_attribute(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build) +{ + MD_UNUSED(ctx); + + if(build->substr_alloc > 0) { + free(build->text); + free(build->substr_types); + free(build->substr_offsets); + } +} + +static int +md_build_attribute(MD_CTX* ctx, const CHAR* raw_text, SZ raw_size, + unsigned flags, MD_ATTRIBUTE* attr, MD_ATTRIBUTE_BUILD* build) +{ + OFF raw_off, off; + int is_trivial; + int ret = 0; + + memset(build, 0, sizeof(MD_ATTRIBUTE_BUILD)); + + /* If there is no backslash and no ampersand, build trivial attribute + * without any malloc(). */ + is_trivial = TRUE; + for(raw_off = 0; raw_off < raw_size; raw_off++) { + if(ISANYOF3_(raw_text[raw_off], _T('\\'), _T('&'), _T('\0'))) { + is_trivial = FALSE; + break; + } + } + + if(is_trivial) { + build->text = (CHAR*) (raw_size ? raw_text : NULL); + build->substr_types = build->trivial_types; + build->substr_offsets = build->trivial_offsets; + build->substr_count = 1; + build->substr_alloc = 0; + build->trivial_types[0] = MD_TEXT_NORMAL; + build->trivial_offsets[0] = 0; + build->trivial_offsets[1] = raw_size; + off = raw_size; + } else { + build->text = (CHAR*) malloc(raw_size * sizeof(CHAR)); + if(build->text == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + + raw_off = 0; + off = 0; + + while(raw_off < raw_size) { + if(raw_text[raw_off] == _T('\0')) { + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_NULLCHAR, off)); + memcpy(build->text + off, raw_text + raw_off, 1); + off++; + raw_off++; + continue; + } + + if(raw_text[raw_off] == _T('&')) { + OFF ent_end; + + if(md_is_entity_str(ctx, raw_text, raw_off, raw_size, &ent_end)) { + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_ENTITY, off)); + memcpy(build->text + off, raw_text + raw_off, ent_end - raw_off); + off += ent_end - raw_off; + raw_off = ent_end; + continue; + } + } + + if(build->substr_count == 0 || build->substr_types[build->substr_count-1] != MD_TEXT_NORMAL) + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_NORMAL, off)); + + if(!(flags & MD_BUILD_ATTR_NO_ESCAPES) && + raw_text[raw_off] == _T('\\') && raw_off+1 < raw_size && + (ISPUNCT_(raw_text[raw_off+1]) || ISNEWLINE_(raw_text[raw_off+1]))) + raw_off++; + + build->text[off++] = raw_text[raw_off++]; + } + build->substr_offsets[build->substr_count] = off; + } + + attr->text = build->text; + attr->size = off; + attr->substr_offsets = build->substr_offsets; + attr->substr_types = build->substr_types; + return 0; + +abort: + md_free_attribute(ctx, build); + return -1; +} + + +/********************************************* + *** Dictionary of Reference Definitions *** + *********************************************/ + +#define MD_FNV1A_BASE 2166136261U +#define MD_FNV1A_PRIME 16777619U + +static inline unsigned +md_fnv1a(unsigned base, const void* data, size_t n) +{ + const unsigned char* buf = (const unsigned char*) data; + unsigned hash = base; + size_t i; + + for(i = 0; i < n; i++) { + hash ^= buf[i]; + hash *= MD_FNV1A_PRIME; + } + + return hash; +} + + +struct MD_REF_DEF_tag { + CHAR* label; + CHAR* title; + unsigned hash; + SZ label_size; + SZ title_size; + OFF dest_beg; + OFF dest_end; + unsigned char label_needs_free : 1; + unsigned char title_needs_free : 1; +}; + +/* Label equivalence is quite complicated with regards to whitespace and case + * folding. This complicates computing a hash of it as well as direct comparison + * of two labels. */ + +static unsigned +md_link_label_hash(const CHAR* label, SZ size) +{ + unsigned hash = MD_FNV1A_BASE; + OFF off; + unsigned codepoint; + int is_whitespace = FALSE; + + off = md_skip_unicode_whitespace(label, 0, size); + while(off < size) { + SZ char_size; + + codepoint = md_decode_unicode(label, off, size, &char_size); + is_whitespace = ISUNICODEWHITESPACE_(codepoint) || ISNEWLINE_(label[off]); + + if(is_whitespace) { + codepoint = ' '; + hash = md_fnv1a(hash, &codepoint, sizeof(unsigned)); + off = md_skip_unicode_whitespace(label, off, size); + } else { + MD_UNICODE_FOLD_INFO fold_info; + + md_get_unicode_fold_info(codepoint, &fold_info); + hash = md_fnv1a(hash, fold_info.codepoints, fold_info.n_codepoints * sizeof(unsigned)); + off += char_size; + } + } + + return hash; +} + +static OFF +md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size, + MD_UNICODE_FOLD_INFO* fold_info) +{ + unsigned codepoint; + SZ char_size; + + if(off >= size) { + /* Treat end of a link label as a whitespace. */ + goto whitespace; + } + + codepoint = md_decode_unicode(label, off, size, &char_size); + off += char_size; + if(ISUNICODEWHITESPACE_(codepoint)) { + /* Treat all whitespace as equivalent */ + goto whitespace; + } + + /* Get real folding info. */ + md_get_unicode_fold_info(codepoint, fold_info); + return off; + +whitespace: + fold_info->codepoints[0] = _T(' '); + fold_info->n_codepoints = 1; + return md_skip_unicode_whitespace(label, off, size); +} + +static int +md_link_label_cmp(const CHAR* a_label, SZ a_size, const CHAR* b_label, SZ b_size) +{ + OFF a_off; + OFF b_off; + MD_UNICODE_FOLD_INFO a_fi = { { 0 }, 0 }; + MD_UNICODE_FOLD_INFO b_fi = { { 0 }, 0 }; + OFF a_fi_off = 0; + OFF b_fi_off = 0; + int cmp; + + a_off = md_skip_unicode_whitespace(a_label, 0, a_size); + b_off = md_skip_unicode_whitespace(b_label, 0, b_size); + while(a_off < a_size || a_fi_off < a_fi.n_codepoints || + b_off < b_size || b_fi_off < b_fi.n_codepoints) + { + /* If needed, load fold info for next char. */ + if(a_fi_off >= a_fi.n_codepoints) { + a_fi_off = 0; + a_off = md_link_label_cmp_load_fold_info(a_label, a_off, a_size, &a_fi); + } + if(b_fi_off >= b_fi.n_codepoints) { + b_fi_off = 0; + b_off = md_link_label_cmp_load_fold_info(b_label, b_off, b_size, &b_fi); + } + + cmp = b_fi.codepoints[b_fi_off] - a_fi.codepoints[a_fi_off]; + if(cmp != 0) + return cmp; + + a_fi_off++; + b_fi_off++; + } + + return 0; +} + +typedef struct MD_REF_DEF_LIST_tag MD_REF_DEF_LIST; +struct MD_REF_DEF_LIST_tag { + int n_ref_defs; + int alloc_ref_defs; + MD_REF_DEF* ref_defs[]; /* Valid items always point into ctx->ref_defs[] */ +}; + +static int +md_ref_def_cmp(const void* a, const void* b) +{ + const MD_REF_DEF* a_ref = *(const MD_REF_DEF**)a; + const MD_REF_DEF* b_ref = *(const MD_REF_DEF**)b; + + if(a_ref->hash < b_ref->hash) + return -1; + else if(a_ref->hash > b_ref->hash) + return +1; + else + return md_link_label_cmp(a_ref->label, a_ref->label_size, b_ref->label, b_ref->label_size); +} + +static int +md_ref_def_cmp_for_sort(const void* a, const void* b) +{ + int cmp; + + cmp = md_ref_def_cmp(a, b); + + /* Ensure stability of the sorting. */ + if(cmp == 0) { + const MD_REF_DEF* a_ref = *(const MD_REF_DEF**)a; + const MD_REF_DEF* b_ref = *(const MD_REF_DEF**)b; + + if(a_ref < b_ref) + cmp = -1; + else if(a_ref > b_ref) + cmp = +1; + else + cmp = 0; + } + + return cmp; +} + +static int +md_build_ref_def_hashtable(MD_CTX* ctx) +{ + int i, j; + + if(ctx->n_ref_defs == 0) + return 0; + + ctx->ref_def_hashtable_size = (ctx->n_ref_defs * 5) / 4; + ctx->ref_def_hashtable = (void **) malloc(ctx->ref_def_hashtable_size * sizeof(void*)); + if(ctx->ref_def_hashtable == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + memset(ctx->ref_def_hashtable, 0, ctx->ref_def_hashtable_size * sizeof(void*)); + + /* Each member of ctx->ref_def_hashtable[] can be: + * -- NULL, + * -- pointer to the MD_REF_DEF in ctx->ref_defs[], or + * -- pointer to a MD_REF_DEF_LIST, which holds multiple pointers to + * such MD_REF_DEFs. + */ + for(i = 0; i < ctx->n_ref_defs; i++) { + MD_REF_DEF* def = &ctx->ref_defs[i]; + void* bucket; + MD_REF_DEF_LIST* list; + + def->hash = md_link_label_hash(def->label, def->label_size); + bucket = ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size]; + + if(bucket == NULL) { + /* The bucket is empty. Make it just point to the def. */ + ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = def; + continue; + } + + if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) { + /* The bucket already contains one ref. def. Lets see whether it + * is the same label (ref. def. duplicate) or different one + * (hash conflict). */ + MD_REF_DEF* old_def = (MD_REF_DEF*) bucket; + + if(md_link_label_cmp(def->label, def->label_size, old_def->label, old_def->label_size) == 0) { + /* Duplicate label: Ignore this ref. def. */ + continue; + } + + /* Make the bucket complex, i.e. able to hold more ref. defs. */ + list = (MD_REF_DEF_LIST*) malloc(sizeof(MD_REF_DEF_LIST) + 2 * sizeof(MD_REF_DEF*)); + if(list == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + list->ref_defs[0] = old_def; + list->ref_defs[1] = def; + list->n_ref_defs = 2; + list->alloc_ref_defs = 2; + ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list; + continue; + } + + /* Append the def to the complex bucket list. + * + * Note in this case we ignore potential duplicates to avoid expensive + * iterating over the complex bucket. Below, we revisit all the complex + * buckets and handle it more cheaply after the complex bucket contents + * is sorted. */ + list = (MD_REF_DEF_LIST*) bucket; + if(list->n_ref_defs >= list->alloc_ref_defs) { + int alloc_ref_defs = list->alloc_ref_defs + list->alloc_ref_defs / 2; + MD_REF_DEF_LIST* list_tmp = (MD_REF_DEF_LIST*) realloc(list, + sizeof(MD_REF_DEF_LIST) + alloc_ref_defs * sizeof(MD_REF_DEF*)); + if(list_tmp == NULL) { + MD_LOG("realloc() failed."); + goto abort; + } + list = list_tmp; + list->alloc_ref_defs = alloc_ref_defs; + ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list; + } + + list->ref_defs[list->n_ref_defs] = def; + list->n_ref_defs++; + } + + /* Sort the complex buckets so we can use bsearch() with them. */ + for(i = 0; i < ctx->ref_def_hashtable_size; i++) { + void* bucket = ctx->ref_def_hashtable[i]; + MD_REF_DEF_LIST* list; + + if(bucket == NULL) + continue; + if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) + continue; + + list = (MD_REF_DEF_LIST*) bucket; + qsort(list->ref_defs, list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp_for_sort); + + /* Disable all duplicates in the complex bucket by forcing all such + * records to point to the 1st such ref. def. I.e. no matter which + * record is found during the lookup, it will always point to the right + * ref. def. in ctx->ref_defs[]. */ + for(j = 1; j < list->n_ref_defs; j++) { + if(md_ref_def_cmp(&list->ref_defs[j-1], &list->ref_defs[j]) == 0) + list->ref_defs[j] = list->ref_defs[j-1]; + } + } + + return 0; + +abort: + return -1; +} + +static void +md_free_ref_def_hashtable(MD_CTX* ctx) +{ + if(ctx->ref_def_hashtable != NULL) { + int i; + + for(i = 0; i < ctx->ref_def_hashtable_size; i++) { + void* bucket = ctx->ref_def_hashtable[i]; + if(bucket == NULL) + continue; + if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) + continue; + free(bucket); + } + + free(ctx->ref_def_hashtable); + } +} + +static const MD_REF_DEF* +md_lookup_ref_def(MD_CTX* ctx, const CHAR* label, SZ label_size) +{ + unsigned hash; + void* bucket; + + if(ctx->ref_def_hashtable_size == 0) + return NULL; + + hash = md_link_label_hash(label, label_size); + bucket = ctx->ref_def_hashtable[hash % ctx->ref_def_hashtable_size]; + + if(bucket == NULL) { + return NULL; + } else if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) { + const MD_REF_DEF* def = (MD_REF_DEF*) bucket; + + if(md_link_label_cmp(def->label, def->label_size, label, label_size) == 0) + return def; + else + return NULL; + } else { + MD_REF_DEF_LIST* list = (MD_REF_DEF_LIST*) bucket; + MD_REF_DEF key_buf; + const MD_REF_DEF* key = &key_buf; + const MD_REF_DEF** ret; + + key_buf.label = (CHAR*) label; + key_buf.label_size = label_size; + key_buf.hash = md_link_label_hash(key_buf.label, key_buf.label_size); + + ret = (const MD_REF_DEF**) bsearch(&key, list->ref_defs, + list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp); + if(ret != NULL) + return *ret; + else + return NULL; + } +} + + +/*************************** + *** Recognizing Links *** + ***************************/ + +/* Note this code is partially shared between processing inlines and blocks + * as reference definitions and links share some helper parser functions. + */ + +typedef struct MD_LINK_ATTR_tag MD_LINK_ATTR; +struct MD_LINK_ATTR_tag { + OFF dest_beg; + OFF dest_end; + + CHAR* title; + SZ title_size; + int title_needs_free; +}; + + +static int +md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, + OFF* p_end, int* p_beg_line_index, int* p_end_line_index, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + OFF contents_beg = 0; + OFF contents_end = 0; + int line_index = 0; + int len = 0; + + if(CH(off) != _T('[')) + return FALSE; + off++; + + while(1) { + OFF line_end = lines[line_index].end; + + while(off < line_end) { + if(CH(off) == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + if(contents_end == 0) { + contents_beg = off; + *p_beg_line_index = line_index; + } + contents_end = off + 2; + off += 2; + } else if(CH(off) == _T('[')) { + return FALSE; + } else if(CH(off) == _T(']')) { + if(contents_beg < contents_end) { + /* Success. */ + *p_contents_beg = contents_beg; + *p_contents_end = contents_end; + *p_end = off+1; + *p_end_line_index = line_index; + return TRUE; + } else { + /* Link label must have some non-whitespace contents. */ + return FALSE; + } + } else { + unsigned codepoint; + SZ char_size; + + codepoint = md_decode_unicode(ctx->text, off, ctx->size, &char_size); + if(!ISUNICODEWHITESPACE_(codepoint)) { + if(contents_end == 0) { + contents_beg = off; + *p_beg_line_index = line_index; + } + contents_end = off + char_size; + } + + off += char_size; + } + + len++; + if(len > 999) + return FALSE; + } + + line_index++; + len++; + if(line_index < n_lines) + off = lines[line_index].beg; + else + break; + } + + return FALSE; +} + +static int +md_is_link_destination_A(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + + if(off >= max_end || CH(off) != _T('<')) + return FALSE; + off++; + + while(off < max_end) { + if(CH(off) == _T('\\') && off+1 < max_end && ISPUNCT(off+1)) { + off += 2; + continue; + } + + if(ISNEWLINE(off) || CH(off) == _T('<')) + return FALSE; + + if(CH(off) == _T('>')) { + /* Success. */ + *p_contents_beg = beg+1; + *p_contents_end = off; + *p_end = off+1; + return TRUE; + } + + off++; + } + + return FALSE; +} + +static int +md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + int parenthesis_level = 0; + + while(off < max_end) { + if(CH(off) == _T('\\') && off+1 < max_end && ISPUNCT(off+1)) { + off += 2; + continue; + } + + if(ISWHITESPACE(off) || ISCNTRL(off)) + break; + + /* Link destination may include balanced pairs of unescaped '(' ')'. + * Note we limit the maximal nesting level by 32 to protect us from + * https://github.com/jgm/cmark/issues/214 */ + if(CH(off) == _T('(')) { + parenthesis_level++; + if(parenthesis_level > 32) + return FALSE; + } else if(CH(off) == _T(')')) { + if(parenthesis_level == 0) + break; + parenthesis_level--; + } + + off++; + } + + if(parenthesis_level != 0 || off == beg) + return FALSE; + + /* Success. */ + *p_contents_beg = beg; + *p_contents_end = off; + *p_end = off; + return TRUE; +} + +static inline int +md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + if(CH(beg) == _T('<')) + return md_is_link_destination_A(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end); + else + return md_is_link_destination_B(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end); +} + +static int +md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, + OFF* p_end, int* p_beg_line_index, int* p_end_line_index, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + CHAR closer_char; + int line_index = 0; + + /* White space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end) { + line_index++; + if(line_index >= n_lines) + return FALSE; + off = lines[line_index].beg; + } + if(off == beg) + return FALSE; + + *p_beg_line_index = line_index; + + /* First char determines how to detect end of it. */ + switch(CH(off)) { + case _T('"'): closer_char = _T('"'); break; + case _T('\''): closer_char = _T('\''); break; + case _T('('): closer_char = _T(')'); break; + default: return FALSE; + } + off++; + + *p_contents_beg = off; + + while(line_index < n_lines) { + OFF line_end = lines[line_index].end; + + while(off < line_end) { + if(CH(off) == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + off++; + } else if(CH(off) == closer_char) { + /* Success. */ + *p_contents_end = off; + *p_end = off+1; + *p_end_line_index = line_index; + return TRUE; + } else if(closer_char == _T(')') && CH(off) == _T('(')) { + /* ()-style title cannot contain (unescaped '(')) */ + return FALSE; + } + + off++; + } + + line_index++; + } + + return FALSE; +} + +/* Returns 0 if it is not a reference definition. + * + * Returns N > 0 if it is a reference definition. N then corresponds to the + * number of lines forming it). In this case the definition is stored for + * resolving any links referring to it. + * + * Returns -1 in case of an error (out of memory). + */ +static int +md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) +{ + OFF label_contents_beg; + OFF label_contents_end; + int label_contents_line_index = -1; + int label_is_multiline = FALSE; + OFF dest_contents_beg; + OFF dest_contents_end; + OFF title_contents_beg; + OFF title_contents_end; + int title_contents_line_index; + int title_is_multiline = FALSE; + OFF off; + int line_index = 0; + int tmp_line_index; + MD_REF_DEF* def = NULL; + int ret = 0; + + /* Link label. */ + if(!md_is_link_label(ctx, lines, n_lines, lines[0].beg, + &off, &label_contents_line_index, &line_index, + &label_contents_beg, &label_contents_end)) + return FALSE; + label_is_multiline = (label_contents_line_index != line_index); + + /* Colon. */ + if(off >= lines[line_index].end || CH(off) != _T(':')) + return FALSE; + off++; + + /* Optional white space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end) { + line_index++; + if(line_index >= n_lines) + return FALSE; + off = lines[line_index].beg; + } + + /* Link destination. */ + if(!md_is_link_destination(ctx, off, lines[line_index].end, + &off, &dest_contents_beg, &dest_contents_end)) + return FALSE; + + /* (Optional) title. Note we interpret it as an title only if nothing + * more follows on its last line. */ + if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off, + &off, &title_contents_line_index, &tmp_line_index, + &title_contents_beg, &title_contents_end) + && off >= lines[line_index + tmp_line_index].end) + { + title_is_multiline = (tmp_line_index != title_contents_line_index); + title_contents_line_index += line_index; + line_index += tmp_line_index; + } else { + /* Not a title. */ + title_is_multiline = FALSE; + title_contents_beg = off; + title_contents_end = off; + title_contents_line_index = 0; + } + + /* Nothing more can follow on the last line. */ + if(off < lines[line_index].end) + return FALSE; + + /* So, it _is_ a reference definition. Remember it. */ + if(ctx->n_ref_defs >= ctx->alloc_ref_defs) { + MD_REF_DEF* new_defs; + + ctx->alloc_ref_defs = (ctx->alloc_ref_defs > 0 + ? ctx->alloc_ref_defs + ctx->alloc_ref_defs / 2 + : 16); + new_defs = (MD_REF_DEF*) realloc(ctx->ref_defs, ctx->alloc_ref_defs * sizeof(MD_REF_DEF)); + if(new_defs == NULL) { + MD_LOG("realloc() failed."); + goto abort; + } + + ctx->ref_defs = new_defs; + } + def = &ctx->ref_defs[ctx->n_ref_defs]; + memset(def, 0, sizeof(MD_REF_DEF)); + + if(label_is_multiline) { + MD_CHECK(md_merge_lines_alloc(ctx, label_contents_beg, label_contents_end, + lines + label_contents_line_index, n_lines - label_contents_line_index, + _T(' '), &def->label, &def->label_size)); + def->label_needs_free = TRUE; + } else { + def->label = (CHAR*) STR(label_contents_beg); + def->label_size = label_contents_end - label_contents_beg; + } + + if(title_is_multiline) { + MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, + lines + title_contents_line_index, n_lines - title_contents_line_index, + _T('\n'), &def->title, &def->title_size)); + def->title_needs_free = TRUE; + } else { + def->title = (CHAR*) STR(title_contents_beg); + def->title_size = title_contents_end - title_contents_beg; + } + + def->dest_beg = dest_contents_beg; + def->dest_end = dest_contents_end; + + /* Success. */ + ctx->n_ref_defs++; + return line_index + 1; + +abort: + /* Failure. */ + if(def != NULL && def->label_needs_free) + free(def->label); + if(def != NULL && def->title_needs_free) + free(def->title); + return ret; +} + +static int +md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines, + OFF beg, OFF end, MD_LINK_ATTR* attr) +{ + const MD_REF_DEF* def; + const MD_LINE* beg_line; + const MD_LINE* end_line; + CHAR* label; + SZ label_size; + int ret; + + MD_ASSERT(CH(beg) == _T('[') || CH(beg) == _T('!')); + MD_ASSERT(CH(end-1) == _T(']')); + + beg += (CH(beg) == _T('!') ? 2 : 1); + end--; + + /* Find lines corresponding to the beg and end positions. */ + MD_ASSERT(lines[0].beg <= beg); + beg_line = lines; + while(beg >= beg_line->end) + beg_line++; + + MD_ASSERT(end <= lines[n_lines-1].end); + end_line = beg_line; + while(end >= end_line->end) + end_line++; + + if(beg_line != end_line) { + MD_CHECK(md_merge_lines_alloc(ctx, beg, end, beg_line, + (int)(n_lines - (beg_line - lines)), _T(' '), &label, &label_size)); + } else { + label = (CHAR*) STR(beg); + label_size = end - beg; + } + + def = md_lookup_ref_def(ctx, label, label_size); + if(def != NULL) { + attr->dest_beg = def->dest_beg; + attr->dest_end = def->dest_end; + attr->title = def->title; + attr->title_size = def->title_size; + attr->title_needs_free = FALSE; + } + + if(beg_line != end_line) + free(label); + + ret = (def != NULL); + +abort: + return ret; +} + +static int +md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines, + OFF beg, OFF* p_end, MD_LINK_ATTR* attr) +{ + int line_index = 0; + int tmp_line_index; + OFF title_contents_beg; + OFF title_contents_end; + int title_contents_line_index; + int title_is_multiline; + OFF off = beg; + int ret = FALSE; + + while(off >= lines[line_index].end) + line_index++; + + MD_ASSERT(CH(off) == _T('(')); + off++; + + /* Optional white space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end && ISNEWLINE(off)) { + line_index++; + if(line_index >= n_lines) + return FALSE; + off = lines[line_index].beg; + } + + /* Link destination may be omitted, but only when not also having a title. */ + if(off < ctx->size && CH(off) == _T(')')) { + attr->dest_beg = off; + attr->dest_end = off; + attr->title = NULL; + attr->title_size = 0; + attr->title_needs_free = FALSE; + off++; + *p_end = off; + return TRUE; + } + + /* Link destination. */ + if(!md_is_link_destination(ctx, off, lines[line_index].end, + &off, &attr->dest_beg, &attr->dest_end)) + return FALSE; + + /* (Optional) title. */ + if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off, + &off, &title_contents_line_index, &tmp_line_index, + &title_contents_beg, &title_contents_end)) + { + title_is_multiline = (tmp_line_index != title_contents_line_index); + title_contents_line_index += line_index; + line_index += tmp_line_index; + } else { + /* Not a title. */ + title_is_multiline = FALSE; + title_contents_beg = off; + title_contents_end = off; + title_contents_line_index = 0; + } + + /* Optional whitespace followed with final ')'. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end && ISNEWLINE(off)) { + line_index++; + if(line_index >= n_lines) + return FALSE; + off = lines[line_index].beg; + } + if(CH(off) != _T(')')) + goto abort; + off++; + + if(title_contents_beg >= title_contents_end) { + attr->title = NULL; + attr->title_size = 0; + attr->title_needs_free = FALSE; + } else if(!title_is_multiline) { + attr->title = (CHAR*) STR(title_contents_beg); + attr->title_size = title_contents_end - title_contents_beg; + attr->title_needs_free = FALSE; + } else { + MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, + lines + title_contents_line_index, n_lines - title_contents_line_index, + _T('\n'), &attr->title, &attr->title_size)); + attr->title_needs_free = TRUE; + } + + *p_end = off; + ret = TRUE; + +abort: + return ret; +} + +static void +md_free_ref_defs(MD_CTX* ctx) +{ + int i; + + for(i = 0; i < ctx->n_ref_defs; i++) { + MD_REF_DEF* def = &ctx->ref_defs[i]; + + if(def->label_needs_free) + free(def->label); + if(def->title_needs_free) + free(def->title); + } + + free(ctx->ref_defs); +} + + +/****************************************** + *** Processing Inlines (a.k.a Spans) *** + ******************************************/ + +/* We process inlines in few phases: + * + * (1) We go through the block text and collect all significant characters + * which may start/end a span or some other significant position into + * ctx->marks[]. Core of this is what md_collect_marks() does. + * + * We also do some very brief preliminary context-less analysis, whether + * it might be opener or closer (e.g. of an emphasis span). + * + * This speeds the other steps as we do not need to re-iterate over all + * characters anymore. + * + * (2) We analyze each potential mark types, in order by their precedence. + * + * In each md_analyze_XXX() function, we re-iterate list of the marks, + * skipping already resolved regions (in preceding precedences) and try to + * resolve them. + * + * (2.1) For trivial marks, which are single (e.g. HTML entity), we just mark + * them as resolved. + * + * (2.2) For range-type marks, we analyze whether the mark could be closer + * and, if yes, whether there is some preceding opener it could satisfy. + * + * If not we check whether it could be really an opener and if yes, we + * remember it so subsequent closers may resolve it. + * + * (3) Finally, when all marks were analyzed, we render the block contents + * by calling MD_RENDERER::text() callback, interrupting by ::enter_span() + * or ::close_span() whenever we reach a resolved mark. + */ + + +/* The mark structure. + * + * '\\': Maybe escape sequence. + * '\0': NULL char. + * '*': Maybe (strong) emphasis start/end. + * '_': Maybe (strong) emphasis start/end. + * '~': Maybe strikethrough start/end (needs MD_FLAG_STRIKETHROUGH). + * '`': Maybe code span start/end. + * '&': Maybe start of entity. + * ';': Maybe end of entity. + * '<': Maybe start of raw HTML or autolink. + * '>': Maybe end of raw HTML or autolink. + * '[': Maybe start of link label or link text. + * '!': Equivalent of '[' for image. + * ']': Maybe end of link label or link text. + * '@': Maybe permissive e-mail auto-link (needs MD_FLAG_PERMISSIVEEMAILAUTOLINKS). + * ':': Maybe permissive URL auto-link (needs MD_FLAG_PERMISSIVEURLAUTOLINKS). + * '.': Maybe permissive WWW auto-link (needs MD_FLAG_PERMISSIVEWWWAUTOLINKS). + * 'D': Dummy mark, it reserves a space for splitting a previous mark + * (e.g. emphasis) or to make more space for storing some special data + * related to the preceding mark (e.g. link). + * + * Note that not all instances of these chars in the text imply creation of the + * structure. Only those which have (or may have, after we see more context) + * the special meaning. + * + * (Keep this struct as small as possible to fit as much of them into CPU + * cache line.) + */ +struct MD_MARK_tag { + OFF beg; + OFF end; + + /* For unresolved openers, 'prev' and 'next' form the chain of open openers + * of given type 'ch'. + * + * During resolving, we disconnect from the chain and point to the + * corresponding counterpart so opener points to its closer and vice versa. + */ + int prev; + int next; + CHAR ch; + unsigned char flags; +}; + +/* Mark flags (these apply to ALL mark types). */ +#define MD_MARK_POTENTIAL_OPENER 0x01 /* Maybe opener. */ +#define MD_MARK_POTENTIAL_CLOSER 0x02 /* Maybe closer. */ +#define MD_MARK_OPENER 0x04 /* Definitely opener. */ +#define MD_MARK_CLOSER 0x08 /* Definitely closer. */ +#define MD_MARK_RESOLVED 0x10 /* Resolved in any definite way. */ + +/* Mark flags specific for various mark types (so they can share bits). */ +#define MD_MARK_EMPH_INTRAWORD 0x20 /* Helper for the "rule of 3". */ +#define MD_MARK_EMPH_MOD3_0 0x40 +#define MD_MARK_EMPH_MOD3_1 0x80 +#define MD_MARK_EMPH_MOD3_2 (0x40 | 0x80) +#define MD_MARK_EMPH_MOD3_MASK (0x40 | 0x80) +#define MD_MARK_AUTOLINK 0x20 /* Distinguisher for '<', '>'. */ +#define MD_MARK_VALIDPERMISSIVEAUTOLINK 0x20 /* For permissive autolinks. */ + +static MD_MARKCHAIN* +md_asterisk_chain(MD_CTX* ctx, unsigned flags) +{ + switch(flags & (MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_MASK)) { + case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_0: return &ASTERISK_OPENERS_intraword_mod3_0; + case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_1: return &ASTERISK_OPENERS_intraword_mod3_1; + case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_2: return &ASTERISK_OPENERS_intraword_mod3_2; + case MD_MARK_EMPH_MOD3_0: return &ASTERISK_OPENERS_extraword_mod3_0; + case MD_MARK_EMPH_MOD3_1: return &ASTERISK_OPENERS_extraword_mod3_1; + case MD_MARK_EMPH_MOD3_2: return &ASTERISK_OPENERS_extraword_mod3_2; + default: MD_UNREACHABLE(); + } + return NULL; +} + +static MD_MARKCHAIN* +md_mark_chain(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + switch(mark->ch) { + case _T('*'): return md_asterisk_chain(ctx, mark->flags); + case _T('_'): return &UNDERSCORE_OPENERS; + case _T('~'): return (mark->end - mark->beg == 1) ? &TILDE_OPENERS_1 : &TILDE_OPENERS_2; + case _T('['): return &BRACKET_OPENERS; + case _T('|'): return &TABLECELLBOUNDARIES; + default: return NULL; + } +} + +static MD_MARK* +md_push_mark(MD_CTX* ctx) +{ + if(ctx->n_marks >= ctx->alloc_marks) { + MD_MARK* new_marks; + + ctx->alloc_marks = (ctx->alloc_marks > 0 + ? ctx->alloc_marks + ctx->alloc_marks / 2 + : 64); + new_marks = (MD_MARK *) realloc(ctx->marks, ctx->alloc_marks * sizeof(MD_MARK)); + if(new_marks == NULL) { + MD_LOG("realloc() failed."); + return NULL; + } + + ctx->marks = new_marks; + } + + return &ctx->marks[ctx->n_marks++]; +} + +#define PUSH_MARK_() \ + do { \ + mark = md_push_mark(ctx); \ + if(mark == NULL) { \ + ret = -1; \ + goto abort; \ + } \ + } while(0) + +#define PUSH_MARK(ch_, beg_, end_, flags_) \ + do { \ + PUSH_MARK_(); \ + mark->beg = (beg_); \ + mark->end = (end_); \ + mark->prev = -1; \ + mark->next = -1; \ + mark->ch = (char)(ch_); \ + mark->flags = (flags_); \ + } while(0) + + +static void +md_mark_chain_append(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index) +{ + if(chain->tail >= 0) + ctx->marks[chain->tail].next = mark_index; + else + chain->head = mark_index; + + ctx->marks[mark_index].prev = chain->tail; + ctx->marks[mark_index].next = -1; + chain->tail = mark_index; +} + +/* Sometimes, we need to store a pointer into the mark. It is quite rare + * so we do not bother to make MD_MARK use union, and it can only happen + * for dummy marks. */ +static inline void +md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + MD_ASSERT(mark->ch == 'D'); + + /* Check only members beg and end are misused for this. */ + MD_ASSERT(sizeof(void*) <= 2 * sizeof(OFF)); + memcpy(mark, &ptr, sizeof(void*)); +} + +static inline void* +md_mark_get_ptr(MD_CTX* ctx, int mark_index) +{ + void* ptr; + MD_MARK* mark = &ctx->marks[mark_index]; + MD_ASSERT(mark->ch == 'D'); + memcpy(&ptr, mark, sizeof(void*)); + return ptr; +} + +static void +md_resolve_range(MD_CTX* ctx, MD_MARKCHAIN* chain, int opener_index, int closer_index) +{ + MD_MARK* opener = &ctx->marks[opener_index]; + MD_MARK* closer = &ctx->marks[closer_index]; + + /* Remove opener from the list of openers. */ + if(chain != NULL) { + if(opener->prev >= 0) + ctx->marks[opener->prev].next = opener->next; + else + chain->head = opener->next; + + if(opener->next >= 0) + ctx->marks[opener->next].prev = opener->prev; + else + chain->tail = opener->prev; + } + + /* Interconnect opener and closer and mark both as resolved. */ + opener->next = closer_index; + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + closer->prev = opener_index; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; +} + + +#define MD_ROLLBACK_ALL 0 +#define MD_ROLLBACK_CROSSING 1 + +/* In the range ctx->marks[opener_index] ... [closer_index], undo some or all + * resolvings accordingly to these rules: + * + * (1) All openers BEFORE the range corresponding to any closer inside the + * range are un-resolved and they are re-added to their respective chains + * of unresolved openers. This ensures we can reuse the opener for closers + * AFTER the range. + * + * (2) If 'how' is MD_ROLLBACK_ALL, then ALL resolved marks inside the range + * are discarded. + * + * (3) If 'how' is MD_ROLLBACK_CROSSING, only closers with openers handled + * in (1) are discarded. I.e. pairs of openers and closers which are both + * inside the range are retained as well as any unpaired marks. + */ +static void +md_rollback(MD_CTX* ctx, int opener_index, int closer_index, int how) +{ + int i; + int mark_index; + + /* Cut all unresolved openers at the mark index. */ + for(i = OPENERS_CHAIN_FIRST; i < OPENERS_CHAIN_LAST+1; i++) { + MD_MARKCHAIN* chain = &ctx->mark_chains[i]; + + while(chain->tail >= opener_index) + chain->tail = ctx->marks[chain->tail].prev; + + if(chain->tail >= 0) + ctx->marks[chain->tail].next = -1; + else + chain->head = -1; + } + + /* Go backwards so that unresolved openers are re-added into their + * respective chains, in the right order. */ + mark_index = closer_index - 1; + while(mark_index > opener_index) { + MD_MARK* mark = &ctx->marks[mark_index]; + int mark_flags = mark->flags; + int discard_flag = (how == MD_ROLLBACK_ALL); + + if(mark->flags & MD_MARK_CLOSER) { + int mark_opener_index = mark->prev; + + /* Undo opener BEFORE the range. */ + if(mark_opener_index < opener_index) { + MD_MARK* mark_opener = &ctx->marks[mark_opener_index]; + MD_MARKCHAIN* chain; + + mark_opener->flags &= ~(MD_MARK_OPENER | MD_MARK_CLOSER | MD_MARK_RESOLVED); + chain = md_mark_chain(ctx, opener_index); + if(chain != NULL) { + md_mark_chain_append(ctx, chain, mark_opener_index); + discard_flag = 1; + } + } + } + + /* And reset our flags. */ + if(discard_flag) + mark->flags &= ~(MD_MARK_OPENER | MD_MARK_CLOSER | MD_MARK_RESOLVED); + + /* Jump as far as we can over unresolved or non-interesting marks. */ + switch(how) { + case MD_ROLLBACK_CROSSING: + if((mark_flags & MD_MARK_CLOSER) && mark->prev > opener_index) { + /* If we are closer with opener INSIDE the range, there may + * not be any other crosser inside the subrange. */ + mark_index = mark->prev; + break; + } + MD_FALLTHROUGH(); + default: + mark_index--; + break; + } + } +} + +static void +md_build_mark_char_map(MD_CTX* ctx) +{ + memset(ctx->mark_char_map, 0, sizeof(ctx->mark_char_map)); + + ctx->mark_char_map['\\'] = 1; + ctx->mark_char_map['*'] = 1; + ctx->mark_char_map['_'] = 1; + ctx->mark_char_map['`'] = 1; + ctx->mark_char_map['&'] = 1; + ctx->mark_char_map[';'] = 1; + ctx->mark_char_map['<'] = 1; + ctx->mark_char_map['>'] = 1; + ctx->mark_char_map['['] = 1; + ctx->mark_char_map['!'] = 1; + ctx->mark_char_map[']'] = 1; + ctx->mark_char_map['\0'] = 1; + + if(ctx->parser.flags & MD_FLAG_STRIKETHROUGH) + ctx->mark_char_map['~'] = 1; + + if(ctx->parser.flags & MD_FLAG_LATEXMATHSPANS) + ctx->mark_char_map['$'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEEMAILAUTOLINKS) + ctx->mark_char_map['@'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEURLAUTOLINKS) + ctx->mark_char_map[':'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEWWWAUTOLINKS) + ctx->mark_char_map['.'] = 1; + + if((ctx->parser.flags & MD_FLAG_TABLES) || (ctx->parser.flags & MD_FLAG_WIKILINKS)) + ctx->mark_char_map['|'] = 1; + + if(ctx->parser.flags & MD_FLAG_COLLAPSEWHITESPACE) { + int i; + + for(i = 0; i < (int) sizeof(ctx->mark_char_map); i++) { + if(ISWHITESPACE_(i)) + ctx->mark_char_map[i] = 1; + } + } +} + +/* We limit code span marks to lower than 32 backticks. This solves the + * pathologic case of too many openers, each of different length: Their + * resolving would be then O(n^2). */ +#define CODESPAN_MARK_MAXLEN 32 + +static int +md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, + OFF* p_opener_beg, OFF* p_opener_end, + OFF* p_closer_beg, OFF* p_closer_end, + OFF last_potential_closers[CODESPAN_MARK_MAXLEN], + int* p_reached_paragraph_end) +{ + OFF opener_beg = beg; + OFF opener_end; + OFF closer_beg; + OFF closer_end; + SZ mark_len; + OFF line_end; + int has_space_after_opener = FALSE; + int has_eol_after_opener = FALSE; + int has_space_before_closer = FALSE; + int has_eol_before_closer = FALSE; + int has_only_space = TRUE; + int line_index = 0; + + line_end = lines[0].end; + opener_end = opener_beg; + while(opener_end < line_end && CH(opener_end) == _T('`')) + opener_end++; + has_space_after_opener = (opener_end < line_end && CH(opener_end) == _T(' ')); + has_eol_after_opener = (opener_end == line_end); + + /* The caller needs to know end of the opening mark even if we fail. */ + *p_opener_end = opener_end; + + mark_len = opener_end - opener_beg; + if(mark_len > CODESPAN_MARK_MAXLEN) + return FALSE; + + /* Check whether we already know there is no closer of this length. + * If so, re-scan does no sense. This fixes issue #59. */ + if(last_potential_closers[mark_len-1] >= lines[n_lines-1].end || + (*p_reached_paragraph_end && last_potential_closers[mark_len-1] < opener_end)) + return FALSE; + + closer_beg = opener_end; + closer_end = opener_end; + + /* Find closer mark. */ + while(TRUE) { + while(closer_beg < line_end && CH(closer_beg) != _T('`')) { + if(CH(closer_beg) != _T(' ')) + has_only_space = FALSE; + closer_beg++; + } + closer_end = closer_beg; + while(closer_end < line_end && CH(closer_end) == _T('`')) + closer_end++; + + if(closer_end - closer_beg == mark_len) { + /* Success. */ + has_space_before_closer = (closer_beg > lines[line_index].beg && CH(closer_beg-1) == _T(' ')); + has_eol_before_closer = (closer_beg == lines[line_index].beg); + break; + } + + if(closer_end - closer_beg > 0) { + /* We have found a back-tick which is not part of the closer. */ + has_only_space = FALSE; + + /* But if we eventually fail, remember it as a potential closer + * of its own length for future attempts. This mitigates needs for + * rescans. */ + if(closer_end - closer_beg < CODESPAN_MARK_MAXLEN) { + if(closer_beg > last_potential_closers[closer_end - closer_beg - 1]) + last_potential_closers[closer_end - closer_beg - 1] = closer_beg; + } + } + + if(closer_end >= line_end) { + line_index++; + if(line_index >= n_lines) { + /* Reached end of the paragraph and still nothing. */ + *p_reached_paragraph_end = TRUE; + return FALSE; + } + /* Try on the next line. */ + line_end = lines[line_index].end; + closer_beg = lines[line_index].beg; + } else { + closer_beg = closer_end; + } + } + + /* If there is a space or a new line both after and before the opener + * (and if the code span is not made of spaces only), consume one initial + * and one trailing space as part of the marks. */ + if(!has_only_space && + (has_space_after_opener || has_eol_after_opener) && + (has_space_before_closer || has_eol_before_closer)) + { + if(has_space_after_opener) + opener_end++; + else + opener_end = lines[1].beg; + + if(has_space_before_closer) + closer_beg--; + else { + closer_beg = lines[line_index-1].end; + /* We need to eat the preceding "\r\n" but not any line trailing + * spaces. */ + while(closer_beg < ctx->size && ISBLANK(closer_beg)) + closer_beg++; + } + } + + *p_opener_beg = opener_beg; + *p_opener_end = opener_end; + *p_closer_beg = closer_beg; + *p_closer_end = closer_end; + return TRUE; +} + +static int +md_is_autolink_uri(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg+1; + + MD_ASSERT(CH(beg) == _T('<')); + + /* Check for scheme. */ + if(off >= max_end || !ISASCII(off)) + return FALSE; + off++; + while(1) { + if(off >= max_end) + return FALSE; + if(off - beg > 32) + return FALSE; + if(CH(off) == _T(':') && off - beg >= 3) + break; + if(!ISALNUM(off) && CH(off) != _T('+') && CH(off) != _T('-') && CH(off) != _T('.')) + return FALSE; + off++; + } + + /* Check the path after the scheme. */ + while(off < max_end && CH(off) != _T('>')) { + if(ISWHITESPACE(off) || ISCNTRL(off) || CH(off) == _T('<')) + return FALSE; + off++; + } + + if(off >= max_end) + return FALSE; + + MD_ASSERT(CH(off) == _T('>')); + *p_end = off+1; + return TRUE; +} + +static int +md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg + 1; + int label_len; + + MD_ASSERT(CH(beg) == _T('<')); + + /* The code should correspond to this regexp: + /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+ + @[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? + (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ + */ + + /* Username (before '@'). */ + while(off < max_end && (ISALNUM(off) || ISANYOF(off, _T(".!#$%&'*+/=?^_`{|}~-")))) + off++; + if(off <= beg+1) + return FALSE; + + /* '@' */ + if(off >= max_end || CH(off) != _T('@')) + return FALSE; + off++; + + /* Labels delimited with '.'; each label is sequence of 1 - 63 alnum + * characters or '-', but '-' is not allowed as first or last char. */ + label_len = 0; + while(off < max_end) { + if(ISALNUM(off)) + label_len++; + else if(CH(off) == _T('-') && label_len > 0) + label_len++; + else if(CH(off) == _T('.') && label_len > 0 && CH(off-1) != _T('-')) + label_len = 0; + else + break; + + if(label_len > 63) + return FALSE; + + off++; + } + + if(label_len <= 0 || off >= max_end || CH(off) != _T('>') || CH(off-1) == _T('-')) + return FALSE; + + *p_end = off+1; + return TRUE; +} + +static int +md_is_autolink(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, int* p_missing_mailto) +{ + if(md_is_autolink_uri(ctx, beg, max_end, p_end)) { + *p_missing_mailto = FALSE; + return TRUE; + } + + if(md_is_autolink_email(ctx, beg, max_end, p_end)) { + *p_missing_mailto = TRUE; + return TRUE; + } + + return FALSE; +} + +static int +md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) +{ + int i; + int ret = 0; + MD_MARK* mark; + OFF codespan_last_potential_closers[CODESPAN_MARK_MAXLEN] = { 0 }; + int codespan_scanned_till_paragraph_end = FALSE; + + for(i = 0; i < n_lines; i++) { + const MD_LINE* line = &lines[i]; + OFF off = line->beg; + OFF line_end = line->end; + + while(TRUE) { + CHAR ch; + +#ifdef MD4C_USE_UTF16 + /* For UTF-16, mark_char_map[] covers only ASCII. */ + #define IS_MARK_CHAR(off) ((CH(off) < SIZEOF_ARRAY(ctx->mark_char_map)) && \ + (ctx->mark_char_map[(unsigned char) CH(off)])) +#else + /* For 8-bit encodings, mark_char_map[] covers all 256 elements. */ + #define IS_MARK_CHAR(off) (ctx->mark_char_map[(unsigned char) CH(off)]) +#endif + + /* Optimization: Use some loop unrolling. */ + while(off + 3 < line_end && !IS_MARK_CHAR(off+0) && !IS_MARK_CHAR(off+1) + && !IS_MARK_CHAR(off+2) && !IS_MARK_CHAR(off+3)) + off += 4; + while(off < line_end && !IS_MARK_CHAR(off+0)) + off++; + + if(off >= line_end) + break; + + ch = CH(off); + + /* A backslash escape. + * It can go beyond line->end as it may involve escaped new + * line to form a hard break. */ + if(ch == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + /* Hard-break cannot be on the last line of the block. */ + if(!ISNEWLINE(off+1) || i+1 < n_lines) + PUSH_MARK(ch, off, off+2, MD_MARK_RESOLVED); + off += 2; + continue; + } + + /* A potential (string) emphasis start/end. */ + if(ch == _T('*') || ch == _T('_')) { + OFF tmp = off+1; + int left_level; /* What precedes: 0 = whitespace; 1 = punctuation; 2 = other char. */ + int right_level; /* What follows: 0 = whitespace; 1 = punctuation; 2 = other char. */ + + while(tmp < line_end && CH(tmp) == ch) + tmp++; + + if(off == line->beg || ISUNICODEWHITESPACEBEFORE(off)) + left_level = 0; + else if(ISUNICODEPUNCTBEFORE(off)) + left_level = 1; + else + left_level = 2; + + if(tmp == line_end || ISUNICODEWHITESPACE(tmp)) + right_level = 0; + else if(ISUNICODEPUNCT(tmp)) + right_level = 1; + else + right_level = 2; + + /* Intra-word underscore doesn't have special meaning. */ + if(ch == _T('_') && left_level == 2 && right_level == 2) { + left_level = 0; + right_level = 0; + } + + if(left_level != 0 || right_level != 0) { + unsigned flags = 0; + + if(left_level > 0 && left_level >= right_level) + flags |= MD_MARK_POTENTIAL_CLOSER; + if(right_level > 0 && right_level >= left_level) + flags |= MD_MARK_POTENTIAL_OPENER; + if(left_level == 2 && right_level == 2) + flags |= MD_MARK_EMPH_INTRAWORD; + + /* For "the rule of three" we need to remember the original + * size of the mark (modulo three), before we potentially + * split the mark when being later resolved partially by some + * shorter closer. */ + switch((tmp - off) % 3) { + case 0: flags |= MD_MARK_EMPH_MOD3_0; break; + case 1: flags |= MD_MARK_EMPH_MOD3_1; break; + case 2: flags |= MD_MARK_EMPH_MOD3_2; break; + } + + PUSH_MARK(ch, off, tmp, flags); + + /* During resolving, multiple asterisks may have to be + * split into independent span start/ends. Consider e.g. + * "**foo* bar*". Therefore we push also some empty dummy + * marks to have enough space for that. */ + off++; + while(off < tmp) { + PUSH_MARK('D', off, off, 0); + off++; + } + continue; + } + + off = tmp; + continue; + } + + /* A potential code span start/end. */ + if(ch == _T('`')) { + OFF opener_beg, opener_end; + OFF closer_beg, closer_end; + int is_code_span; + + is_code_span = md_is_code_span(ctx, lines + i, n_lines - i, off, + &opener_beg, &opener_end, &closer_beg, &closer_end, + codespan_last_potential_closers, + &codespan_scanned_till_paragraph_end); + if(is_code_span) { + PUSH_MARK(_T('`'), opener_beg, opener_end, MD_MARK_OPENER | MD_MARK_RESOLVED); + PUSH_MARK(_T('`'), closer_beg, closer_end, MD_MARK_CLOSER | MD_MARK_RESOLVED); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + + off = closer_end; + + /* Advance the current line accordingly. */ + while(off > line_end) { + i++; + line++; + line_end = line->end; + } + continue; + } + + off = opener_end; + continue; + } + + /* A potential entity start. */ + if(ch == _T('&')) { + PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER); + off++; + continue; + } + + /* A potential entity end. */ + if(ch == _T(';')) { + /* We surely cannot be entity unless the previous mark is '&'. */ + if(ctx->n_marks > 0 && ctx->marks[ctx->n_marks-1].ch == _T('&')) + PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER); + + off++; + continue; + } + + /* A potential autolink or raw HTML start/end. */ + if(ch == _T('<')) { + int is_autolink; + OFF autolink_end; + int missing_mailto; + + if(!(ctx->parser.flags & MD_FLAG_NOHTMLSPANS)) { + int is_html; + OFF html_end; + + /* Given the nature of the raw HTML, we have to recognize + * it here. Doing so later in md_analyze_lt_gt() could + * open can of worms of quadratic complexity. */ + is_html = md_is_html_any(ctx, lines + i, n_lines - i, off, + lines[n_lines-1].end, &html_end); + if(is_html) { + PUSH_MARK(_T('<'), off, off, MD_MARK_OPENER | MD_MARK_RESOLVED); + PUSH_MARK(_T('>'), html_end, html_end, MD_MARK_CLOSER | MD_MARK_RESOLVED); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + off = html_end; + + /* Advance the current line accordingly. */ + while(off > line_end) { + i++; + line++; + line_end = line->end; + } + continue; + } + } + + is_autolink = md_is_autolink(ctx, off, lines[n_lines-1].end, + &autolink_end, &missing_mailto); + if(is_autolink) { + PUSH_MARK((missing_mailto ? _T('@') : _T('<')), off, off+1, + MD_MARK_OPENER | MD_MARK_RESOLVED | MD_MARK_AUTOLINK); + PUSH_MARK(_T('>'), autolink_end-1, autolink_end, + MD_MARK_CLOSER | MD_MARK_RESOLVED | MD_MARK_AUTOLINK); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + off = autolink_end; + continue; + } + + off++; + continue; + } + + /* A potential link or its part. */ + if(ch == _T('[') || (ch == _T('!') && off+1 < line_end && CH(off+1) == _T('['))) { + OFF tmp = (ch == _T('[') ? off+1 : off+2); + PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER); + off = tmp; + /* Two dummies to make enough place for data we need if it is + * a link. */ + PUSH_MARK('D', off, off, 0); + PUSH_MARK('D', off, off, 0); + continue; + } + if(ch == _T(']')) { + PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER); + off++; + continue; + } + + /* A potential permissive e-mail autolink. */ + if(ch == _T('@')) { + if(line->beg + 1 <= off && ISALNUM(off-1) && + off + 3 < line->end && ISALNUM(off+1)) + { + PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + PUSH_MARK('D', off, off, 0); + } + + off++; + continue; + } + + /* A potential permissive URL autolink. */ + if(ch == _T(':')) { + static struct { + const CHAR* scheme; + SZ scheme_size; + const CHAR* suffix; + SZ suffix_size; + } scheme_map[] = { + /* In the order from the most frequently used, arguably. */ + { _T("http"), 4, _T("//"), 2 }, + { _T("https"), 5, _T("//"), 2 }, + { _T("ftp"), 3, _T("//"), 2 } + }; + int scheme_index; + + for(scheme_index = 0; scheme_index < (int) SIZEOF_ARRAY(scheme_map); scheme_index++) { + const CHAR* scheme = scheme_map[scheme_index].scheme; + const SZ scheme_size = scheme_map[scheme_index].scheme_size; + const CHAR* suffix = scheme_map[scheme_index].suffix; + const SZ suffix_size = scheme_map[scheme_index].suffix_size; + + if(line->beg + scheme_size <= off && md_ascii_eq(STR(off-scheme_size), scheme, scheme_size) && + (line->beg + scheme_size == off || ISWHITESPACE(off-scheme_size-1) || ISANYOF(off-scheme_size-1, _T("*_~(["))) && + off + 1 + suffix_size < line->end && md_ascii_eq(STR(off+1), suffix, suffix_size)) + { + PUSH_MARK(ch, off-scheme_size, off+1+suffix_size, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + PUSH_MARK('D', off, off, 0); + off += 1 + suffix_size; + break; + } + } + + off++; + continue; + } + + /* A potential permissive WWW autolink. */ + if(ch == _T('.')) { + if(line->beg + 3 <= off && md_ascii_eq(STR(off-3), _T("www"), 3) && + (line->beg + 3 == off || ISWHITESPACE(off-4) || ISANYOF(off-4, _T("*_~(["))) && + off + 1 < line_end) + { + PUSH_MARK(ch, off-3, off+1, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + PUSH_MARK('D', off, off, 0); + off++; + continue; + } + + off++; + continue; + } + + /* A potential table cell boundary or wiki link label delimiter. */ + if((table_mode || ctx->parser.flags & MD_FLAG_WIKILINKS) && ch == _T('|')) { + PUSH_MARK(ch, off, off+1, 0); + off++; + continue; + } + + /* A potential strikethrough start/end. */ + if(ch == _T('~')) { + OFF tmp = off+1; + + while(tmp < line_end && CH(tmp) == _T('~')) + tmp++; + + if(tmp - off < 3) { + unsigned flags = 0; + + if(tmp < line_end && !ISUNICODEWHITESPACE(tmp)) + flags |= MD_MARK_POTENTIAL_OPENER; + if(off > line->beg && !ISUNICODEWHITESPACEBEFORE(off)) + flags |= MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + PUSH_MARK(ch, off, tmp, flags); + } + + off = tmp; + continue; + } + + /* A potential equation start/end */ + if(ch == _T('$')) { + /* We can have at most two consecutive $ signs, + * where two dollar signs signify a display equation. */ + OFF tmp = off+1; + + while(tmp < line_end && CH(tmp) == _T('$')) + tmp++; + + if (tmp - off <= 2) + PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER); + off = tmp; + continue; + } + + /* Turn non-trivial whitespace into single space. */ + if(ISWHITESPACE_(ch)) { + OFF tmp = off+1; + + while(tmp < line_end && ISWHITESPACE(tmp)) + tmp++; + + if(tmp - off > 1 || ch != _T(' ')) + PUSH_MARK(ch, off, tmp, MD_MARK_RESOLVED); + + off = tmp; + continue; + } + + /* NULL character. */ + if(ch == _T('\0')) { + PUSH_MARK(ch, off, off+1, MD_MARK_RESOLVED); + off++; + continue; + } + + off++; + } + } + + /* Add a dummy mark at the end of the mark vector to simplify + * process_inlines(). */ + PUSH_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED); + +abort: + return ret; +} + +static void +md_analyze_bracket(MD_CTX* ctx, int mark_index) +{ + /* We cannot really resolve links here as for that we would need + * more context. E.g. a following pair of brackets (reference link), + * or enclosing pair of brackets (if the inner is the link, the outer + * one cannot be.) + * + * Therefore we here only construct a list of resolved '[' ']' pairs + * ordered by position of the closer. This allows ur to analyze what is + * or is not link in the right order, from inside to outside in case + * of nested brackets. + * + * The resolving itself is deferred into md_resolve_links(). + */ + + MD_MARK* mark = &ctx->marks[mark_index]; + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) { + md_mark_chain_append(ctx, &BRACKET_OPENERS, mark_index); + return; + } + + if(BRACKET_OPENERS.tail >= 0) { + /* Pop the opener from the chain. */ + int opener_index = BRACKET_OPENERS.tail; + MD_MARK* opener = &ctx->marks[opener_index]; + if(opener->prev >= 0) + ctx->marks[opener->prev].next = -1; + else + BRACKET_OPENERS.head = -1; + BRACKET_OPENERS.tail = opener->prev; + + /* Interconnect the opener and closer. */ + opener->next = mark_index; + mark->prev = opener_index; + + /* Add the pair into chain of potential links for md_resolve_links(). + * Note we misuse opener->prev for this as opener->next points to its + * closer. */ + if(ctx->unresolved_link_tail >= 0) + ctx->marks[ctx->unresolved_link_tail].prev = opener_index; + else + ctx->unresolved_link_head = opener_index; + ctx->unresolved_link_tail = opener_index; + opener->prev = -1; + } +} + +/* Forward declaration. */ +static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines, + int mark_beg, int mark_end); + +static int +md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines) +{ + int opener_index = ctx->unresolved_link_head; + OFF last_link_beg = 0; + OFF last_link_end = 0; + OFF last_img_beg = 0; + OFF last_img_end = 0; + + while(opener_index >= 0) { + MD_MARK* opener = &ctx->marks[opener_index]; + int closer_index = opener->next; + MD_MARK* closer = &ctx->marks[closer_index]; + int next_index = opener->prev; + MD_MARK* next_opener; + MD_MARK* next_closer; + MD_LINK_ATTR attr; + int is_link = FALSE; + + if(next_index >= 0) { + next_opener = &ctx->marks[next_index]; + next_closer = &ctx->marks[next_opener->next]; + } else { + next_opener = NULL; + next_closer = NULL; + } + + /* If nested ("[ [ ] ]"), we need to make sure that: + * - The outer does not end inside of (...) belonging to the inner. + * - The outer cannot be link if the inner is link (i.e. not image). + * + * (Note we here analyze from inner to outer as the marks are ordered + * by closer->beg.) + */ + if((opener->beg < last_link_beg && closer->end < last_link_end) || + (opener->beg < last_img_beg && closer->end < last_img_end) || + (opener->beg < last_link_end && opener->ch == '[')) + { + opener_index = next_index; + continue; + } + + /* Recognize and resolve wiki links. + * Wiki-links maybe '[[destination]]' or '[[destination|label]]'. + */ + if ((ctx->parser.flags & MD_FLAG_WIKILINKS) && + (opener->end - opener->beg == 1) && /* not image */ + next_opener != NULL && /* double '[' opener */ + next_opener->ch == '[' && + (next_opener->beg == opener->beg - 1) && + (next_opener->end - next_opener->beg == 1) && + next_closer != NULL && /* double ']' closer */ + next_closer->ch == ']' && + (next_closer->beg == closer->beg + 1) && + (next_closer->end - next_closer->beg == 1)) + { + MD_MARK* delim = NULL; + int delim_index; + OFF dest_beg, dest_end; + + is_link = TRUE; + + /* We don't allow destination to be longer than 100 characters. + * Lets scan to see whether there is '|'. (If not then the whole + * wiki-link has to be below the 100 characters.) */ + delim_index = opener_index + 1; + while(delim_index < closer_index) { + MD_MARK* m = &ctx->marks[delim_index]; + if(m->ch == '|') { + delim = m; + break; + } + if(m->ch != 'D' && m->beg - opener->end > 100) + break; + delim_index++; + } + dest_beg = opener->end; + dest_end = (delim != NULL) ? delim->beg : closer->beg; + if(dest_end - dest_beg == 0 || dest_end - dest_beg > 100) + is_link = FALSE; + + /* There may not be any new line in the destination. */ + if(is_link) { + OFF off; + for(off = dest_beg; off < dest_end; off++) { + if(ISNEWLINE(off)) { + is_link = FALSE; + break; + } + } + } + + if(is_link) { + if(delim != NULL) { + if(delim->end < closer->beg) { + opener->end = delim->beg; + } else { + /* The pipe is just before the closer: [[foo|]] */ + closer->beg = delim->beg; + delim = NULL; + } + } + + opener->beg = next_opener->beg; + opener->next = closer_index; + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + + closer->end = next_closer->end; + closer->prev = opener_index; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; + + last_link_beg = opener->beg; + last_link_end = closer->end; + + if(delim != NULL) { + delim->flags |= MD_MARK_RESOLVED; + md_rollback(ctx, opener_index, delim_index, MD_ROLLBACK_ALL); + md_analyze_link_contents(ctx, lines, n_lines, opener_index+1, closer_index); + } else { + md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL); + } + + opener_index = next_opener->prev; + continue; + } + } + + if(next_opener != NULL && next_opener->beg == closer->end) { + if(next_closer->beg > closer->end + 1) { + /* Might be full reference link. */ + is_link = md_is_link_reference(ctx, lines, n_lines, next_opener->beg, next_closer->end, &attr); + } else { + /* Might be shortcut reference link. */ + is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr); + } + + if(is_link < 0) + return -1; + + if(is_link) { + /* Eat the 2nd "[...]". */ + closer->end = next_closer->end; + + /* Do not analyze the label as a standalone link in the next + * iteration. */ + next_index = ctx->marks[next_index].prev; + } + } else { + if(closer->end < ctx->size && CH(closer->end) == _T('(')) { + /* Might be inline link. */ + OFF inline_link_end = UINT_MAX; + + is_link = md_is_inline_link_spec(ctx, lines, n_lines, closer->end, &inline_link_end, &attr); + if(is_link < 0) + return -1; + + /* Check the closing ')' is not inside an already resolved range + * (i.e. a range with a higher priority), e.g. a code span. */ + if(is_link) { + int i = closer_index + 1; + + while(i < ctx->n_marks) { + MD_MARK* mark = &ctx->marks[i]; + + if(mark->beg >= inline_link_end) + break; + if((mark->flags & (MD_MARK_OPENER | MD_MARK_RESOLVED)) == (MD_MARK_OPENER | MD_MARK_RESOLVED)) { + if(ctx->marks[mark->next].beg >= inline_link_end) { + /* Cancel the link status. */ + if(attr.title_needs_free) + free(attr.title); + is_link = FALSE; + break; + } + + i = mark->next + 1; + } else { + i++; + } + } + } + + if(is_link) { + /* Eat the "(...)" */ + closer->end = inline_link_end; + } + } + + if(!is_link) { + /* Might be collapsed reference link. */ + is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr); + if(is_link < 0) + return -1; + } + } + + if(is_link) { + /* Resolve the brackets as a link. */ + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; + + /* If it is a link, we store the destination and title in the two + * dummy marks after the opener. */ + MD_ASSERT(ctx->marks[opener_index+1].ch == 'D'); + ctx->marks[opener_index+1].beg = attr.dest_beg; + ctx->marks[opener_index+1].end = attr.dest_end; + + MD_ASSERT(ctx->marks[opener_index+2].ch == 'D'); + md_mark_store_ptr(ctx, opener_index+2, attr.title); + /* The title might or might not have been allocated for us. */ + if(attr.title_needs_free) + md_mark_chain_append(ctx, &PTR_CHAIN, opener_index+2); + ctx->marks[opener_index+2].prev = attr.title_size; + + if(opener->ch == '[') { + last_link_beg = opener->beg; + last_link_end = closer->end; + } else { + last_img_beg = opener->beg; + last_img_end = closer->end; + } + + md_analyze_link_contents(ctx, lines, n_lines, opener_index+1, closer_index); + + /* If the link text is formed by nothing but permissive autolink, + * suppress the autolink. + * See https://github.com/mity/md4c/issues/152 for more info. */ + if(ctx->parser.flags & MD_FLAG_PERMISSIVEAUTOLINKS) { + MD_MARK* first_nested; + MD_MARK* last_nested; + + first_nested = opener + 1; + while(first_nested->ch == _T('D') && first_nested < closer) + first_nested++; + + last_nested = closer - 1; + while(first_nested->ch == _T('D') && last_nested > opener) + last_nested--; + + if((first_nested->flags & MD_MARK_RESOLVED) && + first_nested->beg == opener->end && + ISANYOF_(first_nested->ch, _T("@:.")) && + first_nested->next == (last_nested - ctx->marks) && + last_nested->end == closer->beg) + { + first_nested->ch = _T('D'); + first_nested->flags &= ~MD_MARK_RESOLVED; + last_nested->ch = _T('D'); + last_nested->flags &= ~MD_MARK_RESOLVED; + } + } + } + + opener_index = next_index; + } + + return 0; +} + +/* Analyze whether the mark '&' starts a HTML entity. + * If so, update its flags as well as flags of corresponding closer ';'. */ +static void +md_analyze_entity(MD_CTX* ctx, int mark_index) +{ + MD_MARK* opener = &ctx->marks[mark_index]; + MD_MARK* closer; + OFF off; + + /* Cannot be entity if there is no closer as the next mark. + * (Any other mark between would mean strange character which cannot be + * part of the entity. + * + * So we can do all the work on '&' and do not call this later for the + * closing mark ';'. + */ + if(mark_index + 1 >= ctx->n_marks) + return; + closer = &ctx->marks[mark_index+1]; + if(closer->ch != ';') + return; + + if(md_is_entity(ctx, opener->beg, closer->end, &off)) { + MD_ASSERT(off == closer->end); + + md_resolve_range(ctx, NULL, mark_index, mark_index+1); + opener->end = closer->end; + } +} + +static void +md_analyze_table_cell_boundary(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + mark->flags |= MD_MARK_RESOLVED; + + md_mark_chain_append(ctx, &TABLECELLBOUNDARIES, mark_index); + ctx->n_table_cell_boundaries++; +} + +/* Split a longer mark into two. The new mark takes the given count of + * characters. May only be called if an adequate number of dummy 'D' marks + * follows. + */ +static int +md_split_emph_mark(MD_CTX* ctx, int mark_index, SZ n) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + int new_mark_index = mark_index + (mark->end - mark->beg - n); + MD_MARK* dummy = &ctx->marks[new_mark_index]; + + MD_ASSERT(mark->end - mark->beg > n); + MD_ASSERT(dummy->ch == 'D'); + + memcpy(dummy, mark, sizeof(MD_MARK)); + mark->end -= n; + dummy->beg = mark->end; + + return new_mark_index; +} + +static void +md_analyze_emph(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + MD_MARKCHAIN* chain = md_mark_chain(ctx, mark_index); + + /* If we can be a closer, try to resolve with the preceding opener. */ + if(mark->flags & MD_MARK_POTENTIAL_CLOSER) { + MD_MARK* opener = NULL; + int opener_index = 0; + + if(mark->ch == _T('*')) { + MD_MARKCHAIN* opener_chains[6]; + int i, n_opener_chains; + unsigned flags = mark->flags; + + /* Apply the "rule of three". */ + n_opener_chains = 0; + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_0; + if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_1; + if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1) + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_2; + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_0; + if(!(flags & MD_MARK_EMPH_INTRAWORD) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_1; + if(!(flags & MD_MARK_EMPH_INTRAWORD) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1) + opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_2; + + /* Opener is the most recent mark from the allowed chains. */ + for(i = 0; i < n_opener_chains; i++) { + if(opener_chains[i]->tail >= 0) { + int tmp_index = opener_chains[i]->tail; + MD_MARK* tmp_mark = &ctx->marks[tmp_index]; + if(opener == NULL || tmp_mark->end > opener->end) { + opener_index = tmp_index; + opener = tmp_mark; + } + } + } + } else { + /* Simple emph. mark */ + if(chain->tail >= 0) { + opener_index = chain->tail; + opener = &ctx->marks[opener_index]; + } + } + + /* Resolve, if we have found matching opener. */ + if(opener != NULL) { + SZ opener_size = opener->end - opener->beg; + SZ closer_size = mark->end - mark->beg; + MD_MARKCHAIN* opener_chain = md_mark_chain(ctx, opener_index); + + if(opener_size > closer_size) { + opener_index = md_split_emph_mark(ctx, opener_index, closer_size); + md_mark_chain_append(ctx, opener_chain, opener_index); + } else if(opener_size < closer_size) { + md_split_emph_mark(ctx, mark_index, closer_size - opener_size); + } + + md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); + md_resolve_range(ctx, opener_chain, opener_index, mark_index); + return; + } + } + + /* If we could not resolve as closer, we may be yet be an opener. */ + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_chain_append(ctx, chain, mark_index); +} + +static void +md_analyze_tilde(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + MD_MARKCHAIN* chain = md_mark_chain(ctx, mark_index); + + /* We attempt to be Github Flavored Markdown compatible here. GFM accepts + * only tildes sequences of length 1 and 2, and the length of the opener + * and closer has to match. */ + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && chain->head >= 0) { + int opener_index = chain->head; + + md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); + md_resolve_range(ctx, chain, opener_index, mark_index); + return; + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_chain_append(ctx, chain, mark_index); +} + +static void +md_analyze_dollar(MD_CTX* ctx, int mark_index) +{ + /* This should mimic the way inline equations work in LaTeX, so there + * can only ever be one item in the chain (i.e. the dollars can't be + * nested). This is basically the same as the md_analyze_tilde function, + * except that we require matching openers and closers to be of the same + * length. + * + * E.g.: $abc$$def$$ => abc (display equation) def (end equation) */ + if(DOLLAR_OPENERS.head >= 0) { + /* If the potential closer has a non-matching number of $, discard */ + MD_MARK* open = &ctx->marks[DOLLAR_OPENERS.head]; + MD_MARK* close = &ctx->marks[mark_index]; + + int opener_index = DOLLAR_OPENERS.head; + md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_ALL); + if (open->end - open->beg == close->end - close->beg) { + /* We are the matching closer */ + md_resolve_range(ctx, &DOLLAR_OPENERS, opener_index, mark_index); + } else { + /* We don't match the opener, so discard old opener and insert as opener */ + md_mark_chain_append(ctx, &DOLLAR_OPENERS, mark_index); + } + } else { + /* No unmatched openers, so we are opener */ + md_mark_chain_append(ctx, &DOLLAR_OPENERS, mark_index); + } +} + +static void +md_analyze_permissive_url_autolink(MD_CTX* ctx, int mark_index) +{ + MD_MARK* opener = &ctx->marks[mark_index]; + int closer_index = mark_index + 1; + MD_MARK* closer = &ctx->marks[closer_index]; + MD_MARK* next_resolved_mark; + OFF off = opener->end; + int n_dots = FALSE; + int has_underscore_in_last_seg = FALSE; + int has_underscore_in_next_to_last_seg = FALSE; + int n_opened_parenthesis = 0; + int n_excess_parenthesis = 0; + + /* Check for domain. */ + while(off < ctx->size) { + if(ISALNUM(off) || CH(off) == _T('-')) { + off++; + } else if(CH(off) == _T('.')) { + /* We must see at least one period. */ + n_dots++; + has_underscore_in_next_to_last_seg = has_underscore_in_last_seg; + has_underscore_in_last_seg = FALSE; + off++; + } else if(CH(off) == _T('_')) { + /* No underscore may be present in the last two domain segments. */ + has_underscore_in_last_seg = TRUE; + off++; + } else { + break; + } + } + if(off > opener->end && CH(off-1) == _T('.')) { + off--; + n_dots--; + } + if(off <= opener->end || n_dots == 0 || has_underscore_in_next_to_last_seg || has_underscore_in_last_seg) + return; + + /* Check for path. */ + next_resolved_mark = closer + 1; + while(next_resolved_mark->ch == 'D' || !(next_resolved_mark->flags & MD_MARK_RESOLVED)) + next_resolved_mark++; + while(off < next_resolved_mark->beg && CH(off) != _T('<') && !ISWHITESPACE(off) && !ISNEWLINE(off)) { + /* Parenthesis must be balanced. */ + if(CH(off) == _T('(')) { + n_opened_parenthesis++; + } else if(CH(off) == _T(')')) { + if(n_opened_parenthesis > 0) + n_opened_parenthesis--; + else + n_excess_parenthesis++; + } + + off++; + } + + /* Trim a trailing punctuation from the end. */ + while(TRUE) { + if(ISANYOF(off-1, _T("?!.,:*_~"))) { + off--; + } else if(CH(off-1) == ')' && n_excess_parenthesis > 0) { + /* Unmatched ')' can be in an interior of the path but not at the + * of it, so the auto-link may be safely nested in a parenthesis + * pair. */ + off--; + n_excess_parenthesis--; + } else { + break; + } + } + + /* Ok. Lets call it an auto-link. Adapt opener and create closer to zero + * length so all the contents becomes the link text. */ + MD_ASSERT(closer->ch == 'D'); + opener->end = opener->beg; + closer->ch = opener->ch; + closer->beg = off; + closer->end = off; + md_resolve_range(ctx, NULL, mark_index, closer_index); +} + +/* The permissive autolinks do not have to be enclosed in '<' '>' but we + * instead impose stricter rules what is understood as an e-mail address + * here. Actually any non-alphanumeric characters with exception of '.' + * are prohibited both in username and after '@'. */ +static void +md_analyze_permissive_email_autolink(MD_CTX* ctx, int mark_index) +{ + MD_MARK* opener = &ctx->marks[mark_index]; + int closer_index; + MD_MARK* closer; + OFF beg = opener->beg; + OFF end = opener->end; + int dot_count = 0; + + MD_ASSERT(CH(beg) == _T('@')); + + /* Scan for name before '@'. */ + while(beg > 0 && (ISALNUM(beg-1) || ISANYOF(beg-1, _T(".-_+")))) + beg--; + + /* Scan for domain after '@'. */ + while(end < ctx->size && (ISALNUM(end) || ISANYOF(end, _T(".-_")))) { + if(CH(end) == _T('.')) + dot_count++; + end++; + } + if(CH(end-1) == _T('.')) { /* Final '.' not part of it. */ + dot_count--; + end--; + } + else if(ISANYOF2(end-1, _T('-'), _T('_'))) /* These are forbidden at the end. */ + return; + if(CH(end-1) == _T('@') || dot_count == 0) + return; + + /* Ok. Lets call it auto-link. Adapt opener and create closer to zero + * length so all the contents becomes the link text. */ + closer_index = mark_index + 1; + closer = &ctx->marks[closer_index]; + MD_ASSERT(closer->ch == 'D'); + + opener->beg = beg; + opener->end = beg; + closer->ch = opener->ch; + closer->beg = end; + closer->end = end; + md_resolve_range(ctx, NULL, mark_index, closer_index); +} + +static inline void +md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, + int mark_beg, int mark_end, const CHAR* mark_chars) +{ + int i = mark_beg; + MD_UNUSED(lines); + MD_UNUSED(n_lines); + + while(i < mark_end) { + MD_MARK* mark = &ctx->marks[i]; + + /* Skip resolved spans. */ + if(mark->flags & MD_MARK_RESOLVED) { + if(mark->flags & MD_MARK_OPENER) { + MD_ASSERT(i < mark->next); + i = mark->next + 1; + } else { + i++; + } + continue; + } + + /* Skip marks we do not want to deal with. */ + if(!ISANYOF_(mark->ch, mark_chars)) { + i++; + continue; + } + + /* Analyze the mark. */ + switch(mark->ch) { + case '[': /* Pass through. */ + case '!': /* Pass through. */ + case ']': md_analyze_bracket(ctx, i); break; + case '&': md_analyze_entity(ctx, i); break; + case '|': md_analyze_table_cell_boundary(ctx, i); break; + case '_': /* Pass through. */ + case '*': md_analyze_emph(ctx, i); break; + case '~': md_analyze_tilde(ctx, i); break; + case '$': md_analyze_dollar(ctx, i); break; + case '.': /* Pass through. */ + case ':': md_analyze_permissive_url_autolink(ctx, i); break; + case '@': md_analyze_permissive_email_autolink(ctx, i); break; + } + + i++; + } +} + +/* Analyze marks (build ctx->marks). */ +static int +md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) +{ + int ret; + + /* Reset the previously collected stack of marks. */ + ctx->n_marks = 0; + + /* Collect all marks. */ + MD_CHECK(md_collect_marks(ctx, lines, n_lines, table_mode)); + + /* We analyze marks in few groups to handle their precedence. */ + /* (1) Entities; code spans; autolinks; raw HTML. */ + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("&")); + + /* (2) Links. */ + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!")); + MD_CHECK(md_resolve_links(ctx, lines, n_lines)); + BRACKET_OPENERS.head = -1; + BRACKET_OPENERS.tail = -1; + ctx->unresolved_link_head = -1; + ctx->unresolved_link_tail = -1; + + if(table_mode) { + /* (3) Analyze table cell boundaries. + * Note we reset TABLECELLBOUNDARIES chain prior to the call md_analyze_marks(), + * not after, because caller may need it. */ + MD_ASSERT(n_lines == 1); + TABLECELLBOUNDARIES.head = -1; + TABLECELLBOUNDARIES.tail = -1; + ctx->n_table_cell_boundaries = 0; + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("|")); + return ret; + } + + /* (4) Emphasis and strong emphasis; permissive autolinks. */ + md_analyze_link_contents(ctx, lines, n_lines, 0, ctx->n_marks); + +abort: + return ret; +} + +static void +md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines, + int mark_beg, int mark_end) +{ + int i; + + md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("*_~$@:.")); + + for(i = OPENERS_CHAIN_FIRST; i <= OPENERS_CHAIN_LAST; i++) { + ctx->mark_chains[i].head = -1; + ctx->mark_chains[i].tail = -1; + } +} + +static int +md_enter_leave_span_a(MD_CTX* ctx, int enter, MD_SPANTYPE type, + const CHAR* dest, SZ dest_size, int prohibit_escapes_in_dest, + const CHAR* title, SZ title_size) +{ + MD_ATTRIBUTE_BUILD href_build = { 0 }; + MD_ATTRIBUTE_BUILD title_build = { 0 }; + MD_SPAN_A_DETAIL det; + int ret = 0; + + /* Note we here rely on fact that MD_SPAN_A_DETAIL and + * MD_SPAN_IMG_DETAIL are binary-compatible. */ + memset(&det, 0, sizeof(MD_SPAN_A_DETAIL)); + MD_CHECK(md_build_attribute(ctx, dest, dest_size, + (prohibit_escapes_in_dest ? MD_BUILD_ATTR_NO_ESCAPES : 0), + &det.href, &href_build)); + MD_CHECK(md_build_attribute(ctx, title, title_size, 0, &det.title, &title_build)); + + if(enter) + MD_ENTER_SPAN(type, &det); + else + MD_LEAVE_SPAN(type, &det); + +abort: + md_free_attribute(ctx, &href_build); + md_free_attribute(ctx, &title_build); + return ret; +} + +static int +md_enter_leave_span_wikilink(MD_CTX* ctx, int enter, const CHAR* target, SZ target_size) +{ + MD_ATTRIBUTE_BUILD target_build = { 0 }; + MD_SPAN_WIKILINK_DETAIL det; + int ret = 0; + + memset(&det, 0, sizeof(MD_SPAN_WIKILINK_DETAIL)); + MD_CHECK(md_build_attribute(ctx, target, target_size, 0, &det.target, &target_build)); + + if (enter) + MD_ENTER_SPAN(MD_SPAN_WIKILINK, &det); + else + MD_LEAVE_SPAN(MD_SPAN_WIKILINK, &det); + +abort: + md_free_attribute(ctx, &target_build); + return ret; +} + + +/* Render the output, accordingly to the analyzed ctx->marks. */ +static int +md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines) +{ + MD_TEXTTYPE text_type; + const MD_LINE* line = lines; + MD_MARK* prev_mark = NULL; + MD_MARK* mark; + OFF off = lines[0].beg; + OFF end = lines[n_lines-1].end; + int enforce_hardbreak = 0; + int ret = 0; + + /* Find first resolved mark. Note there is always at least one resolved + * mark, the dummy last one after the end of the latest line we actually + * never really reach. This saves us of a lot of special checks and cases + * in this function. */ + mark = ctx->marks; + while(!(mark->flags & MD_MARK_RESOLVED)) + mark++; + + text_type = MD_TEXT_NORMAL; + + while(1) { + /* Process the text up to the next mark or end-of-line. */ + OFF tmp = (line->end < mark->beg ? line->end : mark->beg); + if(tmp > off) { + MD_TEXT(text_type, STR(off), tmp - off); + off = tmp; + } + + /* If reached the mark, process it and move to next one. */ + if(off >= mark->beg) { + switch(mark->ch) { + case '\\': /* Backslash escape. */ + if(ISNEWLINE(mark->beg+1)) + enforce_hardbreak = 1; + else + MD_TEXT(text_type, STR(mark->beg+1), 1); + break; + + case ' ': /* Non-trivial space. */ + MD_TEXT(text_type, _T(" "), 1); + break; + + case '`': /* Code span. */ + if(mark->flags & MD_MARK_OPENER) { + MD_ENTER_SPAN(MD_SPAN_CODE, NULL); + text_type = MD_TEXT_CODE; + } else { + MD_LEAVE_SPAN(MD_SPAN_CODE, NULL); + text_type = MD_TEXT_NORMAL; + } + break; + + case '_': /* Underline (or emphasis if we fall through). */ + if(ctx->parser.flags & MD_FLAG_UNDERLINE) { + if(mark->flags & MD_MARK_OPENER) { + while(off < mark->end) { + MD_ENTER_SPAN(MD_SPAN_U, NULL); + off++; + } + } else { + while(off < mark->end) { + MD_LEAVE_SPAN(MD_SPAN_U, NULL); + off++; + } + } + break; + } + MD_FALLTHROUGH(); + + case '*': /* Emphasis, strong emphasis. */ + if(mark->flags & MD_MARK_OPENER) { + if((mark->end - off) % 2) { + MD_ENTER_SPAN(MD_SPAN_EM, NULL); + off++; + } + while(off + 1 < mark->end) { + MD_ENTER_SPAN(MD_SPAN_STRONG, NULL); + off += 2; + } + } else { + while(off + 1 < mark->end) { + MD_LEAVE_SPAN(MD_SPAN_STRONG, NULL); + off += 2; + } + if((mark->end - off) % 2) { + MD_LEAVE_SPAN(MD_SPAN_EM, NULL); + off++; + } + } + break; + + case '~': + if(mark->flags & MD_MARK_OPENER) + MD_ENTER_SPAN(MD_SPAN_DEL, NULL); + else + MD_LEAVE_SPAN(MD_SPAN_DEL, NULL); + break; + + case '$': + if(mark->flags & MD_MARK_OPENER) { + MD_ENTER_SPAN((mark->end - off) % 2 ? MD_SPAN_LATEXMATH : MD_SPAN_LATEXMATH_DISPLAY, NULL); + text_type = MD_TEXT_LATEXMATH; + } else { + MD_LEAVE_SPAN((mark->end - off) % 2 ? MD_SPAN_LATEXMATH : MD_SPAN_LATEXMATH_DISPLAY, NULL); + text_type = MD_TEXT_NORMAL; + } + break; + + case '[': /* Link, wiki link, image. */ + case '!': + case ']': + { + const MD_MARK* opener = (mark->ch != ']' ? mark : &ctx->marks[mark->prev]); + const MD_MARK* closer = &ctx->marks[opener->next]; + const MD_MARK* dest_mark; + const MD_MARK* title_mark; + + if ((opener->ch == '[' && closer->ch == ']') && + opener->end - opener->beg >= 2 && + closer->end - closer->beg >= 2) + { + int has_label = (opener->end - opener->beg > 2); + SZ target_sz; + + if(has_label) + target_sz = opener->end - (opener->beg+2); + else + target_sz = closer->beg - opener->end; + + MD_CHECK(md_enter_leave_span_wikilink(ctx, (mark->ch != ']'), + has_label ? STR(opener->beg+2) : STR(opener->end), + target_sz)); + + break; + } + + dest_mark = opener+1; + MD_ASSERT(dest_mark->ch == 'D'); + title_mark = opener+2; + MD_ASSERT(title_mark->ch == 'D'); + + MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'), + (opener->ch == '!' ? MD_SPAN_IMG : MD_SPAN_A), + STR(dest_mark->beg), dest_mark->end - dest_mark->beg, FALSE, + (MD_CHAR *) md_mark_get_ptr(ctx, (int)(title_mark - ctx->marks)), + title_mark->prev)); + + /* link/image closer may span multiple lines. */ + if(mark->ch == ']') { + while(mark->end > line->end) + line++; + } + + break; + } + + case '<': + case '>': /* Autolink or raw HTML. */ + if(!(mark->flags & MD_MARK_AUTOLINK)) { + /* Raw HTML. */ + if(mark->flags & MD_MARK_OPENER) + text_type = MD_TEXT_HTML; + else + text_type = MD_TEXT_NORMAL; + break; + } + /* Pass through, if auto-link. */ + MD_FALLTHROUGH(); + + case '@': /* Permissive e-mail autolink. */ + case ':': /* Permissive URL autolink. */ + case '.': /* Permissive WWW autolink. */ + { + MD_MARK* opener = ((mark->flags & MD_MARK_OPENER) ? mark : &ctx->marks[mark->prev]); + MD_MARK* closer = &ctx->marks[opener->next]; + const CHAR* dest = STR(opener->end); + SZ dest_size = closer->beg - opener->end; + + /* For permissive auto-links we do not know closer mark + * position at the time of md_collect_marks(), therefore + * it can be out-of-order in ctx->marks[]. + * + * With this flag, we make sure that we output the closer + * only if we processed the opener. */ + if(mark->flags & MD_MARK_OPENER) + closer->flags |= MD_MARK_VALIDPERMISSIVEAUTOLINK; + + if(opener->ch == '@' || opener->ch == '.') { + dest_size += 7; + MD_TEMP_BUFFER(dest_size * sizeof(CHAR)); + memcpy(ctx->buffer, + (opener->ch == '@' ? _T("mailto:") : _T("http://")), + 7 * sizeof(CHAR)); + memcpy(ctx->buffer + 7, dest, (dest_size-7) * sizeof(CHAR)); + dest = ctx->buffer; + } + + if(closer->flags & MD_MARK_VALIDPERMISSIVEAUTOLINK) + MD_CHECK(md_enter_leave_span_a(ctx, (mark->flags & MD_MARK_OPENER), + MD_SPAN_A, dest, dest_size, TRUE, NULL, 0)); + break; + } + + case '&': /* Entity. */ + MD_TEXT(MD_TEXT_ENTITY, STR(mark->beg), mark->end - mark->beg); + break; + + case '\0': + MD_TEXT(MD_TEXT_NULLCHAR, _T(""), 1); + break; + + case 127: + goto abort; + } + + off = mark->end; + + /* Move to next resolved mark. */ + prev_mark = mark; + mark++; + while(!(mark->flags & MD_MARK_RESOLVED) || mark->beg < off) + mark++; + } + + /* If reached end of line, move to next one. */ + if(off >= line->end) { + /* If it is the last line, we are done. */ + if(off >= end) + break; + + if(text_type == MD_TEXT_CODE || text_type == MD_TEXT_LATEXMATH) { + OFF tmp; + + MD_ASSERT(prev_mark != NULL); + MD_ASSERT(ISANYOF2_(prev_mark->ch, '`', '$') && (prev_mark->flags & MD_MARK_OPENER)); + MD_ASSERT(ISANYOF2_(mark->ch, '`', '$') && (mark->flags & MD_MARK_CLOSER)); + + /* Inside a code span, trailing line whitespace has to be + * outputted. */ + tmp = off; + while(off < ctx->size && ISBLANK(off)) + off++; + if(off > tmp) + MD_TEXT(text_type, STR(tmp), off-tmp); + + /* and new lines are transformed into single spaces. */ + if(prev_mark->end < off && off < mark->beg) + MD_TEXT(text_type, _T(" "), 1); + } else if(text_type == MD_TEXT_HTML) { + /* Inside raw HTML, we output the new line verbatim, including + * any trailing spaces. */ + OFF tmp = off; + + while(tmp < end && ISBLANK(tmp)) + tmp++; + if(tmp > off) + MD_TEXT(MD_TEXT_HTML, STR(off), tmp - off); + MD_TEXT(MD_TEXT_HTML, _T("\n"), 1); + } else { + /* Output soft or hard line break. */ + MD_TEXTTYPE break_type = MD_TEXT_SOFTBR; + + if(text_type == MD_TEXT_NORMAL) { + if(enforce_hardbreak) + break_type = MD_TEXT_BR; + else if((CH(line->end) == _T(' ') && CH(line->end+1) == _T(' '))) + break_type = MD_TEXT_BR; + } + + MD_TEXT(break_type, _T("\n"), 1); + } + + /* Move to the next line. */ + line++; + off = line->beg; + + enforce_hardbreak = 0; + } + } + +abort: + return ret; +} + + +/*************************** + *** Processing Tables *** + ***************************/ + +static void +md_analyze_table_alignment(MD_CTX* ctx, OFF beg, OFF end, MD_ALIGN* align, int n_align) +{ + static const MD_ALIGN align_map[] = { MD_ALIGN_DEFAULT, MD_ALIGN_LEFT, MD_ALIGN_RIGHT, MD_ALIGN_CENTER }; + OFF off = beg; + + while(n_align > 0) { + int index = 0; /* index into align_map[] */ + + while(CH(off) != _T('-')) + off++; + if(off > beg && CH(off-1) == _T(':')) + index |= 1; + while(off < end && CH(off) == _T('-')) + off++; + if(off < end && CH(off) == _T(':')) + index |= 2; + + *align = align_map[index]; + align++; + n_align--; + } + +} + +/* Forward declaration. */ +static int md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines); + +static int +md_process_table_cell(MD_CTX* ctx, MD_BLOCKTYPE cell_type, MD_ALIGN align, OFF beg, OFF end) +{ + MD_LINE line; + MD_BLOCK_TD_DETAIL det; + int ret = 0; + + while(beg < end && ISWHITESPACE(beg)) + beg++; + while(end > beg && ISWHITESPACE(end-1)) + end--; + + det.align = align; + line.beg = beg; + line.end = end; + + MD_ENTER_BLOCK(cell_type, &det); + MD_CHECK(md_process_normal_block_contents(ctx, &line, 1)); + MD_LEAVE_BLOCK(cell_type, &det); + +abort: + return ret; +} + +static int +md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, + const MD_ALIGN* align, int col_count) +{ + MD_LINE line; + OFF* pipe_offs = NULL; + int i, j, k, n; + int ret = 0; + + line.beg = beg; + line.end = end; + + /* Break the line into table cells by identifying pipe characters who + * form the cell boundary. */ + MD_CHECK(md_analyze_inlines(ctx, &line, 1, TRUE)); + + /* We have to remember the cell boundaries in local buffer because + * ctx->marks[] shall be reused during cell contents processing. */ + n = ctx->n_table_cell_boundaries + 2; + pipe_offs = (OFF*) malloc(n * sizeof(OFF)); + if(pipe_offs == NULL) { + MD_LOG("malloc() failed."); + ret = -1; + goto abort; + } + j = 0; + pipe_offs[j++] = beg; + for(i = TABLECELLBOUNDARIES.head; i >= 0; i = ctx->marks[i].next) { + MD_MARK* mark = &ctx->marks[i]; + pipe_offs[j++] = mark->end; + } + pipe_offs[j++] = end+1; + + /* Process cells. */ + MD_ENTER_BLOCK(MD_BLOCK_TR, NULL); + k = 0; + for(i = 0; i < j-1 && k < col_count; i++) { + if(pipe_offs[i] < pipe_offs[i+1]-1) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], pipe_offs[i], pipe_offs[i+1]-1)); + } + /* Make sure we call enough table cells even if the current table contains + * too few of them. */ + while(k < col_count) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], 0, 0)); + MD_LEAVE_BLOCK(MD_BLOCK_TR, NULL); + +abort: + free(pipe_offs); + + /* Free any temporary memory blocks stored within some dummy marks. */ + for(i = PTR_CHAIN.head; i >= 0; i = ctx->marks[i].next) + free(md_mark_get_ptr(ctx, i)); + PTR_CHAIN.head = -1; + PTR_CHAIN.tail = -1; + + return ret; +} + +static int +md_process_table_block_contents(MD_CTX* ctx, int col_count, const MD_LINE* lines, int n_lines) +{ + MD_ALIGN* align; + int i; + int ret = 0; + + /* At least two lines have to be present: The column headers and the line + * with the underlines. */ + MD_ASSERT(n_lines >= 2); + + align = (MD_ALIGN *) malloc(col_count * sizeof(MD_ALIGN)); + if(align == NULL) { + MD_LOG("malloc() failed."); + ret = -1; + goto abort; + } + + md_analyze_table_alignment(ctx, lines[1].beg, lines[1].end, align, col_count); + + MD_ENTER_BLOCK(MD_BLOCK_THEAD, NULL); + MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TH, + lines[0].beg, lines[0].end, align, col_count)); + MD_LEAVE_BLOCK(MD_BLOCK_THEAD, NULL); + + if(n_lines > 2) { + MD_ENTER_BLOCK(MD_BLOCK_TBODY, NULL); + for(i = 2; i < n_lines; i++) { + MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TD, + lines[i].beg, lines[i].end, align, col_count)); + } + MD_LEAVE_BLOCK(MD_BLOCK_TBODY, NULL); + } + +abort: + free(align); + return ret; +} + + +/************************** + *** Processing Block *** + **************************/ + +#define MD_BLOCK_CONTAINER_OPENER 0x01 +#define MD_BLOCK_CONTAINER_CLOSER 0x02 +#define MD_BLOCK_CONTAINER (MD_BLOCK_CONTAINER_OPENER | MD_BLOCK_CONTAINER_CLOSER) +#define MD_BLOCK_LOOSE_LIST 0x04 +#define MD_BLOCK_SETEXT_HEADER 0x08 + +struct MD_BLOCK_tag { + MD_BLOCKTYPE type : 8; + unsigned flags : 8; + + /* MD_BLOCK_H: Header level (1 - 6) + * MD_BLOCK_CODE: Non-zero if fenced, zero if indented. + * MD_BLOCK_LI: Task mark character (0 if not task list item, 'x', 'X' or ' '). + * MD_BLOCK_TABLE: Column count (as determined by the table underline). + */ + unsigned data : 16; + + /* Leaf blocks: Count of lines (MD_LINE or MD_VERBATIMLINE) on the block. + * MD_BLOCK_LI: Task mark offset in the input doc. + * MD_BLOCK_OL: Start item number. + */ + unsigned n_lines; +}; + +struct MD_CONTAINER_tag { + CHAR ch; + unsigned is_loose : 8; + unsigned is_task : 8; + unsigned start; + unsigned mark_indent; + unsigned contents_indent; + OFF block_byte_off; + OFF task_mark_off; +}; + + +static int +md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines) +{ + int i; + int ret; + + MD_CHECK(md_analyze_inlines(ctx, lines, n_lines, FALSE)); + MD_CHECK(md_process_inlines(ctx, lines, n_lines)); + +abort: + /* Free any temporary memory blocks stored within some dummy marks. */ + for(i = PTR_CHAIN.head; i >= 0; i = ctx->marks[i].next) + free(md_mark_get_ptr(ctx, i)); + PTR_CHAIN.head = -1; + PTR_CHAIN.tail = -1; + + return ret; +} + +static int +md_process_verbatim_block_contents(MD_CTX* ctx, MD_TEXTTYPE text_type, const MD_VERBATIMLINE* lines, int n_lines) +{ + static const CHAR indent_chunk_str[] = _T(" "); + static const SZ indent_chunk_size = SIZEOF_ARRAY(indent_chunk_str) - 1; + + int i; + int ret = 0; + + for(i = 0; i < n_lines; i++) { + const MD_VERBATIMLINE* line = &lines[i]; + int indent = line->indent; + + MD_ASSERT(indent >= 0); + + /* Output code indentation. */ + while(indent > (int) indent_chunk_size) { + MD_TEXT(text_type, indent_chunk_str, indent_chunk_size); + indent -= indent_chunk_size; + } + if(indent > 0) + MD_TEXT(text_type, indent_chunk_str, indent); + + /* Output the code line itself. */ + MD_TEXT_INSECURE(text_type, STR(line->beg), line->end - line->beg); + + /* Enforce end-of-line. */ + MD_TEXT(text_type, _T("\n"), 1); + } + +abort: + return ret; +} + +static int +md_process_code_block_contents(MD_CTX* ctx, int is_fenced, const MD_VERBATIMLINE* lines, int n_lines) +{ + if(is_fenced) { + /* Skip the first line in case of fenced code: It is the fence. + * (Only the starting fence is present due to logic in md_analyze_line().) */ + lines++; + n_lines--; + } else { + /* Ignore blank lines at start/end of indented code block. */ + while(n_lines > 0 && lines[0].beg == lines[0].end) { + lines++; + n_lines--; + } + while(n_lines > 0 && lines[n_lines-1].beg == lines[n_lines-1].end) { + n_lines--; + } + } + + if(n_lines == 0) + return 0; + + return md_process_verbatim_block_contents(ctx, MD_TEXT_CODE, lines, n_lines); +} + +static int +md_setup_fenced_code_detail(MD_CTX* ctx, const MD_BLOCK* block, MD_BLOCK_CODE_DETAIL* det, + MD_ATTRIBUTE_BUILD* info_build, MD_ATTRIBUTE_BUILD* lang_build) +{ + const MD_VERBATIMLINE* fence_line = (const MD_VERBATIMLINE*)(block + 1); + OFF beg = fence_line->beg; + OFF end = fence_line->end; + OFF lang_end; + CHAR fence_ch = CH(fence_line->beg); + int ret = 0; + + /* Skip the fence itself. */ + while(beg < ctx->size && CH(beg) == fence_ch) + beg++; + /* Trim initial spaces. */ + while(beg < ctx->size && CH(beg) == _T(' ')) + beg++; + + /* Trim trailing spaces. */ + while(end > beg && CH(end-1) == _T(' ')) + end--; + + /* Build info string attribute. */ + MD_CHECK(md_build_attribute(ctx, STR(beg), end - beg, 0, &det->info, info_build)); + + /* Build info string attribute. */ + lang_end = beg; + while(lang_end < end && !ISWHITESPACE(lang_end)) + lang_end++; + MD_CHECK(md_build_attribute(ctx, STR(beg), lang_end - beg, 0, &det->lang, lang_build)); + + det->fence_char = fence_ch; + +abort: + return ret; +} + +static int +md_process_leaf_block(MD_CTX* ctx, const MD_BLOCK* block) +{ + union { + MD_BLOCK_H_DETAIL header; + MD_BLOCK_CODE_DETAIL code; + MD_BLOCK_TABLE_DETAIL table; + } det; + MD_ATTRIBUTE_BUILD info_build; + MD_ATTRIBUTE_BUILD lang_build; + int is_in_tight_list; + int clean_fence_code_detail = FALSE; + int ret = 0; + + memset(&det, 0, sizeof(det)); + + if(ctx->n_containers == 0) + is_in_tight_list = FALSE; + else + is_in_tight_list = !ctx->containers[ctx->n_containers-1].is_loose; + + switch(block->type) { + case MD_BLOCK_H: + det.header.level = block->data; + break; + + case MD_BLOCK_CODE: + /* For fenced code block, we may need to set the info string. */ + if(block->data != 0) { + memset(&det.code, 0, sizeof(MD_BLOCK_CODE_DETAIL)); + clean_fence_code_detail = TRUE; + MD_CHECK(md_setup_fenced_code_detail(ctx, block, &det.code, &info_build, &lang_build)); + } + break; + + case MD_BLOCK_TABLE: + det.table.col_count = block->data; + det.table.head_row_count = 1; + det.table.body_row_count = block->n_lines - 2; + break; + + default: + /* Noop. */ + break; + } + + if(!is_in_tight_list || block->type != MD_BLOCK_P) + MD_ENTER_BLOCK(block->type, (void*) &det); + + /* Process the block contents accordingly to is type. */ + switch(block->type) { + case MD_BLOCK_HR: + /* noop */ + break; + + case MD_BLOCK_CODE: + MD_CHECK(md_process_code_block_contents(ctx, (block->data != 0), + (const MD_VERBATIMLINE*)(block + 1), block->n_lines)); + break; + + case MD_BLOCK_HTML: + MD_CHECK(md_process_verbatim_block_contents(ctx, MD_TEXT_HTML, + (const MD_VERBATIMLINE*)(block + 1), block->n_lines)); + break; + + case MD_BLOCK_TABLE: + MD_CHECK(md_process_table_block_contents(ctx, block->data, + (const MD_LINE*)(block + 1), block->n_lines)); + break; + + default: + MD_CHECK(md_process_normal_block_contents(ctx, + (const MD_LINE*)(block + 1), block->n_lines)); + break; + } + + if(!is_in_tight_list || block->type != MD_BLOCK_P) + MD_LEAVE_BLOCK(block->type, (void*) &det); + +abort: + if(clean_fence_code_detail) { + md_free_attribute(ctx, &info_build); + md_free_attribute(ctx, &lang_build); + } + return ret; +} + +static int +md_process_all_blocks(MD_CTX* ctx) +{ + int byte_off = 0; + int ret = 0; + + /* ctx->containers now is not needed for detection of lists and list items + * so we reuse it for tracking what lists are loose or tight. We rely + * on the fact the vector is large enough to hold the deepest nesting + * level of lists. */ + ctx->n_containers = 0; + + while(byte_off < ctx->n_block_bytes) { + MD_BLOCK* block = (MD_BLOCK*)((char*)ctx->block_bytes + byte_off); + union { + MD_BLOCK_UL_DETAIL ul; + MD_BLOCK_OL_DETAIL ol; + MD_BLOCK_LI_DETAIL li; + } det; + + switch(block->type) { + case MD_BLOCK_UL: + det.ul.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? FALSE : TRUE; + det.ul.mark = (CHAR) block->data; + break; + + case MD_BLOCK_OL: + det.ol.start = block->n_lines; + det.ol.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? FALSE : TRUE; + det.ol.mark_delimiter = (CHAR) block->data; + break; + + case MD_BLOCK_LI: + det.li.is_task = (block->data != 0); + det.li.task_mark = (CHAR) block->data; + det.li.task_mark_offset = (OFF) block->n_lines; + break; + + default: + /* noop */ + break; + } + + if(block->flags & MD_BLOCK_CONTAINER) { + if(block->flags & MD_BLOCK_CONTAINER_CLOSER) { + MD_LEAVE_BLOCK(block->type, &det); + + if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL || block->type == MD_BLOCK_QUOTE) + ctx->n_containers--; + } + + if(block->flags & MD_BLOCK_CONTAINER_OPENER) { + MD_ENTER_BLOCK(block->type, &det); + + if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL) { + ctx->containers[ctx->n_containers].is_loose = (block->flags & MD_BLOCK_LOOSE_LIST); + ctx->n_containers++; + } else if(block->type == MD_BLOCK_QUOTE) { + /* This causes that any text in a block quote, even if + * nested inside a tight list item, is wrapped with + * <p>...</p>. */ + ctx->containers[ctx->n_containers].is_loose = TRUE; + ctx->n_containers++; + } + } + } else { + MD_CHECK(md_process_leaf_block(ctx, block)); + + if(block->type == MD_BLOCK_CODE || block->type == MD_BLOCK_HTML) + byte_off += block->n_lines * sizeof(MD_VERBATIMLINE); + else + byte_off += block->n_lines * sizeof(MD_LINE); + } + + byte_off += sizeof(MD_BLOCK); + } + + ctx->n_block_bytes = 0; + +abort: + return ret; +} + + +/************************************ + *** Grouping Lines into Blocks *** + ************************************/ + +static void* +md_push_block_bytes(MD_CTX* ctx, int n_bytes) +{ + void* ptr; + + if(ctx->n_block_bytes + n_bytes > ctx->alloc_block_bytes) { + void* new_block_bytes; + + ctx->alloc_block_bytes = (ctx->alloc_block_bytes > 0 + ? ctx->alloc_block_bytes + ctx->alloc_block_bytes / 2 + : 512); + new_block_bytes = realloc(ctx->block_bytes, ctx->alloc_block_bytes); + if(new_block_bytes == NULL) { + MD_LOG("realloc() failed."); + return NULL; + } + + /* Fix the ->current_block after the reallocation. */ + if(ctx->current_block != NULL) { + OFF off_current_block = (OFF) ((char*) ctx->current_block - (char*) ctx->block_bytes); + ctx->current_block = (MD_BLOCK*) ((char*) new_block_bytes + off_current_block); + } + + ctx->block_bytes = new_block_bytes; + } + + ptr = (char*)ctx->block_bytes + ctx->n_block_bytes; + ctx->n_block_bytes += n_bytes; + return ptr; +} + +static int +md_start_new_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* line) +{ + MD_BLOCK* block; + + MD_ASSERT(ctx->current_block == NULL); + + block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); + if(block == NULL) + return -1; + + switch(line->type) { + case MD_LINE_HR: + block->type = MD_BLOCK_HR; + break; + + case MD_LINE_ATXHEADER: + case MD_LINE_SETEXTHEADER: + block->type = MD_BLOCK_H; + break; + + case MD_LINE_FENCEDCODE: + case MD_LINE_INDENTEDCODE: + block->type = MD_BLOCK_CODE; + break; + + case MD_LINE_TEXT: + block->type = MD_BLOCK_P; + break; + + case MD_LINE_HTML: + block->type = MD_BLOCK_HTML; + break; + + case MD_LINE_BLANK: + case MD_LINE_SETEXTUNDERLINE: + case MD_LINE_TABLEUNDERLINE: + default: + MD_UNREACHABLE(); + break; + } + + block->flags = 0; + block->data = line->data; + block->n_lines = 0; + + ctx->current_block = block; + return 0; +} + +/* Eat from start of current (textual) block any reference definitions and + * remember them so we can resolve any links referring to them. + * + * (Reference definitions can only be at start of it as they cannot break + * a paragraph.) + */ +static int +md_consume_link_reference_definitions(MD_CTX* ctx) +{ + MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); + int n_lines = ctx->current_block->n_lines; + int n = 0; + + /* Compute how many lines at the start of the block form one or more + * reference definitions. */ + while(n < n_lines) { + int n_link_ref_lines; + + n_link_ref_lines = md_is_link_reference_definition(ctx, + lines + n, n_lines - n); + /* Not a reference definition? */ + if(n_link_ref_lines == 0) + break; + + /* We fail if it is the ref. def. but it could not be stored due + * a memory allocation error. */ + if(n_link_ref_lines < 0) + return -1; + + n += n_link_ref_lines; + } + + /* If there was at least one reference definition, we need to remove + * its lines from the block, or perhaps even the whole block. */ + if(n > 0) { + if(n == n_lines) { + /* Remove complete block. */ + ctx->n_block_bytes -= n * sizeof(MD_LINE); + ctx->n_block_bytes -= sizeof(MD_BLOCK); + ctx->current_block = NULL; + } else { + /* Remove just some initial lines from the block. */ + memmove(lines, lines + n, (n_lines - n) * sizeof(MD_LINE)); + ctx->current_block->n_lines -= n; + ctx->n_block_bytes -= n * sizeof(MD_LINE); + } + } + + return 0; +} + +static int +md_end_current_block(MD_CTX* ctx) +{ + int ret = 0; + + if(ctx->current_block == NULL) + return ret; + + /* Check whether there is a reference definition. (We do this here instead + * of in md_analyze_line() because reference definition can take multiple + * lines.) */ + if(ctx->current_block->type == MD_BLOCK_P || + (ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER))) + { + MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); + if(CH(lines[0].beg) == _T('[')) { + MD_CHECK(md_consume_link_reference_definitions(ctx)); + if(ctx->current_block == NULL) + return ret; + } + } + + if(ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER)) { + int n_lines = ctx->current_block->n_lines; + + if(n_lines > 1) { + /* Get rid of the underline. */ + ctx->current_block->n_lines--; + ctx->n_block_bytes -= sizeof(MD_LINE); + } else { + /* Only the underline has left after eating the ref. defs. + * Keep the line as beginning of a new ordinary paragraph. */ + ctx->current_block->type = MD_BLOCK_P; + return 0; + } + } + + /* Mark we are not building any block anymore. */ + ctx->current_block = NULL; + +abort: + return ret; +} + +static int +md_add_line_into_current_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* analysis) +{ + MD_ASSERT(ctx->current_block != NULL); + + if(ctx->current_block->type == MD_BLOCK_CODE || ctx->current_block->type == MD_BLOCK_HTML) { + MD_VERBATIMLINE* line; + + line = (MD_VERBATIMLINE*) md_push_block_bytes(ctx, sizeof(MD_VERBATIMLINE)); + if(line == NULL) + return -1; + + line->indent = analysis->indent; + line->beg = analysis->beg; + line->end = analysis->end; + } else { + MD_LINE* line; + + line = (MD_LINE*) md_push_block_bytes(ctx, sizeof(MD_LINE)); + if(line == NULL) + return -1; + + line->beg = analysis->beg; + line->end = analysis->end; + } + ctx->current_block->n_lines++; + + return 0; +} + +static int +md_push_container_bytes(MD_CTX* ctx, MD_BLOCKTYPE type, unsigned start, + unsigned data, unsigned flags) +{ + MD_BLOCK* block; + int ret = 0; + + MD_CHECK(md_end_current_block(ctx)); + + block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); + if(block == NULL) + return -1; + + block->type = type; + block->flags = flags; + block->data = data; + block->n_lines = start; + +abort: + return ret; +} + + + +/*********************** + *** Line Analysis *** + ***********************/ + +static int +md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end, OFF* p_killer) +{ + OFF off = beg + 1; + int n = 1; + + while(off < ctx->size && (CH(off) == CH(beg) || CH(off) == _T(' ') || CH(off) == _T('\t'))) { + if(CH(off) == CH(beg)) + n++; + off++; + } + + if(n < 3) { + *p_killer = off; + return FALSE; + } + + /* Nothing else can be present on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) { + *p_killer = off; + return FALSE; + } + + *p_end = off; + return TRUE; +} + +static int +md_is_atxheader_line(MD_CTX* ctx, OFF beg, OFF* p_beg, OFF* p_end, unsigned* p_level) +{ + int n; + OFF off = beg + 1; + + while(off < ctx->size && CH(off) == _T('#') && off - beg < 7) + off++; + n = off - beg; + + if(n > 6) + return FALSE; + *p_level = n; + + if(!(ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS) && off < ctx->size && + CH(off) != _T(' ') && CH(off) != _T('\t') && !ISNEWLINE(off)) + return FALSE; + + while(off < ctx->size && CH(off) == _T(' ')) + off++; + *p_beg = off; + *p_end = off; + return TRUE; +} + +static int +md_is_setext_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_level) +{ + OFF off = beg + 1; + + while(off < ctx->size && CH(off) == CH(beg)) + off++; + + /* Optionally, space(s) can follow. */ + while(off < ctx->size && CH(off) == _T(' ')) + off++; + + /* But nothing more is allowed on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) + return FALSE; + + *p_level = (CH(beg) == _T('=') ? 1 : 2); + *p_end = off; + return TRUE; +} + +static int +md_is_table_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_col_count) +{ + OFF off = beg; + int found_pipe = FALSE; + unsigned col_count = 0; + + if(off < ctx->size && CH(off) == _T('|')) { + found_pipe = TRUE; + off++; + while(off < ctx->size && ISWHITESPACE(off)) + off++; + } + + while(1) { + OFF cell_beg; + int delimited = FALSE; + + /* Cell underline ("-----", ":----", "----:" or ":----:") */ + cell_beg = off; + if(off < ctx->size && CH(off) == _T(':')) + off++; + while(off < ctx->size && CH(off) == _T('-')) + off++; + if(off < ctx->size && CH(off) == _T(':')) + off++; + if(off - cell_beg < 3) + return FALSE; + + col_count++; + + /* Pipe delimiter (optional at the end of line). */ + while(off < ctx->size && ISWHITESPACE(off)) + off++; + if(off < ctx->size && CH(off) == _T('|')) { + delimited = TRUE; + found_pipe = TRUE; + off++; + while(off < ctx->size && ISWHITESPACE(off)) + off++; + } + + /* Success, if we reach end of line. */ + if(off >= ctx->size || ISNEWLINE(off)) + break; + + if(!delimited) + return FALSE; + } + + if(!found_pipe) + return FALSE; + + *p_end = off; + *p_col_count = col_count; + return TRUE; +} + +static int +md_is_opening_code_fence(MD_CTX* ctx, OFF beg, OFF* p_end) +{ + OFF off = beg; + + while(off < ctx->size && CH(off) == CH(beg)) + off++; + + /* Fence must have at least three characters. */ + if(off - beg < 3) + return FALSE; + + ctx->code_fence_length = off - beg; + + /* Optionally, space(s) can follow. */ + while(off < ctx->size && CH(off) == _T(' ')) + off++; + + /* Optionally, an info string can follow. */ + while(off < ctx->size && !ISNEWLINE(off)) { + /* Backtick-based fence must not contain '`' in the info string. */ + if(CH(beg) == _T('`') && CH(off) == _T('`')) + return FALSE; + off++; + } + + *p_end = off; + return TRUE; +} + +static int +md_is_closing_code_fence(MD_CTX* ctx, CHAR ch, OFF beg, OFF* p_end) +{ + OFF off = beg; + int ret = FALSE; + + /* Closing fence must have at least the same length and use same char as + * opening one. */ + while(off < ctx->size && CH(off) == ch) + off++; + if(off - beg < ctx->code_fence_length) + goto out; + + /* Optionally, space(s) can follow */ + while(off < ctx->size && CH(off) == _T(' ')) + off++; + + /* But nothing more is allowed on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) + goto out; + + ret = TRUE; + +out: + /* Note we set *p_end even on failure: If we are not closing fence, caller + * would eat the line anyway without any parsing. */ + *p_end = off; + return ret; +} + +/* Returns type of the raw HTML block, or FALSE if it is not HTML block. + * (Refer to CommonMark specification for details about the types.) + */ +static int +md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) +{ + typedef struct TAG_tag TAG; + struct TAG_tag { + const CHAR* name; + unsigned len : 8; + }; + + /* Type 6 is started by a long list of allowed tags. We use two-level + * tree to speed-up the search. */ +#ifdef X + #undef X +#endif +#define X(name) { _T(name), (sizeof(name)-1) / sizeof(CHAR) } +#define Xend { NULL, 0 } + static const TAG t1[] = { X("pre"), X("script"), X("style"), X("textarea"), Xend }; + + static const TAG a6[] = { X("address"), X("article"), X("aside"), Xend }; + static const TAG b6[] = { X("base"), X("basefont"), X("blockquote"), X("body"), Xend }; + static const TAG c6[] = { X("caption"), X("center"), X("col"), X("colgroup"), Xend }; + static const TAG d6[] = { X("dd"), X("details"), X("dialog"), X("dir"), + X("div"), X("dl"), X("dt"), Xend }; + static const TAG f6[] = { X("fieldset"), X("figcaption"), X("figure"), X("footer"), + X("form"), X("frame"), X("frameset"), Xend }; + static const TAG h6[] = { X("h1"), X("head"), X("header"), X("hr"), X("html"), Xend }; + static const TAG i6[] = { X("iframe"), Xend }; + static const TAG l6[] = { X("legend"), X("li"), X("link"), Xend }; + static const TAG m6[] = { X("main"), X("menu"), X("menuitem"), Xend }; + static const TAG n6[] = { X("nav"), X("noframes"), Xend }; + static const TAG o6[] = { X("ol"), X("optgroup"), X("option"), Xend }; + static const TAG p6[] = { X("p"), X("param"), Xend }; + static const TAG s6[] = { X("section"), X("source"), X("summary"), Xend }; + static const TAG t6[] = { X("table"), X("tbody"), X("td"), X("tfoot"), X("th"), + X("thead"), X("title"), X("tr"), X("track"), Xend }; + static const TAG u6[] = { X("ul"), Xend }; + static const TAG xx[] = { Xend }; +#undef X + + static const TAG* map6[26] = { + a6, b6, c6, d6, xx, f6, xx, h6, i6, xx, xx, l6, m6, + n6, o6, p6, xx, xx, s6, t6, u6, xx, xx, xx, xx, xx + }; + OFF off = beg + 1; + int i; + + /* Check for type 1: <script, <pre, or <style */ + for(i = 0; t1[i].name != NULL; i++) { + if(off + t1[i].len <= ctx->size) { + if(md_ascii_case_eq(STR(off), t1[i].name, t1[i].len)) + return 1; + } + } + + /* Check for type 2: <!-- */ + if(off + 3 < ctx->size && CH(off) == _T('!') && CH(off+1) == _T('-') && CH(off+2) == _T('-')) + return 2; + + /* Check for type 3: <? */ + if(off < ctx->size && CH(off) == _T('?')) + return 3; + + /* Check for type 4 or 5: <! */ + if(off < ctx->size && CH(off) == _T('!')) { + /* Check for type 4: <! followed by uppercase letter. */ + if(off + 1 < ctx->size && ISASCII(off+1)) + return 4; + + /* Check for type 5: <![CDATA[ */ + if(off + 8 < ctx->size) { + if(md_ascii_eq(STR(off), _T("![CDATA["), 8)) + return 5; + } + } + + /* Check for type 6: Many possible starting tags listed above. */ + if(off + 1 < ctx->size && (ISALPHA(off) || (CH(off) == _T('/') && ISALPHA(off+1)))) { + int slot; + const TAG* tags; + + if(CH(off) == _T('/')) + off++; + + slot = (ISUPPER(off) ? CH(off) - 'A' : CH(off) - 'a'); + tags = map6[slot]; + + for(i = 0; tags[i].name != NULL; i++) { + if(off + tags[i].len <= ctx->size) { + if(md_ascii_case_eq(STR(off), tags[i].name, tags[i].len)) { + OFF tmp = off + tags[i].len; + if(tmp >= ctx->size) + return 6; + if(ISBLANK(tmp) || ISNEWLINE(tmp) || CH(tmp) == _T('>')) + return 6; + if(tmp+1 < ctx->size && CH(tmp) == _T('/') && CH(tmp+1) == _T('>')) + return 6; + break; + } + } + } + } + + /* Check for type 7: any COMPLETE other opening or closing tag. */ + if(off + 1 < ctx->size) { + OFF end; + + if(md_is_html_tag(ctx, NULL, 0, beg, ctx->size, &end)) { + /* Only optional whitespace and new line may follow. */ + while(end < ctx->size && ISWHITESPACE(end)) + end++; + if(end >= ctx->size || ISNEWLINE(end)) + return 7; + } + } + + return FALSE; +} + +/* Case sensitive check whether there is a substring 'what' between 'beg' + * and end of line. */ +static int +md_line_contains(MD_CTX* ctx, OFF beg, const CHAR* what, SZ what_len, OFF* p_end) +{ + OFF i; + for(i = beg; i + what_len < ctx->size; i++) { + if(ISNEWLINE(i)) + break; + if(memcmp(STR(i), what, what_len * sizeof(CHAR)) == 0) { + *p_end = i + what_len; + return TRUE; + } + } + + *p_end = i; + return FALSE; +} + +/* Returns type of HTML block end condition or FALSE if not an end condition. + * + * Note it fills p_end even when it is not end condition as the caller + * does not need to analyze contents of a raw HTML block. + */ +static int +md_is_html_block_end_condition(MD_CTX* ctx, OFF beg, OFF* p_end) +{ + switch(ctx->html_block_type) { + case 1: + { + OFF off = beg; + + while(off < ctx->size && !ISNEWLINE(off)) { + if(CH(off) == _T('<')) { + if(md_ascii_case_eq(STR(off), _T("</script>"), 9)) { + *p_end = off + 9; + return TRUE; + } + + if(md_ascii_case_eq(STR(off), _T("</style>"), 8)) { + *p_end = off + 8; + return TRUE; + } + + if(md_ascii_case_eq(STR(off), _T("</pre>"), 6)) { + *p_end = off + 6; + return TRUE; + } + } + + off++; + } + *p_end = off; + return FALSE; + } + + case 2: + return (md_line_contains(ctx, beg, _T("-->"), 3, p_end) ? 2 : FALSE); + + case 3: + return (md_line_contains(ctx, beg, _T("?>"), 2, p_end) ? 3 : FALSE); + + case 4: + return (md_line_contains(ctx, beg, _T(">"), 1, p_end) ? 4 : FALSE); + + case 5: + return (md_line_contains(ctx, beg, _T("]]>"), 3, p_end) ? 5 : FALSE); + + case 6: /* Pass through */ + case 7: + *p_end = beg; + return (ISNEWLINE(beg) ? ctx->html_block_type : FALSE); + + default: + MD_UNREACHABLE(); + } + return FALSE; +} + + +static int +md_is_container_compatible(const MD_CONTAINER* pivot, const MD_CONTAINER* container) +{ + /* Block quote has no "items" like lists. */ + if(container->ch == _T('>')) + return FALSE; + + if(container->ch != pivot->ch) + return FALSE; + if(container->mark_indent > pivot->contents_indent) + return FALSE; + + return TRUE; +} + +static int +md_push_container(MD_CTX* ctx, const MD_CONTAINER* container) +{ + if(ctx->n_containers >= ctx->alloc_containers) { + MD_CONTAINER* new_containers; + + ctx->alloc_containers = (ctx->alloc_containers > 0 + ? ctx->alloc_containers + ctx->alloc_containers / 2 + : 16); + new_containers = (MD_CONTAINER *) realloc(ctx->containers, ctx->alloc_containers * sizeof(MD_CONTAINER)); + if(new_containers == NULL) { + MD_LOG("realloc() failed."); + return -1; + } + + ctx->containers = new_containers; + } + + memcpy(&ctx->containers[ctx->n_containers++], container, sizeof(MD_CONTAINER)); + return 0; +} + +static int +md_enter_child_containers(MD_CTX* ctx, int n_children) +{ + int i; + int ret = 0; + + for(i = ctx->n_containers - n_children; i < ctx->n_containers; i++) { + MD_CONTAINER* c = &ctx->containers[i]; + int is_ordered_list = FALSE; + + switch(c->ch) { + case _T(')'): + case _T('.'): + is_ordered_list = TRUE; + MD_FALLTHROUGH(); + + case _T('-'): + case _T('+'): + case _T('*'): + /* Remember offset in ctx->block_bytes so we can revisit the + * block if we detect it is a loose list. */ + md_end_current_block(ctx); + c->block_byte_off = ctx->n_block_bytes; + + MD_CHECK(md_push_container_bytes(ctx, + (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), + c->start, c->ch, MD_BLOCK_CONTAINER_OPENER)); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + c->task_mark_off, + (c->is_task ? CH(c->task_mark_off) : 0), + MD_BLOCK_CONTAINER_OPENER)); + break; + + case _T('>'): + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, 0, MD_BLOCK_CONTAINER_OPENER)); + break; + + default: + MD_UNREACHABLE(); + break; + } + } + +abort: + return ret; +} + +static int +md_leave_child_containers(MD_CTX* ctx, int n_keep) +{ + int ret = 0; + + while(ctx->n_containers > n_keep) { + MD_CONTAINER* c = &ctx->containers[ctx->n_containers-1]; + int is_ordered_list = FALSE; + + switch(c->ch) { + case _T(')'): + case _T('.'): + is_ordered_list = TRUE; + MD_FALLTHROUGH(); + + case _T('-'): + case _T('+'): + case _T('*'): + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + c->task_mark_off, (c->is_task ? CH(c->task_mark_off) : 0), + MD_BLOCK_CONTAINER_CLOSER)); + MD_CHECK(md_push_container_bytes(ctx, + (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), 0, + c->ch, MD_BLOCK_CONTAINER_CLOSER)); + break; + + case _T('>'): + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, + 0, MD_BLOCK_CONTAINER_CLOSER)); + break; + + default: + MD_UNREACHABLE(); + break; + } + + ctx->n_containers--; + } + +abort: + return ret; +} + +static int +md_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTAINER* p_container) +{ + OFF off = beg; + OFF max_end; + + if(off >= ctx->size || indent >= ctx->code_indent_offset) + return FALSE; + + /* Check for block quote mark. */ + if(CH(off) == _T('>')) { + off++; + p_container->ch = _T('>'); + p_container->is_loose = FALSE; + p_container->is_task = FALSE; + p_container->mark_indent = indent; + p_container->contents_indent = indent + 1; + *p_end = off; + return TRUE; + } + + /* Check for list item bullet mark. */ + if(ISANYOF(off, _T("-+*")) && (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) { + p_container->ch = CH(off); + p_container->is_loose = FALSE; + p_container->is_task = FALSE; + p_container->mark_indent = indent; + p_container->contents_indent = indent + 1; + *p_end = off+1; + return TRUE; + } + + /* Check for ordered list item marks. */ + max_end = off + 9; + if(max_end > ctx->size) + max_end = ctx->size; + p_container->start = 0; + while(off < max_end && ISDIGIT(off)) { + p_container->start = p_container->start * 10 + CH(off) - _T('0'); + off++; + } + if(off > beg && + (CH(off) == _T('.') || CH(off) == _T(')')) && + (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) + { + p_container->ch = CH(off); + p_container->is_loose = FALSE; + p_container->is_task = FALSE; + p_container->mark_indent = indent; + p_container->contents_indent = indent + off - beg + 1; + *p_end = off+1; + return TRUE; + } + + return FALSE; +} + +static unsigned +md_line_indentation(MD_CTX* ctx, unsigned total_indent, OFF beg, OFF* p_end) +{ + OFF off = beg; + unsigned indent = total_indent; + + while(off < ctx->size && ISBLANK(off)) { + if(CH(off) == _T('\t')) + indent = (indent + 4) & ~3; + else + indent++; + off++; + } + + *p_end = off; + return indent - total_indent; +} + +static const MD_LINE_ANALYSIS md_dummy_blank_line = { MD_LINE_BLANK, 0, 0, 0, 0 }; + +/* Analyze type of the line and find some its properties. This serves as a + * main input for determining type and boundaries of a block. */ +static int +md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, + const MD_LINE_ANALYSIS* pivot_line, MD_LINE_ANALYSIS* line) +{ + unsigned total_indent = 0; + int n_parents = 0; + int n_brothers = 0; + int n_children = 0; + MD_CONTAINER container = { 0 }; + int prev_line_has_list_loosening_effect = ctx->last_line_has_list_loosening_effect; + OFF off = beg; + OFF hr_killer = 0; + int ret = 0; + + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + line->beg = off; + + /* Given the indentation and block quote marks '>', determine how many of + * the current containers are our parents. */ + while(n_parents < ctx->n_containers) { + MD_CONTAINER* c = &ctx->containers[n_parents]; + + if(c->ch == _T('>') && line->indent < ctx->code_indent_offset && + off < ctx->size && CH(off) == _T('>')) + { + /* Block quote mark. */ + off++; + total_indent++; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + + /* The optional 1st space after '>' is part of the block quote mark. */ + if(line->indent > 0) + line->indent--; + + line->beg = off; + + } else if(c->ch != _T('>') && line->indent >= c->contents_indent) { + /* List. */ + line->indent -= c->contents_indent; + } else { + break; + } + + n_parents++; + } + + if(off >= ctx->size || ISNEWLINE(off)) { + /* Blank line does not need any real indentation to be nested inside + * a list. */ + if(n_brothers + n_children == 0) { + while(n_parents < ctx->n_containers && ctx->containers[n_parents].ch != _T('>')) + n_parents++; + } + } + + while(TRUE) { + /* Check whether we are fenced code continuation. */ + if(pivot_line->type == MD_LINE_FENCEDCODE) { + line->beg = off; + + /* We are another MD_LINE_FENCEDCODE unless we are closing fence + * which we transform into MD_LINE_BLANK. */ + if(line->indent < ctx->code_indent_offset) { + if(md_is_closing_code_fence(ctx, CH(pivot_line->beg), off, &off)) { + line->type = MD_LINE_BLANK; + ctx->last_line_has_list_loosening_effect = FALSE; + break; + } + } + + /* Change indentation accordingly to the initial code fence. */ + if(n_parents == ctx->n_containers) { + if(line->indent > pivot_line->indent) + line->indent -= pivot_line->indent; + else + line->indent = 0; + + line->type = MD_LINE_FENCEDCODE; + break; + } + } + + /* Check whether we are HTML block continuation. */ + if(pivot_line->type == MD_LINE_HTML && ctx->html_block_type > 0) { + if(n_parents < ctx->n_containers) { + /* HTML block is implicitly ended if the enclosing container + * block ends. */ + ctx->html_block_type = 0; + } else { + int html_block_type; + + html_block_type = md_is_html_block_end_condition(ctx, off, &off); + if(html_block_type > 0) { + MD_ASSERT(html_block_type == ctx->html_block_type); + + /* Make sure this is the last line of the block. */ + ctx->html_block_type = 0; + + /* Some end conditions serve as blank lines at the same time. */ + if(html_block_type == 6 || html_block_type == 7) { + line->type = MD_LINE_BLANK; + line->indent = 0; + break; + } + } + + line->type = MD_LINE_HTML; + n_parents = ctx->n_containers; + break; + } + } + + /* Check for blank line. */ + if(off >= ctx->size || ISNEWLINE(off)) { + if(pivot_line->type == MD_LINE_INDENTEDCODE && n_parents == ctx->n_containers) { + line->type = MD_LINE_INDENTEDCODE; + if(line->indent > ctx->code_indent_offset) + line->indent -= ctx->code_indent_offset; + else + line->indent = 0; + ctx->last_line_has_list_loosening_effect = FALSE; + } else { + line->type = MD_LINE_BLANK; + ctx->last_line_has_list_loosening_effect = (n_parents > 0 && + n_brothers + n_children == 0 && + ctx->containers[n_parents-1].ch != _T('>')); + + #if 1 + /* See https://github.com/mity/md4c/issues/6 + * + * This ugly checking tests we are in (yet empty) list item but + * not its very first line (i.e. not the line with the list + * item mark). + * + * If we are such a blank line, then any following non-blank + * line which would be part of the list item actually has to + * end the list because according to the specification, "a list + * item can begin with at most one blank line." + */ + if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') && + n_brothers + n_children == 0 && ctx->current_block == NULL && + ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) + { + MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); + if(top_block->type == MD_BLOCK_LI) + ctx->last_list_item_starts_with_two_blank_lines = TRUE; + } + #endif + } + break; + } else { + #if 1 + /* This is the 2nd half of the hack. If the flag is set (i.e. there + * was a 2nd blank line at the beginning of the list item) and if + * we would otherwise still belong to the list item, we enforce + * the end of the list. */ + ctx->last_line_has_list_loosening_effect = FALSE; + if(ctx->last_list_item_starts_with_two_blank_lines) { + if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') && + n_brothers + n_children == 0 && ctx->current_block == NULL && + ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) + { + MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); + if(top_block->type == MD_BLOCK_LI) + n_parents--; + } + + ctx->last_list_item_starts_with_two_blank_lines = FALSE; + } + #endif + } + + /* Check whether we are Setext underline. */ + if(line->indent < ctx->code_indent_offset && pivot_line->type == MD_LINE_TEXT + && off < ctx->size && ISANYOF2(off, _T('='), _T('-')) + && (n_parents == ctx->n_containers)) + { + unsigned level; + + if(md_is_setext_underline(ctx, off, &off, &level)) { + line->type = MD_LINE_SETEXTUNDERLINE; + line->data = level; + break; + } + } + + /* Check for thematic break line. */ + if(line->indent < ctx->code_indent_offset + && off < ctx->size && off >= hr_killer + && ISANYOF(off, _T("-_*"))) + { + if(md_is_hr_line(ctx, off, &off, &hr_killer)) { + line->type = MD_LINE_HR; + break; + } + } + + /* Check for "brother" container. I.e. whether we are another list item + * in already started list. */ + if(n_parents < ctx->n_containers && n_brothers + n_children == 0) { + OFF tmp; + + if(md_is_container_mark(ctx, line->indent, off, &tmp, &container) && + md_is_container_compatible(&ctx->containers[n_parents], &container)) + { + pivot_line = &md_dummy_blank_line; + + off = tmp; + + total_indent += container.contents_indent - container.mark_indent; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + line->beg = off; + + /* Some of the following whitespace actually still belongs to the mark. */ + if(off >= ctx->size || ISNEWLINE(off)) { + container.contents_indent++; + } else if(line->indent <= ctx->code_indent_offset) { + container.contents_indent += line->indent; + line->indent = 0; + } else { + container.contents_indent += 1; + line->indent--; + } + + ctx->containers[n_parents].mark_indent = container.mark_indent; + ctx->containers[n_parents].contents_indent = container.contents_indent; + + n_brothers++; + continue; + } + } + + /* Check for indented code. + * Note indented code block cannot interrupt a paragraph. */ + if(line->indent >= ctx->code_indent_offset && + (pivot_line->type == MD_LINE_BLANK || pivot_line->type == MD_LINE_INDENTEDCODE)) + { + line->type = MD_LINE_INDENTEDCODE; + MD_ASSERT(line->indent >= ctx->code_indent_offset); + line->indent -= ctx->code_indent_offset; + line->data = 0; + break; + } + + /* Check for start of a new container block. */ + if(line->indent < ctx->code_indent_offset && + md_is_container_mark(ctx, line->indent, off, &off, &container)) + { + if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && + (off >= ctx->size || ISNEWLINE(off)) && container.ch != _T('>')) + { + /* Noop. List mark followed by a blank line cannot interrupt a paragraph. */ + } else if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && + ISANYOF2_(container.ch, _T('.'), _T(')')) && container.start != 1) + { + /* Noop. Ordered list cannot interrupt a paragraph unless the start index is 1. */ + } else { + total_indent += container.contents_indent - container.mark_indent; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + + line->beg = off; + line->data = container.ch; + + /* Some of the following whitespace actually still belongs to the mark. */ + if(off >= ctx->size || ISNEWLINE(off)) { + container.contents_indent++; + } else if(line->indent <= ctx->code_indent_offset) { + container.contents_indent += line->indent; + line->indent = 0; + } else { + container.contents_indent += 1; + line->indent--; + } + + if(n_brothers + n_children == 0) + pivot_line = &md_dummy_blank_line; + + if(n_children == 0) + MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); + + n_children++; + MD_CHECK(md_push_container(ctx, &container)); + continue; + } + } + + /* Check whether we are table continuation. */ + if(pivot_line->type == MD_LINE_TABLE && n_parents == ctx->n_containers) { + line->type = MD_LINE_TABLE; + break; + } + + /* Check for ATX header. */ + if(line->indent < ctx->code_indent_offset && + off < ctx->size && CH(off) == _T('#')) + { + unsigned level; + + if(md_is_atxheader_line(ctx, off, &line->beg, &off, &level)) { + line->type = MD_LINE_ATXHEADER; + line->data = level; + break; + } + } + + /* Check whether we are starting code fence. */ + if(off < ctx->size && ISANYOF2(off, _T('`'), _T('~'))) { + if(md_is_opening_code_fence(ctx, off, &off)) { + line->type = MD_LINE_FENCEDCODE; + line->data = 1; + break; + } + } + + /* Check for start of raw HTML block. */ + if(off < ctx->size && CH(off) == _T('<') + && !(ctx->parser.flags & MD_FLAG_NOHTMLBLOCKS)) + { + ctx->html_block_type = md_is_html_block_start_condition(ctx, off); + + /* HTML block type 7 cannot interrupt paragraph. */ + if(ctx->html_block_type == 7 && pivot_line->type == MD_LINE_TEXT) + ctx->html_block_type = 0; + + if(ctx->html_block_type > 0) { + /* The line itself also may immediately close the block. */ + if(md_is_html_block_end_condition(ctx, off, &off) == ctx->html_block_type) { + /* Make sure this is the last line of the block. */ + ctx->html_block_type = 0; + } + + line->type = MD_LINE_HTML; + break; + } + } + + /* Check for table underline. */ + if((ctx->parser.flags & MD_FLAG_TABLES) && pivot_line->type == MD_LINE_TEXT + && off < ctx->size && ISANYOF3(off, _T('|'), _T('-'), _T(':')) + && n_parents == ctx->n_containers) + { + unsigned col_count; + + if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 && + md_is_table_underline(ctx, off, &off, &col_count)) + { + line->data = col_count; + line->type = MD_LINE_TABLEUNDERLINE; + break; + } + } + + /* By default, we are normal text line. */ + line->type = MD_LINE_TEXT; + if(pivot_line->type == MD_LINE_TEXT && n_brothers + n_children == 0) { + /* Lazy continuation. */ + n_parents = ctx->n_containers; + } + + /* Check for task mark. */ + if((ctx->parser.flags & MD_FLAG_TASKLISTS) && n_brothers + n_children > 0 && + ISANYOF_(ctx->containers[ctx->n_containers-1].ch, _T("-+*.)"))) + { + OFF tmp = off; + + while(tmp < ctx->size && tmp < off + 3 && ISBLANK(tmp)) + tmp++; + if(tmp + 2 < ctx->size && CH(tmp) == _T('[') && + ISANYOF(tmp+1, _T("xX ")) && CH(tmp+2) == _T(']') && + (tmp + 3 == ctx->size || ISBLANK(tmp+3) || ISNEWLINE(tmp+3))) + { + MD_CONTAINER* task_container = (n_children > 0 ? &ctx->containers[ctx->n_containers-1] : &container); + task_container->is_task = TRUE; + task_container->task_mark_off = tmp + 1; + off = tmp + 3; + while(ISWHITESPACE(off)) + off++; + line->beg = off; + } + } + + break; + } + + /* Scan for end of the line. + * + * Note this is quite a bottleneck of the parsing as we here iterate almost + * over compete document. + */ +#if defined __linux__ && !defined MD4C_USE_UTF16 + /* Recent glibc versions have superbly optimized strcspn(), even using + * vectorization if available. */ + if(ctx->doc_ends_with_newline && off < ctx->size) { + while(TRUE) { + off += (OFF) strcspn(STR(off), "\r\n"); + + /* strcspn() can stop on zero terminator; but that can appear + * anywhere in the Markfown input... */ + if(CH(off) == _T('\0')) + off++; + else + break; + } + } else +#endif + { + /* Optimization: Use some loop unrolling. */ + while(off + 3 < ctx->size && !ISNEWLINE(off+0) && !ISNEWLINE(off+1) + && !ISNEWLINE(off+2) && !ISNEWLINE(off+3)) + off += 4; + while(off < ctx->size && !ISNEWLINE(off)) + off++; + } + + /* Set end of the line. */ + line->end = off; + + /* But for ATX header, we should exclude the optional trailing mark. */ + if(line->type == MD_LINE_ATXHEADER) { + OFF tmp = line->end; + while(tmp > line->beg && CH(tmp-1) == _T(' ')) + tmp--; + while(tmp > line->beg && CH(tmp-1) == _T('#')) + tmp--; + if(tmp == line->beg || CH(tmp-1) == _T(' ') || (ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS)) + line->end = tmp; + } + + /* Trim trailing spaces. */ + if(line->type != MD_LINE_INDENTEDCODE && line->type != MD_LINE_FENCEDCODE) { + while(line->end > line->beg && CH(line->end-1) == _T(' ')) + line->end--; + } + + /* Eat also the new line. */ + if(off < ctx->size && CH(off) == _T('\r')) + off++; + if(off < ctx->size && CH(off) == _T('\n')) + off++; + + *p_end = off; + + /* If we belong to a list after seeing a blank line, the list is loose. */ + if(prev_line_has_list_loosening_effect && line->type != MD_LINE_BLANK && n_parents + n_brothers > 0) { + MD_CONTAINER* c = &ctx->containers[n_parents + n_brothers - 1]; + if(c->ch != _T('>')) { + MD_BLOCK* block = (MD_BLOCK*) (((char*)ctx->block_bytes) + c->block_byte_off); + block->flags |= MD_BLOCK_LOOSE_LIST; + } + } + + /* Leave any containers we are not part of anymore. */ + if(n_children == 0 && n_parents + n_brothers < ctx->n_containers) + MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); + + /* Enter any container we found a mark for. */ + if(n_brothers > 0) { + MD_ASSERT(n_brothers == 1); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + ctx->containers[n_parents].task_mark_off, + (ctx->containers[n_parents].is_task ? CH(ctx->containers[n_parents].task_mark_off) : 0), + MD_BLOCK_CONTAINER_CLOSER)); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + container.task_mark_off, + (container.is_task ? CH(container.task_mark_off) : 0), + MD_BLOCK_CONTAINER_OPENER)); + ctx->containers[n_parents].is_task = container.is_task; + ctx->containers[n_parents].task_mark_off = container.task_mark_off; + } + + if(n_children > 0) + MD_CHECK(md_enter_child_containers(ctx, n_children)); + +abort: + return ret; +} + +static int +md_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, MD_LINE_ANALYSIS* line) +{ + const MD_LINE_ANALYSIS* pivot_line = *p_pivot_line; + int ret = 0; + + /* Blank line ends current leaf block. */ + if(line->type == MD_LINE_BLANK) { + MD_CHECK(md_end_current_block(ctx)); + *p_pivot_line = &md_dummy_blank_line; + return 0; + } + + /* Some line types form block on their own. */ + if(line->type == MD_LINE_HR || line->type == MD_LINE_ATXHEADER) { + MD_CHECK(md_end_current_block(ctx)); + + /* Add our single-line block. */ + MD_CHECK(md_start_new_block(ctx, line)); + MD_CHECK(md_add_line_into_current_block(ctx, line)); + MD_CHECK(md_end_current_block(ctx)); + *p_pivot_line = &md_dummy_blank_line; + return 0; + } + + /* MD_LINE_SETEXTUNDERLINE changes meaning of the current block and ends it. */ + if(line->type == MD_LINE_SETEXTUNDERLINE) { + MD_ASSERT(ctx->current_block != NULL); + ctx->current_block->type = MD_BLOCK_H; + ctx->current_block->data = line->data; + ctx->current_block->flags |= MD_BLOCK_SETEXT_HEADER; + MD_CHECK(md_add_line_into_current_block(ctx, line)); + MD_CHECK(md_end_current_block(ctx)); + if(ctx->current_block == NULL) { + *p_pivot_line = &md_dummy_blank_line; + } else { + /* This happens if we have consumed all the body as link ref. defs. + * and downgraded the underline into start of a new paragraph block. */ + line->type = MD_LINE_TEXT; + *p_pivot_line = line; + } + return 0; + } + + /* MD_LINE_TABLEUNDERLINE changes meaning of the current block. */ + if(line->type == MD_LINE_TABLEUNDERLINE) { + MD_ASSERT(ctx->current_block != NULL); + MD_ASSERT(ctx->current_block->n_lines == 1); + ctx->current_block->type = MD_BLOCK_TABLE; + ctx->current_block->data = line->data; + MD_ASSERT(pivot_line != &md_dummy_blank_line); + ((MD_LINE_ANALYSIS*)pivot_line)->type = MD_LINE_TABLE; + MD_CHECK(md_add_line_into_current_block(ctx, line)); + return 0; + } + + /* The current block also ends if the line has different type. */ + if(line->type != pivot_line->type) + MD_CHECK(md_end_current_block(ctx)); + + /* The current line may start a new block. */ + if(ctx->current_block == NULL) { + MD_CHECK(md_start_new_block(ctx, line)); + *p_pivot_line = line; + } + + /* In all other cases the line is just a continuation of the current block. */ + MD_CHECK(md_add_line_into_current_block(ctx, line)); + +abort: + return ret; +} + +static int +md_process_doc(MD_CTX *ctx) +{ + const MD_LINE_ANALYSIS* pivot_line = &md_dummy_blank_line; + MD_LINE_ANALYSIS line_buf[2]; + MD_LINE_ANALYSIS* line = &line_buf[0]; + OFF off = 0; + int ret = 0; + + MD_ENTER_BLOCK(MD_BLOCK_DOC, NULL); + + while(off < ctx->size) { + if(line == pivot_line) + line = (line == &line_buf[0] ? &line_buf[1] : &line_buf[0]); + + MD_CHECK(md_analyze_line(ctx, off, &off, pivot_line, line)); + MD_CHECK(md_process_line(ctx, &pivot_line, line)); + } + + md_end_current_block(ctx); + + MD_CHECK(md_build_ref_def_hashtable(ctx)); + + /* Process all blocks. */ + MD_CHECK(md_leave_child_containers(ctx, 0)); + MD_CHECK(md_process_all_blocks(ctx)); + + MD_LEAVE_BLOCK(MD_BLOCK_DOC, NULL); + +abort: + +#if 0 + /* Output some memory consumption statistics. */ + { + char buffer[256]; + sprintf(buffer, "Alloced %u bytes for block buffer.", + (unsigned)(ctx->alloc_block_bytes)); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for containers buffer.", + (unsigned)(ctx->alloc_containers * sizeof(MD_CONTAINER))); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for marks buffer.", + (unsigned)(ctx->alloc_marks * sizeof(MD_MARK))); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for aux. buffer.", + (unsigned)(ctx->alloc_buffer * sizeof(MD_CHAR))); + MD_LOG(buffer); + } +#endif + + return ret; +} + + +/******************** + *** Public API *** + ********************/ + +int +md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata) +{ + MD_CTX ctx; + int i; + int ret; + + if(parser->abi_version != 0) { + if(parser->debug_log != NULL) + parser->debug_log("Unsupported abi_version.", userdata); + return -1; + } + + /* Setup context structure. */ + memset(&ctx, 0, sizeof(MD_CTX)); + ctx.text = text; + ctx.size = size; + memcpy(&ctx.parser, parser, sizeof(MD_PARSER)); + ctx.userdata = userdata; + ctx.code_indent_offset = (ctx.parser.flags & MD_FLAG_NOINDENTEDCODEBLOCKS) ? (OFF)(-1) : 4; + md_build_mark_char_map(&ctx); + ctx.doc_ends_with_newline = (size > 0 && ISNEWLINE_(text[size-1])); + + /* Reset all unresolved opener mark chains. */ + for(i = 0; i < (int) SIZEOF_ARRAY(ctx.mark_chains); i++) { + ctx.mark_chains[i].head = -1; + ctx.mark_chains[i].tail = -1; + } + ctx.unresolved_link_head = -1; + ctx.unresolved_link_tail = -1; + + /* All the work. */ + ret = md_process_doc(&ctx); + + /* Clean-up. */ + md_free_ref_defs(&ctx); + md_free_ref_def_hashtable(&ctx); + free(ctx.buffer); + free(ctx.marks); + free(ctx.block_bytes); + free(ctx.containers); + + return ret; +} diff --git a/ports/md4c/md4c.h b/ports/md4c/md4c.h new file mode 100644 index 0000000..95f78f9 --- /dev/null +++ b/ports/md4c/md4c.h @@ -0,0 +1,405 @@ +/* + * MD4C: Markdown parser for C + * (http://github.com/mity/md4c) + * + * Copyright (c) 2016-2020 Martin Mitas + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef MD4C_H +#define MD4C_H + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined MD4C_USE_UTF16 + /* Magic to support UTF-16. Note that in order to use it, you have to define + * the macro MD4C_USE_UTF16 both when building MD4C as well as when + * including this header in your code. */ + #ifdef _WIN32 + #include <windows.h> + typedef WCHAR MD_CHAR; + #else + #error MD4C_USE_UTF16 is only supported on Windows. + #endif +#else + typedef char MD_CHAR; +#endif + +typedef unsigned MD_SIZE; +typedef unsigned MD_OFFSET; + + +/* Block represents a part of document hierarchy structure like a paragraph + * or list item. + */ +typedef enum MD_BLOCKTYPE { + /* <body>...</body> */ + MD_BLOCK_DOC = 0, + + /* <blockquote>...</blockquote> */ + MD_BLOCK_QUOTE, + + /* <ul>...</ul> + * Detail: Structure MD_BLOCK_UL_DETAIL. */ + MD_BLOCK_UL, + + /* <ol>...</ol> + * Detail: Structure MD_BLOCK_OL_DETAIL. */ + MD_BLOCK_OL, + + /* <li>...</li> + * Detail: Structure MD_BLOCK_LI_DETAIL. */ + MD_BLOCK_LI, + + /* <hr> */ + MD_BLOCK_HR, + + /* <h1>...</h1> (for levels up to 6) + * Detail: Structure MD_BLOCK_H_DETAIL. */ + MD_BLOCK_H, + + /* <pre><code>...</code></pre> + * Note the text lines within code blocks are terminated with '\n' + * instead of explicit MD_TEXT_BR. */ + MD_BLOCK_CODE, + + /* Raw HTML block. This itself does not correspond to any particular HTML + * tag. The contents of it _is_ raw HTML source intended to be put + * in verbatim form to the HTML output. */ + MD_BLOCK_HTML, + + /* <p>...</p> */ + MD_BLOCK_P, + + /* <table>...</table> and its contents. + * Detail: Structure MD_BLOCK_TABLE_DETAIL (for MD_BLOCK_TABLE), + * structure MD_BLOCK_TD_DETAIL (for MD_BLOCK_TH and MD_BLOCK_TD) + * Note all of these are used only if extension MD_FLAG_TABLES is enabled. */ + MD_BLOCK_TABLE, + MD_BLOCK_THEAD, + MD_BLOCK_TBODY, + MD_BLOCK_TR, + MD_BLOCK_TH, + MD_BLOCK_TD +} MD_BLOCKTYPE; + +/* Span represents an in-line piece of a document which should be rendered with + * the same font, color and other attributes. A sequence of spans forms a block + * like paragraph or list item. */ +typedef enum MD_SPANTYPE { + /* <em>...</em> */ + MD_SPAN_EM, + + /* <strong>...</strong> */ + MD_SPAN_STRONG, + + /* <a href="xxx">...</a> + * Detail: Structure MD_SPAN_A_DETAIL. */ + MD_SPAN_A, + + /* <img src="xxx">...</a> + * Detail: Structure MD_SPAN_IMG_DETAIL. + * Note: Image text can contain nested spans and even nested images. + * If rendered into ALT attribute of HTML <IMG> tag, it's responsibility + * of the parser to deal with it. + */ + MD_SPAN_IMG, + + /* <code>...</code> */ + MD_SPAN_CODE, + + /* <del>...</del> + * Note: Recognized only when MD_FLAG_STRIKETHROUGH is enabled. + */ + MD_SPAN_DEL, + + /* For recognizing inline ($) and display ($$) equations + * Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled. + */ + MD_SPAN_LATEXMATH, + MD_SPAN_LATEXMATH_DISPLAY, + + /* Wiki links + * Note: Recognized only when MD_FLAG_WIKILINKS is enabled. + */ + MD_SPAN_WIKILINK, + + /* <u>...</u> + * Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */ + MD_SPAN_U +} MD_SPANTYPE; + +/* Text is the actual textual contents of span. */ +typedef enum MD_TEXTTYPE { + /* Normal text. */ + MD_TEXT_NORMAL = 0, + + /* NULL character. CommonMark requires replacing NULL character with + * the replacement char U+FFFD, so this allows caller to do that easily. */ + MD_TEXT_NULLCHAR, + + /* Line breaks. + * Note these are not sent from blocks with verbatim output (MD_BLOCK_CODE + * or MD_BLOCK_HTML). In such cases, '\n' is part of the text itself. */ + MD_TEXT_BR, /* <br> (hard break) */ + MD_TEXT_SOFTBR, /* '\n' in source text where it is not semantically meaningful (soft break) */ + + /* Entity. + * (a) Named entity, e.g.   + * (Note MD4C does not have a list of known entities. + * Anything matching the regexp /&[A-Za-z][A-Za-z0-9]{1,47};/ is + * treated as a named entity.) + * (b) Numerical entity, e.g. Ӓ + * (c) Hexadecimal entity, e.g. ካ + * + * As MD4C is mostly encoding agnostic, application gets the verbatim + * entity text into the MD_PARSER::text_callback(). */ + MD_TEXT_ENTITY, + + /* Text in a code block (inside MD_BLOCK_CODE) or inlined code (`code`). + * If it is inside MD_BLOCK_CODE, it includes spaces for indentation and + * '\n' for new lines. MD_TEXT_BR and MD_TEXT_SOFTBR are not sent for this + * kind of text. */ + MD_TEXT_CODE, + + /* Text is a raw HTML. If it is contents of a raw HTML block (i.e. not + * an inline raw HTML), then MD_TEXT_BR and MD_TEXT_SOFTBR are not used. + * The text contains verbatim '\n' for the new lines. */ + MD_TEXT_HTML, + + /* Text is inside an equation. This is processed the same way as inlined code + * spans (`code`). */ + MD_TEXT_LATEXMATH +} MD_TEXTTYPE; + + +/* Alignment enumeration. */ +typedef enum MD_ALIGN { + MD_ALIGN_DEFAULT = 0, /* When unspecified. */ + MD_ALIGN_LEFT, + MD_ALIGN_CENTER, + MD_ALIGN_RIGHT +} MD_ALIGN; + + +/* String attribute. + * + * This wraps strings which are outside of a normal text flow and which are + * propagated within various detailed structures, but which still may contain + * string portions of different types like e.g. entities. + * + * So, for example, lets consider this image: + * + * ![image alt text](http://example.org/image.png 'foo " bar') + * + * The image alt text is propagated as a normal text via the MD_PARSER::text() + * callback. However, the image title ('foo " bar') is propagated as + * MD_ATTRIBUTE in MD_SPAN_IMG_DETAIL::title. + * + * Then the attribute MD_SPAN_IMG_DETAIL::title shall provide the following: + * -- [0]: "foo " (substr_types[0] == MD_TEXT_NORMAL; substr_offsets[0] == 0) + * -- [1]: """ (substr_types[1] == MD_TEXT_ENTITY; substr_offsets[1] == 4) + * -- [2]: " bar" (substr_types[2] == MD_TEXT_NORMAL; substr_offsets[2] == 10) + * -- [3]: (n/a) (n/a ; substr_offsets[3] == 14) + * + * Note that these invariants are always guaranteed: + * -- substr_offsets[0] == 0 + * -- substr_offsets[LAST+1] == size + * -- Currently, only MD_TEXT_NORMAL, MD_TEXT_ENTITY, MD_TEXT_NULLCHAR + * substrings can appear. This could change only of the specification + * changes. + */ +typedef struct MD_ATTRIBUTE { + const MD_CHAR* text; + MD_SIZE size; + const MD_TEXTTYPE* substr_types; + const MD_OFFSET* substr_offsets; +} MD_ATTRIBUTE; + + +/* Detailed info for MD_BLOCK_UL. */ +typedef struct MD_BLOCK_UL_DETAIL { + int is_tight; /* Non-zero if tight list, zero if loose. */ + MD_CHAR mark; /* Item bullet character in MarkDown source of the list, e.g. '-', '+', '*'. */ +} MD_BLOCK_UL_DETAIL; + +/* Detailed info for MD_BLOCK_OL. */ +typedef struct MD_BLOCK_OL_DETAIL { + unsigned start; /* Start index of the ordered list. */ + int is_tight; /* Non-zero if tight list, zero if loose. */ + MD_CHAR mark_delimiter; /* Character delimiting the item marks in MarkDown source, e.g. '.' or ')' */ +} MD_BLOCK_OL_DETAIL; + +/* Detailed info for MD_BLOCK_LI. */ +typedef struct MD_BLOCK_LI_DETAIL { + int is_task; /* Can be non-zero only with MD_FLAG_TASKLISTS */ + MD_CHAR task_mark; /* If is_task, then one of 'x', 'X' or ' '. Undefined otherwise. */ + MD_OFFSET task_mark_offset; /* If is_task, then offset in the input of the char between '[' and ']'. */ +} MD_BLOCK_LI_DETAIL; + +/* Detailed info for MD_BLOCK_H. */ +typedef struct MD_BLOCK_H_DETAIL { + unsigned level; /* Header level (1 - 6) */ +} MD_BLOCK_H_DETAIL; + +/* Detailed info for MD_BLOCK_CODE. */ +typedef struct MD_BLOCK_CODE_DETAIL { + MD_ATTRIBUTE info; + MD_ATTRIBUTE lang; + MD_CHAR fence_char; /* The character used for fenced code block; or zero for indented code block. */ +} MD_BLOCK_CODE_DETAIL; + +/* Detailed info for MD_BLOCK_TABLE. */ +typedef struct MD_BLOCK_TABLE_DETAIL { + unsigned col_count; /* Count of columns in the table. */ + unsigned head_row_count; /* Count of rows in the table header (currently always 1) */ + unsigned body_row_count; /* Count of rows in the table body */ +} MD_BLOCK_TABLE_DETAIL; + +/* Detailed info for MD_BLOCK_TH and MD_BLOCK_TD. */ +typedef struct MD_BLOCK_TD_DETAIL { + MD_ALIGN align; +} MD_BLOCK_TD_DETAIL; + +/* Detailed info for MD_SPAN_A. */ +typedef struct MD_SPAN_A_DETAIL { + MD_ATTRIBUTE href; + MD_ATTRIBUTE title; +} MD_SPAN_A_DETAIL; + +/* Detailed info for MD_SPAN_IMG. */ +typedef struct MD_SPAN_IMG_DETAIL { + MD_ATTRIBUTE src; + MD_ATTRIBUTE title; +} MD_SPAN_IMG_DETAIL; + +/* Detailed info for MD_SPAN_WIKILINK. */ +typedef struct MD_SPAN_WIKILINK { + MD_ATTRIBUTE target; +} MD_SPAN_WIKILINK_DETAIL; + +/* Flags specifying extensions/deviations from CommonMark specification. + * + * By default (when MD_PARSER::flags == 0), we follow CommonMark specification. + * The following flags may allow some extensions or deviations from it. + */ +#define MD_FLAG_COLLAPSEWHITESPACE 0x0001 /* In MD_TEXT_NORMAL, collapse non-trivial whitespace into single ' ' */ +#define MD_FLAG_PERMISSIVEATXHEADERS 0x0002 /* Do not require space in ATX headers ( ###header ) */ +#define MD_FLAG_PERMISSIVEURLAUTOLINKS 0x0004 /* Recognize URLs as autolinks even without '<', '>' */ +#define MD_FLAG_PERMISSIVEEMAILAUTOLINKS 0x0008 /* Recognize e-mails as autolinks even without '<', '>' and 'mailto:' */ +#define MD_FLAG_NOINDENTEDCODEBLOCKS 0x0010 /* Disable indented code blocks. (Only fenced code works.) */ +#define MD_FLAG_NOHTMLBLOCKS 0x0020 /* Disable raw HTML blocks. */ +#define MD_FLAG_NOHTMLSPANS 0x0040 /* Disable raw HTML (inline). */ +#define MD_FLAG_TABLES 0x0100 /* Enable tables extension. */ +#define MD_FLAG_STRIKETHROUGH 0x0200 /* Enable strikethrough extension. */ +#define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */ +#define MD_FLAG_TASKLISTS 0x0800 /* Enable task list extension. */ +#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */ +#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */ +#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */ + +#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS) +#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS) + +/* Convenient sets of flags corresponding to well-known Markdown dialects. + * + * Note we may only support subset of features of the referred dialect. + * The constant just enables those extensions which bring us as close as + * possible given what features we implement. + * + * ABI compatibility note: Meaning of these can change in time as new + * extensions, bringing the dialect closer to the original, are implemented. + */ +#define MD_DIALECT_COMMONMARK 0 +#define MD_DIALECT_GITHUB (MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_TABLES | MD_FLAG_STRIKETHROUGH | MD_FLAG_TASKLISTS) + +/* Parser structure. + */ +typedef struct MD_PARSER { + /* Reserved. Set to zero. + */ + unsigned abi_version; + + /* Dialect options. Bitmask of MD_FLAG_xxxx values. + */ + unsigned flags; + + /* Caller-provided rendering callbacks. + * + * For some block/span types, more detailed information is provided in a + * type-specific structure pointed by the argument 'detail'. + * + * The last argument of all callbacks, 'userdata', is just propagated from + * md_parse() and is available for any use by the application. + * + * Note any strings provided to the callbacks as their arguments or as + * members of any detail structure are generally not zero-terminated. + * Application has to take the respective size information into account. + * + * Any rendering callback may abort further parsing of the document by + * returning non-zero. + */ + int (*enter_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + int (*leave_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + + int (*enter_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + int (*leave_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + + int (*text)(MD_TEXTTYPE /*type*/, const MD_CHAR* /*text*/, MD_SIZE /*size*/, void* /*userdata*/); + + /* Debug callback. Optional (may be NULL). + * + * If provided and something goes wrong, this function gets called. + * This is intended for debugging and problem diagnosis for developers; + * it is not intended to provide any errors suitable for displaying to an + * end user. + */ + void (*debug_log)(const char* /*msg*/, void* /*userdata*/); + + /* Reserved. Set to NULL. + */ + void (*syntax)(void); +} MD_PARSER; + + +/* For backward compatibility. Do not use in new code. + */ +typedef MD_PARSER MD_RENDERER; + + +/* Parse the Markdown document stored in the string 'text' of size 'size'. + * The parser provides callbacks to be called during the parsing so the + * caller can render the document on the screen or convert the Markdown + * to another format. + * + * Zero is returned on success. If a runtime error occurs (e.g. a memory + * fails), -1 is returned. If the processing is aborted due any callback + * returning non-zero, the return value of the callback is returned. + */ +int md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata); + + +#ifdef __cplusplus + } /* extern "C" { */ +#endif + +#endif /* MD4C_H */ diff --git a/ports/mesa/changes/include_c11_threads_posix.h b/ports/mesa/changes/include_c11_threads_posix.h new file mode 100644 index 0000000..a827f49 --- /dev/null +++ b/ports/mesa/changes/include_c11_threads_posix.h @@ -0,0 +1,396 @@ +/* + * C11 <threads.h> emulation library + * + * (C) Copyright yohhoy 2012. + * Distributed under the Boost Software License, Version 1.0. + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare [[derivative work]]s of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <stdlib.h> +#ifndef assert +#include <assert.h> +#endif +#include <limits.h> +#include <errno.h> +#include <unistd.h> +#include <sched.h> +#include <stdint.h> /* for intptr_t */ + +/* +Configuration macro: + + EMULATED_THREADS_USE_NATIVE_TIMEDLOCK + Use pthread_mutex_timedlock() for `mtx_timedlock()' + Otherwise use mtx_trylock() + *busy loop* emulation. +*/ +#if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__NetBSD__) +#define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK +#endif + + +#include <pthread.h> + +/*---------------------------- macros ----------------------------*/ +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT +#ifdef INIT_ONCE_STATIC_INIT +#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS +#else +#define TSS_DTOR_ITERATIONS 1 // assume TSS dtor MAY be called at least once. +#endif + +// FIXME: temporary non-standard hack to ease transition +#define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER + +/*---------------------------- types ----------------------------*/ +typedef pthread_cond_t cnd_t; +typedef pthread_t thrd_t; +typedef pthread_key_t tss_t; +typedef pthread_mutex_t mtx_t; +typedef pthread_once_t once_flag; + + +/* +Implementation limits: + - Conditionally emulation for "mutex with timeout" + (see EMULATED_THREADS_USE_NATIVE_TIMEDLOCK macro) +*/ +struct impl_thrd_param { + thrd_start_t func; + void *arg; +}; + +static inline void * +impl_thrd_routine(void *p) +{ + struct impl_thrd_param pack = *((struct impl_thrd_param *)p); + free(p); + return (void*)(intptr_t)pack.func(pack.arg); +} + + +/*--------------- 7.25.2 Initialization functions ---------------*/ +// 7.25.2.1 +static inline void +call_once(once_flag *flag, void (*func)(void)) +{ + pthread_once(flag, func); +} + + +/*------------- 7.25.3 Condition variable functions -------------*/ +// 7.25.3.1 +static inline int +cnd_broadcast(cnd_t *cond) +{ + assert(cond != NULL); + return (pthread_cond_broadcast(cond) == 0) ? thrd_success : thrd_error; +} + +// 7.25.3.2 +static inline void +cnd_destroy(cnd_t *cond) +{ + assert(cond); + pthread_cond_destroy(cond); +} + +// 7.25.3.3 +static inline int +cnd_init(cnd_t *cond) +{ + assert(cond != NULL); + return (pthread_cond_init(cond, NULL) == 0) ? thrd_success : thrd_error; +} + +// 7.25.3.4 +static inline int +cnd_signal(cnd_t *cond) +{ + assert(cond != NULL); + return (pthread_cond_signal(cond) == 0) ? thrd_success : thrd_error; +} + +// 7.25.3.5 +static inline int +cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time) +{ + int rt; + + assert(mtx != NULL); + assert(cond != NULL); + assert(abs_time != NULL); + + rt = pthread_cond_timedwait(cond, mtx, abs_time); + if (rt == ETIMEDOUT) + return thrd_busy; + return (rt == 0) ? thrd_success : thrd_error; +} + +// 7.25.3.6 +static inline int +cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + assert(mtx != NULL); + assert(cond != NULL); + return (pthread_cond_wait(cond, mtx) == 0) ? thrd_success : thrd_error; +} + + +/*-------------------- 7.25.4 Mutex functions --------------------*/ +// 7.25.4.1 +static inline void +mtx_destroy(mtx_t *mtx) +{ + assert(mtx != NULL); + pthread_mutex_destroy(mtx); +} + +/* + * XXX: Workaround when building with -O0 and without pthreads link. + * + * In such cases constant folding and dead code elimination won't be + * available, thus the compiler will always add the pthread_mutexattr* + * functions into the binary. As we try to link, we'll fail as the + * symbols are unresolved. + * + * Ideally we'll enable the optimisations locally, yet that does not + * seem to work. + * + * So the alternative workaround is to annotate the symbols as weak. + * Thus the linker will be happy and things don't clash when building + * with -O1 or greater. + */ +#if defined(HAVE_FUNC_ATTRIBUTE_WEAK) && !defined(__CYGWIN__) && !defined(OS_ESSENCE) +__attribute__((weak)) +int pthread_mutexattr_init(pthread_mutexattr_t *attr); + +__attribute__((weak)) +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); + +__attribute__((weak)) +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); +#endif + +// 7.25.4.2 +static inline int +mtx_init(mtx_t *mtx, int type) +{ + pthread_mutexattr_t attr; + assert(mtx != NULL); + if (type != mtx_plain && type != mtx_timed && type != mtx_try + && type != (mtx_plain|mtx_recursive) + && type != (mtx_timed|mtx_recursive) + && type != (mtx_try|mtx_recursive)) + return thrd_error; + + if ((type & mtx_recursive) == 0) { + pthread_mutex_init(mtx, NULL); + return thrd_success; + } + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + return thrd_success; +} + +// 7.25.4.3 +static inline int +mtx_lock(mtx_t *mtx) +{ + assert(mtx != NULL); + return (pthread_mutex_lock(mtx) == 0) ? thrd_success : thrd_error; +} + +static inline int +mtx_trylock(mtx_t *mtx); + +static inline void +thrd_yield(void); + +// 7.25.4.4 +static inline int +mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + assert(mtx != NULL); + assert(ts != NULL); + + { +#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK + int rt; + rt = pthread_mutex_timedlock(mtx, ts); + if (rt == 0) + return thrd_success; + return (rt == ETIMEDOUT) ? thrd_busy : thrd_error; +#else + time_t expire = time(NULL); + expire += ts->tv_sec; + while (mtx_trylock(mtx) != thrd_success) { + time_t now = time(NULL); + if (expire < now) + return thrd_busy; + // busy loop! + thrd_yield(); + } + return thrd_success; +#endif + } +} + +// 7.25.4.5 +static inline int +mtx_trylock(mtx_t *mtx) +{ + assert(mtx != NULL); + return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; +} + +// 7.25.4.6 +static inline int +mtx_unlock(mtx_t *mtx) +{ + assert(mtx != NULL); + return (pthread_mutex_unlock(mtx) == 0) ? thrd_success : thrd_error; +} + + +/*------------------- 7.25.5 Thread functions -------------------*/ +// 7.25.5.1 +static inline int +thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + struct impl_thrd_param *pack; + assert(thr != NULL); + pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param)); + if (!pack) return thrd_nomem; + pack->func = func; + pack->arg = arg; + if (pthread_create(thr, NULL, impl_thrd_routine, pack) != 0) { + free(pack); + return thrd_error; + } + return thrd_success; +} + +// 7.25.5.2 +static inline thrd_t +thrd_current(void) +{ + return pthread_self(); +} + +// 7.25.5.3 +static inline int +thrd_detach(thrd_t thr) +{ + return (pthread_detach(thr) == 0) ? thrd_success : thrd_error; +} + +// 7.25.5.4 +static inline int +thrd_equal(thrd_t thr0, thrd_t thr1) +{ + return pthread_equal(thr0, thr1); +} + +// 7.25.5.5 +static inline void +thrd_exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +// 7.25.5.6 +static inline int +thrd_join(thrd_t thr, int *res) +{ + void *code; + if (pthread_join(thr, &code) != 0) + return thrd_error; + if (res) + *res = (int)(intptr_t)code; + return thrd_success; +} + +// 7.25.5.7 +static inline void +thrd_sleep(const struct timespec *time_point, struct timespec *remaining) +{ + assert(time_point != NULL); + nanosleep(time_point, remaining); +} + +// 7.25.5.8 +static inline void +thrd_yield(void) +{ + sched_yield(); +} + + +/*----------- 7.25.6 Thread-specific storage functions -----------*/ +// 7.25.6.1 +static inline int +tss_create(tss_t *key, tss_dtor_t dtor) +{ + assert(key != NULL); + return (pthread_key_create(key, dtor) == 0) ? thrd_success : thrd_error; +} + +// 7.25.6.2 +static inline void +tss_delete(tss_t key) +{ + pthread_key_delete(key); +} + +// 7.25.6.3 +static inline void * +tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +// 7.25.6.4 +static inline int +tss_set(tss_t key, void *val) +{ + return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error; +} + + +/*-------------------- 7.25.7 Time functions --------------------*/ +// 7.25.6.1 +#ifndef HAVE_TIMESPEC_GET +static inline int +timespec_get(struct timespec *ts, int base) +{ + if (!ts) return 0; + if (base == TIME_UTC) { + clock_gettime(CLOCK_REALTIME, ts); + return base; + } + return 0; +} +#endif diff --git a/ports/mesa/changes/meson.build b/ports/mesa/changes/meson.build new file mode 100644 index 0000000..79f064b --- /dev/null +++ b/ports/mesa/changes/meson.build @@ -0,0 +1,1869 @@ +# Copyright © 2017-2019 Intel Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +project( + 'mesa', + ['c', 'cpp'], + version : run_command( + [find_program('python', 'python3'), 'bin/meson_get_version.py'] + ).stdout(), + license : 'MIT', + meson_version : '>= 0.46', + default_options : ['buildtype=debugoptimized', 'b_ndebug=if-release', 'c_std=c99', 'cpp_std=c++14'] +) + +cc = meson.get_compiler('c') +cpp = meson.get_compiler('cpp') + +null_dep = dependency('', required : false) + +if get_option('layout') != 'mirror' + error('`mirror` is the only build directory layout supported') +endif + +# Arguments for the preprocessor, put these in a separate array from the C and +# C++ (cpp in meson terminology) arguments since they need to be added to the +# default arguments for both C and C++. +pre_args = [ + '-D__STDC_CONSTANT_MACROS', + '-D__STDC_FORMAT_MACROS', + '-D__STDC_LIMIT_MACROS', + '-DPACKAGE_VERSION="@0@"'.format(meson.project_version()), + '-DPACKAGE_BUGREPORT="https://gitlab.freedesktop.org/mesa/mesa/-/issues"', +] + +with_vulkan_icd_dir = get_option('vulkan-icd-dir') +with_tests = get_option('build-tests') +with_valgrind = get_option('valgrind') +with_libunwind = get_option('libunwind') +with_glx_read_only_text = get_option('glx-read-only-text') +with_glx_direct = get_option('glx-direct') +with_osmesa = get_option('osmesa') +with_swr_arches = get_option('swr-arches') +with_vulkan_overlay_layer = get_option('vulkan-overlay-layer') +with_tools = get_option('tools') +if with_tools.contains('all') + with_tools = [ + 'drm-shim', + 'etnaviv', + 'freedreno', + 'glsl', + 'intel', + 'intel-ui', + 'lima', + 'nir', + 'nouveau', + 'xvmc', + ] +endif + +with_intel_tools = with_tools.contains('intel') or with_tools.contains('intel-ui') +with_imgui = with_intel_tools or with_vulkan_overlay_layer + +dri_drivers_path = get_option('dri-drivers-path') +if dri_drivers_path == '' + dri_drivers_path = join_paths(get_option('prefix'), get_option('libdir'), 'dri') +endif +dri_search_path = get_option('dri-search-path') +if dri_search_path == '' + dri_search_path = dri_drivers_path +endif + +with_gles1 = get_option('gles1') +with_gles2 = get_option('gles2') +if host_machine.system() == 'windows' + if with_gles1 == 'auto' + with_gles1 = 'false' + endif + if with_gles2 == 'auto' + with_gles2 = 'false' + endif +endif +with_opengl = get_option('opengl') + +# Default shared glapi off for windows, on elsewhere. +_sg = get_option('shared-glapi') +if _sg == 'auto' + with_shared_glapi = host_machine.system() != 'windows' and host_machine.system() != 'essence' +else + with_shared_glapi = _sg == 'true' +endif + +# shared-glapi is required if at least two OpenGL APIs are being built +if not with_shared_glapi + if ((with_gles1 == 'true' and with_gles2 == 'true') or + (with_gles1 == 'true' and with_opengl) or + (with_gles2 == 'true' and with_opengl)) + error('shared-glapi required for building two or more of OpenGL, OpenGL ES 1.x, OpenGL ES 2.x') + endif + with_gles1 = 'false' + with_gles2 = 'false' +endif + +# We require OpenGL for OpenGL ES +if not with_opengl + if (with_gles1 == 'true' or with_gles2 == 'true') and not with_opengl + error('building OpenGL ES without OpenGL is not supported.') + endif + with_gles1 = 'false' + with_gles2 = 'false' +endif + +with_gles1 = with_gles1 != 'false' +with_gles2 = with_gles2 != 'false' +with_any_opengl = with_opengl or with_gles1 or with_gles2 +# Only build shared_glapi if at least one OpenGL API is enabled +with_shared_glapi = with_shared_glapi and with_any_opengl + +system_has_kms_drm = ['openbsd', 'netbsd', 'freebsd', 'gnu/kfreebsd', 'dragonfly', 'linux', 'sunos'].contains(host_machine.system()) + +dri_drivers = get_option('dri-drivers') +if dri_drivers.contains('auto') + if system_has_kms_drm + # TODO: PPC, Sparc + if ['x86', 'x86_64'].contains(host_machine.cpu_family()) + dri_drivers = ['i915', 'i965', 'r100', 'r200', 'nouveau'] + elif ['arm', 'aarch64'].contains(host_machine.cpu_family()) + dri_drivers = [] + else + error('Unknown architecture @0@. Please pass -Ddri-drivers to set driver options. Patches gladly accepted to fix this.'.format( + host_machine.cpu_family())) + endif + elif ['darwin', 'windows', 'cygwin', 'haiku', 'essence'].contains(host_machine.system()) + # only swrast would make sense here, but gallium swrast is a much better default + dri_drivers = [] + else + error('Unknown OS @0@. Please pass -Ddri-drivers to set driver options. Patches gladly accepted to fix this.'.format( + host_machine.system())) + endif +endif + +with_dri_i915 = dri_drivers.contains('i915') +with_dri_i965 = dri_drivers.contains('i965') +with_dri_r100 = dri_drivers.contains('r100') +with_dri_r200 = dri_drivers.contains('r200') +with_dri_nouveau = dri_drivers.contains('nouveau') +with_dri_swrast = dri_drivers.contains('swrast') + +with_dri = dri_drivers.length() != 0 and dri_drivers != [''] + +gallium_drivers = get_option('gallium-drivers') +if gallium_drivers.contains('auto') + if system_has_kms_drm + # TODO: PPC, Sparc + if ['x86', 'x86_64'].contains(host_machine.cpu_family()) + gallium_drivers = [ + 'r300', 'r600', 'radeonsi', 'nouveau', 'virgl', 'svga', 'swrast', + 'iris' + ] + elif ['arm', 'aarch64'].contains(host_machine.cpu_family()) + gallium_drivers = [ + 'kmsro', 'v3d', 'vc4', 'freedreno', 'etnaviv', 'nouveau', + 'tegra', 'virgl', 'lima', 'panfrost', 'swrast' + ] + else + error('Unknown architecture @0@. Please pass -Dgallium-drivers to set driver options. Patches gladly accepted to fix this.'.format( + host_machine.cpu_family())) + endif + elif ['darwin', 'windows', 'cygwin', 'haiku', 'essence'].contains(host_machine.system()) + gallium_drivers = ['swrast'] + else + error('Unknown OS @0@. Please pass -Dgallium-drivers to set driver options. Patches gladly accepted to fix this.'.format( + host_machine.system())) + endif +endif +with_gallium_kmsro = gallium_drivers.contains('kmsro') +with_gallium_radeonsi = gallium_drivers.contains('radeonsi') +with_gallium_r300 = gallium_drivers.contains('r300') +with_gallium_r600 = gallium_drivers.contains('r600') +with_gallium_nouveau = gallium_drivers.contains('nouveau') +with_gallium_freedreno = gallium_drivers.contains('freedreno') +with_gallium_softpipe = gallium_drivers.contains('swrast') +with_gallium_vc4 = gallium_drivers.contains('vc4') +with_gallium_v3d = gallium_drivers.contains('v3d') +with_gallium_panfrost = gallium_drivers.contains('panfrost') +with_gallium_etnaviv = gallium_drivers.contains('etnaviv') +with_gallium_tegra = gallium_drivers.contains('tegra') +with_gallium_iris = gallium_drivers.contains('iris') +with_gallium_i915 = gallium_drivers.contains('i915') +with_gallium_svga = gallium_drivers.contains('svga') +with_gallium_virgl = gallium_drivers.contains('virgl') +with_gallium_swr = gallium_drivers.contains('swr') +with_gallium_lima = gallium_drivers.contains('lima') +with_gallium_zink = gallium_drivers.contains('zink') + +if cc.get_id().startswith('intel') and meson.version().version_compare('< 0.49.1') + error('Meson does not have sufficient support of ICC before 0.49.1 to compile mesa') +endif + +with_gallium = gallium_drivers.length() != 0 and gallium_drivers != [''] + +if with_gallium and system_has_kms_drm + _glx = get_option('glx') + _egl = get_option('egl') + if _glx == 'dri' or _egl == 'true' or (_glx == 'disabled' and _egl != 'false') + with_dri = true + endif +endif + +_vulkan_drivers = get_option('vulkan-drivers') +if _vulkan_drivers.contains('auto') + if system_has_kms_drm + if host_machine.cpu_family().startswith('x86') + _vulkan_drivers = ['amd', 'intel'] + elif ['arm', 'aarch64'].contains(host_machine.cpu_family()) + _vulkan_drivers = [] + else + error('Unknown architecture @0@. Please pass -Dvulkan-drivers to set driver options. Patches gladly accepted to fix this.'.format( + host_machine.cpu_family())) + endif + elif ['darwin', 'windows', 'cygwin', 'haiku', 'essence'].contains(host_machine.system()) + # No vulkan driver supports windows or macOS currently + _vulkan_drivers = [] + else + error('Unknown OS @0@. Please pass -Dvulkan-drivers to set driver options. Patches gladly accepted to fix this.'.format( + host_machine.system())) + endif +endif + +with_intel_vk = _vulkan_drivers.contains('intel') +with_amd_vk = _vulkan_drivers.contains('amd') +with_freedreno_vk = _vulkan_drivers.contains('freedreno') +with_any_vk = _vulkan_drivers.length() != 0 and _vulkan_drivers != [''] + +if with_dri_swrast and (with_gallium_softpipe or with_gallium_swr) + error('Only one swrast provider can be built') +endif +if with_dri_i915 and with_gallium_i915 + error('Only one i915 provider can be built') +endif +if with_gallium_kmsro and not (with_gallium_v3d or with_gallium_vc4 or with_gallium_etnaviv or with_gallium_freedreno or with_gallium_panfrost or with_gallium_lima) + error('kmsro driver requires one or more renderonly drivers (vc4, etnaviv, freedreno, panfrost, lima)') +endif +if with_gallium_tegra and not with_gallium_nouveau + error('tegra driver requires nouveau driver') +endif + +if host_machine.system() == 'darwin' + with_dri_platform = 'apple' + pre_args += '-DBUILDING_MESA' +elif ['windows', 'cygwin'].contains(host_machine.system()) + with_dri_platform = 'windows' +elif system_has_kms_drm + with_dri_platform = 'drm' +else + # FIXME: haiku doesn't use dri, and xlib doesn't use dri, probably should + # assert here that one of those cases has been met. + # FIXME: illumos ends up here as well + with_dri_platform = 'none' +endif + +_platforms = get_option('platforms') +if _platforms.contains('auto') + if system_has_kms_drm + _platforms = ['x11', 'wayland', 'drm', 'surfaceless'] + elif ['darwin', 'cygwin'].contains(host_machine.system()) + _platforms = ['x11', 'surfaceless'] + elif ['haiku'].contains(host_machine.system()) + _platforms = ['haiku'] + elif host_machine.system() == 'windows' + _platforms = ['windows'] + elif host_machine.system() == 'essence' + _platforms = ['essence'] + else + error('Unknown OS @0@. Please pass -Dplatforms to set platforms. Patches gladly accepted to fix this.'.format( + host_machine.system())) + endif +endif + +with_platform_android = _platforms.contains('android') +with_platform_x11 = _platforms.contains('x11') +with_platform_wayland = _platforms.contains('wayland') +with_platform_drm = _platforms.contains('drm') +with_platform_haiku = _platforms.contains('haiku') +with_platform_surfaceless = _platforms.contains('surfaceless') +with_platform_windows = _platforms.contains('windows') +with_platform_essence = _platforms.contains('essence') + +with_platforms = false +if _platforms.length() != 0 and _platforms != [''] + # sanity check that list contains no empty strings + if _platforms.contains('') + error('Invalid argument list given to -Dplatforms, please fix.') + endif + with_platforms = true + egl_native_platform = _platforms[0] +endif + +_xlib_lease = get_option('xlib-lease') +if _xlib_lease == 'auto' + with_xlib_lease = with_platform_x11 and with_platform_drm +else + with_xlib_lease = _xlib_lease == 'true' +endif + +with_glx = get_option('glx') +if with_glx == 'auto' + if with_dri + with_glx = 'dri' + elif with_platform_haiku + with_glx = 'disabled' + elif with_platform_essence + with_glx = 'disabled' + elif host_machine.system() == 'windows' + with_glx = 'disabled' + elif with_gallium + # Even when building just gallium drivers the user probably wants dri + with_glx = 'dri' + elif with_platform_x11 and with_any_opengl and not with_any_vk + # The automatic behavior should not be to turn on xlib based glx when + # building only vulkan drivers + with_glx = 'xlib' + else + with_glx = 'disabled' + endif +endif +if with_glx == 'dri' + if with_gallium + with_dri = true + endif +endif + +if not (with_dri or with_gallium or with_glx != 'disabled') + with_gles1 = false + with_gles2 = false + with_opengl = false + with_any_opengl = false + with_shared_glapi = false +endif + +_gbm = get_option('gbm') +if _gbm == 'auto' + with_gbm = system_has_kms_drm and with_dri +else + with_gbm = _gbm == 'true' +endif +if with_gbm and not system_has_kms_drm + error('GBM only supports DRM/KMS platforms') +endif + +_egl = get_option('egl') +if _egl == 'auto' + with_egl = ( + not ['darwin', 'windows'].contains(host_machine.system()) and + with_dri and with_shared_glapi and with_platforms + ) +elif _egl == 'true' + if not with_dri + error('EGL requires dri') + elif not with_shared_glapi + error('EGL requires shared-glapi') + elif not with_platforms + error('No platforms specified, consider -Dplatforms=drm,x11,surfaceless at least') + elif not ['disabled', 'dri'].contains(with_glx) + error('EGL requires dri, but a GLX is being built without dri') + elif ['darwin', 'windows'].contains(host_machine.system()) + error('EGL is not available on Windows or MacOS') + endif + with_egl = true +else + with_egl = false +endif + +if with_egl and not (with_platform_drm or with_platform_surfaceless or with_platform_android) + if with_gallium_radeonsi + error('RadeonSI requires the drm, surfaceless or android platform when using EGL') + endif + if with_gallium_virgl + error('Virgl requires the drm, surfaceless or android platform when using EGL') + endif +endif + +# Android uses emutls for versions <= P/28. For USE_ELF_TLS we need ELF TLS. +if not ['windows', 'freebsd'].contains(host_machine.system()) and (not with_platform_android or get_option('platform-sdk-version') >= 29) + pre_args += '-DUSE_ELF_TLS' +endif + +if with_glx != 'disabled' + if not (with_platform_x11 and with_any_opengl) + error('Cannot build GLX support without X11 platform support and at least one OpenGL API') + elif with_glx == 'gallium-xlib' + if not with_gallium + error('Gallium-xlib based GLX requires at least one gallium driver') + elif not with_gallium_softpipe + error('Gallium-xlib based GLX requires softpipe or llvmpipe.') + elif with_dri + error('gallium-xlib conflicts with any dri driver') + endif + elif with_glx == 'xlib' + if with_dri + error('xlib conflicts with any dri driver') + endif + elif with_glx == 'dri' + if not with_shared_glapi + error('dri based GLX requires shared-glapi') + endif + endif +endif + +with_glvnd = get_option('glvnd') +if with_glvnd + if with_platform_windows + error('glvnd cannot be used on Windows') + elif with_glx == 'xlib' or with_glx == 'gallium-xlib' + error('Cannot build glvnd support for GLX that is not DRI based.') + elif with_glx == 'disabled' and not with_egl + error('glvnd requires DRI based GLX and/or EGL') + endif + if get_option('egl-lib-suffix') != '' + error('''EGL lib suffix can't be used with libglvnd''') + endif +endif + +if with_vulkan_icd_dir == '' + with_vulkan_icd_dir = join_paths(get_option('datadir'), 'vulkan/icd.d') +endif + +# GNU/Hurd includes egl_dri2, without drm. +with_dri2 = (with_dri or with_any_vk) and (with_dri_platform == 'drm' or + host_machine.system() == 'gnu') +_dri3 = get_option('dri3') +if _dri3 == 'auto' + with_dri3 = system_has_kms_drm and with_dri2 +else + with_dri3 = _dri3 == 'true' +endif + +if with_any_vk and (with_platform_x11 and not with_dri3) + error('Vulkan drivers require dri3 for X11 support') +endif +if with_dri + if with_glx == 'disabled' and not with_egl and not with_gbm and with_osmesa != 'classic' + error('building dri drivers require at least one windowing system or classic osmesa') + endif +endif + +_vdpau = get_option('gallium-vdpau') +if not system_has_kms_drm + if _vdpau == 'true' + error('VDPAU state tracker can only be build on unix-like OSes.') + else + _vdpau = 'false' + endif +elif not with_platform_x11 + if _vdpau == 'true' + error('VDPAU state tracker requires X11 support.') + else + _vdpau = 'false' + endif +elif not (with_gallium_r300 or with_gallium_r600 or with_gallium_radeonsi or + with_gallium_nouveau) + if _vdpau == 'true' + error('VDPAU state tracker requires at least one of the following gallium drivers: r300, r600, radeonsi, nouveau.') + else + _vdpau = 'false' + endif +endif +dep_vdpau = null_dep +with_gallium_vdpau = false +if _vdpau != 'false' + dep_vdpau = dependency('vdpau', version : '>= 1.1', required : _vdpau == 'true') + if dep_vdpau.found() + dep_vdpau = dep_vdpau.partial_dependency(compile_args : true) + with_gallium_vdpau = true + endif +endif + +if with_gallium_vdpau + pre_args += '-DHAVE_ST_VDPAU' +endif +vdpau_drivers_path = get_option('vdpau-libs-path') +if vdpau_drivers_path == '' + vdpau_drivers_path = join_paths(get_option('libdir'), 'vdpau') +endif + +if with_gallium_zink + dep_vulkan = dependency('vulkan') +endif + +_xvmc = get_option('gallium-xvmc') +if not system_has_kms_drm + if _xvmc == 'true' + error('XVMC state tracker can only be build on unix-like OSes.') + else + _xvmc = 'false' + endif +elif not with_platform_x11 + if _xvmc == 'true' + error('XVMC state tracker requires X11 support.') + else + _xvmc = 'false' + endif +elif not (with_gallium_r600 or with_gallium_nouveau) + if _xvmc == 'true' + error('XVMC state tracker requires at least one of the following gallium drivers: r600, nouveau.') + else + _xvmc = 'false' + endif +endif +dep_xvmc = null_dep +dep_xv = null_dep +with_gallium_xvmc = false +if _xvmc != 'false' + dep_xvmc = dependency('xvmc', version : '>= 1.0.6', required : _xvmc == 'true') + dep_xv = dependency('xv', required : _xvmc == 'true') + with_gallium_xvmc = dep_xvmc.found() and dep_xv.found() +endif + +xvmc_drivers_path = get_option('xvmc-libs-path') +if xvmc_drivers_path == '' + xvmc_drivers_path = get_option('libdir') +endif + +_omx = get_option('gallium-omx') +if not system_has_kms_drm + if ['auto', 'disabled'].contains(_omx) + _omx = 'disabled' + else + error('OMX state tracker can only be built on unix-like OSes.') + endif +elif not (with_gallium_r600 or with_gallium_radeonsi or with_gallium_nouveau) + if ['auto', 'disabled'].contains(_omx) + _omx = 'disabled' + else + error('OMX state tracker requires at least one of the following gallium drivers: r600, radeonsi, nouveau.') + endif +endif +with_gallium_omx = _omx +dep_omx = null_dep +dep_omx_other = [] +if ['auto', 'bellagio'].contains(_omx) + dep_omx = dependency( + 'libomxil-bellagio', required : _omx == 'bellagio' + ) + if dep_omx.found() + with_gallium_omx = 'bellagio' + endif +endif +if ['auto', 'tizonia'].contains(_omx) + if with_dri and with_egl + dep_omx = dependency( + 'libtizonia', version : '>= 0.10.0', + required : _omx == 'tizonia', + ) + dep_omx_other = [ + dependency('libtizplatform', required : _omx == 'tizonia'), + dependency('tizilheaders', required : _omx == 'tizonia'), + ] + if dep_omx.found() and dep_omx_other[0].found() and dep_omx_other[1].found() + with_gallium_omx = 'tizonia' + endif + elif _omx == 'tizonia' + error('OMX-Tizonia state tracker requires dri and egl') + endif +endif +if _omx == 'auto' + with_gallium_omx = 'disabled' +else + with_gallium_omx = _omx +endif + +pre_args += [ + '-DENABLE_ST_OMX_BELLAGIO=' + (with_gallium_omx == 'bellagio' ? '1' : '0'), + '-DENABLE_ST_OMX_TIZONIA=' + (with_gallium_omx == 'tizonia' ? '1' : '0'), +] + + +omx_drivers_path = get_option('omx-libs-path') + +if with_gallium_omx != 'disabled' + # Figure out where to put the omx driver. + # FIXME: this could all be vastly simplified by adding a 'defined_variable' + # argument to meson's get_pkgconfig_variable method. + if omx_drivers_path == '' + _omx_libdir = dep_omx.get_pkgconfig_variable('libdir') + _omx_drivers_dir = dep_omx.get_pkgconfig_variable('pluginsdir') + if _omx_libdir == get_option('libdir') + omx_drivers_path = _omx_drivers_dir + else + _omx_base_dir = [] + # This will fail on windows. Does OMX run on windows? + _omx_libdir = _omx_libdir.split('/') + _omx_drivers_dir = _omx_drivers_dir.split('/') + foreach o : _omx_drivers_dir + if not _omx_libdir.contains(o) + _omx_base_dir += o + endif + endforeach + omx_drivers_path = join_paths(get_option('libdir'), _omx_base_dir) + endif + endif +endif + +_va = get_option('gallium-va') +if not system_has_kms_drm + if _va == 'true' + error('VA state tracker can only be built on unix-like OSes.') + else + _va = 'false' + endif +elif not (with_gallium_r600 or with_gallium_radeonsi or with_gallium_nouveau) + if _va == 'true' + error('VA state tracker requires at least one of the following gallium drivers: r600, radeonsi, nouveau.') + else + _va = 'false' + endif +endif +with_gallium_va = false +dep_va = null_dep +if _va != 'false' + dep_va = dependency('libva', version : '>= 0.38.0', required : _va == 'true') + if dep_va.found() + dep_va_headers = dep_va.partial_dependency(compile_args : true) + with_gallium_va = true + endif +endif + +va_drivers_path = get_option('va-libs-path') +if va_drivers_path == '' + va_drivers_path = join_paths(get_option('libdir'), 'dri') +endif + +_xa = get_option('gallium-xa') +if not system_has_kms_drm + if _xa == 'true' + error('XA state tracker can only be built on unix-like OSes.') + else + _xa = 'false' + endif +elif not (with_gallium_nouveau or with_gallium_freedreno or with_gallium_i915 + or with_gallium_svga) + if _xa == 'true' + error('XA state tracker requires at least one of the following gallium drivers: nouveau, freedreno, i915, svga.') + else + _xa = 'false' + endif +endif +with_gallium_xa = _xa != 'false' + +d3d_drivers_path = get_option('d3d-drivers-path') +if d3d_drivers_path == '' + d3d_drivers_path = join_paths(get_option('prefix'), get_option('libdir'), 'd3d') +endif + +with_gallium_st_nine = get_option('gallium-nine') +if with_gallium_st_nine + if not with_gallium_softpipe + error('The nine state tracker requires gallium softpipe/llvmpipe.') + elif not (with_gallium_radeonsi or with_gallium_nouveau or with_gallium_r600 + or with_gallium_r300 or with_gallium_svga or with_gallium_i915 + or with_gallium_iris) + error('The nine state tracker requires at least one non-swrast gallium driver.') + endif + if not with_dri3 + error('Using nine with wine requires dri3') + endif +endif + +if get_option('power8') != 'false' + # on old versions of meson the cpu family would return as ppc64le on little + # endian power8, this was changed in 0.48 such that the family would always + # be ppc64 regardless of endianness, and then the machine.endian() value + # should be checked. Since we support versions < 0.48 we need to use + # startswith. + if host_machine.cpu_family().startswith('ppc64') and host_machine.endian() == 'little' + if cc.get_id() == 'gcc' and cc.version().version_compare('< 4.8') + error('Altivec is not supported with gcc version < 4.8.') + endif + if cc.compiles(''' + #include <altivec.h> + int main() { + vector unsigned char r; + vector unsigned int v = vec_splat_u32 (1); + r = __builtin_vec_vgbbd ((vector unsigned char) v); + return 0; + }''', + args : '-mpower8-vector', + name : 'POWER8 intrinsics') + pre_args += ['-D_ARCH_PWR8', '-mpower8-vector'] + elif get_option('power8') == 'true' + error('POWER8 intrinsic support required but not found.') + endif + endif +endif + +_opencl = get_option('gallium-opencl') +if _opencl != 'disabled' + if not with_gallium + error('OpenCL Clover implementation requires at least one gallium driver.') + endif + + dep_clc = dependency('libclc') + with_gallium_opencl = true + with_opencl_icd = _opencl == 'icd' + + with_opencl_spirv = get_option('opencl-spirv') + if with_opencl_spirv + dep_spirv_tools = dependency('SPIRV-Tools', required : true, version : '>= 2018.0') + # LLVMSPIRVLib is available at https://github.com/KhronosGroup/SPIRV-LLVM-Translator + dep_llvmspirvlib = dependency('LLVMSPIRVLib', required : true, version : '>= 0.2.1') + else + dep_spirv_tools = null_dep + dep_llvmspirvlib = null_dep + endif +else + dep_clc = null_dep + dep_spirv_tools = null_dep + dep_llvmspirvlib = null_dep + with_gallium_opencl = false + with_opencl_icd = false + with_opencl_spirv = false +endif + +gl_pkgconfig_c_flags = [] +if with_platform_x11 + if with_any_vk or with_egl or (with_glx == 'dri' and with_dri_platform == 'drm') + pre_args += '-DHAVE_X11_PLATFORM' + endif + if with_glx == 'xlib' or with_glx == 'gallium-xlib' + pre_args += '-DUSE_XSHM' + else + pre_args += '-DGLX_INDIRECT_RENDERING' + if with_glx_direct + pre_args += '-DGLX_DIRECT_RENDERING' + endif + if with_dri_platform == 'drm' + pre_args += '-DGLX_USE_DRM' + elif with_dri_platform == 'apple' + pre_args += '-DGLX_USE_APPLEGL' + elif with_dri_platform == 'windows' + pre_args += '-DGLX_USE_WINDOWSGL' + endif + endif +else + pre_args += '-DEGL_NO_X11' + gl_pkgconfig_c_flags += '-DEGL_NO_X11' +endif +if with_platform_drm + if with_egl and not with_gbm + error('EGL drm platform requires gbm') + endif + pre_args += '-DHAVE_DRM_PLATFORM' +endif +if with_platform_surfaceless + pre_args += '-DHAVE_SURFACELESS_PLATFORM' +endif +if with_platform_android + dep_android = [ + dependency('cutils'), + dependency('hardware'), + dependency('sync'), + ] + if with_gallium + dep_android += dependency('backtrace') + endif + if get_option('platform-sdk-version') >= 26 + dep_android += dependency('nativewindow') + endif + pre_args += '-DHAVE_ANDROID_PLATFORM' +endif +if with_platform_haiku + pre_args += '-DHAVE_HAIKU_PLATFORM' +endif + +if meson.version().version_compare('>=0.50') + prog_python = import('python').find_installation('python3') +else + prog_python = import('python3').find_python() +endif +has_mako = run_command( + prog_python, '-c', + ''' +from distutils.version import StrictVersion +import mako +assert StrictVersion(mako.__version__) > StrictVersion("0.8.0") + ''') +if has_mako.returncode() != 0 + error('Python (3.x) mako module >= 0.8.0 required to build mesa.') +endif + +if cc.get_id() == 'gcc' and cc.version().version_compare('< 4.4.6') + error('When using GCC, version 4.4.6 or later is required.') +endif + +# Support systems without ETIME (e.g. FreeBSD) +if cc.get_define('ETIME', prefix : '#include <errno.h>') == '' + pre_args += '-DETIME=ETIMEDOUT' +endif + +# Define DEBUG for debug builds only (debugoptimized is not included on this one) +if get_option('buildtype') == 'debug' + pre_args += '-DDEBUG' +endif + +with_shader_cache = false +_shader_cache = get_option('shader-cache') +if _shader_cache != 'false' + if host_machine.system() == 'windows' + if _shader_cache == 'true' + error('Shader Cache does not currently work on Windows') + endif + else + pre_args += '-DENABLE_SHADER_CACHE' + with_shader_cache = true + endif +endif + +# Check for GCC style builtins +foreach b : ['bswap32', 'bswap64', 'clz', 'clzll', 'ctz', 'expect', 'ffs', + 'ffsll', 'popcount', 'popcountll', 'unreachable'] + if cc.has_function(b) + pre_args += '-DHAVE___BUILTIN_@0@'.format(b.to_upper()) + endif +endforeach + +# check for GCC __attribute__ +foreach a : ['const', 'flatten', 'malloc', 'pure', 'unused', + 'warn_unused_result', 'weak',] + if cc.compiles('int foo(void) __attribute__((@0@));'.format(a), + name : '__attribute__((@0@))'.format(a)) + pre_args += '-DHAVE_FUNC_ATTRIBUTE_@0@'.format(a.to_upper()) + endif +endforeach +if cc.compiles('int foo(const char *p, ...) __attribute__((format(printf, 1, 2)));', + name : '__attribute__((format(...)))') + pre_args += '-DHAVE_FUNC_ATTRIBUTE_FORMAT' +endif +if cc.compiles('struct __attribute__((packed)) foo { int bar; };', + name : '__attribute__((packed))') + pre_args += '-DHAVE_FUNC_ATTRIBUTE_PACKED' +endif +if cc.compiles('int *foo(void) __attribute__((returns_nonnull));', + name : '__attribute__((returns_nonnull))') + pre_args += '-DHAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL' +endif +if cc.compiles('''int foo_def(void) __attribute__((visibility("default"))); + int foo_hid(void) __attribute__((visibility("hidden"))); + int foo_int(void) __attribute__((visibility("internal"))); + int foo_pro(void) __attribute__((visibility("protected")));''', + name : '__attribute__((visibility(...)))') + pre_args += '-DHAVE_FUNC_ATTRIBUTE_VISIBILITY' +endif +if cc.compiles('int foo(void) { return 0; } int bar(void) __attribute__((alias("foo")));', + name : '__attribute__((alias(...)))') + pre_args += '-DHAVE_FUNC_ATTRIBUTE_ALIAS' +endif +if cc.compiles('int foo(void) __attribute__((__noreturn__));', + name : '__attribute__((__noreturn__))') + pre_args += '-DHAVE_FUNC_ATTRIBUTE_NORETURN' +endif +if cc.compiles('__uint128_t foo(void) { return 0; }', + name : '__uint128_t') + pre_args += '-DHAVE_UINT128' +endif + +# TODO: this is very incomplete +if ['linux', 'cygwin', 'gnu', 'freebsd', 'gnu/kfreebsd', 'essence'].contains(host_machine.system()) + pre_args += '-D_GNU_SOURCE' +elif host_machine.system() == 'sunos' + pre_args += '-D__EXTENSIONS__' +elif host_machine.system() == 'windows' + pre_args += [ + '-D_WINDOWS', '-D_WIN32_WINNT=0x0601', '-DWINVER=0x0601', + '-DPIPE_SUBSYSTEM_WINDOWS_USER', + '-D_USE_MATH_DEFINES', # XXX: scons doesn't use this for mingw + ] + if cc.get_id() == 'msvc' + pre_args += [ + '-DVC_EXTRALEAN', + '-D_CRT_SECURE_NO_WARNINGS', + '-D_CRT_SECURE_NO_DEPRECATE', + '-D_SCL_SECURE_NO_WARNINGS', + '-D_SCL_SECURE_NO_DEPRECATE', + '-D_ALLOW_KEYWORD_MACROS', + '-D_HAS_EXCEPTIONS=0', # Tell C++ STL to not use exceptions + ] + else + pre_args += ['-D__MSVCRT_VERSION__=0x0700'] + endif +elif host_machine.system() == 'openbsd' + pre_args += '-D_ISOC11_SOURCE' +endif + +# Check for generic C arguments +c_args = [] +c_vis_args = [] +c_msvc_compat_args = [] +no_override_init_args = [] +cpp_args = [] +cpp_vis_args = [] +cpp_msvc_compat_args = [] +if cc.get_id() == 'msvc' + foreach a : ['/wd4018', # signed/unsigned mismatch + '/wd4056', # overflow in floating-point constant arithmetic + '/wd4244', # conversion from 'type1' to 'type2', possible loss of data + '/wd4267', # 'var' : conversion from 'size_t' to 'type', possible loss of data + '/wd4305', # trancation from 'type1' to 'type2' + '/wd4351', # new behavior: elements of array 'array' will be default initialized + '/wd4756', # overflow in constant arithmetic + '/wd4800', # forcing value to bool 'true' or 'false' (performance warning) + '/wd4996', # disabled deprecated POSIX name warnings + '/wd4291', # no matching operator delete found + '/wd4146', # unary minus operator applied to unsigned type, result still unsigned + '/wd4200', # nonstandard extension used: zero-sized array in struct/union + '/wd4624', # destructor was implicitly defined as deleted [from LLVM] + ] + if cc.has_argument(a) + c_args += a + endif + if cpp.has_argument(a) + cpp_args += a + endif + endforeach + if cc.has_argument('-Wmicrosoft-enum-value') # Clang + c_args += '-Wno-microsoft-enum-value' + cpp_args += '-Wno-microsoft-enum-value' + endif +else + _trial = [ + '-Werror=implicit-function-declaration', + '-Werror=missing-prototypes', + '-Werror=return-type', + '-Werror=empty-body', + '-Werror=incompatible-pointer-types', + '-Werror=int-conversion', + '-Wno-missing-field-initializers', + '-Wno-format-truncation', + '-fno-math-errno', + '-fno-trapping-math', + '-Qunused-arguments', + '-fno-common', + ] + # MinGW chokes on format specifiers and I can't get it all working + if not (cc.get_id() == 'gcc' and host_machine.system() == 'windows') + _trial += ['-Werror=format', '-Wformat-security'] + endif + foreach a : _trial + if cc.has_argument(a) + c_args += a + endif + endforeach + + _trial = [ + '-Werror=return-type', + '-Werror=empty-body', + '-Wno-non-virtual-dtor', + '-Wno-missing-field-initializers', + '-Wno-format-truncation', + '-fno-math-errno', + '-fno-trapping-math', + '-Qunused-arguments', + # Some classes use custom new operator which zeroes memory, however + # gcc does aggressive dead-store elimination which threats all writes + # to the memory before the constructor as "dead stores". + # For now we disable this optimization. + '-flifetime-dse=1', + ] + # MinGW chokes on format specifiers and I can't get it all working + if not (cc.get_id() == 'gcc' and host_machine.system() == 'windows') + _trial += ['-Werror=format', '-Wformat-security'] + endif + foreach a : _trial + if cpp.has_argument(a) + cpp_args += a + endif + endforeach + + foreach a : ['-Wno-override-init', '-Wno-initializer-overrides'] + if cc.has_argument(a) + no_override_init_args += a + endif + endforeach + + if cc.has_argument('-fvisibility=hidden') + c_vis_args += '-fvisibility=hidden' + endif + + # Check for C and C++ arguments for MSVC compatibility. These are only used + # in parts of the mesa code base that need to compile with MSVC, mainly + # common code + foreach a : ['-Werror=pointer-arith', '-Werror=vla', '-Werror=gnu-empty-initializer'] + if cc.has_argument(a) + c_msvc_compat_args += a + endif + if cpp.has_argument(a) + cpp_msvc_compat_args += a + endif + endforeach + + if cpp.has_argument('-fvisibility=hidden') + cpp_vis_args += '-fvisibility=hidden' + endif + +endif + +# set linker arguments +if host_machine.system() == 'windows' + if cc.get_id() == 'msvc' + add_project_link_arguments( + '/fixed:no', + '/dynamicbase', + '/nxcompat', + language : ['c', 'cpp'], + ) + if get_option('buildtype') != 'debug' + add_project_link_arguments( + '/incremental:no', + language : ['c', 'cpp'], + ) + endif + else + add_project_link_arguments( + '-Wl,--nxcompat', + '-Wl,--dynamicbase', + '-static-libgcc', + '-static-libstdc++', + language : ['c', 'cpp'], + ) + endif +endif + +if host_machine.cpu_family().startswith('x86') and cc.get_id() != 'msvc' + pre_args += '-DUSE_SSE41' + with_sse41 = true + sse41_args = ['-msse4.1'] + + # GCC on x86 (not x86_64) with -msse* assumes a 16 byte aligned stack, but + # that's not guaranteed + if host_machine.cpu_family() == 'x86' + sse41_args += '-mstackrealign' + endif +else + with_sse41 = false + sse41_args = [] +endif + +# Check for GCC style atomics +dep_atomic = null_dep + +if cc.compiles('''#include <stdint.h> + int main() { + struct { + uint64_t *v; + } x; + return (int)__atomic_load_n(x.v, __ATOMIC_ACQUIRE) & + (int)__atomic_add_fetch(x.v, (uint64_t)1, __ATOMIC_ACQ_REL); + + }''', + name : 'GCC atomic builtins') + pre_args += '-DUSE_GCC_ATOMIC_BUILTINS' + + # Not all atomic calls can be turned into lock-free instructions, in which + # GCC will make calls into the libatomic library. Check whether we need to + # link with -latomic. + # + # This can happen for 64-bit atomic operations on 32-bit architectures such + # as ARM. + if not cc.links('''#include <stdint.h> + int main() { + struct { + uint64_t *v; + } x; + return (int)__atomic_load_n(x.v, __ATOMIC_ACQUIRE) & + (int)__atomic_add_fetch(x.v, (uint64_t)1, __ATOMIC_ACQ_REL); + }''', + name : 'GCC atomic builtins required -latomic') + dep_atomic = cc.find_library('atomic') + endif +endif +if not cc.links('''#include <stdint.h> + uint64_t v; + int main() { + return __sync_add_and_fetch(&v, (uint64_t)1); + }''', + dependencies : dep_atomic, + name : 'GCC 64bit atomics') + pre_args += '-DMISSING_64BIT_ATOMICS' +endif + +dep_ws2_32 = cc.find_library('ws2_32', required : with_platform_windows) + +# TODO: shared/static? Is this even worth doing? + +with_asm_arch = '' +if host_machine.cpu_family() == 'x86' + if system_has_kms_drm or host_machine.system() == 'gnu' + with_asm_arch = 'x86' + pre_args += ['-DUSE_X86_ASM', '-DUSE_MMX_ASM', '-DUSE_3DNOW_ASM', + '-DUSE_SSE_ASM'] + + if with_glx_read_only_text + pre_args += ['-DGLX_X86_READONLY_TEXT'] + endif + endif +elif host_machine.cpu_family() == 'x86_64' + if system_has_kms_drm + with_asm_arch = 'x86_64' + pre_args += ['-DUSE_X86_64_ASM'] + endif +elif host_machine.cpu_family() == 'arm' + if system_has_kms_drm + with_asm_arch = 'arm' + pre_args += ['-DUSE_ARM_ASM'] + endif +elif host_machine.cpu_family() == 'aarch64' + if system_has_kms_drm + with_asm_arch = 'aarch64' + pre_args += ['-DUSE_AARCH64_ASM'] + endif +elif host_machine.cpu_family() == 'sparc64' + if system_has_kms_drm + with_asm_arch = 'sparc' + pre_args += ['-DUSE_SPARC_ASM'] + endif +elif host_machine.cpu_family().startswith('ppc64') and host_machine.endian() == 'little' + if system_has_kms_drm + with_asm_arch = 'ppc64le' + pre_args += ['-DUSE_PPC64LE_ASM'] + endif +endif + +# Check for standard headers and functions +if (cc.has_header_symbol('sys/sysmacros.h', 'major') and + cc.has_header_symbol('sys/sysmacros.h', 'minor') and + cc.has_header_symbol('sys/sysmacros.h', 'makedev')) + pre_args += '-DMAJOR_IN_SYSMACROS' +endif +if (cc.has_header_symbol('sys/mkdev.h', 'major') and + cc.has_header_symbol('sys/mkdev.h', 'minor') and + cc.has_header_symbol('sys/mkdev.h', 'makedev')) + pre_args += '-DMAJOR_IN_MKDEV' +endif + +if not ['linux'].contains(host_machine.system()) + # Deprecated on Linux and requires <sys/types.h> on FreeBSD and OpenBSD + if cc.compiles('#include <sys/types.h>\n#include <sys/sysctl.h>', name : 'sys/sysctl.h') + pre_args += '-DHAVE_SYS_SYSCTL_H' + endif +endif + +foreach h : ['xlocale.h', 'linux/futex.h', 'endian.h', 'dlfcn.h', 'execinfo.h', 'sys/shm.h', 'cet.h', 'pthread_np.h'] + if cc.compiles('#include <@0@>'.format(h), name : '@0@'.format(h)) + pre_args += '-DHAVE_@0@'.format(h.to_upper().underscorify()) + endif +endforeach + +foreach f : ['strtof', 'mkostemp', 'timespec_get', 'memfd_create', 'random_r', 'flock', 'strtok_r'] + if cc.has_function(f) + pre_args += '-DHAVE_@0@'.format(f.to_upper()) + endif +endforeach + +if cc.has_header_symbol('errno.h', 'program_invocation_name', + args : '-D_GNU_SOURCE') + pre_args += '-DHAVE_PROGRAM_INVOCATION_NAME' +elif with_tools.contains('intel') + error('Intel tools require the program_invocation_name variable') +endif + +# MinGW provides a __builtin_posix_memalign function, but not a posix_memalign. +# This means that this check will succeed, but then compilation will later +# fail. MSVC doesn't have this function at all, so only check for it on +# non-windows platforms. +if host_machine.system() != 'windows' + if cc.has_function('posix_memalign') + pre_args += '-DHAVE_POSIX_MEMALIGN' + endif +endif + +if cc.has_member('struct dirent', 'd_type', prefix: '''#include <sys/types.h> + #include <dirent.h>''') + pre_args += '-DHAVE_DIRENT_D_TYPE' +endif + +# strtod locale support +if cc.links(''' + #define _GNU_SOURCE + #include <stdlib.h> + #include <locale.h> + #ifdef HAVE_XLOCALE_H + #include <xlocale.h> + #endif + int main() { + locale_t loc = newlocale(LC_CTYPE_MASK, "C", NULL); + const char *s = "1.0"; + char *end; + double d = strtod_l(s, end, loc); + float f = strtof_l(s, end, loc); + freelocale(loc); + return 0; + }''', + args : pre_args, + name : 'strtod has locale support') + pre_args += '-DHAVE_STRTOD_L' +endif + +# Check for some linker flags +ld_args_bsymbolic = [] +if cc.links('int main() { return 0; }', args : '-Wl,-Bsymbolic', name : 'Bsymbolic') + ld_args_bsymbolic += '-Wl,-Bsymbolic' +endif +ld_args_gc_sections = [] +if cc.links('static char unused() { return 5; } int main() { return 0; }', + args : '-Wl,--gc-sections', name : 'gc-sections') + ld_args_gc_sections += '-Wl,--gc-sections' +endif +with_ld_version_script = false +if cc.links('int main() { return 0; }', + args : '-Wl,--version-script=@0@'.format( + join_paths(meson.source_root(), 'build-support/conftest.map')), + name : 'version-script') + with_ld_version_script = true +endif +with_ld_dynamic_list = false +if cc.links('int main() { return 0; }', + args : '-Wl,--dynamic-list=@0@'.format( + join_paths(meson.source_root(), 'build-support/conftest.dyn')), + name : 'dynamic-list') + with_ld_dynamic_list = true +endif + +ld_args_build_id = cc.get_supported_link_arguments('-Wl,--build-id=sha1') + +# check for dl support +dep_dl = null_dep +if not cc.has_function('dlopen') + dep_dl = cc.find_library('dl', required : host_machine.system() != 'windows') +endif +if cc.has_function('dladdr', dependencies : dep_dl) + # This is really only required for megadrivers + pre_args += '-DHAVE_DLADDR' +endif + +if cc.has_function('dl_iterate_phdr') + pre_args += '-DHAVE_DL_ITERATE_PHDR' +elif with_intel_vk + error('Intel "Anvil" Vulkan driver requires the dl_iterate_phdr function') +elif with_dri_i965 and with_shader_cache + error('Intel i965 GL driver requires dl_iterate_phdr when built with shader caching.') +endif + +# Determine whether or not the rt library is needed for time functions +if host_machine.system() == 'windows' or cc.has_function('clock_gettime') + dep_clock = null_dep +else + dep_clock = cc.find_library('rt') +endif + +# TODO: some of these may be conditional +dep_zlib = dependency('zlib', version : '>= 1.2.3', fallback : ['zlib', 'zlib_dep']) +pre_args += '-DHAVE_ZLIB' + +_zstd = get_option('zstd') +if _zstd != 'false' + dep_zstd = dependency('libzstd', required : _zstd == 'true') + if dep_zstd.found() + pre_args += '-DHAVE_ZSTD' + endif +else + dep_zstd = null_dep +endif + +# hack for essence +dep_thread = declare_dependency() +pre_args += '-DHAVE_PTHREAD' + +if host_machine.system() != 'windows' + dep_expat = dependency('expat', fallback : ['expat', 'expat_dep']) +else + dep_expat = null_dep +endif +# this only exists on linux so either this is linux and it will be found, or +# it's not linux and wont +dep_m = cc.find_library('m', required : false) + +# Check for libdrm. Various drivers have different libdrm version requirements, +# but we always want to use the same version for all libdrm modules. That means +# even if driver foo requires 2.4.0 and driver bar requires 2.4.3, if foo and +# bar are both on use 2.4.3 for both of them +dep_libdrm_amdgpu = null_dep +dep_libdrm_radeon = null_dep +dep_libdrm_nouveau = null_dep +dep_libdrm_intel = null_dep + +_drm_amdgpu_ver = '2.4.100' +_drm_radeon_ver = '2.4.71' +_drm_nouveau_ver = '2.4.66' +_drm_intel_ver = '2.4.75' +_drm_ver = '2.4.81' + +_libdrm_checks = [ + ['intel', with_dri_i915 or with_gallium_i915], + ['amdgpu', with_amd_vk or with_gallium_radeonsi], + ['radeon', (with_gallium_radeonsi or with_dri_r100 or with_dri_r200 or + with_gallium_r300 or with_gallium_r600)], + ['nouveau', (with_gallium_nouveau or with_dri_nouveau)], +] + +# VC4 only needs core libdrm support of this version, not a libdrm_vc4 +# library. +if with_gallium_vc4 + _drm_ver = '2.4.89' +endif + +# etnaviv only needs core libdrm +if with_gallium_etnaviv + _drm_ver = '2.4.89' +endif + +# Loop over the enables versions and get the highest libdrm requirement for all +# active drivers. +_drm_blame = '' +foreach d : _libdrm_checks + ver = get_variable('_drm_@0@_ver'.format(d[0])) + if d[1] and ver.version_compare('>' + _drm_ver) + _drm_ver = ver + _drm_blame = d[0] + endif +endforeach +if _drm_blame != '' + message('libdrm @0@ needed because @1@ has the highest requirement'.format(_drm_ver, _drm_blame)) +endif + +# Then get each libdrm module +foreach d : _libdrm_checks + if d[1] + set_variable( + 'dep_libdrm_' + d[0], + dependency('libdrm_' + d[0], version : '>=' + _drm_ver) + ) + endif +endforeach + +with_gallium_drisw_kms = false +dep_libdrm = dependency( + 'libdrm', version : '>=' + _drm_ver, + # GNU/Hurd includes egl_dri2, without drm. + required : (with_dri2 and host_machine.system() != 'gnu') or with_dri3 +) +if dep_libdrm.found() + pre_args += '-DHAVE_LIBDRM' + if with_dri_platform == 'drm' and with_dri + with_gallium_drisw_kms = true + endif +endif + +llvm_modules = ['bitwriter', 'engine', 'mcdisassembler', 'mcjit', 'core', 'executionengine', 'scalaropts', 'transformutils', 'instcombine'] +llvm_optional_modules = ['coroutines'] +if with_amd_vk or with_gallium_radeonsi or with_gallium_r600 + llvm_modules += ['amdgpu', 'native', 'bitreader', 'ipo'] + if with_gallium_r600 + llvm_modules += 'asmparser' + endif +endif +if with_gallium_opencl + llvm_modules += [ + 'all-targets', 'linker', 'coverage', 'instrumentation', 'ipo', 'irreader', + 'lto', 'option', 'objcarcopts', 'profiledata', + ] +endif + +if with_amd_vk or with_gallium_radeonsi + _llvm_version = '>= 8.0.0' +elif with_gallium_swr + _llvm_version = '>= 6.0.0' +else + _llvm_version = '>= 3.9.0' +endif + +_shared_llvm = get_option('shared-llvm') +if _shared_llvm == 'auto' + _shared_llvm = (host_machine.system() != 'windows') +else + _shared_llvm = (_shared_llvm == 'true') +endif +_llvm = get_option('llvm') + +# the cmake method can only link statically, so don't attempt to use it if we +# want to link dynamically. Before 0.54.0 meson will try cmake even when shared +# linking is requested, so we need to force the config-tool method to be used +# in that case, but in 0.54.0 meson won't try the cmake method if shared +# linking is requested. +_llvm_method = 'auto' +if meson.version().version_compare('< 0.54.0') and _shared_llvm + _llvm_method = 'config-tool' +endif + +dep_llvm = null_dep +with_llvm = false +if _llvm != 'false' + dep_llvm = dependency( + 'llvm', + version : _llvm_version, + modules : llvm_modules, + optional_modules : llvm_optional_modules, + required : ( + with_amd_vk or with_gallium_radeonsi or with_gallium_swr or + with_gallium_opencl or _llvm == 'true' + ), + static : not _shared_llvm, + method : _llvm_method, + fallback : ['llvm', 'dep_llvm'], + ) + with_llvm = dep_llvm.found() +endif +if with_llvm + pre_args += '-DLLVM_AVAILABLE' + pre_args += '-DMESA_LLVM_VERSION_STRING="@0@"'.format(dep_llvm.version()) + + # LLVM can be built without rtti, turning off rtti changes the ABI of C++ + # programs, so we need to build all C++ code in mesa without rtti as well to + # ensure that linking works. + # + # In meson 0.51.0 we can use cmake to find LLVM in addittion to meson's + # builtin llvm-config based finder. A new generic variable getter method + # has also been added, so we'll use that if we can, to cover the cmake case. + if dep_llvm.type_name() == 'internal' + _rtti = subproject('llvm').get_variable('has_rtti', true) + elif meson.version().version_compare('>=0.51') + # The CMake finder will return 'ON', the llvm-config will return 'YES' + _rtti = ['ON', 'YES'].contains(dep_llvm.get_variable(cmake : 'LLVM_ENABLE_RTTI', configtool: 'has-rtti')) + else + _rtti = dep_llvm.get_configtool_variable('has-rtti') == 'YES' + endif + if not _rtti + if with_gallium_nouveau + error('The Nouveau driver requires rtti. You either need to turn off nouveau or use an LLVM built with LLVM_ENABLE_RTTI.') + elif with_gallium_opencl + error('The Clover OpenCL state tracker requires rtti, you need to turn off clover or use an LLVM built with LLVM_ENABLE_RTTI.') + endif + if cc.get_id() == 'msvc' + cpp_args += '/GR-' + else + cpp_args += '-fno-rtti' + endif + endif +elif with_amd_vk or with_gallium_radeonsi or with_gallium_swr + error('The following drivers require LLVM: Radv, RadeonSI, SWR. One of these is enabled, but LLVM is disabled.') +elif with_gallium_opencl + error('The OpenCL "Clover" state tracker requires LLVM, but LLVM is disabled.') +endif + +if (with_amd_vk or with_gallium_radeonsi or with_gallium_opencl or + (with_gallium_r600 and with_llvm)) + dep_elf = dependency('libelf', required : false) + if not dep_elf.found() + dep_elf = cc.find_library('elf') + endif +else + dep_elf = null_dep +endif + +dep_glvnd = null_dep +if with_glvnd + dep_glvnd = dependency('libglvnd', version : '>= 1.2.0') + pre_args += '-DUSE_LIBGLVND=1' +endif + +if with_valgrind != 'false' + dep_valgrind = dependency('valgrind', required : with_valgrind == 'true') + if dep_valgrind.found() + pre_args += '-DHAVE_VALGRIND' + endif +else + dep_valgrind = null_dep +endif + +# pthread stubs. Lets not and say we didn't + +if host_machine.system() == 'windows' + # Prefer the winflexbison versions, they're much easier to install and have + # better windows support. + + prog_flex = find_program('win_flex', required : false) + if prog_flex.found() + # windows compatibility (uses <io.h> instead of <unistd.h> and _isatty, + # _fileno functions) + prog_flex = [prog_flex, '--wincompat', '-D__STDC_VERSION__=199901'] + else + prog_flex = [find_program('lex', 'flex', required : with_any_opengl)] + endif + # Force flex to use const keyword in prototypes, as relies on __cplusplus or + # __STDC__ macro to determine whether it's safe to use const keyword, but + # MSVC never defines __STDC__ unless we disable all MSVC extensions. + prog_flex += '-DYY_USE_CONST=' + + prog_bison = find_program('win_bison', required : false) + if not prog_bison.found() + prog_bison = find_program('yacc', 'bison', required : with_any_opengl) + endif +else + prog_bison = find_program('bison', required : with_any_opengl) + + # Disable deprecated keyword warnings, since we have to use them for + # old-bison compat. See discussion in + # https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/2161 + if meson.version().version_compare('>= 0.52.0') and find_program('bison', required : false, version : '> 2.3').found() + prog_bison = [prog_bison, '-Wno-deprecated'] + endif + + prog_flex = find_program('flex', required : with_any_opengl) +endif + +dep_selinux = null_dep +if get_option('selinux') + dep_selinux = dependency('libselinux') + pre_args += '-DMESA_SELINUX' +endif + +if with_libunwind != 'false' + dep_unwind = dependency('libunwind', required : with_libunwind == 'true') + if dep_unwind.found() + pre_args += '-DHAVE_LIBUNWIND' + endif +else + dep_unwind = null_dep +endif + +if with_osmesa != 'none' + if with_osmesa == 'gallium' and not with_gallium_softpipe + error('OSMesa gallium requires gallium softpipe or llvmpipe.') + endif + if host_machine.system() == 'windows' + osmesa_lib_name = 'osmesa' + else + osmesa_lib_name = 'OSMesa' + endif + osmesa_bits = get_option('osmesa-bits') + if osmesa_bits != '8' + if with_dri or with_glx != 'disabled' + error('OSMesa bits must be 8 if building glx or dir based drivers') + endif + osmesa_lib_name = osmesa_lib_name + osmesa_bits + pre_args += [ + '-DCHAN_BITS=@0@'.format(osmesa_bits), '-DDEFAULT_SOFTWARE_DEPTH_BITS=31' + ] + endif +endif + +# TODO: symbol mangling + +if with_platform_wayland + dep_wl_scanner = dependency('wayland-scanner', native: true) + prog_wl_scanner = find_program(dep_wl_scanner.get_pkgconfig_variable('wayland_scanner')) + if dep_wl_scanner.version().version_compare('>= 1.15') + wl_scanner_arg = 'private-code' + else + wl_scanner_arg = 'code' + endif + dep_wl_protocols = dependency('wayland-protocols', version : '>= 1.8') + dep_wayland_client = dependency('wayland-client', version : '>=1.11') + dep_wayland_server = dependency('wayland-server', version : '>=1.11') + if with_egl + dep_wayland_egl = dependency('wayland-egl-backend', version : '>= 3') + dep_wayland_egl_headers = dep_wayland_egl.partial_dependency(compile_args : true) + endif + wayland_dmabuf_xml = join_paths( + dep_wl_protocols.get_pkgconfig_variable('pkgdatadir'), 'unstable', + 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml' + ) + pre_args += ['-DHAVE_WAYLAND_PLATFORM', '-DWL_HIDE_DEPRECATED'] +endif + +dep_x11 = null_dep +dep_xext = null_dep +dep_xdamage = null_dep +dep_xfixes = null_dep +dep_x11_xcb = null_dep +dep_xcb = null_dep +dep_xcb_glx = null_dep +dep_xcb_dri2 = null_dep +dep_xcb_dri3 = null_dep +dep_dri2proto = null_dep +dep_glproto = null_dep +dep_xxf86vm = null_dep +dep_xcb_dri3 = null_dep +dep_xcb_present = null_dep +dep_xcb_sync = null_dep +dep_xcb_xfixes = null_dep +dep_xshmfence = null_dep +dep_xcb_xrandr = null_dep +dep_xlib_xrandr = null_dep +if with_platform_x11 + if with_glx == 'xlib' or with_glx == 'gallium-xlib' + dep_x11 = dependency('x11') + dep_xext = dependency('xext') + dep_xcb = dependency('xcb') + elif with_glx == 'dri' + dep_x11 = dependency('x11') + dep_xext = dependency('xext') + dep_xdamage = dependency('xdamage', version : '>= 1.1') + dep_xfixes = dependency('xfixes') + dep_xcb_glx = dependency('xcb-glx', version : '>= 1.8.1') + endif + if (with_any_vk or with_glx == 'dri' or with_egl or + (with_gallium_vdpau or with_gallium_xvmc or with_gallium_va or + with_gallium_omx != 'disabled')) + dep_xcb = dependency('xcb') + dep_x11_xcb = dependency('x11-xcb') + if with_dri_platform == 'drm' and not dep_libdrm.found() + error('libdrm required for gallium video statetrackers when using x11') + endif + endif + if with_any_vk or with_egl or (with_glx == 'dri' and with_dri_platform == 'drm') + dep_xcb_dri2 = dependency('xcb-dri2', version : '>= 1.8') + + if with_dri3 + pre_args += '-DHAVE_DRI3' + dep_xcb_dri3 = dependency('xcb-dri3') + dep_xcb_present = dependency('xcb-present') + # until xcb-dri3 has been around long enough to make a hard-dependency: + if (dep_xcb_dri3.version().version_compare('>= 1.13') and + dep_xcb_present.version().version_compare('>= 1.13')) + pre_args += '-DHAVE_DRI3_MODIFIERS' + endif + dep_xcb_sync = dependency('xcb-sync') + dep_xshmfence = dependency('xshmfence', version : '>= 1.1') + endif + endif + if with_glx == 'dri' or with_glx == 'gallium-xlib' + dep_glproto = dependency('glproto', version : '>= 1.4.14') + endif + if with_glx == 'dri' + if with_dri_platform == 'drm' + dep_dri2proto = dependency('dri2proto', version : '>= 2.8') + dep_xxf86vm = dependency('xxf86vm') + endif + endif + if (with_egl or ( + with_gallium_vdpau or with_gallium_xvmc or with_gallium_xa or + with_gallium_omx != 'disabled')) + dep_xcb_xfixes = dependency('xcb-xfixes') + endif + if with_xlib_lease + dep_xcb_xrandr = dependency('xcb-randr') + dep_xlib_xrandr = dependency('xrandr', version : '>= 1.3') + endif +endif + +if get_option('gallium-extra-hud') + pre_args += '-DHAVE_GALLIUM_EXTRA_HUD=1' +endif + +_sensors = get_option('lmsensors') +if _sensors != 'false' + dep_lmsensors = cc.find_library('sensors', required : _sensors == 'true') + if dep_lmsensors.found() + pre_args += '-DHAVE_LIBSENSORS=1' + endif +else + dep_lmsensors = null_dep +endif + +foreach a : pre_args + add_project_arguments(a, language : ['c', 'cpp']) +endforeach +foreach a : c_args + add_project_arguments(a, language : ['c']) +endforeach +foreach a : cpp_args + add_project_arguments(a, language : ['cpp']) +endforeach + +gl_priv_reqs = [] + +if with_glx == 'xlib' or with_glx == 'gallium-xlib' + gl_priv_reqs += ['x11', 'xext', 'xcb'] +elif with_glx == 'dri' + gl_priv_reqs += [ + 'x11', 'xext', 'xdamage >= 1.1', 'xfixes', 'x11-xcb', 'xcb', + 'xcb-glx >= 1.8.1'] + if with_dri_platform == 'drm' + gl_priv_reqs += 'xcb-dri2 >= 1.8' + gl_priv_reqs += 'xxf86vm' + endif +endif +if dep_libdrm.found() + gl_priv_reqs += 'libdrm >= 2.4.75' +endif + +gl_priv_libs = [] +if dep_thread.found() + gl_priv_libs += ['-lpthread'] +endif +if dep_m.found() + gl_priv_libs += '-lm' +endif +if dep_dl.found() + gl_priv_libs += '-ldl' +endif + +# FIXME: autotools lists this as incomplete +gbm_priv_libs = [] +if dep_dl.found() + gbm_priv_libs += '-ldl' +endif + +pkg = import('pkgconfig') + +if host_machine.system() == 'windows' + prog_dumpbin = find_program('dumpbin', required : false) + with_symbols_check = prog_dumpbin.found() and with_tests + symbols_check_args = ['--dumpbin', prog_dumpbin.path()] +else + prog_nm = find_program('nm') + with_symbols_check = with_tests + symbols_check_args = ['--nm', prog_nm.path()] +endif + +# This quirk needs to be applied to sources with functions defined in assembly +# as GCC LTO drops them. See: https://bugs.freedesktop.org/show_bug.cgi?id=109391 +gcc_lto_quirk = (cc.get_id() == 'gcc') ? ['-fno-lto'] : [] + +subdir('include') +subdir('bin') +subdir('src') + +# Meson 0.49 and earlier seems to have a bug that fails to evaluate the string- +# formatting below unless the first argument is passed as a variable. This has +# been fixed in Meson 0.50 and beyond, but we need to keep it like this for now +# for backwards compatibility. +_with_opengl_string = with_opengl ? 'yes' : 'no' + +lines = ['', + 'prefix: ' + get_option('prefix'), + 'libdir: ' + get_option('libdir'), + 'includedir: ' + get_option('includedir'), + '', + 'OpenGL: @0@ (ES1: @1@ ES2: @2@)'.format(_with_opengl_string, + with_gles1 ? 'yes' : 'no', + with_gles2 ? 'yes' : 'no'), +] + +if with_osmesa != 'none' + lines += '' + suffix = '' + if with_osmesa == 'gallium' + suffix = '(Gallium)' + endif + lines += 'OSMesa: lib' + osmesa_lib_name + suffix +else + lines += 'OSMesa: no' +endif + +if with_dri + lines += '' + lines += 'DRI platform: ' + with_dri_platform + if dri_drivers.length() != 0 and dri_drivers != [''] + lines += 'DRI drivers: ' + ' '.join(dri_drivers) + else + lines += 'DRI drivers: no' + endif + lines += 'DRI driver dir: ' + dri_drivers_path +endif + +if with_glx != 'disabled' + lines += '' + if with_glx == 'dri' + lines += 'GLX: DRI-based' + elif with_glx == 'xlib' + lines += 'GLX: Xlib-based' + elif with_glx == 'gallium-xlib' + lines += 'GLX: Xlib-based (Gallium)' + else + lines += 'GLX: ' + with_glx + endif +endif + +lines += '' +lines += 'EGL: ' + (with_egl ? 'yes' : 'no') +if with_egl + egl_drivers = [] + if with_dri + egl_drivers += 'builtin:egl_dri2' + endif + if with_dri3 + egl_drivers += 'builtin:egl_dri3' + endif + lines += 'EGL drivers: ' + ' '.join(egl_drivers) +endif +lines += 'GBM: ' + (with_gbm ? 'yes' : 'no') +if with_platforms + lines += 'EGL/Vulkan/VL platforms: ' + ' '.join(_platforms) +endif + +lines += '' +if with_any_vk + lines += 'Vulkan drivers: ' + ' '.join(_vulkan_drivers) + lines += 'Vulkan ICD dir: ' + with_vulkan_icd_dir +else + lines += 'Vulkan drivers: no' +endif + +lines += '' +if with_llvm + lines += 'llvm: yes' + lines += 'llvm-version: ' + dep_llvm.version() +else + lines += 'llvm: no' +endif + +lines += '' +if with_gallium + lines += 'Gallium drivers: ' + ' '.join(gallium_drivers) + gallium_st = ['mesa'] + if with_gallium_xa + gallium_st += 'xa' + endif + if with_gallium_xvmc + gallium_st += 'xvmc' + endif + if with_gallium_xvmc + gallium_st += 'xvmc' + endif + if with_gallium_vdpau + gallium_st += 'vdpau' + endif + if with_gallium_omx != 'disabled' + gallium_st += 'omx' + with_gallium_omx + endif + if with_gallium_va + gallium_st += 'va' + endif + if with_gallium_st_nine + gallium_st += 'nine' + endif + if with_gallium_opencl + gallium_st += 'clover' + endif + lines += 'Gallium st: ' + ' '.join(gallium_st) +else + lines += 'Gallium: no' +endif + +lines += 'HUD lmsensors: ' + (dep_lmsensors.found() ? 'yes' : 'no') + +lines += '' +lines += 'Shared-glapi: ' + (with_shared_glapi ? 'yes' : 'no') + + +indent = ' ' +summary = indent + ('\n' + indent).join(lines) +message('Configuration summary:\n@0@\n'.format(summary)) diff --git a/ports/mesa/changes/src_gallium_targets_osmesa_meson.build b/ports/mesa/changes/src_gallium_targets_osmesa_meson.build new file mode 100644 index 0000000..3b11bce --- /dev/null +++ b/ports/mesa/changes/src_gallium_targets_osmesa_meson.build @@ -0,0 +1,86 @@ +# Copyright © 2017 Intel Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +osmesa_link_with = [] +osmesa_link_args = [] +osmesa_link_deps = [] + +if with_shared_glapi + osmesa_link_with += libglapi +endif +if with_ld_version_script + osmesa_link_args += [ + '-Wl,--version-script', join_paths(meson.current_source_dir(), 'osmesa.sym') + ] + osmesa_link_deps += files('osmesa.sym') +endif + +if cc.get_id() == 'gcc' and host_machine.cpu_family() != 'x86_64' + osmesa_def = 'osmesa.mingw.def' +else + osmesa_def = 'osmesa.def' +endif + +libosmesa = static_library( + osmesa_lib_name, + 'target.c', + c_args : [c_vis_args], + cpp_args : cpp_vis_args, + link_args : [ld_args_gc_sections, osmesa_link_args], + vs_module_defs : osmesa_def, + include_directories : [ + inc_include, inc_src, inc_gallium, inc_gallium_aux, inc_gallium_winsys, + inc_gallium_drivers, + ], + link_depends : osmesa_link_deps, + link_whole : [libosmesa_st, libglapi_static], + link_with : [ + libmesa_gallium, libgallium, libws_null, osmesa_link_with, + ], + dependencies : [ + dep_ws2_32, dep_selinux, dep_thread, dep_clock, dep_unwind, + driver_swrast, driver_swr, + ], + name_prefix : host_machine.system() == 'windows' ? '' : 'lib', # otherwise mingw will create libosmesa.dll + soversion : host_machine.system() == 'windows' ? '' : '8', + version : '8.0.0', + install : true, +) + +pkg.generate( + name : 'osmesa', + description : 'Mesa Off-screen Rendering Library', + version : '8.0.0', + libraries : libosmesa, + libraries_private : gl_priv_libs, +) + +if with_tests + test('osmesa-render', + executable( + 'osmesa-render', + 'test-render.cpp', + include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux], + link_with: libosmesa, + dependencies : [idep_gtest], + ), + suite: 'gallium' + ) +endif diff --git a/ports/mesa/changes/src_util_anon_file.c b/ports/mesa/changes/src_util_anon_file.c new file mode 100644 index 0000000..c23dccc --- /dev/null +++ b/ports/mesa/changes/src_util_anon_file.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Based on weston shared/os-compatibility.c + */ + +#ifndef _WIN32 +#include "anon_file.h" + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#include <sys/mman.h> +#elif defined(HAVE_MEMFD_CREATE) || defined(ANDROID) +#include <sys/syscall.h> +#ifndef OS_ESSENCE +#include <linux/memfd.h> +#else +#include <sys/mman.h> +#endif +#else +#include <stdio.h> +#endif + +#if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(HAVE_MKOSTEMP) || defined(ANDROID)) +static int +set_cloexec_or_close(int fd) +{ + long flags; + + if (fd == -1) + return -1; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + goto err; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + goto err; + + return fd; + +err: + close(fd); + return -1; +} +#endif + +#if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(ANDROID)) +static int +create_tmpfile_cloexec(char *tmpname) +{ + int fd; + +#ifdef HAVE_MKOSTEMP + fd = mkostemp(tmpname, O_CLOEXEC); +#else + fd = mkstemp(tmpname); +#endif + + if (fd < 0) { + return fd; + } + +#ifndef HAVE_MKOSTEMP + fd = set_cloexec_or_close(fd); +#endif + + unlink(tmpname); + return fd; +} +#endif + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * An optional name for debugging can be provided as the second argument. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * If memfd or SHM_ANON is supported, the filesystem is not touched at all. + * Otherwise, the file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + */ +int +os_create_anonymous_file(off_t size, const char *debug_name) +{ + int fd, ret; +#ifdef __FreeBSD__ + (void*)debug_name; + fd = shm_open(SHM_ANON, O_CREAT | O_RDWR | O_CLOEXEC, 0600); +#elif defined(__OpenBSD__) + char template[] = "/tmp/mesa-XXXXXXXXXX"; + fd = shm_mkstemp(template); + if (fd != -1) + shm_unlink(template); +#elif defined(HAVE_MEMFD_CREATE) || defined(ANDROID) + if (!debug_name) + debug_name = "mesa-shared"; + fd = syscall(SYS_memfd_create, debug_name, MFD_CLOEXEC); +#else + const char *path; + char *name; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + + if (debug_name) + asprintf(&name, "%s/mesa-shared-%s-XXXXXX", path, debug_name); + else + asprintf(&name, "%s/mesa-shared-XXXXXX", path); + if (!name) + return -1; + + fd = create_tmpfile_cloexec(name); + + free(name); +#endif + + if (fd < 0) + return -1; + + ret = ftruncate(fd, size); + if (ret < 0) { + close(fd); + return -1; + } + + return fd; +} +#endif diff --git a/ports/mesa/changes/src_util_detect_os.h b/ports/mesa/changes/src_util_detect_os.h new file mode 100644 index 0000000..027a03e --- /dev/null +++ b/ports/mesa/changes/src_util_detect_os.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright 2008 VMware, Inc. */ + +/** + * Auto-detect the operating system family. + * + * See also: + * - http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html + * - echo | gcc -dM -E - | sort + * - http://msdn.microsoft.com/en-us/library/b0084kay.aspx + * + * @author José Fonseca <jfonseca@vmware.com> + */ + +#ifndef DETECT_OS_H +#define DETECT_OS_H + +#if defined(__linux__) +#define DETECT_OS_LINUX 1 +#define DETECT_OS_UNIX 1 +#endif + +/* + * Android defines __linux__, so DETECT_OS_LINUX and DETECT_OS_UNIX will + * also be defined. + */ +#if defined(ANDROID) +#define DETECT_OS_ANDROID 1 +#endif + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#define DETECT_OS_FREEBSD 1 +#define DETECT_OS_BSD 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(__OpenBSD__) +#define DETECT_OS_OPENBSD 1 +#define DETECT_OS_BSD 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(__NetBSD__) +#define DETECT_OS_NETBSD 1 +#define DETECT_OS_BSD 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(__DragonFly__) +#define DETECT_OS_DRAGONFLY 1 +#define DETECT_OS_BSD 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(__GNU__) +#define DETECT_OS_HURD 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(__sun) +#define DETECT_OS_SOLARIS 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(__APPLE__) +#define DETECT_OS_APPLE 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(_WIN32) || defined(WIN32) +#define DETECT_OS_WINDOWS 1 +#endif + +#if defined(__HAIKU__) +#define DETECT_OS_HAIKU 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(__CYGWIN__) +#define DETECT_OS_CYGWIN 1 +#define DETECT_OS_UNIX 1 +#endif + +#if defined(OS_ESSENCE) +#define DETECT_OS_UNIX 1 +#define DETECT_OS_ESSENCE 1 +#endif + + +/* + * Make sure DETECT_OS_* are always defined, so that they can be used with #if + */ +#ifndef DETECT_OS_ANDROID +#define DETECT_OS_ANDROID 0 +#endif +#ifndef DETECT_OS_APPLE +#define DETECT_OS_APPLE 0 +#endif +#ifndef DETECT_OS_BSD +#define DETECT_OS_BSD 0 +#endif +#ifndef DETECT_OS_CYGWIN +#define DETECT_OS_CYGWIN 0 +#endif +#ifndef DETECT_OS_DRAGONFLY +#define DETECT_OS_DRAGONFLY 0 +#endif +#ifndef DETECT_OS_FREEBSD +#define DETECT_OS_FREEBSD 0 +#endif +#ifndef DETECT_OS_HAIKU +#define DETECT_OS_HAIKU 0 +#endif +#ifndef DETECT_OS_HURD +#define DETECT_OS_HURD 0 +#endif +#ifndef DETECT_OS_LINUX +#define DETECT_OS_LINUX 0 +#endif +#ifndef DETECT_OS_NETBSD +#define DETECT_OS_NETBSD 0 +#endif +#ifndef DETECT_OS_OPENBSD +#define DETECT_OS_OPENBSD 0 +#endif +#ifndef DETECT_OS_SOLARIS +#define DETECT_OS_SOLARIS 0 +#endif +#ifndef DETECT_OS_UNIX +#define DETECT_OS_UNIX 0 +#endif +#ifndef DETECT_OS_WINDOWS +#define DETECT_OS_WINDOWS 0 +#endif + +#endif /* DETECT_OS_H */ diff --git a/ports/mesa/changes/src_util_os_misc.c b/ports/mesa/changes/src_util_os_misc.c new file mode 100644 index 0000000..4f9b32a --- /dev/null +++ b/ports/mesa/changes/src_util_os_misc.c @@ -0,0 +1,235 @@ +/************************************************************************** + * + * Copyright 2008-2010 Vmware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "os_misc.h" +#include "os_file.h" +#include "macros.h" + +#include <stdarg.h> + + +#if DETECT_OS_WINDOWS + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> + +#else + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#endif + + +#if DETECT_OS_ANDROID +# define LOG_TAG "MESA" +# include <unistd.h> +# include <log/log.h> +#elif DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD || DETECT_OS_ESSENCE +# include <unistd.h> +#elif DETECT_OS_OPENBSD +# include <sys/resource.h> +# include <sys/sysctl.h> +#elif DETECT_OS_APPLE || DETECT_OS_BSD +# include <sys/sysctl.h> +#elif DETECT_OS_HAIKU +# include <kernel/OS.h> +#elif DETECT_OS_WINDOWS +# include <windows.h> +#else +#error unexpected platform in os_sysinfo.c +#endif + + +void +os_log_message(const char *message) +{ + /* If the GALLIUM_LOG_FILE environment variable is set to a valid filename, + * write all messages to that file. + */ + static FILE *fout = NULL; + + if (!fout) { +#ifdef DEBUG + /* one-time init */ + const char *filename = os_get_option("GALLIUM_LOG_FILE"); + if (filename) { + const char *mode = "w"; + if (filename[0] == '+') { + /* If the filename is prefixed with '+' then open the file for + * appending instead of normal writing. + */ + mode = "a"; + filename++; /* skip the '+' */ + } + fout = fopen(filename, mode); + } +#endif + if (!fout) + fout = stderr; + } + +#if DETECT_OS_WINDOWS + OutputDebugStringA(message); + if(GetConsoleWindow() && !IsDebuggerPresent()) { + fflush(stdout); + fputs(message, fout); + fflush(fout); + } + else if (fout != stderr) { + fputs(message, fout); + fflush(fout); + } +#else /* !DETECT_OS_WINDOWS */ + fflush(stdout); + fputs(message, fout); + fflush(fout); +# if DETECT_OS_ANDROID + LOG_PRI(ANDROID_LOG_ERROR, LOG_TAG, "%s", message); +# endif +#endif +} + + +#if !defined(EMBEDDED_DEVICE) +const char * +os_get_option(const char *name) +{ + return getenv(name); +} +#endif /* !EMBEDDED_DEVICE */ + + +/** + * Return the size of the total physical memory. + * \param size returns the size of the total physical memory + * \return true for success, or false on failure + */ +bool +os_get_total_physical_memory(uint64_t *size) +{ +#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD || DETECT_OS_ESSENCE + const long phys_pages = sysconf(_SC_PHYS_PAGES); + const long page_size = sysconf(_SC_PAGE_SIZE); + + if (phys_pages <= 0 || page_size <= 0) + return false; + + *size = (uint64_t)phys_pages * (uint64_t)page_size; + return true; +#elif DETECT_OS_APPLE || DETECT_OS_BSD + size_t len = sizeof(*size); + int mib[2]; + + mib[0] = CTL_HW; +#if DETECT_OS_APPLE + mib[1] = HW_MEMSIZE; +#elif DETECT_OS_NETBSD || DETECT_OS_OPENBSD + mib[1] = HW_PHYSMEM64; +#elif DETECT_OS_FREEBSD + mib[1] = HW_REALMEM; +#elif DETECT_OS_DRAGONFLY + mib[1] = HW_PHYSMEM; +#else +#error Unsupported *BSD +#endif + + return (sysctl(mib, 2, size, &len, NULL, 0) == 0); +#elif DETECT_OS_HAIKU + system_info info; + status_t ret; + + ret = get_system_info(&info); + if (ret != B_OK || info.max_pages <= 0) + return false; + + *size = (uint64_t)info.max_pages * (uint64_t)B_PAGE_SIZE; + return true; +#elif DETECT_OS_WINDOWS + MEMORYSTATUSEX status; + BOOL ret; + + status.dwLength = sizeof(status); + ret = GlobalMemoryStatusEx(&status); + *size = status.ullTotalPhys; + return (ret == TRUE); +#else +#error unexpected platform in os_sysinfo.c + return false; +#endif +} + +bool +os_get_available_system_memory(uint64_t *size) +{ +#if DETECT_OS_LINUX + char *meminfo = os_read_file("/proc/meminfo", NULL); + if (!meminfo) + return false; + + char *str = strstr(meminfo, "MemAvailable:"); + if (!str) { + free(meminfo); + return false; + } + + uint64_t kb_mem_available; + if (sscanf(str, "MemAvailable: %" PRIx64, &kb_mem_available) == 1) { + free(meminfo); + *size = kb_mem_available << 10; + return true; + } + + free(meminfo); + return false; +#elif DETECT_OS_OPENBSD + struct rlimit rl; + int mib[] = { CTL_HW, HW_USERMEM64 }; + int64_t mem_available; + size_t len = sizeof(mem_available); + + /* physmem - wired */ + if (sysctl(mib, 2, &mem_available, &len, NULL, 0) == -1) + return false; + + /* static login.conf limit */ + if (getrlimit(RLIMIT_DATA, &rl) == -1) + return false; + + *size = MIN2(mem_available, rl.rlim_cur); + return true; +#else + return false; +#endif +} diff --git a/ports/mesa/changes/src_util_u_thread.h b/ports/mesa/changes/src_util_u_thread.h new file mode 100644 index 0000000..7548f00 --- /dev/null +++ b/ports/mesa/changes/src_util_u_thread.h @@ -0,0 +1,256 @@ +/************************************************************************** + * + * Copyright 1999-2006 Brian Paul + * Copyright 2008 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef U_THREAD_H_ +#define U_THREAD_H_ + +#include <stdint.h> +#include <stdbool.h> + +#include "c11/threads.h" +#include "detect_os.h" + +#ifdef HAVE_PTHREAD +#include <signal.h> +#ifdef HAVE_PTHREAD_NP_H +#include <pthread_np.h> +#endif +#endif + +#ifdef __HAIKU__ +#include <OS.h> +#endif + +#ifdef __FreeBSD__ +/* pthread_np.h -> sys/param.h -> machine/param.h + * - defines ALIGN which clashes with our ALIGN + */ +#undef ALIGN +#define cpu_set_t cpuset_t +#endif + +static inline thrd_t u_thread_create(int (*routine)(void *), void *param) +{ + thrd_t thread; +#ifdef HAVE_PTHREAD + sigset_t saved_set, new_set; + int ret; + + sigfillset(&new_set); + sigdelset(&new_set, SIGSYS); + pthread_sigmask(SIG_BLOCK, &new_set, &saved_set); + ret = thrd_create( &thread, routine, param ); + pthread_sigmask(SIG_SETMASK, &saved_set, NULL); +#else + int ret; + ret = thrd_create( &thread, routine, param ); +#endif + if (ret) + return 0; + + return thread; +} + +static inline void u_thread_setname( const char *name ) +{ +#if defined(HAVE_PTHREAD) +#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_ESSENCE + pthread_setname_np(pthread_self(), name); +#elif DETECT_OS_FREEBSD || DETECT_OS_OPENBSD + pthread_set_name_np(pthread_self(), name); +#elif DETECT_OS_NETBSD + pthread_setname_np(pthread_self(), "%s", (void *)name); +#elif DETECT_OS_APPLE + pthread_setname_np(name); +#elif DETECT_OS_HAIKU + rename_thread(find_thread(NULL), name); +#else +#warning Not sure how to call pthread_setname_np +#endif +#endif + (void)name; +} + +/** + * An AMD Zen CPU consists of multiple modules where each module has its own L3 + * cache. Inter-thread communication such as locks and atomics between modules + * is very expensive. It's desirable to pin a group of closely cooperating + * threads to one group of cores sharing L3. + * + * \param thread thread + * \param L3_index index of the L3 cache + * \param cores_per_L3 number of CPU cores shared by one L3 + */ +static inline void +util_pin_thread_to_L3(thrd_t thread, unsigned L3_index, unsigned cores_per_L3) +{ +#if defined(HAVE_PTHREAD_SETAFFINITY) + cpu_set_t cpuset; + + CPU_ZERO(&cpuset); + for (unsigned i = 0; i < cores_per_L3; i++) + CPU_SET(L3_index * cores_per_L3 + i, &cpuset); + pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset); +#endif +} + +/** + * Return the index of L3 that the thread is pinned to. If the thread is + * pinned to multiple L3 caches, return -1. + * + * \param thread thread + * \param cores_per_L3 number of CPU cores shared by one L3 + */ +static inline int +util_get_L3_for_pinned_thread(thrd_t thread, unsigned cores_per_L3) +{ +#if defined(HAVE_PTHREAD_SETAFFINITY) + cpu_set_t cpuset; + + if (pthread_getaffinity_np(thread, sizeof(cpuset), &cpuset) == 0) { + int L3_index = -1; + + for (unsigned i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, &cpuset)) { + int x = i / cores_per_L3; + + if (L3_index != x) { + if (L3_index == -1) + L3_index = x; + else + return -1; /* multiple L3s are set */ + } + } + } + return L3_index; + } +#endif + return -1; +} + +/* + * Thread statistics. + */ + +/* Return the time of a thread's CPU time clock. */ +static inline int64_t +u_thread_get_time_nano(thrd_t thread) +{ +#if defined(HAVE_PTHREAD) && !defined(__APPLE__) && !defined(__HAIKU__) + struct timespec ts; + clockid_t cid; + + pthread_getcpuclockid(thread, &cid); + clock_gettime(cid, &ts); + return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; +#else + return 0; +#endif +} + +static inline bool u_thread_is_self(thrd_t thread) +{ +#if defined(HAVE_PTHREAD) + return pthread_equal(pthread_self(), thread); +#endif + return false; +} + +/* + * util_barrier + */ + +#if defined(HAVE_PTHREAD) && !defined(__APPLE__) + +typedef pthread_barrier_t util_barrier; + +static inline void util_barrier_init(util_barrier *barrier, unsigned count) +{ + pthread_barrier_init(barrier, NULL, count); +} + +static inline void util_barrier_destroy(util_barrier *barrier) +{ + pthread_barrier_destroy(barrier); +} + +static inline void util_barrier_wait(util_barrier *barrier) +{ + pthread_barrier_wait(barrier); +} + + +#else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */ + +typedef struct { + unsigned count; + unsigned waiters; + uint64_t sequence; + mtx_t mutex; + cnd_t condvar; +} util_barrier; + +static inline void util_barrier_init(util_barrier *barrier, unsigned count) +{ + barrier->count = count; + barrier->waiters = 0; + barrier->sequence = 0; + (void) mtx_init(&barrier->mutex, mtx_plain); + cnd_init(&barrier->condvar); +} + +static inline void util_barrier_destroy(util_barrier *barrier) +{ + assert(barrier->waiters == 0); + mtx_destroy(&barrier->mutex); + cnd_destroy(&barrier->condvar); +} + +static inline void util_barrier_wait(util_barrier *barrier) +{ + mtx_lock(&barrier->mutex); + + assert(barrier->waiters < barrier->count); + barrier->waiters++; + + if (barrier->waiters < barrier->count) { + uint64_t sequence = barrier->sequence; + + do { + cnd_wait(&barrier->condvar, &barrier->mutex); + } while (sequence == barrier->sequence); + } else { + barrier->waiters = 0; + barrier->sequence++; + cnd_broadcast(&barrier->condvar); + } + + mtx_unlock(&barrier->mutex); +} + +#endif + +#endif /* U_THREAD_H_ */ diff --git a/ports/mesa/port.sh b/ports/mesa/port.sh new file mode 100755 index 0000000..d8e2582 --- /dev/null +++ b/ports/mesa/port.sh @@ -0,0 +1,47 @@ +set -e + +if [ ! -f "bin/mesa.tar.xz" ]; then + curl https://archive.mesa3d.org//mesa-20.1.8.tar.xz > bin/mesa.tar.xz +fi + +tar -xJf bin/mesa.tar.xz +mv mesa-20.1.8 bin/mesa + +echo "" > bin/meson_cross.txt +echo "[binaries]" >> bin/meson_cross.txt +echo "c = 'x86_64-essence-gcc'" >> bin/meson_cross.txt +echo "cpp = 'x86_64-essence-g++'" >> bin/meson_cross.txt +echo "ar = 'x86_64-essence-ar'" >> bin/meson_cross.txt +echo "strip = 'x86_64-essence-strip'" >> bin/meson_cross.txt +echo "[properties]" >> bin/meson_cross.txt +echo sys_root = \'$(realpath root)\' >> bin/meson_cross.txt +echo "c_args = ['-D_POSIX_SOURCE']" >> bin/meson_cross.txt +echo "cpp_args = c_args" >> bin/meson_cross.txt +echo "[host_machine]" >> bin/meson_cross.txt +echo "system = 'essence'" >> bin/meson_cross.txt +echo "cpu_family = 'x86_64'" >> bin/meson_cross.txt +echo "cpu = 'generic'" >> bin/meson_cross.txt +echo "endian = 'little'" >> bin/meson_cross.txt + +cp ports/mesa/changes/include_c11_threads_posix.h bin/mesa/include/c11/threads_posix.h +cp ports/mesa/changes/src_util_detect_os.h bin/mesa/src/util/detect_os.h +cp ports/mesa/changes/src_util_u_thread.h bin/mesa/src/util/u_thread.h +cp ports/mesa/changes/src_util_anon_file.c bin/mesa/src/util/anon_file.c +cp ports/mesa/changes/src_util_os_misc.c bin/mesa/src/util/os_misc.c +cp ports/mesa/changes/meson.build bin/mesa/meson.build +cp ports/mesa/changes/src_gallium_targets_osmesa_meson.build bin/mesa/src/gallium/targets/osmesa/meson.build + +cd bin/mesa +meson ../build-mesa --cross-file ../meson_cross.txt \ + -Dosmesa=gallium \ + -Ddefault_library=static && \ + ninja -C ../build-mesa +cd ../.. + +cp bin/build-mesa/subprojects/expat-2.2.5/libexpat.a root/Applications/POSIX/lib +cp bin/build-mesa/subprojects/zlib-1.2.11/libz.a root/Applications/POSIX/lib +cp bin/build-mesa/src/gallium/targets/osmesa/libOSMesa.a root/Applications/POSIX/lib +cp -r bin/mesa/include/GL root/Applications/POSIX/include +cp -r bin/mesa/include/KHR root/Applications/POSIX/include + +rm -r bin/mesa bin/build-mesa diff --git a/ports/musl/COPYRIGHT b/ports/musl/COPYRIGHT new file mode 100644 index 0000000..c1628e9 --- /dev/null +++ b/ports/musl/COPYRIGHT @@ -0,0 +1,193 @@ +musl as a whole is licensed under the following standard MIT license: + +---------------------------------------------------------------------- +Copyright © 2005-2020 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- + +Authors/contributors include: + +A. Wilcox +Ada Worcester +Alex Dowad +Alex Suykov +Alexander Monakov +Andre McCurdy +Andrew Kelley +Anthony G. Basile +Aric Belsito +Arvid Picciani +Bartosz Brachaczek +Benjamin Peterson +Bobby Bingham +Boris Brezillon +Brent Cook +Chris Spiegel +Clément Vasseur +Daniel Micay +Daniel Sabogal +Daurnimator +David Carlier +David Edelsohn +Denys Vlasenko +Dmitry Ivanov +Dmitry V. Levin +Drew DeVault +Emil Renner Berthing +Fangrui Song +Felix Fietkau +Felix Janda +Gianluca Anzolin +Hauke Mehrtens +He X +Hiltjo Posthuma +Isaac Dunham +Jaydeep Patil +Jens Gustedt +Jeremy Huntwork +Jo-Philipp Wich +Joakim Sindholt +John Spencer +Julien Ramseier +Justin Cormack +Kaarle Ritvanen +Khem Raj +Kylie McClain +Leah Neukirchen +Luca Barbato +Luka Perkov +M Farkas-Dyck (Strake) +Mahesh Bodapati +Markus Wichmann +Masanori Ogino +Michael Clark +Michael Forney +Mikhail Kremnyov +Natanael Copa +Nicholas J. Kain +orc +Pascal Cuoq +Patrick Oppenlander +Petr Hosek +Petr Skocik +Pierre Carrier +Reini Urban +Rich Felker +Richard Pennington +Ryan Fairfax +Samuel Holland +Segev Finer +Shiz +sin +Solar Designer +Stefan Kristiansson +Stefan O'Rear +Szabolcs Nagy +Timo Teräs +Trutz Behn +Valentin Ochs +Will Dietz +William Haddon +William Pitcock + +Portions of this software are derived from third-party works licensed +under terms compatible with the above MIT license: + +The TRE regular expression implementation (src/regex/reg* and +src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed +under a 2-clause BSD license (license text in the source files). The +included version has been heavily modified by Rich Felker in 2012, in +the interests of size, simplicity, and namespace cleanliness. + +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier or +Copyright © 2017-2018 Arm Limited +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. + +The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 +The Android Open Source Project and is licensed under a two-clause BSD +license. It was taken from Bionic libc, used on Android. + +The AArch64 memcpy and memset code (src/string/aarch64/*) are +Copyright © 1999-2019, Arm Limited. + +The implementation of DES for crypt (src/crypt/crypt_des.c) is +Copyright © 1994 David Burren. It is licensed under a BSD license. + +The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was +originally written by Solar Designer and placed into the public +domain. The code also comes with a fallback permissive license for use +in jurisdictions that may not recognize the public domain. + +The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 +Valentin Ochs and is licensed under an MIT-style license. + +The x86_64 port was written by Nicholas J. Kain and is licensed under +the standard MIT terms. + +The mips and microblaze ports were originally written by Richard +Pennington for use in the ellcc project. The original code was adapted +by Rich Felker for build system and code conventions during upstream +integration. It is licensed under the standard MIT terms. + +The mips64 port was contributed by Imagination Technologies and is +licensed under the standard MIT terms. + +The powerpc port was also originally written by Richard Pennington, +and later supplemented and integrated by John Spencer. It is licensed +under the standard MIT terms. + +All other files which have no copyright comments are original works +produced specifically for use as part of this library, written either +by Rich Felker, the main author of the library, or by one or more +contibutors listed above. Details on authorship of individual files +can be found in the git version control history of the project. The +omission of copyright and license comments in each file is in the +interest of source tree size. + +In addition, permission is hereby granted for all public header files +(include/* and arch/*/bits/*) and crt files intended to be linked into +applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit +the copyright notice and permission notice otherwise required by the +license, and to use these files without any requirement of +attribution. These files include substantial contributions from: + +Bobby Bingham +John Spencer +Nicholas J. Kain +Rich Felker +Richard Pennington +Stefan Kristiansson +Szabolcs Nagy + +all of whom have explicitly granted such permission. + +This file previously contained text expressing a belief that most of +the files covered by the above exception were sufficiently trivial not +to be subject to copyright, resulting in confusion over whether it +negated the permissions granted in the license. In the spirit of +permissive licensing, and of not having licensing issues being an +obstacle to adoption, that text has been removed. diff --git a/ports/musl/build.sh b/ports/musl/build.sh new file mode 100755 index 0000000..919d7b2 --- /dev/null +++ b/ports/musl/build.sh @@ -0,0 +1,35 @@ +if [ ! -d "bin/musl" ]; then + echo " Downloading source for Musl..." + curl https://musl.libc.org/releases/musl-1.2.1.tar.gz > bin/musl-1.2.1.tar.gz + + gunzip bin/musl-1.2.1.tar.gz + tar -xf bin/musl-1.2.1.tar + mv musl-1.2.1 bin/musl + + cp ports/musl/changes/config.mak bin/musl/config.mak + cp ports/musl/changes/dist_config.mak bin/musl/dist/config.mak + cp ports/musl/changes/arch_x86_64_syscall_arch.h bin/musl/arch/x86_64/syscall_arch.h + cp ports/musl/changes/src_env___init_tls.c bin/musl/src/env/__init_tls.c + cp ports/musl/changes/src_process_x86_64_vfork.s bin/musl/src/process/x86_64/vfork.s + cp ports/musl/changes/src_signal_x86_64_restore.s bin/musl/src/signal/x86_64/restore.s + cp ports/musl/changes/src_thread_x86_64___unmapself.s bin/musl/src/thread/x86_64/__unmapself.s + cp ports/musl/changes/src_thread_x86_64_clone.s bin/musl/src/thread/x86_64/clone.s + cp ports/musl/changes/src_thread_x86_64_syscall_cp.s bin/musl/src/thread/x86_64/syscall_cp.s +fi + +# To rebuild: +# cd bin/musl +# make clean +# make -j 4 lib/libc.a +# cd ../.. +# cp bin/musl/lib/libc.a ports/musl + +mkdir -p root/Applications/POSIX/lib root/Applications/POSIX/include +cp -p ports/musl/libc.a "root/Applications/POSIX/lib/libc.a" +cp -p ports/musl/empty.a "root/Applications/POSIX/lib/libm.a" +cp -p ports/musl/empty.a "root/Applications/POSIX/lib/libpthread.a" +cp -p ports/musl/empty.a "root/Applications/POSIX/lib/librt.a" +cp -p -r ports/musl/obj_bits/* "root/Applications/POSIX/include/" +cp -p -r bin/musl/arch/x86_64/* "root/Applications/POSIX/include/" +cp -p -r bin/musl/arch/generic/* "root/Applications/POSIX/include/" +cp -p -r bin/musl/include/* "root/Applications/POSIX/include/" diff --git a/ports/musl/changes/arch_x86_64_syscall_arch.h b/ports/musl/changes/arch_x86_64_syscall_arch.h new file mode 100644 index 0000000..1e956c0 --- /dev/null +++ b/ports/musl/changes/arch_x86_64_syscall_arch.h @@ -0,0 +1,49 @@ +#define __SYSCALL_LL_E(x) (x) +#define __SYSCALL_LL_O(x) (x) + +long OSMakeLinuxSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long a6); + +static __inline long __syscall0(long n) +{ + return OSMakeLinuxSystemCall(n, 0, 0, 0, 0, 0, 0); +} + +static __inline long __syscall1(long n, long a1) +{ + return OSMakeLinuxSystemCall(n, a1, 0, 0, 0, 0, 0); +} + +static __inline long __syscall2(long n, long a1, long a2) +{ + return OSMakeLinuxSystemCall(n, a1, a2, 0, 0, 0, 0); +} + +static __inline long __syscall3(long n, long a1, long a2, long a3) +{ + return OSMakeLinuxSystemCall(n, a1, a2, a3, 0, 0, 0); +} + +static __inline long __syscall4(long n, long a1, long a2, long a3, long a4) +{ + return OSMakeLinuxSystemCall(n, a1, a2, a3, a4, 0, 0); +} + +static __inline long __syscall5(long n, long a1, long a2, long a3, long a4, long a5) +{ + return OSMakeLinuxSystemCall(n, a1, a2, a3, a4, a5, 0); +} + +static __inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ + return OSMakeLinuxSystemCall(n, a1, a2, a3, a4, a5, a6); +} + +#if 0 +#define VDSO_USEFUL +#define VDSO_CGT_SYM "__vdso_clock_gettime" +#define VDSO_CGT_VER "LINUX_2.6" +#define VDSO_GETCPU_SYM "__vdso_getcpu" +#define VDSO_GETCPU_VER "LINUX_2.6" +#endif + +#define IPC_64 0 diff --git a/ports/musl/changes/config.mak b/ports/musl/changes/config.mak new file mode 100644 index 0000000..fdd031a --- /dev/null +++ b/ports/musl/changes/config.mak @@ -0,0 +1,30 @@ +# This version of config.mak was generated by: +# ./configure +# Any changes made here will be lost if configure is re-run +ARCH = x86_64 +SUBARCH = +ASMSUBARCH = +srcdir = . +prefix = /usr/local/musl +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +libdir = $(prefix)/lib +includedir = $(prefix)/include +syslibdir = /lib +CC = x86_64-essence-gcc +CFLAGS = -ffreestanding -g +CFLAGS_AUTO = -Os -pipe -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -Werror=implicit-function-declaration -Werror=implicit-int -Werror=pointer-sign -Werror=pointer-arith +CFLAGS_C99FSE = -std=c99 -nostdinc -ffreestanding -fexcess-precision=standard -frounding-math -Wa,--noexecstack +CFLAGS_MEMOPS = -fno-tree-loop-distribute-patterns +CFLAGS_NOSSP = -fno-stack-protector +CPPFLAGS = +LDFLAGS = -T ../../util/linker_userland64.ld -z max-page-size=0x1000 +LDFLAGS_AUTO = -Wl,--sort-section,alignment -Wl,--sort-common -Wl,--gc-sections -Wl,--hash-style=both -Wl,--no-undefined -Wl,--exclude-libs=ALL -Wl,-Bsymbolic-functions +CROSS_COMPILE = +LIBCC = -lgcc +OPTIMIZE_GLOBS = internal/*.c malloc/*.c string/*.c +ALL_TOOLS = obj/musl-gcc +TOOL_LIBS = lib/musl-gcc.specs +ADD_CFI = no +WRAPCC_GCC = $(CC) +AOBJS = $(LOBJS) diff --git a/ports/musl/changes/dist_config.mak b/ports/musl/changes/dist_config.mak new file mode 100644 index 0000000..189b7f5 --- /dev/null +++ b/ports/musl/changes/dist_config.mak @@ -0,0 +1,36 @@ +# +# musl config.mak template (original in dist/config.mak) +# + +# Target CPU architecture. Supported values: i386, x86_64 +ARCH = x86_64 + +# Installation prefix. DO NOT use /, /usr, or /usr/local ! +prefix = /usr/local/musl + +# Installation prefix for musl-gcc compiler wrapper. +exec_prefix = /usr/local + +# Location for the dynamic linker ld-musl-$(ARCH).so.1 +syslibdir = /lib + +# Uncomment if you want to build i386 musl on a 64-bit host +#CFLAGS += -m32 + +# Uncomment to fix broken distro-patched toolchains where hash-style=gnu(only) +#LDFLAGS += -Wl,--hash-style,both + +# Uncomment to fix broken distro-patched toolchains where stack-protector=on +#CFLAGS += -fno-stack-protector + +# Uncomment for smaller code size. +#CFLAGS += -fomit-frame-pointer -mno-accumulate-outgoing-args + +# Uncomment to omit massive GCC4 DWARF2 bloat (only useful for debugging) +#CFLAGS += -fno-asynchronous-unwind-tables + +# Uncomment for warnings (as errors). Might need tuning to your gcc version. +#CFLAGS += -Werror -Wall -Wpointer-arith -Wcast-align -Wno-parentheses -Wno-char-subscripts -Wno-uninitialized -Wno-sequence-point -Wno-missing-braces -Wno-unused-value -Wno-overflow -Wno-int-to-pointer-cast + +# Uncomment if you want to disable building the shared library. +#SHARED_LIBS = diff --git a/ports/musl/changes/src_env___init_tls.c b/ports/musl/changes/src_env___init_tls.c new file mode 100644 index 0000000..2f2495d --- /dev/null +++ b/ports/musl/changes/src_env___init_tls.c @@ -0,0 +1,157 @@ +#define SYSCALL_NO_TLS 1 +#include <elf.h> +#include <limits.h> +#include <sys/mman.h> +#include <string.h> +#include <stddef.h> +#include "pthread_impl.h" +#include "libc.h" +#include "atomic.h" +#include "syscall.h" + +volatile int __thread_list_lock; + +long OSMakeLinuxSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long a6); + +int __init_tp(void *p) +{ + pthread_t td = p; + td->self = td; + // nakst: redirect to OSMakeLinuxSystemCall + int r = OSMakeLinuxSystemCall(-1000, (long) TP_ADJ(p), libc.tls_size - sizeof(struct pthread), 0, 0, 0, 0); + if (r < 0) return -1; + if (!r) libc.can_do_threads = 1; + td->detach_state = DT_JOINABLE; + td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock); + td->locale = &libc.global_locale; + td->robust_list.head = &td->robust_list.head; + td->sysinfo = __sysinfo; + td->next = td->prev = td; + return 0; +} + +static struct builtin_tls { + char c; + struct pthread pt; + void *space[16]; +} builtin_tls[1]; +#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt) + +static struct tls_module main_tls; + +void *__copy_tls(unsigned char *mem) +{ + pthread_t td; + struct tls_module *p; + size_t i; + uintptr_t *dtv; + +#ifdef TLS_ABOVE_TP + dtv = (uintptr_t*)(mem + libc.tls_size) - (libc.tls_cnt + 1); + + mem += -((uintptr_t)mem + sizeof(struct pthread)) & (libc.tls_align-1); + td = (pthread_t)mem; + mem += sizeof(struct pthread); + + for (i=1, p=libc.tls_head; p; i++, p=p->next) { + dtv[i] = (uintptr_t)(mem + p->offset) + DTP_OFFSET; + memcpy(mem + p->offset, p->image, p->len); + } +#else + dtv = (uintptr_t *)mem; + + mem += libc.tls_size - sizeof(struct pthread); + mem -= (uintptr_t)mem & (libc.tls_align-1); + td = (pthread_t)mem; + + for (i=1, p=libc.tls_head; p; i++, p=p->next) { + dtv[i] = (uintptr_t)(mem - p->offset) + DTP_OFFSET; + memcpy(mem - p->offset, p->image, p->len); + } +#endif + dtv[0] = libc.tls_cnt; + td->dtv = td->dtv_copy = dtv; + return td; +} + +#if ULONG_MAX == 0xffffffff +typedef Elf32_Phdr Phdr; +#else +typedef Elf64_Phdr Phdr; +#endif + +extern weak hidden const size_t _DYNAMIC[]; + +static void static_init_tls(size_t *aux) +{ + unsigned char *p; + size_t n; + Phdr *phdr, *tls_phdr=0; + size_t base = 0; + void *mem; + + for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) { + phdr = (void *)p; + if (phdr->p_type == PT_PHDR) + base = aux[AT_PHDR] - phdr->p_vaddr; + if (phdr->p_type == PT_DYNAMIC && _DYNAMIC) + base = (size_t)_DYNAMIC - phdr->p_vaddr; + if (phdr->p_type == PT_TLS) + tls_phdr = phdr; + if (phdr->p_type == PT_GNU_STACK && + phdr->p_memsz > __default_stacksize) + __default_stacksize = + phdr->p_memsz < DEFAULT_STACK_MAX ? + phdr->p_memsz : DEFAULT_STACK_MAX; + } + + if (tls_phdr) { + main_tls.image = (void *)(base + tls_phdr->p_vaddr); + main_tls.len = tls_phdr->p_filesz; + main_tls.size = tls_phdr->p_memsz; + main_tls.align = tls_phdr->p_align; + libc.tls_cnt = 1; + libc.tls_head = &main_tls; + } + + main_tls.size += (-main_tls.size - (uintptr_t)main_tls.image) + & (main_tls.align-1); +#ifdef TLS_ABOVE_TP + main_tls.offset = GAP_ABOVE_TP; + main_tls.offset += (-GAP_ABOVE_TP + (uintptr_t)main_tls.image) + & (main_tls.align-1); +#else + main_tls.offset = main_tls.size; +#endif + if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN; + + libc.tls_align = main_tls.align; + libc.tls_size = 2*sizeof(void *) + sizeof(struct pthread) + + sizeof(void *) // nakst: for essence API context pointer +#ifdef TLS_ABOVE_TP + + main_tls.offset +#endif + + main_tls.size + main_tls.align + + MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN; + + if (libc.tls_size > sizeof builtin_tls) { +#ifndef SYS_mmap2 +#define SYS_mmap2 SYS_mmap +#endif + mem = (void *)__syscall( + SYS_mmap2, + 0, libc.tls_size, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + /* -4095...-1 cast to void * will crash on dereference anyway, + * so don't bloat the init code checking for error codes and + * explicitly calling a_crash(). */ + } else { + mem = builtin_tls; + } + + /* Failure to initialize thread pointer is always fatal. */ + if (__init_tp(__copy_tls(mem)) < 0) + a_crash(); +} + +weak_alias(static_init_tls, __init_tls); diff --git a/ports/musl/changes/src_process_x86_64_vfork.s b/ports/musl/changes/src_process_x86_64_vfork.s new file mode 100644 index 0000000..8086b50 --- /dev/null +++ b/ports/musl/changes/src_process_x86_64_vfork.s @@ -0,0 +1,11 @@ +.global vfork +.type vfork,@function +vfork: +#nakst - redirect to OSMakeLinuxSystemCall + mov $58,%edi + mov $OSMakeLinuxSystemCall,%rax + sub $8,%rsp # keep stack aligned + call *%rax + add $8,%rsp + mov %rax,%rdi + jmp __syscall_ret diff --git a/ports/musl/changes/src_signal_x86_64_restore.s b/ports/musl/changes/src_signal_x86_64_restore.s new file mode 100644 index 0000000..bc2768e --- /dev/null +++ b/ports/musl/changes/src_signal_x86_64_restore.s @@ -0,0 +1,8 @@ + nop +.global __restore_rt +.hidden __restore_rt +.type __restore_rt,@function +__restore_rt: + mov $15, %rax + nop #nakst - we don't support signals +.size __restore_rt,.-__restore_rt diff --git a/ports/musl/changes/src_thread_x86_64___unmapself.s b/ports/musl/changes/src_thread_x86_64___unmapself.s new file mode 100644 index 0000000..6adc115 --- /dev/null +++ b/ports/musl/changes/src_thread_x86_64___unmapself.s @@ -0,0 +1,13 @@ +/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ +.text +.global __unmapself +.type __unmapself,@function +__unmapself: + #nakst - we don't support detached threads + mov -1,%rdi + syscall + movl $11,%eax /* SYS_munmap */ + syscall /* munmap(arg2,arg3) */ + xor %rdi,%rdi /* exit() args: always return success */ + movl $60,%eax /* SYS_exit */ + syscall /* exit(0) */ diff --git a/ports/musl/changes/src_thread_x86_64_clone.s b/ports/musl/changes/src_thread_x86_64_clone.s new file mode 100644 index 0000000..367d439 --- /dev/null +++ b/ports/musl/changes/src_thread_x86_64_clone.s @@ -0,0 +1,32 @@ +.text +.global __clone +.hidden __clone +.type __clone,@function +__clone: + #nakst - we don't support forking/cloning + mov -1,%rdi + mov $1,%rsi + syscall + xor %eax,%eax + mov $56,%al + mov %rdi,%r11 + mov %rdx,%rdi + mov %r8,%rdx + mov %r9,%r8 + mov 8(%rsp),%r10 + mov %r11,%r9 + and $-16,%rsi + sub $8,%rsi + mov %rcx,(%rsi) + syscall + test %eax,%eax + jnz 1f + xor %ebp,%ebp + pop %rdi + call *%r9 + mov %eax,%edi + xor %eax,%eax + mov $60,%al + syscall + hlt +1: ret diff --git a/ports/musl/changes/src_thread_x86_64_syscall_cp.s b/ports/musl/changes/src_thread_x86_64_syscall_cp.s new file mode 100644 index 0000000..acc6d38 --- /dev/null +++ b/ports/musl/changes/src_thread_x86_64_syscall_cp.s @@ -0,0 +1,37 @@ +.text +.global __cp_begin +.hidden __cp_begin +.global __cp_end +.hidden __cp_end +.global __cp_cancel +.hidden __cp_cancel +.hidden __cancel +.global __syscall_cp_asm +.hidden __syscall_cp_asm +.type __syscall_cp_asm,@function +__syscall_cp_asm: + + #Nakst - what on earth is this for?!? + + mov -1,%rdi + mov $1,%rsi + syscall + +__cp_begin: + mov (%rdi),%eax + test %eax,%eax + jnz __cp_cancel + mov %rdi,%r11 + mov %rsi,%rax + mov %rdx,%rdi + mov %rcx,%rsi + mov %r8,%rdx + mov %r9,%r10 + mov 8(%rsp),%r8 + mov 16(%rsp),%r9 + mov %r11,8(%rsp) + syscall +__cp_end: + ret +__cp_cancel: + jmp __cancel diff --git a/ports/musl/empty.a b/ports/musl/empty.a new file mode 100644 index 0000000..8b277f0 --- /dev/null +++ b/ports/musl/empty.a @@ -0,0 +1 @@ +!<arch> diff --git a/ports/musl/libc.a b/ports/musl/libc.a new file mode 100644 index 0000000..f6c1e40 Binary files /dev/null and b/ports/musl/libc.a differ diff --git a/ports/musl/obj_bits/bits/alltypes.h b/ports/musl/obj_bits/bits/alltypes.h new file mode 100644 index 0000000..d827d1c --- /dev/null +++ b/ports/musl/obj_bits/bits/alltypes.h @@ -0,0 +1,409 @@ +#define _Addr long +#define _Int64 long +#define _Reg long + +#define __BYTE_ORDER 1234 +#define __LONG_MAX 0x7fffffffffffffffL + +#ifndef __cplusplus +#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t) +typedef int wchar_t; +#define __DEFINED_wchar_t +#endif + +#endif + +#if defined(__FLT_EVAL_METHOD__) && __FLT_EVAL_METHOD__ == 2 +#if defined(__NEED_float_t) && !defined(__DEFINED_float_t) +typedef long double float_t; +#define __DEFINED_float_t +#endif + +#if defined(__NEED_double_t) && !defined(__DEFINED_double_t) +typedef long double double_t; +#define __DEFINED_double_t +#endif + +#else +#if defined(__NEED_float_t) && !defined(__DEFINED_float_t) +typedef float float_t; +#define __DEFINED_float_t +#endif + +#if defined(__NEED_double_t) && !defined(__DEFINED_double_t) +typedef double double_t; +#define __DEFINED_double_t +#endif + +#endif + +#if defined(__NEED_max_align_t) && !defined(__DEFINED_max_align_t) +typedef struct { long long __ll; long double __ld; } max_align_t; +#define __DEFINED_max_align_t +#endif + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __USE_TIME_BITS64 1 + +#if defined(__NEED_size_t) && !defined(__DEFINED_size_t) +typedef unsigned _Addr size_t; +#define __DEFINED_size_t +#endif + +#if defined(__NEED_uintptr_t) && !defined(__DEFINED_uintptr_t) +typedef unsigned _Addr uintptr_t; +#define __DEFINED_uintptr_t +#endif + +#if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t) +typedef _Addr ptrdiff_t; +#define __DEFINED_ptrdiff_t +#endif + +#if defined(__NEED_ssize_t) && !defined(__DEFINED_ssize_t) +typedef _Addr ssize_t; +#define __DEFINED_ssize_t +#endif + +#if defined(__NEED_intptr_t) && !defined(__DEFINED_intptr_t) +typedef _Addr intptr_t; +#define __DEFINED_intptr_t +#endif + +#if defined(__NEED_regoff_t) && !defined(__DEFINED_regoff_t) +typedef _Addr regoff_t; +#define __DEFINED_regoff_t +#endif + +#if defined(__NEED_register_t) && !defined(__DEFINED_register_t) +typedef _Reg register_t; +#define __DEFINED_register_t +#endif + +#if defined(__NEED_time_t) && !defined(__DEFINED_time_t) +typedef _Int64 time_t; +#define __DEFINED_time_t +#endif + +#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t) +typedef _Int64 suseconds_t; +#define __DEFINED_suseconds_t +#endif + + +#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t) +typedef signed char int8_t; +#define __DEFINED_int8_t +#endif + +#if defined(__NEED_int16_t) && !defined(__DEFINED_int16_t) +typedef signed short int16_t; +#define __DEFINED_int16_t +#endif + +#if defined(__NEED_int32_t) && !defined(__DEFINED_int32_t) +typedef signed int int32_t; +#define __DEFINED_int32_t +#endif + +#if defined(__NEED_int64_t) && !defined(__DEFINED_int64_t) +typedef signed _Int64 int64_t; +#define __DEFINED_int64_t +#endif + +#if defined(__NEED_intmax_t) && !defined(__DEFINED_intmax_t) +typedef signed _Int64 intmax_t; +#define __DEFINED_intmax_t +#endif + +#if defined(__NEED_uint8_t) && !defined(__DEFINED_uint8_t) +typedef unsigned char uint8_t; +#define __DEFINED_uint8_t +#endif + +#if defined(__NEED_uint16_t) && !defined(__DEFINED_uint16_t) +typedef unsigned short uint16_t; +#define __DEFINED_uint16_t +#endif + +#if defined(__NEED_uint32_t) && !defined(__DEFINED_uint32_t) +typedef unsigned int uint32_t; +#define __DEFINED_uint32_t +#endif + +#if defined(__NEED_uint64_t) && !defined(__DEFINED_uint64_t) +typedef unsigned _Int64 uint64_t; +#define __DEFINED_uint64_t +#endif + +#if defined(__NEED_u_int64_t) && !defined(__DEFINED_u_int64_t) +typedef unsigned _Int64 u_int64_t; +#define __DEFINED_u_int64_t +#endif + +#if defined(__NEED_uintmax_t) && !defined(__DEFINED_uintmax_t) +typedef unsigned _Int64 uintmax_t; +#define __DEFINED_uintmax_t +#endif + + +#if defined(__NEED_mode_t) && !defined(__DEFINED_mode_t) +typedef unsigned mode_t; +#define __DEFINED_mode_t +#endif + +#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t) +typedef unsigned _Reg nlink_t; +#define __DEFINED_nlink_t +#endif + +#if defined(__NEED_off_t) && !defined(__DEFINED_off_t) +typedef _Int64 off_t; +#define __DEFINED_off_t +#endif + +#if defined(__NEED_ino_t) && !defined(__DEFINED_ino_t) +typedef unsigned _Int64 ino_t; +#define __DEFINED_ino_t +#endif + +#if defined(__NEED_dev_t) && !defined(__DEFINED_dev_t) +typedef unsigned _Int64 dev_t; +#define __DEFINED_dev_t +#endif + +#if defined(__NEED_blksize_t) && !defined(__DEFINED_blksize_t) +typedef long blksize_t; +#define __DEFINED_blksize_t +#endif + +#if defined(__NEED_blkcnt_t) && !defined(__DEFINED_blkcnt_t) +typedef _Int64 blkcnt_t; +#define __DEFINED_blkcnt_t +#endif + +#if defined(__NEED_fsblkcnt_t) && !defined(__DEFINED_fsblkcnt_t) +typedef unsigned _Int64 fsblkcnt_t; +#define __DEFINED_fsblkcnt_t +#endif + +#if defined(__NEED_fsfilcnt_t) && !defined(__DEFINED_fsfilcnt_t) +typedef unsigned _Int64 fsfilcnt_t; +#define __DEFINED_fsfilcnt_t +#endif + + +#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t) +typedef unsigned wint_t; +#define __DEFINED_wint_t +#endif + +#if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t) +typedef unsigned long wctype_t; +#define __DEFINED_wctype_t +#endif + + +#if defined(__NEED_timer_t) && !defined(__DEFINED_timer_t) +typedef void * timer_t; +#define __DEFINED_timer_t +#endif + +#if defined(__NEED_clockid_t) && !defined(__DEFINED_clockid_t) +typedef int clockid_t; +#define __DEFINED_clockid_t +#endif + +#if defined(__NEED_clock_t) && !defined(__DEFINED_clock_t) +typedef long clock_t; +#define __DEFINED_clock_t +#endif + +#if defined(__NEED_struct_timeval) && !defined(__DEFINED_struct_timeval) +struct timeval { time_t tv_sec; suseconds_t tv_usec; }; +#define __DEFINED_struct_timeval +#endif + +#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec) +struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); }; +#define __DEFINED_struct_timespec +#endif + + +#if defined(__NEED_pid_t) && !defined(__DEFINED_pid_t) +typedef int pid_t; +#define __DEFINED_pid_t +#endif + +#if defined(__NEED_id_t) && !defined(__DEFINED_id_t) +typedef unsigned id_t; +#define __DEFINED_id_t +#endif + +#if defined(__NEED_uid_t) && !defined(__DEFINED_uid_t) +typedef unsigned uid_t; +#define __DEFINED_uid_t +#endif + +#if defined(__NEED_gid_t) && !defined(__DEFINED_gid_t) +typedef unsigned gid_t; +#define __DEFINED_gid_t +#endif + +#if defined(__NEED_key_t) && !defined(__DEFINED_key_t) +typedef int key_t; +#define __DEFINED_key_t +#endif + +#if defined(__NEED_useconds_t) && !defined(__DEFINED_useconds_t) +typedef unsigned useconds_t; +#define __DEFINED_useconds_t +#endif + + +#ifdef __cplusplus +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef unsigned long pthread_t; +#define __DEFINED_pthread_t +#endif + +#else +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef struct __pthread * pthread_t; +#define __DEFINED_pthread_t +#endif + +#endif +#if defined(__NEED_pthread_once_t) && !defined(__DEFINED_pthread_once_t) +typedef int pthread_once_t; +#define __DEFINED_pthread_once_t +#endif + +#if defined(__NEED_pthread_key_t) && !defined(__DEFINED_pthread_key_t) +typedef unsigned pthread_key_t; +#define __DEFINED_pthread_key_t +#endif + +#if defined(__NEED_pthread_spinlock_t) && !defined(__DEFINED_pthread_spinlock_t) +typedef int pthread_spinlock_t; +#define __DEFINED_pthread_spinlock_t +#endif + +#if defined(__NEED_pthread_mutexattr_t) && !defined(__DEFINED_pthread_mutexattr_t) +typedef struct { unsigned __attr; } pthread_mutexattr_t; +#define __DEFINED_pthread_mutexattr_t +#endif + +#if defined(__NEED_pthread_condattr_t) && !defined(__DEFINED_pthread_condattr_t) +typedef struct { unsigned __attr; } pthread_condattr_t; +#define __DEFINED_pthread_condattr_t +#endif + +#if defined(__NEED_pthread_barrierattr_t) && !defined(__DEFINED_pthread_barrierattr_t) +typedef struct { unsigned __attr; } pthread_barrierattr_t; +#define __DEFINED_pthread_barrierattr_t +#endif + +#if defined(__NEED_pthread_rwlockattr_t) && !defined(__DEFINED_pthread_rwlockattr_t) +typedef struct { unsigned __attr[2]; } pthread_rwlockattr_t; +#define __DEFINED_pthread_rwlockattr_t +#endif + + +#if defined(__NEED_struct__IO_FILE) && !defined(__DEFINED_struct__IO_FILE) +struct _IO_FILE { char __x; }; +#define __DEFINED_struct__IO_FILE +#endif + +#if defined(__NEED_FILE) && !defined(__DEFINED_FILE) +typedef struct _IO_FILE FILE; +#define __DEFINED_FILE +#endif + + +#if defined(__NEED_va_list) && !defined(__DEFINED_va_list) +typedef __builtin_va_list va_list; +#define __DEFINED_va_list +#endif + +#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list) +typedef __builtin_va_list __isoc_va_list; +#define __DEFINED___isoc_va_list +#endif + + +#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t) +typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; +#define __DEFINED_mbstate_t +#endif + + +#if defined(__NEED_locale_t) && !defined(__DEFINED_locale_t) +typedef struct __locale_struct * locale_t; +#define __DEFINED_locale_t +#endif + + +#if defined(__NEED_sigset_t) && !defined(__DEFINED_sigset_t) +typedef struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t; +#define __DEFINED_sigset_t +#endif + + +#if defined(__NEED_struct_iovec) && !defined(__DEFINED_struct_iovec) +struct iovec { void *iov_base; size_t iov_len; }; +#define __DEFINED_struct_iovec +#endif + + +#if defined(__NEED_socklen_t) && !defined(__DEFINED_socklen_t) +typedef unsigned socklen_t; +#define __DEFINED_socklen_t +#endif + +#if defined(__NEED_sa_family_t) && !defined(__DEFINED_sa_family_t) +typedef unsigned short sa_family_t; +#define __DEFINED_sa_family_t +#endif + + +#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t) +typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t; +#define __DEFINED_pthread_attr_t +#endif + +#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t) +typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t; +#define __DEFINED_pthread_mutex_t +#endif + +#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t) +typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t; +#define __DEFINED_mtx_t +#endif + +#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t; +#define __DEFINED_pthread_cond_t +#endif + +#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t; +#define __DEFINED_cnd_t +#endif + +#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t) +typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t; +#define __DEFINED_pthread_rwlock_t +#endif + +#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t) +typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t; +#define __DEFINED_pthread_barrier_t +#endif + + +#undef _Addr +#undef _Int64 +#undef _Reg diff --git a/ports/musl/obj_bits/bits/syscall.h b/ports/musl/obj_bits/bits/syscall.h new file mode 100644 index 0000000..b853ce8 --- /dev/null +++ b/ports/musl/obj_bits/bits/syscall.h @@ -0,0 +1,695 @@ +#define __NR_read 0 +#define __NR_write 1 +#define __NR_open 2 +#define __NR_close 3 +#define __NR_stat 4 +#define __NR_fstat 5 +#define __NR_lstat 6 +#define __NR_poll 7 +#define __NR_lseek 8 +#define __NR_mmap 9 +#define __NR_mprotect 10 +#define __NR_munmap 11 +#define __NR_brk 12 +#define __NR_rt_sigaction 13 +#define __NR_rt_sigprocmask 14 +#define __NR_rt_sigreturn 15 +#define __NR_ioctl 16 +#define __NR_pread64 17 +#define __NR_pwrite64 18 +#define __NR_readv 19 +#define __NR_writev 20 +#define __NR_access 21 +#define __NR_pipe 22 +#define __NR_select 23 +#define __NR_sched_yield 24 +#define __NR_mremap 25 +#define __NR_msync 26 +#define __NR_mincore 27 +#define __NR_madvise 28 +#define __NR_shmget 29 +#define __NR_shmat 30 +#define __NR_shmctl 31 +#define __NR_dup 32 +#define __NR_dup2 33 +#define __NR_pause 34 +#define __NR_nanosleep 35 +#define __NR_getitimer 36 +#define __NR_alarm 37 +#define __NR_setitimer 38 +#define __NR_getpid 39 +#define __NR_sendfile 40 +#define __NR_socket 41 +#define __NR_connect 42 +#define __NR_accept 43 +#define __NR_sendto 44 +#define __NR_recvfrom 45 +#define __NR_sendmsg 46 +#define __NR_recvmsg 47 +#define __NR_shutdown 48 +#define __NR_bind 49 +#define __NR_listen 50 +#define __NR_getsockname 51 +#define __NR_getpeername 52 +#define __NR_socketpair 53 +#define __NR_setsockopt 54 +#define __NR_getsockopt 55 +#define __NR_clone 56 +#define __NR_fork 57 +#define __NR_vfork 58 +#define __NR_execve 59 +#define __NR_exit 60 +#define __NR_wait4 61 +#define __NR_kill 62 +#define __NR_uname 63 +#define __NR_semget 64 +#define __NR_semop 65 +#define __NR_semctl 66 +#define __NR_shmdt 67 +#define __NR_msgget 68 +#define __NR_msgsnd 69 +#define __NR_msgrcv 70 +#define __NR_msgctl 71 +#define __NR_fcntl 72 +#define __NR_flock 73 +#define __NR_fsync 74 +#define __NR_fdatasync 75 +#define __NR_truncate 76 +#define __NR_ftruncate 77 +#define __NR_getdents 78 +#define __NR_getcwd 79 +#define __NR_chdir 80 +#define __NR_fchdir 81 +#define __NR_rename 82 +#define __NR_mkdir 83 +#define __NR_rmdir 84 +#define __NR_creat 85 +#define __NR_link 86 +#define __NR_unlink 87 +#define __NR_symlink 88 +#define __NR_readlink 89 +#define __NR_chmod 90 +#define __NR_fchmod 91 +#define __NR_chown 92 +#define __NR_fchown 93 +#define __NR_lchown 94 +#define __NR_umask 95 +#define __NR_gettimeofday 96 +#define __NR_getrlimit 97 +#define __NR_getrusage 98 +#define __NR_sysinfo 99 +#define __NR_times 100 +#define __NR_ptrace 101 +#define __NR_getuid 102 +#define __NR_syslog 103 +#define __NR_getgid 104 +#define __NR_setuid 105 +#define __NR_setgid 106 +#define __NR_geteuid 107 +#define __NR_getegid 108 +#define __NR_setpgid 109 +#define __NR_getppid 110 +#define __NR_getpgrp 111 +#define __NR_setsid 112 +#define __NR_setreuid 113 +#define __NR_setregid 114 +#define __NR_getgroups 115 +#define __NR_setgroups 116 +#define __NR_setresuid 117 +#define __NR_getresuid 118 +#define __NR_setresgid 119 +#define __NR_getresgid 120 +#define __NR_getpgid 121 +#define __NR_setfsuid 122 +#define __NR_setfsgid 123 +#define __NR_getsid 124 +#define __NR_capget 125 +#define __NR_capset 126 +#define __NR_rt_sigpending 127 +#define __NR_rt_sigtimedwait 128 +#define __NR_rt_sigqueueinfo 129 +#define __NR_rt_sigsuspend 130 +#define __NR_sigaltstack 131 +#define __NR_utime 132 +#define __NR_mknod 133 +#define __NR_uselib 134 +#define __NR_personality 135 +#define __NR_ustat 136 +#define __NR_statfs 137 +#define __NR_fstatfs 138 +#define __NR_sysfs 139 +#define __NR_getpriority 140 +#define __NR_setpriority 141 +#define __NR_sched_setparam 142 +#define __NR_sched_getparam 143 +#define __NR_sched_setscheduler 144 +#define __NR_sched_getscheduler 145 +#define __NR_sched_get_priority_max 146 +#define __NR_sched_get_priority_min 147 +#define __NR_sched_rr_get_interval 148 +#define __NR_mlock 149 +#define __NR_munlock 150 +#define __NR_mlockall 151 +#define __NR_munlockall 152 +#define __NR_vhangup 153 +#define __NR_modify_ldt 154 +#define __NR_pivot_root 155 +#define __NR__sysctl 156 +#define __NR_prctl 157 +#define __NR_arch_prctl 158 +#define __NR_adjtimex 159 +#define __NR_setrlimit 160 +#define __NR_chroot 161 +#define __NR_sync 162 +#define __NR_acct 163 +#define __NR_settimeofday 164 +#define __NR_mount 165 +#define __NR_umount2 166 +#define __NR_swapon 167 +#define __NR_swapoff 168 +#define __NR_reboot 169 +#define __NR_sethostname 170 +#define __NR_setdomainname 171 +#define __NR_iopl 172 +#define __NR_ioperm 173 +#define __NR_create_module 174 +#define __NR_init_module 175 +#define __NR_delete_module 176 +#define __NR_get_kernel_syms 177 +#define __NR_query_module 178 +#define __NR_quotactl 179 +#define __NR_nfsservctl 180 +#define __NR_getpmsg 181 +#define __NR_putpmsg 182 +#define __NR_afs_syscall 183 +#define __NR_tuxcall 184 +#define __NR_security 185 +#define __NR_gettid 186 +#define __NR_readahead 187 +#define __NR_setxattr 188 +#define __NR_lsetxattr 189 +#define __NR_fsetxattr 190 +#define __NR_getxattr 191 +#define __NR_lgetxattr 192 +#define __NR_fgetxattr 193 +#define __NR_listxattr 194 +#define __NR_llistxattr 195 +#define __NR_flistxattr 196 +#define __NR_removexattr 197 +#define __NR_lremovexattr 198 +#define __NR_fremovexattr 199 +#define __NR_tkill 200 +#define __NR_time 201 +#define __NR_futex 202 +#define __NR_sched_setaffinity 203 +#define __NR_sched_getaffinity 204 +#define __NR_set_thread_area 205 +#define __NR_io_setup 206 +#define __NR_io_destroy 207 +#define __NR_io_getevents 208 +#define __NR_io_submit 209 +#define __NR_io_cancel 210 +#define __NR_get_thread_area 211 +#define __NR_lookup_dcookie 212 +#define __NR_epoll_create 213 +#define __NR_epoll_ctl_old 214 +#define __NR_epoll_wait_old 215 +#define __NR_remap_file_pages 216 +#define __NR_getdents64 217 +#define __NR_set_tid_address 218 +#define __NR_restart_syscall 219 +#define __NR_semtimedop 220 +#define __NR_fadvise64 221 +#define __NR_timer_create 222 +#define __NR_timer_settime 223 +#define __NR_timer_gettime 224 +#define __NR_timer_getoverrun 225 +#define __NR_timer_delete 226 +#define __NR_clock_settime 227 +#define __NR_clock_gettime 228 +#define __NR_clock_getres 229 +#define __NR_clock_nanosleep 230 +#define __NR_exit_group 231 +#define __NR_epoll_wait 232 +#define __NR_epoll_ctl 233 +#define __NR_tgkill 234 +#define __NR_utimes 235 +#define __NR_vserver 236 +#define __NR_mbind 237 +#define __NR_set_mempolicy 238 +#define __NR_get_mempolicy 239 +#define __NR_mq_open 240 +#define __NR_mq_unlink 241 +#define __NR_mq_timedsend 242 +#define __NR_mq_timedreceive 243 +#define __NR_mq_notify 244 +#define __NR_mq_getsetattr 245 +#define __NR_kexec_load 246 +#define __NR_waitid 247 +#define __NR_add_key 248 +#define __NR_request_key 249 +#define __NR_keyctl 250 +#define __NR_ioprio_set 251 +#define __NR_ioprio_get 252 +#define __NR_inotify_init 253 +#define __NR_inotify_add_watch 254 +#define __NR_inotify_rm_watch 255 +#define __NR_migrate_pages 256 +#define __NR_openat 257 +#define __NR_mkdirat 258 +#define __NR_mknodat 259 +#define __NR_fchownat 260 +#define __NR_futimesat 261 +#define __NR_newfstatat 262 +#define __NR_unlinkat 263 +#define __NR_renameat 264 +#define __NR_linkat 265 +#define __NR_symlinkat 266 +#define __NR_readlinkat 267 +#define __NR_fchmodat 268 +#define __NR_faccessat 269 +#define __NR_pselect6 270 +#define __NR_ppoll 271 +#define __NR_unshare 272 +#define __NR_set_robust_list 273 +#define __NR_get_robust_list 274 +#define __NR_splice 275 +#define __NR_tee 276 +#define __NR_sync_file_range 277 +#define __NR_vmsplice 278 +#define __NR_move_pages 279 +#define __NR_utimensat 280 +#define __NR_epoll_pwait 281 +#define __NR_signalfd 282 +#define __NR_timerfd_create 283 +#define __NR_eventfd 284 +#define __NR_fallocate 285 +#define __NR_timerfd_settime 286 +#define __NR_timerfd_gettime 287 +#define __NR_accept4 288 +#define __NR_signalfd4 289 +#define __NR_eventfd2 290 +#define __NR_epoll_create1 291 +#define __NR_dup3 292 +#define __NR_pipe2 293 +#define __NR_inotify_init1 294 +#define __NR_preadv 295 +#define __NR_pwritev 296 +#define __NR_rt_tgsigqueueinfo 297 +#define __NR_perf_event_open 298 +#define __NR_recvmmsg 299 +#define __NR_fanotify_init 300 +#define __NR_fanotify_mark 301 +#define __NR_prlimit64 302 +#define __NR_name_to_handle_at 303 +#define __NR_open_by_handle_at 304 +#define __NR_clock_adjtime 305 +#define __NR_syncfs 306 +#define __NR_sendmmsg 307 +#define __NR_setns 308 +#define __NR_getcpu 309 +#define __NR_process_vm_readv 310 +#define __NR_process_vm_writev 311 +#define __NR_kcmp 312 +#define __NR_finit_module 313 +#define __NR_sched_setattr 314 +#define __NR_sched_getattr 315 +#define __NR_renameat2 316 +#define __NR_seccomp 317 +#define __NR_getrandom 318 +#define __NR_memfd_create 319 +#define __NR_kexec_file_load 320 +#define __NR_bpf 321 +#define __NR_execveat 322 +#define __NR_userfaultfd 323 +#define __NR_membarrier 324 +#define __NR_mlock2 325 +#define __NR_copy_file_range 326 +#define __NR_preadv2 327 +#define __NR_pwritev2 328 +#define __NR_pkey_mprotect 329 +#define __NR_pkey_alloc 330 +#define __NR_pkey_free 331 +#define __NR_statx 332 +#define __NR_io_pgetevents 333 +#define __NR_rseq 334 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 + +#define SYS_read 0 +#define SYS_write 1 +#define SYS_open 2 +#define SYS_close 3 +#define SYS_stat 4 +#define SYS_fstat 5 +#define SYS_lstat 6 +#define SYS_poll 7 +#define SYS_lseek 8 +#define SYS_mmap 9 +#define SYS_mprotect 10 +#define SYS_munmap 11 +#define SYS_brk 12 +#define SYS_rt_sigaction 13 +#define SYS_rt_sigprocmask 14 +#define SYS_rt_sigreturn 15 +#define SYS_ioctl 16 +#define SYS_pread64 17 +#define SYS_pwrite64 18 +#define SYS_readv 19 +#define SYS_writev 20 +#define SYS_access 21 +#define SYS_pipe 22 +#define SYS_select 23 +#define SYS_sched_yield 24 +#define SYS_mremap 25 +#define SYS_msync 26 +#define SYS_mincore 27 +#define SYS_madvise 28 +#define SYS_shmget 29 +#define SYS_shmat 30 +#define SYS_shmctl 31 +#define SYS_dup 32 +#define SYS_dup2 33 +#define SYS_pause 34 +#define SYS_nanosleep 35 +#define SYS_getitimer 36 +#define SYS_alarm 37 +#define SYS_setitimer 38 +#define SYS_getpid 39 +#define SYS_sendfile 40 +#define SYS_socket 41 +#define SYS_connect 42 +#define SYS_accept 43 +#define SYS_sendto 44 +#define SYS_recvfrom 45 +#define SYS_sendmsg 46 +#define SYS_recvmsg 47 +#define SYS_shutdown 48 +#define SYS_bind 49 +#define SYS_listen 50 +#define SYS_getsockname 51 +#define SYS_getpeername 52 +#define SYS_socketpair 53 +#define SYS_setsockopt 54 +#define SYS_getsockopt 55 +#define SYS_clone 56 +#define SYS_fork 57 +#define SYS_vfork 58 +#define SYS_execve 59 +#define SYS_exit 60 +#define SYS_wait4 61 +#define SYS_kill 62 +#define SYS_uname 63 +#define SYS_semget 64 +#define SYS_semop 65 +#define SYS_semctl 66 +#define SYS_shmdt 67 +#define SYS_msgget 68 +#define SYS_msgsnd 69 +#define SYS_msgrcv 70 +#define SYS_msgctl 71 +#define SYS_fcntl 72 +#define SYS_flock 73 +#define SYS_fsync 74 +#define SYS_fdatasync 75 +#define SYS_truncate 76 +#define SYS_ftruncate 77 +#define SYS_getdents 78 +#define SYS_getcwd 79 +#define SYS_chdir 80 +#define SYS_fchdir 81 +#define SYS_rename 82 +#define SYS_mkdir 83 +#define SYS_rmdir 84 +#define SYS_creat 85 +#define SYS_link 86 +#define SYS_unlink 87 +#define SYS_symlink 88 +#define SYS_readlink 89 +#define SYS_chmod 90 +#define SYS_fchmod 91 +#define SYS_chown 92 +#define SYS_fchown 93 +#define SYS_lchown 94 +#define SYS_umask 95 +#define SYS_gettimeofday 96 +#define SYS_getrlimit 97 +#define SYS_getrusage 98 +#define SYS_sysinfo 99 +#define SYS_times 100 +#define SYS_ptrace 101 +#define SYS_getuid 102 +#define SYS_syslog 103 +#define SYS_getgid 104 +#define SYS_setuid 105 +#define SYS_setgid 106 +#define SYS_geteuid 107 +#define SYS_getegid 108 +#define SYS_setpgid 109 +#define SYS_getppid 110 +#define SYS_getpgrp 111 +#define SYS_setsid 112 +#define SYS_setreuid 113 +#define SYS_setregid 114 +#define SYS_getgroups 115 +#define SYS_setgroups 116 +#define SYS_setresuid 117 +#define SYS_getresuid 118 +#define SYS_setresgid 119 +#define SYS_getresgid 120 +#define SYS_getpgid 121 +#define SYS_setfsuid 122 +#define SYS_setfsgid 123 +#define SYS_getsid 124 +#define SYS_capget 125 +#define SYS_capset 126 +#define SYS_rt_sigpending 127 +#define SYS_rt_sigtimedwait 128 +#define SYS_rt_sigqueueinfo 129 +#define SYS_rt_sigsuspend 130 +#define SYS_sigaltstack 131 +#define SYS_utime 132 +#define SYS_mknod 133 +#define SYS_uselib 134 +#define SYS_personality 135 +#define SYS_ustat 136 +#define SYS_statfs 137 +#define SYS_fstatfs 138 +#define SYS_sysfs 139 +#define SYS_getpriority 140 +#define SYS_setpriority 141 +#define SYS_sched_setparam 142 +#define SYS_sched_getparam 143 +#define SYS_sched_setscheduler 144 +#define SYS_sched_getscheduler 145 +#define SYS_sched_get_priority_max 146 +#define SYS_sched_get_priority_min 147 +#define SYS_sched_rr_get_interval 148 +#define SYS_mlock 149 +#define SYS_munlock 150 +#define SYS_mlockall 151 +#define SYS_munlockall 152 +#define SYS_vhangup 153 +#define SYS_modify_ldt 154 +#define SYS_pivot_root 155 +#define SYS__sysctl 156 +#define SYS_prctl 157 +#define SYS_arch_prctl 158 +#define SYS_adjtimex 159 +#define SYS_setrlimit 160 +#define SYS_chroot 161 +#define SYS_sync 162 +#define SYS_acct 163 +#define SYS_settimeofday 164 +#define SYS_mount 165 +#define SYS_umount2 166 +#define SYS_swapon 167 +#define SYS_swapoff 168 +#define SYS_reboot 169 +#define SYS_sethostname 170 +#define SYS_setdomainname 171 +#define SYS_iopl 172 +#define SYS_ioperm 173 +#define SYS_create_module 174 +#define SYS_init_module 175 +#define SYS_delete_module 176 +#define SYS_get_kernel_syms 177 +#define SYS_query_module 178 +#define SYS_quotactl 179 +#define SYS_nfsservctl 180 +#define SYS_getpmsg 181 +#define SYS_putpmsg 182 +#define SYS_afs_syscall 183 +#define SYS_tuxcall 184 +#define SYS_security 185 +#define SYS_gettid 186 +#define SYS_readahead 187 +#define SYS_setxattr 188 +#define SYS_lsetxattr 189 +#define SYS_fsetxattr 190 +#define SYS_getxattr 191 +#define SYS_lgetxattr 192 +#define SYS_fgetxattr 193 +#define SYS_listxattr 194 +#define SYS_llistxattr 195 +#define SYS_flistxattr 196 +#define SYS_removexattr 197 +#define SYS_lremovexattr 198 +#define SYS_fremovexattr 199 +#define SYS_tkill 200 +#define SYS_time 201 +#define SYS_futex 202 +#define SYS_sched_setaffinity 203 +#define SYS_sched_getaffinity 204 +#define SYS_set_thread_area 205 +#define SYS_io_setup 206 +#define SYS_io_destroy 207 +#define SYS_io_getevents 208 +#define SYS_io_submit 209 +#define SYS_io_cancel 210 +#define SYS_get_thread_area 211 +#define SYS_lookup_dcookie 212 +#define SYS_epoll_create 213 +#define SYS_epoll_ctl_old 214 +#define SYS_epoll_wait_old 215 +#define SYS_remap_file_pages 216 +#define SYS_getdents64 217 +#define SYS_set_tid_address 218 +#define SYS_restart_syscall 219 +#define SYS_semtimedop 220 +#define SYS_fadvise64 221 +#define SYS_timer_create 222 +#define SYS_timer_settime 223 +#define SYS_timer_gettime 224 +#define SYS_timer_getoverrun 225 +#define SYS_timer_delete 226 +#define SYS_clock_settime 227 +#define SYS_clock_gettime 228 +#define SYS_clock_getres 229 +#define SYS_clock_nanosleep 230 +#define SYS_exit_group 231 +#define SYS_epoll_wait 232 +#define SYS_epoll_ctl 233 +#define SYS_tgkill 234 +#define SYS_utimes 235 +#define SYS_vserver 236 +#define SYS_mbind 237 +#define SYS_set_mempolicy 238 +#define SYS_get_mempolicy 239 +#define SYS_mq_open 240 +#define SYS_mq_unlink 241 +#define SYS_mq_timedsend 242 +#define SYS_mq_timedreceive 243 +#define SYS_mq_notify 244 +#define SYS_mq_getsetattr 245 +#define SYS_kexec_load 246 +#define SYS_waitid 247 +#define SYS_add_key 248 +#define SYS_request_key 249 +#define SYS_keyctl 250 +#define SYS_ioprio_set 251 +#define SYS_ioprio_get 252 +#define SYS_inotify_init 253 +#define SYS_inotify_add_watch 254 +#define SYS_inotify_rm_watch 255 +#define SYS_migrate_pages 256 +#define SYS_openat 257 +#define SYS_mkdirat 258 +#define SYS_mknodat 259 +#define SYS_fchownat 260 +#define SYS_futimesat 261 +#define SYS_newfstatat 262 +#define SYS_unlinkat 263 +#define SYS_renameat 264 +#define SYS_linkat 265 +#define SYS_symlinkat 266 +#define SYS_readlinkat 267 +#define SYS_fchmodat 268 +#define SYS_faccessat 269 +#define SYS_pselect6 270 +#define SYS_ppoll 271 +#define SYS_unshare 272 +#define SYS_set_robust_list 273 +#define SYS_get_robust_list 274 +#define SYS_splice 275 +#define SYS_tee 276 +#define SYS_sync_file_range 277 +#define SYS_vmsplice 278 +#define SYS_move_pages 279 +#define SYS_utimensat 280 +#define SYS_epoll_pwait 281 +#define SYS_signalfd 282 +#define SYS_timerfd_create 283 +#define SYS_eventfd 284 +#define SYS_fallocate 285 +#define SYS_timerfd_settime 286 +#define SYS_timerfd_gettime 287 +#define SYS_accept4 288 +#define SYS_signalfd4 289 +#define SYS_eventfd2 290 +#define SYS_epoll_create1 291 +#define SYS_dup3 292 +#define SYS_pipe2 293 +#define SYS_inotify_init1 294 +#define SYS_preadv 295 +#define SYS_pwritev 296 +#define SYS_rt_tgsigqueueinfo 297 +#define SYS_perf_event_open 298 +#define SYS_recvmmsg 299 +#define SYS_fanotify_init 300 +#define SYS_fanotify_mark 301 +#define SYS_prlimit64 302 +#define SYS_name_to_handle_at 303 +#define SYS_open_by_handle_at 304 +#define SYS_clock_adjtime 305 +#define SYS_syncfs 306 +#define SYS_sendmmsg 307 +#define SYS_setns 308 +#define SYS_getcpu 309 +#define SYS_process_vm_readv 310 +#define SYS_process_vm_writev 311 +#define SYS_kcmp 312 +#define SYS_finit_module 313 +#define SYS_sched_setattr 314 +#define SYS_sched_getattr 315 +#define SYS_renameat2 316 +#define SYS_seccomp 317 +#define SYS_getrandom 318 +#define SYS_memfd_create 319 +#define SYS_kexec_file_load 320 +#define SYS_bpf 321 +#define SYS_execveat 322 +#define SYS_userfaultfd 323 +#define SYS_membarrier 324 +#define SYS_mlock2 325 +#define SYS_copy_file_range 326 +#define SYS_preadv2 327 +#define SYS_pwritev2 328 +#define SYS_pkey_mprotect 329 +#define SYS_pkey_alloc 330 +#define SYS_pkey_free 331 +#define SYS_statx 332 +#define SYS_io_pgetevents 333 +#define SYS_rseq 334 +#define SYS_pidfd_send_signal 424 +#define SYS_io_uring_setup 425 +#define SYS_io_uring_enter 426 +#define SYS_io_uring_register 427 +#define SYS_open_tree 428 +#define SYS_move_mount 429 +#define SYS_fsopen 430 +#define SYS_fsconfig 431 +#define SYS_fsmount 432 +#define SYS_fspick 433 +#define SYS_pidfd_open 434 +#define SYS_clone3 435 diff --git a/ports/nasm/port.sh b/ports/nasm/port.sh new file mode 100755 index 0000000..9112f99 --- /dev/null +++ b/ports/nasm/port.sh @@ -0,0 +1,18 @@ +set -e + +SYSROOT=`realpath root` +VERSION=2.15.05 +NAME=nasm +URL="https://www.nasm.us/pub/nasm/releasebuilds/$VERSION/$NAME-$VERSION.tar.xz" +SOURCE="bin/$NAME-$VERSION.tar.xz" + +if [ ! -f $SOURCE ]; then curl $URL > $SOURCE; fi +tar -xJf $SOURCE +mv $NAME-$VERSION bin/$NAME + +cd bin/$NAME +./configure --host=x86_64-essence CC=x86_64-essence-gcc CXX=x86_64-essence-g++ --prefix=/Applications/POSIX +make -j 4 +DESTDIR=$SYSROOT make install +cd ../.. +rm -r bin/$NAME diff --git a/res/Cursors.png b/res/Cursors.png new file mode 100644 index 0000000..e5e7975 Binary files /dev/null and b/res/Cursors.png differ diff --git a/res/Fly Assets/R07_12.DAT b/res/Fly Assets/R07_12.DAT new file mode 100644 index 0000000..f432ca9 Binary files /dev/null and b/res/Fly Assets/R07_12.DAT differ diff --git a/res/Fly Assets/R07_13.DAT b/res/Fly Assets/R07_13.DAT new file mode 100644 index 0000000..4a92c5d Binary files /dev/null and b/res/Fly Assets/R07_13.DAT differ diff --git a/res/Fly Assets/R07_14.DAT b/res/Fly Assets/R07_14.DAT new file mode 100644 index 0000000..a239e85 Binary files /dev/null and b/res/Fly Assets/R07_14.DAT differ diff --git a/res/Fly Assets/R07_16.DAT b/res/Fly Assets/R07_16.DAT new file mode 100644 index 0000000..4ed0aa9 Binary files /dev/null and b/res/Fly Assets/R07_16.DAT differ diff --git a/res/Fly Assets/R07_17.DAT b/res/Fly Assets/R07_17.DAT new file mode 100644 index 0000000..513b28d Binary files /dev/null and b/res/Fly Assets/R07_17.DAT differ diff --git a/res/Fly Assets/R07_18.DAT b/res/Fly Assets/R07_18.DAT new file mode 100644 index 0000000..90fd167 Binary files /dev/null and b/res/Fly Assets/R07_18.DAT differ diff --git a/res/Fly Assets/R08_12.DAT b/res/Fly Assets/R08_12.DAT new file mode 100644 index 0000000..89b732d Binary files /dev/null and b/res/Fly Assets/R08_12.DAT differ diff --git a/res/Fly Assets/R08_13.DAT b/res/Fly Assets/R08_13.DAT new file mode 100644 index 0000000..ebb7c06 Binary files /dev/null and b/res/Fly Assets/R08_13.DAT differ diff --git a/res/Fly Assets/R08_14.DAT b/res/Fly Assets/R08_14.DAT new file mode 100644 index 0000000..c3ee183 Binary files /dev/null and b/res/Fly Assets/R08_14.DAT differ diff --git a/res/Fly Assets/R08_16.DAT b/res/Fly Assets/R08_16.DAT new file mode 100644 index 0000000..7532e44 Binary files /dev/null and b/res/Fly Assets/R08_16.DAT differ diff --git a/res/Fly Assets/R08_17.DAT b/res/Fly Assets/R08_17.DAT new file mode 100644 index 0000000..dea0d0c Binary files /dev/null and b/res/Fly Assets/R08_17.DAT differ diff --git a/res/Fly Assets/R08_18.DAT b/res/Fly Assets/R08_18.DAT new file mode 100644 index 0000000..d2fa08d Binary files /dev/null and b/res/Fly Assets/R08_18.DAT differ diff --git a/res/Fly Assets/R09_10.DAT b/res/Fly Assets/R09_10.DAT new file mode 100644 index 0000000..885a1c3 Binary files /dev/null and b/res/Fly Assets/R09_10.DAT differ diff --git a/res/Fly Assets/R09_11.DAT b/res/Fly Assets/R09_11.DAT new file mode 100644 index 0000000..14167f6 Binary files /dev/null and b/res/Fly Assets/R09_11.DAT differ diff --git a/res/Fly Assets/R09_12.DAT b/res/Fly Assets/R09_12.DAT new file mode 100644 index 0000000..90b51fa Binary files /dev/null and b/res/Fly Assets/R09_12.DAT differ diff --git a/res/Fly Assets/R09_13.DAT b/res/Fly Assets/R09_13.DAT new file mode 100644 index 0000000..6a73a66 Binary files /dev/null and b/res/Fly Assets/R09_13.DAT differ diff --git a/res/Fly Assets/R09_14.DAT b/res/Fly Assets/R09_14.DAT new file mode 100644 index 0000000..92773b3 Binary files /dev/null and b/res/Fly Assets/R09_14.DAT differ diff --git a/res/Fly Assets/R09_15.DAT b/res/Fly Assets/R09_15.DAT new file mode 100644 index 0000000..b8d4e90 Binary files /dev/null and b/res/Fly Assets/R09_15.DAT differ diff --git a/res/Fly Assets/R09_16.DAT b/res/Fly Assets/R09_16.DAT new file mode 100644 index 0000000..31f1e53 Binary files /dev/null and b/res/Fly Assets/R09_16.DAT differ diff --git a/res/Fly Assets/R09_17.DAT b/res/Fly Assets/R09_17.DAT new file mode 100644 index 0000000..432130c Binary files /dev/null and b/res/Fly Assets/R09_17.DAT differ diff --git a/res/Fly Assets/R09_18.DAT b/res/Fly Assets/R09_18.DAT new file mode 100644 index 0000000..2f180b0 Binary files /dev/null and b/res/Fly Assets/R09_18.DAT differ diff --git a/res/Fly Assets/R10_09.DAT b/res/Fly Assets/R10_09.DAT new file mode 100644 index 0000000..1c2a80a Binary files /dev/null and b/res/Fly Assets/R10_09.DAT differ diff --git a/res/Fly Assets/R10_10.DAT b/res/Fly Assets/R10_10.DAT new file mode 100644 index 0000000..6e70647 Binary files /dev/null and b/res/Fly Assets/R10_10.DAT differ diff --git a/res/Fly Assets/R10_11.DAT b/res/Fly Assets/R10_11.DAT new file mode 100644 index 0000000..2a03887 Binary files /dev/null and b/res/Fly Assets/R10_11.DAT differ diff --git a/res/Fly Assets/R10_12.DAT b/res/Fly Assets/R10_12.DAT new file mode 100644 index 0000000..f1cbc9d Binary files /dev/null and b/res/Fly Assets/R10_12.DAT differ diff --git a/res/Fly Assets/R10_13.DAT b/res/Fly Assets/R10_13.DAT new file mode 100644 index 0000000..5488860 Binary files /dev/null and b/res/Fly Assets/R10_13.DAT differ diff --git a/res/Fly Assets/R10_14.DAT b/res/Fly Assets/R10_14.DAT new file mode 100644 index 0000000..d848c5a Binary files /dev/null and b/res/Fly Assets/R10_14.DAT differ diff --git a/res/Fly Assets/R10_15.DAT b/res/Fly Assets/R10_15.DAT new file mode 100644 index 0000000..ef6e3ce Binary files /dev/null and b/res/Fly Assets/R10_15.DAT differ diff --git a/res/Fly Assets/R10_16.DAT b/res/Fly Assets/R10_16.DAT new file mode 100644 index 0000000..4b3797b Binary files /dev/null and b/res/Fly Assets/R10_16.DAT differ diff --git a/res/Fly Assets/R11_09.DAT b/res/Fly Assets/R11_09.DAT new file mode 100644 index 0000000..40cf3e7 Binary files /dev/null and b/res/Fly Assets/R11_09.DAT differ diff --git a/res/Fly Assets/R11_10.DAT b/res/Fly Assets/R11_10.DAT new file mode 100644 index 0000000..8040831 Binary files /dev/null and b/res/Fly Assets/R11_10.DAT differ diff --git a/res/Fly Assets/R11_11.DAT b/res/Fly Assets/R11_11.DAT new file mode 100644 index 0000000..3b457cd Binary files /dev/null and b/res/Fly Assets/R11_11.DAT differ diff --git a/res/Fly Assets/R11_13.DAT b/res/Fly Assets/R11_13.DAT new file mode 100644 index 0000000..0dac4ed Binary files /dev/null and b/res/Fly Assets/R11_13.DAT differ diff --git a/res/Fly Assets/R11_14.DAT b/res/Fly Assets/R11_14.DAT new file mode 100644 index 0000000..0175aeb Binary files /dev/null and b/res/Fly Assets/R11_14.DAT differ diff --git a/res/Fly Assets/R11_15.DAT b/res/Fly Assets/R11_15.DAT new file mode 100644 index 0000000..39b17bc Binary files /dev/null and b/res/Fly Assets/R11_15.DAT differ diff --git a/res/Fly Assets/R12_09.DAT b/res/Fly Assets/R12_09.DAT new file mode 100644 index 0000000..0f1962c Binary files /dev/null and b/res/Fly Assets/R12_09.DAT differ diff --git a/res/Fly Assets/R12_10.DAT b/res/Fly Assets/R12_10.DAT new file mode 100644 index 0000000..1b0749d Binary files /dev/null and b/res/Fly Assets/R12_10.DAT differ diff --git a/res/Fly Assets/R12_11.DAT b/res/Fly Assets/R12_11.DAT new file mode 100644 index 0000000..3a67d31 Binary files /dev/null and b/res/Fly Assets/R12_11.DAT differ diff --git a/res/Fly Assets/bgm1.mid b/res/Fly Assets/bgm1.mid new file mode 100644 index 0000000..38df148 Binary files /dev/null and b/res/Fly Assets/bgm1.mid differ diff --git a/res/Fly Assets/bgm2.mid b/res/Fly Assets/bgm2.mid new file mode 100644 index 0000000..0b640ed Binary files /dev/null and b/res/Fly Assets/bgm2.mid differ diff --git a/res/Fly Assets/bgm3.mid b/res/Fly Assets/bgm3.mid new file mode 100644 index 0000000..cff11c0 Binary files /dev/null and b/res/Fly Assets/bgm3.mid differ diff --git a/res/Fly Assets/block.png b/res/Fly Assets/block.png new file mode 100644 index 0000000..320e3bf Binary files /dev/null and b/res/Fly Assets/block.png differ diff --git a/res/Fly Assets/block2.png b/res/Fly Assets/block2.png new file mode 100644 index 0000000..ef87ee2 Binary files /dev/null and b/res/Fly Assets/block2.png differ diff --git a/res/Fly Assets/check1.png b/res/Fly Assets/check1.png new file mode 100644 index 0000000..d1ff815 Binary files /dev/null and b/res/Fly Assets/check1.png differ diff --git a/res/Fly Assets/check2.png b/res/Fly Assets/check2.png new file mode 100644 index 0000000..2485fb5 Binary files /dev/null and b/res/Fly Assets/check2.png differ diff --git a/res/Fly Assets/controls.png b/res/Fly Assets/controls.png new file mode 100644 index 0000000..1af2e91 Binary files /dev/null and b/res/Fly Assets/controls.png differ diff --git a/res/Fly Assets/dash_msg.png b/res/Fly Assets/dash_msg.png new file mode 100644 index 0000000..6b2753c Binary files /dev/null and b/res/Fly Assets/dash_msg.png differ diff --git a/res/Fly Assets/end1.png b/res/Fly Assets/end1.png new file mode 100644 index 0000000..80958e6 Binary files /dev/null and b/res/Fly Assets/end1.png differ diff --git a/res/Fly Assets/end2.png b/res/Fly Assets/end2.png new file mode 100644 index 0000000..3d31c1a Binary files /dev/null and b/res/Fly Assets/end2.png differ diff --git a/res/Fly Assets/end3.png b/res/Fly Assets/end3.png new file mode 100644 index 0000000..4b98e61 Binary files /dev/null and b/res/Fly Assets/end3.png differ diff --git a/res/Fly Assets/key.png b/res/Fly Assets/key.png new file mode 100644 index 0000000..ee6efb5 Binary files /dev/null and b/res/Fly Assets/key.png differ diff --git a/res/Fly Assets/key_msg.png b/res/Fly Assets/key_msg.png new file mode 100644 index 0000000..81cbe3e Binary files /dev/null and b/res/Fly Assets/key_msg.png differ diff --git a/res/Fly Assets/lock.png b/res/Fly Assets/lock.png new file mode 100644 index 0000000..3fa83df Binary files /dev/null and b/res/Fly Assets/lock.png differ diff --git a/res/Fly Assets/moveblock.png b/res/Fly Assets/moveblock.png new file mode 100644 index 0000000..b5bdae0 Binary files /dev/null and b/res/Fly Assets/moveblock.png differ diff --git a/res/Fly Assets/numbers.png b/res/Fly Assets/numbers.png new file mode 100644 index 0000000..c273e71 Binary files /dev/null and b/res/Fly Assets/numbers.png differ diff --git a/res/Fly Assets/player.png b/res/Fly Assets/player.png new file mode 100644 index 0000000..44526ab Binary files /dev/null and b/res/Fly Assets/player.png differ diff --git a/res/Fly Assets/powerup.png b/res/Fly Assets/powerup.png new file mode 100644 index 0000000..93400ea Binary files /dev/null and b/res/Fly Assets/powerup.png differ diff --git a/res/Fly Assets/star.png b/res/Fly Assets/star.png new file mode 100644 index 0000000..dfe9b56 Binary files /dev/null and b/res/Fly Assets/star.png differ diff --git a/res/Fly Assets/white.png b/res/Fly Assets/white.png new file mode 100644 index 0000000..5e65d7a Binary files /dev/null and b/res/Fly Assets/white.png differ diff --git a/res/Fonts/Hack Bold Italic.ttf b/res/Fonts/Hack Bold Italic.ttf new file mode 100644 index 0000000..3b137d9 Binary files /dev/null and b/res/Fonts/Hack Bold Italic.ttf differ diff --git a/res/Fonts/Hack Bold.ttf b/res/Fonts/Hack Bold.ttf new file mode 100644 index 0000000..7ff4975 Binary files /dev/null and b/res/Fonts/Hack Bold.ttf differ diff --git a/res/Fonts/Hack License.md b/res/Fonts/Hack License.md new file mode 100644 index 0000000..08927e5 --- /dev/null +++ b/res/Fonts/Hack License.md @@ -0,0 +1,45 @@ +The work in the Hack project is Copyright 2018 Source Foundry Authors and licensed under the MIT License + +The work in the DejaVu project was committed to the public domain. + +Bitstream Vera Sans Mono Copyright 2003 Bitstream Inc. and licensed under the Bitstream Vera License with Reserved Font Names "Bitstream" and "Vera" + +### MIT License + +Copyright (c) 2018 Source Foundry Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +### BITSTREAM VERA LICENSE + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. diff --git a/res/Fonts/Hack Regular Italic.ttf b/res/Fonts/Hack Regular Italic.ttf new file mode 100644 index 0000000..d26198a Binary files /dev/null and b/res/Fonts/Hack Regular Italic.ttf differ diff --git a/res/Fonts/Hack Regular.ttf b/res/Fonts/Hack Regular.ttf new file mode 100644 index 0000000..92a90cb Binary files /dev/null and b/res/Fonts/Hack Regular.ttf differ diff --git a/res/Fonts/Inter Black Italic.otf b/res/Fonts/Inter Black Italic.otf new file mode 100644 index 0000000..b24c8ca Binary files /dev/null and b/res/Fonts/Inter Black Italic.otf differ diff --git a/res/Fonts/Inter Black.otf b/res/Fonts/Inter Black.otf new file mode 100644 index 0000000..8394a9f Binary files /dev/null and b/res/Fonts/Inter Black.otf differ diff --git a/res/Fonts/Inter Bold Italic.otf b/res/Fonts/Inter Bold Italic.otf new file mode 100644 index 0000000..be8a3d3 Binary files /dev/null and b/res/Fonts/Inter Bold Italic.otf differ diff --git a/res/Fonts/Inter Bold.otf b/res/Fonts/Inter Bold.otf new file mode 100644 index 0000000..ed9019a Binary files /dev/null and b/res/Fonts/Inter Bold.otf differ diff --git a/res/Fonts/Inter Extra Bold Italic.otf b/res/Fonts/Inter Extra Bold Italic.otf new file mode 100644 index 0000000..3b196c8 Binary files /dev/null and b/res/Fonts/Inter Extra Bold Italic.otf differ diff --git a/res/Fonts/Inter Extra Bold.otf b/res/Fonts/Inter Extra Bold.otf new file mode 100644 index 0000000..e96535f Binary files /dev/null and b/res/Fonts/Inter Extra Bold.otf differ diff --git a/res/Fonts/Inter Extra Light Italic.otf b/res/Fonts/Inter Extra Light Italic.otf new file mode 100644 index 0000000..00512ba Binary files /dev/null and b/res/Fonts/Inter Extra Light Italic.otf differ diff --git a/res/Fonts/Inter Extra Light.otf b/res/Fonts/Inter Extra Light.otf new file mode 100644 index 0000000..677bce0 Binary files /dev/null and b/res/Fonts/Inter Extra Light.otf differ diff --git a/res/Fonts/Inter License.txt b/res/Fonts/Inter License.txt new file mode 100644 index 0000000..1cf8910 --- /dev/null +++ b/res/Fonts/Inter License.txt @@ -0,0 +1,94 @@ +Copyright (c) 2016-2020 The Inter Project Authors. +"Inter" is a Reserved Font Name. +https://github.com/rsms/inter + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION AND CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/res/Fonts/Inter Light Italic.otf b/res/Fonts/Inter Light Italic.otf new file mode 100644 index 0000000..8dee08c Binary files /dev/null and b/res/Fonts/Inter Light Italic.otf differ diff --git a/res/Fonts/Inter Light.otf b/res/Fonts/Inter Light.otf new file mode 100644 index 0000000..95c69f8 Binary files /dev/null and b/res/Fonts/Inter Light.otf differ diff --git a/res/Fonts/Inter Medium Italic.otf b/res/Fonts/Inter Medium Italic.otf new file mode 100644 index 0000000..abd9877 Binary files /dev/null and b/res/Fonts/Inter Medium Italic.otf differ diff --git a/res/Fonts/Inter Medium.otf b/res/Fonts/Inter Medium.otf new file mode 100644 index 0000000..01b0b4a Binary files /dev/null and b/res/Fonts/Inter Medium.otf differ diff --git a/res/Fonts/Inter Regular Italic.otf b/res/Fonts/Inter Regular Italic.otf new file mode 100644 index 0000000..12319b0 Binary files /dev/null and b/res/Fonts/Inter Regular Italic.otf differ diff --git a/res/Fonts/Inter Regular.otf b/res/Fonts/Inter Regular.otf new file mode 100644 index 0000000..e94fa45 Binary files /dev/null and b/res/Fonts/Inter Regular.otf differ diff --git a/res/Fonts/Inter Semi Bold Italic.otf b/res/Fonts/Inter Semi Bold Italic.otf new file mode 100644 index 0000000..2137d65 Binary files /dev/null and b/res/Fonts/Inter Semi Bold Italic.otf differ diff --git a/res/Fonts/Inter Semi Bold.otf b/res/Fonts/Inter Semi Bold.otf new file mode 100644 index 0000000..2329402 Binary files /dev/null and b/res/Fonts/Inter Semi Bold.otf differ diff --git a/res/Fonts/Inter Thin Italic.otf b/res/Fonts/Inter Thin Italic.otf new file mode 100644 index 0000000..f6e240a Binary files /dev/null and b/res/Fonts/Inter Thin Italic.otf differ diff --git a/res/Fonts/Inter Thin.otf b/res/Fonts/Inter Thin.otf new file mode 100644 index 0000000..0aac1a9 Binary files /dev/null and b/res/Fonts/Inter Thin.otf differ diff --git a/res/Media/A Study in Scarlet.txt b/res/Media/A Study in Scarlet.txt new file mode 100644 index 0000000..3469440 --- /dev/null +++ b/res/Media/A Study in Scarlet.txt @@ -0,0 +1,4633 @@ +A STUDY IN SCARLET. + +PART I. + +CHAPTER I. MR. SHERLOCK HOLMES. + +IN the year 1878 I took my degree of Doctor of Medicine of the +University of London, and proceeded to Netley to go through the course +prescribed for surgeons in the army. Having completed my studies there, +I was duly attached to the Fifth Northumberland Fusiliers as Assistant +Surgeon. The regiment was stationed in India at the time, and before +I could join it, the second Afghan war had broken out. On landing at +Bombay, I learned that my corps had advanced through the passes, and +was already deep in the enemy's country. I followed, however, with many +other officers who were in the same situation as myself, and succeeded +in reaching Candahar in safety, where I found my regiment, and at once +entered upon my new duties. + +The campaign brought honours and promotion to many, but for me it had +nothing but misfortune and disaster. I was removed from my brigade and +attached to the Berkshires, with whom I served at the fatal battle of +Maiwand. There I was struck on the shoulder by a Jezail bullet, which +shattered the bone and grazed the subclavian artery. I should have +fallen into the hands of the murderous Ghazis had it not been for the +devotion and courage shown by Murray, my orderly, who threw me across a +pack-horse, and succeeded in bringing me safely to the British lines. + +Worn with pain, and weak from the prolonged hardships which I had +undergone, I was removed, with a great train of wounded sufferers, to +the base hospital at Peshawar. Here I rallied, and had already improved +so far as to be able to walk about the wards, and even to bask a little +upon the verandah, when I was struck down by enteric fever, that curse +of our Indian possessions. For months my life was despaired of, and +when at last I came to myself and became convalescent, I was so weak and +emaciated that a medical board determined that not a day should be lost +in sending me back to England. I was dispatched, accordingly, in the +troopship Orontes, and landed a month later on Portsmouth jetty, with +my health irretrievably ruined, but with permission from a paternal +government to spend the next nine months in attempting to improve it. + +I had neither kith nor kin in England, and was therefore as free as +air--or as free as an income of eleven shillings and sixpence a day will +permit a man to be. Under such circumstances, I naturally gravitated to +London, that great cesspool into which all the loungers and idlers of +the Empire are irresistibly drained. There I stayed for some time at +a private hotel in the Strand, leading a comfortless, meaningless +existence, and spending such money as I had, considerably more freely +than I ought. So alarming did the state of my finances become, that +I soon realized that I must either leave the metropolis and rusticate +somewhere in the country, or that I must make a complete alteration in +my style of living. Choosing the latter alternative, I began by making +up my mind to leave the hotel, and to take up my quarters in some less +pretentious and less expensive domicile. + +On the very day that I had come to this conclusion, I was standing at +the Criterion Bar, when some one tapped me on the shoulder, and turning +round I recognized young Stamford, who had been a dresser under me at +Barts. The sight of a friendly face in the great wilderness of London is +a pleasant thing indeed to a lonely man. In old days Stamford had never +been a particular crony of mine, but now I hailed him with enthusiasm, +and he, in his turn, appeared to be delighted to see me. In the +exuberance of my joy, I asked him to lunch with me at the Holborn, and +we started off together in a hansom. + +Whatever have you been doing with yourself, Watson? he asked in +undisguised wonder, as we rattled through the crowded London streets. +You are as thin as a lath and as brown as a nut. + +I gave him a short sketch of my adventures, and had hardly concluded it +by the time that we reached our destination. + +Poor devil! he said, commiseratingly, after he had listened to my +misfortunes. What are you up to now? + +Looking for lodgings. [3] I answered. Trying to solve the problem +as to whether it is possible to get comfortable rooms at a reasonable +price. + +That's a strange thing, remarked my companion; you are the second man +to-day that has used that expression to me. + +And who was the first? I asked. + +A fellow who is working at the chemical laboratory up at the hospital. +He was bemoaning himself this morning because he could not get someone +to go halves with him in some nice rooms which he had found, and which +were too much for his purse. + +By Jove! I cried, if he really wants someone to share the rooms and +the expense, I am the very man for him. I should prefer having a partner +to being alone. + +Young Stamford looked rather strangely at me over his wine-glass. You +don't know Sherlock Holmes yet, he said; perhaps you would not care +for him as a constant companion. + +Why, what is there against him? + +Oh, I didn't say there was anything against him. He is a little queer +in his ideas--an enthusiast in some branches of science. As far as I +know he is a decent fellow enough. + +A medical student, I suppose? said I. + +No--I have no idea what he intends to go in for. I believe he is well +up in anatomy, and he is a first-class chemist; but, as far as I know, +he has never taken out any systematic medical classes. His studies are +very desultory and eccentric, but he has amassed a lot of out-of-the way +knowledge which would astonish his professors. + +Did you never ask him what he was going in for? I asked. + +No; he is not a man that it is easy to draw out, though he can be +communicative enough when the fancy seizes him. + +I should like to meet him, I said. If I am to lodge with anyone, I +should prefer a man of studious and quiet habits. I am not strong +enough yet to stand much noise or excitement. I had enough of both in +Afghanistan to last me for the remainder of my natural existence. How +could I meet this friend of yours? + +He is sure to be at the laboratory, returned my companion. He either +avoids the place for weeks, or else he works there from morning to +night. If you like, we shall drive round together after luncheon. + +Certainly, I answered, and the conversation drifted away into other +channels. + +As we made our way to the hospital after leaving the Holborn, Stamford +gave me a few more particulars about the gentleman whom I proposed to +take as a fellow-lodger. + +You mustn't blame me if you don't get on with him, he said; I know +nothing more of him than I have learned from meeting him occasionally in +the laboratory. You proposed this arrangement, so you must not hold me +responsible. + +If we don't get on it will be easy to part company, I answered. It +seems to me, Stamford, I added, looking hard at my companion, that you +have some reason for washing your hands of the matter. Is this fellow's +temper so formidable, or what is it? Don't be mealy-mouthed about it. + +It is not easy to express the inexpressible, he answered with a laugh. +Holmes is a little too scientific for my tastes--it approaches to +cold-bloodedness. I could imagine his giving a friend a little pinch of +the latest vegetable alkaloid, not out of malevolence, you understand, +but simply out of a spirit of inquiry in order to have an accurate idea +of the effects. To do him justice, I think that he would take it himself +with the same readiness. He appears to have a passion for definite and +exact knowledge. + +Very right too. + +Yes, but it may be pushed to excess. When it comes to beating the +subjects in the dissecting-rooms with a stick, it is certainly taking +rather a bizarre shape. + +Beating the subjects! + +Yes, to verify how far bruises may be produced after death. I saw him +at it with my own eyes. + +And yet you say he is not a medical student? + +No. Heaven knows what the objects of his studies are. But here we +are, and you must form your own impressions about him. As he spoke, we +turned down a narrow lane and passed through a small side-door, which +opened into a wing of the great hospital. It was familiar ground to me, +and I needed no guiding as we ascended the bleak stone staircase and +made our way down the long corridor with its vista of whitewashed +wall and dun-coloured doors. Near the further end a low arched passage +branched away from it and led to the chemical laboratory. + +This was a lofty chamber, lined and littered with countless bottles. +Broad, low tables were scattered about, which bristled with retorts, +test-tubes, and little Bunsen lamps, with their blue flickering flames. +There was only one student in the room, who was bending over a distant +table absorbed in his work. At the sound of our steps he glanced round +and sprang to his feet with a cry of pleasure. I've found it! I've +found it, he shouted to my companion, running towards us with a +test-tube in his hand. I have found a re-agent which is precipitated +by hoemoglobin, [4] and by nothing else. Had he discovered a gold mine, +greater delight could not have shone upon his features. + +Dr. Watson, Mr. Sherlock Holmes, said Stamford, introducing us. + +How are you? he said cordially, gripping my hand with a strength +for which I should hardly have given him credit. You have been in +Afghanistan, I perceive. + +How on earth did you know that? I asked in astonishment. + +Never mind, said he, chuckling to himself. The question now is about +hoemoglobin. No doubt you see the significance of this discovery of +mine? + +It is interesting, chemically, no doubt, I answered, but +practically---- + +Why, man, it is the most practical medico-legal discovery for years. +Don't you see that it gives us an infallible test for blood stains. Come +over here now! He seized me by the coat-sleeve in his eagerness, and +drew me over to the table at which he had been working. Let us have +some fresh blood, he said, digging a long bodkin into his finger, and +drawing off the resulting drop of blood in a chemical pipette. Now, I +add this small quantity of blood to a litre of water. You perceive that +the resulting mixture has the appearance of pure water. The proportion +of blood cannot be more than one in a million. I have no doubt, however, +that we shall be able to obtain the characteristic reaction. As he +spoke, he threw into the vessel a few white crystals, and then added +some drops of a transparent fluid. In an instant the contents assumed a +dull mahogany colour, and a brownish dust was precipitated to the bottom +of the glass jar. + +Ha! ha! he cried, clapping his hands, and looking as delighted as a +child with a new toy. What do you think of that? + +It seems to be a very delicate test, I remarked. + +Beautiful! beautiful! The old Guiacum test was very clumsy and +uncertain. So is the microscopic examination for blood corpuscles. The +latter is valueless if the stains are a few hours old. Now, this appears +to act as well whether the blood is old or new. Had this test been +invented, there are hundreds of men now walking the earth who would long +ago have paid the penalty of their crimes. + +Indeed! I murmured. + +Criminal cases are continually hinging upon that one point. A man is +suspected of a crime months perhaps after it has been committed. His +linen or clothes are examined, and brownish stains discovered upon them. +Are they blood stains, or mud stains, or rust stains, or fruit stains, +or what are they? That is a question which has puzzled many an expert, +and why? Because there was no reliable test. Now we have the Sherlock +Holmes' test, and there will no longer be any difficulty. + +His eyes fairly glittered as he spoke, and he put his hand over his +heart and bowed as if to some applauding crowd conjured up by his +imagination. + +You are to be congratulated, I remarked, considerably surprised at his +enthusiasm. + +There was the case of Von Bischoff at Frankfort last year. He would +certainly have been hung had this test been in existence. Then there was +Mason of Bradford, and the notorious Muller, and Lefevre of Montpellier, +and Samson of New Orleans. I could name a score of cases in which it +would have been decisive. + +You seem to be a walking calendar of crime, said Stamford with a +laugh. You might start a paper on those lines. Call it the Police News +of the Past. + +Very interesting reading it might be made, too, remarked Sherlock +Holmes, sticking a small piece of plaster over the prick on his finger. +I have to be careful, he continued, turning to me with a smile, for I +dabble with poisons a good deal. He held out his hand as he spoke, and +I noticed that it was all mottled over with similar pieces of plaster, +and discoloured with strong acids. + +We came here on business, said Stamford, sitting down on a high +three-legged stool, and pushing another one in my direction with +his foot. My friend here wants to take diggings, and as you were +complaining that you could get no one to go halves with you, I thought +that I had better bring you together. + +Sherlock Holmes seemed delighted at the idea of sharing his rooms with +me. I have my eye on a suite in Baker Street, he said, which would +suit us down to the ground. You don't mind the smell of strong tobacco, +I hope? + +I always smoke ship's' myself, I answered. + +That's good enough. I generally have chemicals about, and occasionally +do experiments. Would that annoy you? + +By no means. + +Let me see--what are my other shortcomings. I get in the dumps at +times, and don't open my mouth for days on end. You must not think I am +sulky when I do that. Just let me alone, and I'll soon be right. What +have you to confess now? It's just as well for two fellows to know the +worst of one another before they begin to live together. + +I laughed at this cross-examination. I keep a bull pup, I said, and +I object to rows because my nerves are shaken, and I get up at all sorts +of ungodly hours, and I am extremely lazy. I have another set of vices +when I'm well, but those are the principal ones at present. + +Do you include violin-playing in your category of rows? he asked, +anxiously. + +It depends on the player, I answered. A well-played violin is a treat +for the gods--a badly-played one---- + +Oh, that's all right, he cried, with a merry laugh. I think we may +consider the thing as settled--that is, if the rooms are agreeable to +you. + +When shall we see them? + +Call for me here at noon to-morrow, and we'll go together and settle +everything, he answered. + +All right--noon exactly, said I, shaking his hand. + +We left him working among his chemicals, and we walked together towards +my hotel. + +By the way, I asked suddenly, stopping and turning upon Stamford, how +the deuce did he know that I had come from Afghanistan? + +My companion smiled an enigmatical smile. That's just his little +peculiarity, he said. A good many people have wanted to know how he +finds things out. + +Oh! a mystery is it? I cried, rubbing my hands. This is very piquant. +I am much obliged to you for bringing us together. The proper study of +mankind is man, you know. + +You must study him, then, Stamford said, as he bade me good-bye. +You'll find him a knotty problem, though. I'll wager he learns more +about you than you about him. Good-bye. + +Good-bye, I answered, and strolled on to my hotel, considerably +interested in my new acquaintance. + + + + +CHAPTER II. THE SCIENCE OF DEDUCTION. + + +WE met next day as he had arranged, and inspected the rooms at No. 221B, +[5] Baker Street, of which he had spoken at our meeting. They +consisted of a couple of comfortable bed-rooms and a single large +airy sitting-room, cheerfully furnished, and illuminated by two broad +windows. So desirable in every way were the apartments, and so moderate +did the terms seem when divided between us, that the bargain was +concluded upon the spot, and we at once entered into possession. +That very evening I moved my things round from the hotel, and on the +following morning Sherlock Holmes followed me with several boxes and +portmanteaus. For a day or two we were busily employed in unpacking and +laying out our property to the best advantage. That done, we +gradually began to settle down and to accommodate ourselves to our new +surroundings. + +Holmes was certainly not a difficult man to live with. He was quiet +in his ways, and his habits were regular. It was rare for him to be +up after ten at night, and he had invariably breakfasted and gone out +before I rose in the morning. Sometimes he spent his day at the chemical +laboratory, sometimes in the dissecting-rooms, and occasionally in long +walks, which appeared to take him into the lowest portions of the City. +Nothing could exceed his energy when the working fit was upon him; but +now and again a reaction would seize him, and for days on end he would +lie upon the sofa in the sitting-room, hardly uttering a word or moving +a muscle from morning to night. On these occasions I have noticed such +a dreamy, vacant expression in his eyes, that I might have suspected him +of being addicted to the use of some narcotic, had not the temperance +and cleanliness of his whole life forbidden such a notion. + +As the weeks went by, my interest in him and my curiosity as to his +aims in life, gradually deepened and increased. His very person and +appearance were such as to strike the attention of the most casual +observer. In height he was rather over six feet, and so excessively +lean that he seemed to be considerably taller. His eyes were sharp and +piercing, save during those intervals of torpor to which I have alluded; +and his thin, hawk-like nose gave his whole expression an air of +alertness and decision. His chin, too, had the prominence and squareness +which mark the man of determination. His hands were invariably +blotted with ink and stained with chemicals, yet he was possessed of +extraordinary delicacy of touch, as I frequently had occasion to observe +when I watched him manipulating his fragile philosophical instruments. + +The reader may set me down as a hopeless busybody, when I confess how +much this man stimulated my curiosity, and how often I endeavoured +to break through the reticence which he showed on all that concerned +himself. Before pronouncing judgment, however, be it remembered, how +objectless was my life, and how little there was to engage my attention. +My health forbade me from venturing out unless the weather was +exceptionally genial, and I had no friends who would call upon me and +break the monotony of my daily existence. Under these circumstances, I +eagerly hailed the little mystery which hung around my companion, and +spent much of my time in endeavouring to unravel it. + +He was not studying medicine. He had himself, in reply to a question, +confirmed Stamford's opinion upon that point. Neither did he appear to +have pursued any course of reading which might fit him for a degree in +science or any other recognized portal which would give him an entrance +into the learned world. Yet his zeal for certain studies was remarkable, +and within eccentric limits his knowledge was so extraordinarily ample +and minute that his observations have fairly astounded me. Surely no man +would work so hard or attain such precise information unless he had some +definite end in view. Desultory readers are seldom remarkable for the +exactness of their learning. No man burdens his mind with small matters +unless he has some very good reason for doing so. + +His ignorance was as remarkable as his knowledge. Of contemporary +literature, philosophy and politics he appeared to know next to nothing. +Upon my quoting Thomas Carlyle, he inquired in the naivest way who he +might be and what he had done. My surprise reached a climax, however, +when I found incidentally that he was ignorant of the Copernican Theory +and of the composition of the Solar System. That any civilized human +being in this nineteenth century should not be aware that the earth +travelled round the sun appeared to be to me such an extraordinary fact +that I could hardly realize it. + +You appear to be astonished, he said, smiling at my expression of +surprise. Now that I do know it I shall do my best to forget it. + +To forget it! + +You see, he explained, I consider that a man's brain originally is +like a little empty attic, and you have to stock it with such furniture +as you choose. A fool takes in all the lumber of every sort that he +comes across, so that the knowledge which might be useful to him gets +crowded out, or at best is jumbled up with a lot of other things so that +he has a difficulty in laying his hands upon it. Now the skilful workman +is very careful indeed as to what he takes into his brain-attic. He will +have nothing but the tools which may help him in doing his work, but of +these he has a large assortment, and all in the most perfect order. It +is a mistake to think that that little room has elastic walls and can +distend to any extent. Depend upon it there comes a time when for every +addition of knowledge you forget something that you knew before. It is +of the highest importance, therefore, not to have useless facts elbowing +out the useful ones. + +But the Solar System! I protested. + +What the deuce is it to me? he interrupted impatiently; you say +that we go round the sun. If we went round the moon it would not make a +pennyworth of difference to me or to my work. + +I was on the point of asking him what that work might be, but something +in his manner showed me that the question would be an unwelcome one. I +pondered over our short conversation, however, and endeavoured to draw +my deductions from it. He said that he would acquire no knowledge which +did not bear upon his object. Therefore all the knowledge which he +possessed was such as would be useful to him. I enumerated in my own +mind all the various points upon which he had shown me that he was +exceptionally well-informed. I even took a pencil and jotted them down. +I could not help smiling at the document when I had completed it. It ran +in this way-- + + +SHERLOCK HOLMES--his limits. + + 1. Knowledge of Literature.--Nil. + 2. Philosophy.--Nil. + 3. Astronomy.--Nil. + 4. Politics.--Feeble. + 5. Botany.--Variable. Well up in belladonna, + opium, and poisons generally. + Knows nothing of practical gardening. + 6. Geology.--Practical, but limited. + Tells at a glance different soils + from each other. After walks has + shown me splashes upon his trousers, + and told me by their colour and + consistence in what part of London + he had received them. + 7. Chemistry.--Profound. + 8. Anatomy.--Accurate, but unsystematic. + 9. Sensational Literature.--Immense. He appears + to know every detail of every horror + perpetrated in the century. + 10. Plays the violin well. + 11. Is an expert singlestick player, boxer, and swordsman. + 12. Has a good practical knowledge of British law. + + +When I had got so far in my list I threw it into the fire in despair. +If I can only find what the fellow is driving at by reconciling all +these accomplishments, and discovering a calling which needs them all, + I said to myself, I may as well give up the attempt at once. + +I see that I have alluded above to his powers upon the violin. These +were very remarkable, but as eccentric as all his other accomplishments. +That he could play pieces, and difficult pieces, I knew well, because +at my request he has played me some of Mendelssohn's Lieder, and other +favourites. When left to himself, however, he would seldom produce any +music or attempt any recognized air. Leaning back in his arm-chair of +an evening, he would close his eyes and scrape carelessly at the fiddle +which was thrown across his knee. Sometimes the chords were sonorous and +melancholy. Occasionally they were fantastic and cheerful. Clearly they +reflected the thoughts which possessed him, but whether the music aided +those thoughts, or whether the playing was simply the result of a whim +or fancy was more than I could determine. I might have rebelled against +these exasperating solos had it not been that he usually terminated them +by playing in quick succession a whole series of my favourite airs as a +slight compensation for the trial upon my patience. + +During the first week or so we had no callers, and I had begun to think +that my companion was as friendless a man as I was myself. Presently, +however, I found that he had many acquaintances, and those in the most +different classes of society. There was one little sallow rat-faced, +dark-eyed fellow who was introduced to me as Mr. Lestrade, and who came +three or four times in a single week. One morning a young girl called, +fashionably dressed, and stayed for half an hour or more. The same +afternoon brought a grey-headed, seedy visitor, looking like a Jew +pedlar, who appeared to me to be much excited, and who was closely +followed by a slip-shod elderly woman. On another occasion an old +white-haired gentleman had an interview with my companion; and on +another a railway porter in his velveteen uniform. When any of these +nondescript individuals put in an appearance, Sherlock Holmes used to +beg for the use of the sitting-room, and I would retire to my bed-room. +He always apologized to me for putting me to this inconvenience. I have +to use this room as a place of business, he said, and these people +are my clients. Again I had an opportunity of asking him a point blank +question, and again my delicacy prevented me from forcing another man to +confide in me. I imagined at the time that he had some strong reason for +not alluding to it, but he soon dispelled the idea by coming round to +the subject of his own accord. + +It was upon the 4th of March, as I have good reason to remember, that I +rose somewhat earlier than usual, and found that Sherlock Holmes had not +yet finished his breakfast. The landlady had become so accustomed to my +late habits that my place had not been laid nor my coffee prepared. With +the unreasonable petulance of mankind I rang the bell and gave a curt +intimation that I was ready. Then I picked up a magazine from the table +and attempted to while away the time with it, while my companion munched +silently at his toast. One of the articles had a pencil mark at the +heading, and I naturally began to run my eye through it. + +Its somewhat ambitious title was The Book of Life, and it attempted to +show how much an observant man might learn by an accurate and systematic +examination of all that came in his way. It struck me as being a +remarkable mixture of shrewdness and of absurdity. The reasoning was +close and intense, but the deductions appeared to me to be far-fetched +and exaggerated. The writer claimed by a momentary expression, a twitch +of a muscle or a glance of an eye, to fathom a man's inmost thoughts. +Deceit, according to him, was an impossibility in the case of one +trained to observation and analysis. His conclusions were as infallible +as so many propositions of Euclid. So startling would his results appear +to the uninitiated that until they learned the processes by which he had +arrived at them they might well consider him as a necromancer. + +From a drop of water, said the writer, a logician could infer the +possibility of an Atlantic or a Niagara without having seen or heard of +one or the other. So all life is a great chain, the nature of which is +known whenever we are shown a single link of it. Like all other arts, +the Science of Deduction and Analysis is one which can only be acquired +by long and patient study nor is life long enough to allow any mortal +to attain the highest possible perfection in it. Before turning to +those moral and mental aspects of the matter which present the greatest +difficulties, let the enquirer begin by mastering more elementary +problems. Let him, on meeting a fellow-mortal, learn at a glance to +distinguish the history of the man, and the trade or profession to +which he belongs. Puerile as such an exercise may seem, it sharpens the +faculties of observation, and teaches one where to look and what to look +for. By a man's finger nails, by his coat-sleeve, by his boot, by his +trouser knees, by the callosities of his forefinger and thumb, by his +expression, by his shirt cuffs--by each of these things a man's calling +is plainly revealed. That all united should fail to enlighten the +competent enquirer in any case is almost inconceivable. + +What ineffable twaddle! I cried, slapping the magazine down on the +table, I never read such rubbish in my life. + +What is it? asked Sherlock Holmes. + +Why, this article, I said, pointing at it with my egg spoon as I sat +down to my breakfast. I see that you have read it since you have marked +it. I don't deny that it is smartly written. It irritates me though. It +is evidently the theory of some arm-chair lounger who evolves all these +neat little paradoxes in the seclusion of his own study. It is not +practical. I should like to see him clapped down in a third class +carriage on the Underground, and asked to give the trades of all his +fellow-travellers. I would lay a thousand to one against him. + +You would lose your money, Sherlock Holmes remarked calmly. As for +the article I wrote it myself. + +You! + +Yes, I have a turn both for observation and for deduction. The +theories which I have expressed there, and which appear to you to be so +chimerical are really extremely practical--so practical that I depend +upon them for my bread and cheese. + +And how? I asked involuntarily. + +Well, I have a trade of my own. I suppose I am the only one in the +world. I'm a consulting detective, if you can understand what that is. +Here in London we have lots of Government detectives and lots of private +ones. When these fellows are at fault they come to me, and I manage to +put them on the right scent. They lay all the evidence before me, and I +am generally able, by the help of my knowledge of the history of +crime, to set them straight. There is a strong family resemblance about +misdeeds, and if you have all the details of a thousand at your finger +ends, it is odd if you can't unravel the thousand and first. Lestrade +is a well-known detective. He got himself into a fog recently over a +forgery case, and that was what brought him here. + +And these other people? + +They are mostly sent on by private inquiry agencies. They are +all people who are in trouble about something, and want a little +enlightening. I listen to their story, they listen to my comments, and +then I pocket my fee. + +But do you mean to say, I said, that without leaving your room you +can unravel some knot which other men can make nothing of, although they +have seen every detail for themselves? + +Quite so. I have a kind of intuition that way. Now and again a case +turns up which is a little more complex. Then I have to bustle about and +see things with my own eyes. You see I have a lot of special knowledge +which I apply to the problem, and which facilitates matters wonderfully. +Those rules of deduction laid down in that article which aroused your +scorn, are invaluable to me in practical work. Observation with me is +second nature. You appeared to be surprised when I told you, on our +first meeting, that you had come from Afghanistan. + +You were told, no doubt. + +Nothing of the sort. I _knew_ you came from Afghanistan. From long +habit the train of thoughts ran so swiftly through my mind, that I +arrived at the conclusion without being conscious of intermediate steps. +There were such steps, however. The train of reasoning ran, Here is a +gentleman of a medical type, but with the air of a military man. Clearly +an army doctor, then. He has just come from the tropics, for his face is +dark, and that is not the natural tint of his skin, for his wrists are +fair. He has undergone hardship and sickness, as his haggard face says +clearly. His left arm has been injured. He holds it in a stiff and +unnatural manner. Where in the tropics could an English army doctor have +seen much hardship and got his arm wounded? Clearly in Afghanistan. The +whole train of thought did not occupy a second. I then remarked that you +came from Afghanistan, and you were astonished. + +It is simple enough as you explain it, I said, smiling. You remind +me of Edgar Allen Poe's Dupin. I had no idea that such individuals did +exist outside of stories. + +Sherlock Holmes rose and lit his pipe. No doubt you think that you are +complimenting me in comparing me to Dupin, he observed. Now, in my +opinion, Dupin was a very inferior fellow. That trick of his of breaking +in on his friends' thoughts with an apropos remark after a quarter of +an hour's silence is really very showy and superficial. He had some +analytical genius, no doubt; but he was by no means such a phenomenon as +Poe appeared to imagine. + +Have you read Gaboriau's works? I asked. Does Lecoq come up to your +idea of a detective? + +Sherlock Holmes sniffed sardonically. Lecoq was a miserable bungler, + he said, in an angry voice; he had only one thing to recommend him, and +that was his energy. That book made me positively ill. The question was +how to identify an unknown prisoner. I could have done it in twenty-four +hours. Lecoq took six months or so. It might be made a text-book for +detectives to teach them what to avoid. + +I felt rather indignant at having two characters whom I had admired +treated in this cavalier style. I walked over to the window, and stood +looking out into the busy street. This fellow may be very clever, I +said to myself, but he is certainly very conceited. + +There are no crimes and no criminals in these days, he said, +querulously. What is the use of having brains in our profession. I know +well that I have it in me to make my name famous. No man lives or has +ever lived who has brought the same amount of study and of natural +talent to the detection of crime which I have done. And what is the +result? There is no crime to detect, or, at most, some bungling villainy +with a motive so transparent that even a Scotland Yard official can see +through it. + +I was still annoyed at his bumptious style of conversation. I thought it +best to change the topic. + +I wonder what that fellow is looking for? I asked, pointing to a +stalwart, plainly-dressed individual who was walking slowly down the +other side of the street, looking anxiously at the numbers. He had +a large blue envelope in his hand, and was evidently the bearer of a +message. + +You mean the retired sergeant of Marines, said Sherlock Holmes. + +Brag and bounce! thought I to myself. He knows that I cannot verify +his guess. + +The thought had hardly passed through my mind when the man whom we were +watching caught sight of the number on our door, and ran rapidly across +the roadway. We heard a loud knock, a deep voice below, and heavy steps +ascending the stair. + +For Mr. Sherlock Holmes, he said, stepping into the room and handing +my friend the letter. + +Here was an opportunity of taking the conceit out of him. He little +thought of this when he made that random shot. May I ask, my lad, I +said, in the blandest voice, what your trade may be? + +Commissionaire, sir, he said, gruffly. Uniform away for repairs. + +And you were? I asked, with a slightly malicious glance at my +companion. + +A sergeant, sir, Royal Marine Light Infantry, sir. No answer? Right, +sir. + +He clicked his heels together, raised his hand in a salute, and was +gone. + + + + +CHAPTER III. THE LAURISTON GARDEN MYSTERY [6] + + +I CONFESS that I was considerably startled by this fresh proof of the +practical nature of my companion's theories. My respect for his powers +of analysis increased wondrously. There still remained some lurking +suspicion in my mind, however, that the whole thing was a pre-arranged +episode, intended to dazzle me, though what earthly object he could have +in taking me in was past my comprehension. When I looked at him he +had finished reading the note, and his eyes had assumed the vacant, +lack-lustre expression which showed mental abstraction. + +How in the world did you deduce that? I asked. + +Deduce what? said he, petulantly. + +Why, that he was a retired sergeant of Marines. + +I have no time for trifles, he answered, brusquely; then with a smile, +Excuse my rudeness. You broke the thread of my thoughts; but perhaps +it is as well. So you actually were not able to see that that man was a +sergeant of Marines? + +No, indeed. + +It was easier to know it than to explain why I knew it. If you +were asked to prove that two and two made four, you might find some +difficulty, and yet you are quite sure of the fact. Even across the +street I could see a great blue anchor tattooed on the back of the +fellow's hand. That smacked of the sea. He had a military carriage, +however, and regulation side whiskers. There we have the marine. He was +a man with some amount of self-importance and a certain air of command. +You must have observed the way in which he held his head and swung +his cane. A steady, respectable, middle-aged man, too, on the face of +him--all facts which led me to believe that he had been a sergeant. + +Wonderful! I ejaculated. + +Commonplace, said Holmes, though I thought from his expression that he +was pleased at my evident surprise and admiration. I said just now that +there were no criminals. It appears that I am wrong--look at this! He +threw me over the note which the commissionaire had brought. [7] + +Why, I cried, as I cast my eye over it, this is terrible! + +It does seem to be a little out of the common, he remarked, calmly. +Would you mind reading it to me aloud? + +This is the letter which I read to him---- + + +MY DEAR MR. SHERLOCK HOLMES,-- + +There has been a bad business during the night at 3, Lauriston Gardens, +off the Brixton Road. Our man on the beat saw a light there about two in +the morning, and as the house was an empty one, suspected that something +was amiss. He found the door open, and in the front room, which is bare +of furniture, discovered the body of a gentleman, well dressed, and +having cards in his pocket bearing the name of Enoch J. Drebber, +Cleveland, Ohio, U.S.A. There had been no robbery, nor is there any +evidence as to how the man met his death. There are marks of blood in +the room, but there is no wound upon his person. We are at a loss as to +how he came into the empty house; indeed, the whole affair is a puzzler. +If you can come round to the house any time before twelve, you will find +me there. I have left everything _in statu quo_ until I hear from you. +If you are unable to come I shall give you fuller details, and would +esteem it a great kindness if you would favour me with your opinion. +Yours faithfully, + +TOBIAS GREGSON. + + +Gregson is the smartest of the Scotland Yarders, my friend remarked; +he and Lestrade are the pick of a bad lot. They are both quick and +energetic, but conventional--shockingly so. They have their knives +into one another, too. They are as jealous as a pair of professional +beauties. There will be some fun over this case if they are both put +upon the scent. + +I was amazed at the calm way in which he rippled on. Surely there is +not a moment to be lost, I cried, shall I go and order you a cab? + +I'm not sure about whether I shall go. I am the most incurably lazy +devil that ever stood in shoe leather--that is, when the fit is on me, +for I can be spry enough at times. + +Why, it is just such a chance as you have been longing for. + +My dear fellow, what does it matter to me. Supposing I unravel the +whole matter, you may be sure that Gregson, Lestrade, and Co. will +pocket all the credit. That comes of being an unofficial personage. + +But he begs you to help him. + +Yes. He knows that I am his superior, and acknowledges it to me; but +he would cut his tongue out before he would own it to any third person. +However, we may as well go and have a look. I shall work it out on my +own hook. I may have a laugh at them if I have nothing else. Come on! + +He hustled on his overcoat, and bustled about in a way that showed that +an energetic fit had superseded the apathetic one. + +Get your hat, he said. + +You wish me to come? + +Yes, if you have nothing better to do. A minute later we were both in +a hansom, driving furiously for the Brixton Road. + +It was a foggy, cloudy morning, and a dun-coloured veil hung over the +house-tops, looking like the reflection of the mud-coloured streets +beneath. My companion was in the best of spirits, and prattled away +about Cremona fiddles, and the difference between a Stradivarius and +an Amati. As for myself, I was silent, for the dull weather and the +melancholy business upon which we were engaged, depressed my spirits. + +You don't seem to give much thought to the matter in hand, I said at +last, interrupting Holmes' musical disquisition. + +No data yet, he answered. It is a capital mistake to theorize before +you have all the evidence. It biases the judgment. + +You will have your data soon, I remarked, pointing with my finger; +this is the Brixton Road, and that is the house, if I am not very much +mistaken. + +So it is. Stop, driver, stop! We were still a hundred yards or so from +it, but he insisted upon our alighting, and we finished our journey upon +foot. + +Number 3, Lauriston Gardens wore an ill-omened and minatory look. It was +one of four which stood back some little way from the street, two being +occupied and two empty. The latter looked out with three tiers of vacant +melancholy windows, which were blank and dreary, save that here and +there a To Let card had developed like a cataract upon the bleared +panes. A small garden sprinkled over with a scattered eruption of sickly +plants separated each of these houses from the street, and was traversed +by a narrow pathway, yellowish in colour, and consisting apparently of a +mixture of clay and of gravel. The whole place was very sloppy from the +rain which had fallen through the night. The garden was bounded by a +three-foot brick wall with a fringe of wood rails upon the top, and +against this wall was leaning a stalwart police constable, surrounded by +a small knot of loafers, who craned their necks and strained their eyes +in the vain hope of catching some glimpse of the proceedings within. + +I had imagined that Sherlock Holmes would at once have hurried into the +house and plunged into a study of the mystery. Nothing appeared to be +further from his intention. With an air of nonchalance which, under the +circumstances, seemed to me to border upon affectation, he lounged up +and down the pavement, and gazed vacantly at the ground, the sky, the +opposite houses and the line of railings. Having finished his scrutiny, +he proceeded slowly down the path, or rather down the fringe of grass +which flanked the path, keeping his eyes riveted upon the ground. Twice +he stopped, and once I saw him smile, and heard him utter an exclamation +of satisfaction. There were many marks of footsteps upon the wet clayey +soil, but since the police had been coming and going over it, I was +unable to see how my companion could hope to learn anything from it. +Still I had had such extraordinary evidence of the quickness of his +perceptive faculties, that I had no doubt that he could see a great deal +which was hidden from me. + +At the door of the house we were met by a tall, white-faced, +flaxen-haired man, with a notebook in his hand, who rushed forward and +wrung my companion's hand with effusion. It is indeed kind of you to +come, he said, I have had everything left untouched. + +Except that! my friend answered, pointing at the pathway. If a herd +of buffaloes had passed along there could not be a greater mess. No +doubt, however, you had drawn your own conclusions, Gregson, before you +permitted this. + +I have had so much to do inside the house, the detective said +evasively. My colleague, Mr. Lestrade, is here. I had relied upon him +to look after this. + +Holmes glanced at me and raised his eyebrows sardonically. With two +such men as yourself and Lestrade upon the ground, there will not be +much for a third party to find out, he said. + +Gregson rubbed his hands in a self-satisfied way. I think we have done +all that can be done, he answered; it's a queer case though, and I +knew your taste for such things. + +You did not come here in a cab? asked Sherlock Holmes. + +No, sir. + +Nor Lestrade? + +No, sir. + +Then let us go and look at the room. With which inconsequent remark he +strode on into the house, followed by Gregson, whose features expressed +his astonishment. + +A short passage, bare planked and dusty, led to the kitchen and offices. +Two doors opened out of it to the left and to the right. One of these +had obviously been closed for many weeks. The other belonged to the +dining-room, which was the apartment in which the mysterious affair had +occurred. Holmes walked in, and I followed him with that subdued feeling +at my heart which the presence of death inspires. + +It was a large square room, looking all the larger from the absence +of all furniture. A vulgar flaring paper adorned the walls, but it was +blotched in places with mildew, and here and there great strips had +become detached and hung down, exposing the yellow plaster beneath. +Opposite the door was a showy fireplace, surmounted by a mantelpiece of +imitation white marble. On one corner of this was stuck the stump of a +red wax candle. The solitary window was so dirty that the light was +hazy and uncertain, giving a dull grey tinge to everything, which was +intensified by the thick layer of dust which coated the whole apartment. + +All these details I observed afterwards. At present my attention was +centred upon the single grim motionless figure which lay stretched upon +the boards, with vacant sightless eyes staring up at the discoloured +ceiling. It was that of a man about forty-three or forty-four years of +age, middle-sized, broad shouldered, with crisp curling black hair, and +a short stubbly beard. He was dressed in a heavy broadcloth frock coat +and waistcoat, with light-coloured trousers, and immaculate collar +and cuffs. A top hat, well brushed and trim, was placed upon the floor +beside him. His hands were clenched and his arms thrown abroad, while +his lower limbs were interlocked as though his death struggle had been a +grievous one. On his rigid face there stood an expression of horror, +and as it seemed to me, of hatred, such as I have never seen upon human +features. This malignant and terrible contortion, combined with the low +forehead, blunt nose, and prognathous jaw gave the dead man a singularly +simious and ape-like appearance, which was increased by his writhing, +unnatural posture. I have seen death in many forms, but never has +it appeared to me in a more fearsome aspect than in that dark grimy +apartment, which looked out upon one of the main arteries of suburban +London. + +Lestrade, lean and ferret-like as ever, was standing by the doorway, and +greeted my companion and myself. + +This case will make a stir, sir, he remarked. It beats anything I +have seen, and I am no chicken. + +There is no clue? said Gregson. + +None at all, chimed in Lestrade. + +Sherlock Holmes approached the body, and, kneeling down, examined it +intently. You are sure that there is no wound? he asked, pointing to +numerous gouts and splashes of blood which lay all round. + +Positive! cried both detectives. + +Then, of course, this blood belongs to a second individual--[8] +presumably the murderer, if murder has been committed. It reminds me of +the circumstances attendant on the death of Van Jansen, in Utrecht, in +the year 34. Do you remember the case, Gregson? + +No, sir. + +Read it up--you really should. There is nothing new under the sun. It +has all been done before. + +As he spoke, his nimble fingers were flying here, there, and everywhere, +feeling, pressing, unbuttoning, examining, while his eyes wore the same +far-away expression which I have already remarked upon. So swiftly was +the examination made, that one would hardly have guessed the minuteness +with which it was conducted. Finally, he sniffed the dead man's lips, +and then glanced at the soles of his patent leather boots. + +He has not been moved at all? he asked. + +No more than was necessary for the purposes of our examination. + +You can take him to the mortuary now, he said. There is nothing more +to be learned. + +Gregson had a stretcher and four men at hand. At his call they entered +the room, and the stranger was lifted and carried out. As they raised +him, a ring tinkled down and rolled across the floor. Lestrade grabbed +it up and stared at it with mystified eyes. + +There's been a woman here, he cried. It's a woman's wedding-ring. + +He held it out, as he spoke, upon the palm of his hand. We all gathered +round him and gazed at it. There could be no doubt that that circlet of +plain gold had once adorned the finger of a bride. + +This complicates matters, said Gregson. Heaven knows, they were +complicated enough before. + +You're sure it doesn't simplify them? observed Holmes. There's +nothing to be learned by staring at it. What did you find in his +pockets? + +We have it all here, said Gregson, pointing to a litter of objects +upon one of the bottom steps of the stairs. A gold watch, No. 97163, by +Barraud, of London. Gold Albert chain, very heavy and solid. Gold ring, +with masonic device. Gold pin--bull-dog's head, with rubies as eyes. +Russian leather card-case, with cards of Enoch J. Drebber of Cleveland, +corresponding with the E. J. D. upon the linen. No purse, but loose +money to the extent of seven pounds thirteen. Pocket edition of +Boccaccio's Decameron, with name of Joseph Stangerson upon the +fly-leaf. Two letters--one addressed to E. J. Drebber and one to Joseph +Stangerson. + +At what address? + +American Exchange, Strand--to be left till called for. They are both +from the Guion Steamship Company, and refer to the sailing of their +boats from Liverpool. It is clear that this unfortunate man was about to +return to New York. + +Have you made any inquiries as to this man, Stangerson? + +I did it at once, sir, said Gregson. I have had advertisements +sent to all the newspapers, and one of my men has gone to the American +Exchange, but he has not returned yet. + +Have you sent to Cleveland? + +We telegraphed this morning. + +How did you word your inquiries? + +We simply detailed the circumstances, and said that we should be glad +of any information which could help us. + +You did not ask for particulars on any point which appeared to you to +be crucial? + +I asked about Stangerson. + +Nothing else? Is there no circumstance on which this whole case appears +to hinge? Will you not telegraph again? + +I have said all I have to say, said Gregson, in an offended voice. + +Sherlock Holmes chuckled to himself, and appeared to be about to make +some remark, when Lestrade, who had been in the front room while we +were holding this conversation in the hall, reappeared upon the scene, +rubbing his hands in a pompous and self-satisfied manner. + +Mr. Gregson, he said, I have just made a discovery of the highest +importance, and one which would have been overlooked had I not made a +careful examination of the walls. + +The little man's eyes sparkled as he spoke, and he was evidently in +a state of suppressed exultation at having scored a point against his +colleague. + +Come here, he said, bustling back into the room, the atmosphere of +which felt clearer since the removal of its ghastly inmate. Now, stand +there! + +He struck a match on his boot and held it up against the wall. + +Look at that! he said, triumphantly. + +I have remarked that the paper had fallen away in parts. In this +particular corner of the room a large piece had peeled off, leaving a +yellow square of coarse plastering. Across this bare space there was +scrawled in blood-red letters a single word-- + + RACHE. + + +What do you think of that? cried the detective, with the air of a +showman exhibiting his show. This was overlooked because it was in the +darkest corner of the room, and no one thought of looking there. The +murderer has written it with his or her own blood. See this smear where +it has trickled down the wall! That disposes of the idea of suicide +anyhow. Why was that corner chosen to write it on? I will tell you. See +that candle on the mantelpiece. It was lit at the time, and if it was +lit this corner would be the brightest instead of the darkest portion of +the wall. + +And what does it mean now that you _have_ found it? asked Gregson in a +depreciatory voice. + +Mean? Why, it means that the writer was going to put the female name +Rachel, but was disturbed before he or she had time to finish. You mark +my words, when this case comes to be cleared up you will find that a +woman named Rachel has something to do with it. It's all very well for +you to laugh, Mr. Sherlock Holmes. You may be very smart and clever, but +the old hound is the best, when all is said and done. + +I really beg your pardon! said my companion, who had ruffled the +little man's temper by bursting into an explosion of laughter. You +certainly have the credit of being the first of us to find this out, +and, as you say, it bears every mark of having been written by the other +participant in last night's mystery. I have not had time to examine this +room yet, but with your permission I shall do so now. + +As he spoke, he whipped a tape measure and a large round magnifying +glass from his pocket. With these two implements he trotted noiselessly +about the room, sometimes stopping, occasionally kneeling, and once +lying flat upon his face. So engrossed was he with his occupation that +he appeared to have forgotten our presence, for he chattered away to +himself under his breath the whole time, keeping up a running fire +of exclamations, groans, whistles, and little cries suggestive of +encouragement and of hope. As I watched him I was irresistibly reminded +of a pure-blooded well-trained foxhound as it dashes backwards and +forwards through the covert, whining in its eagerness, until it comes +across the lost scent. For twenty minutes or more he continued his +researches, measuring with the most exact care the distance between +marks which were entirely invisible to me, and occasionally applying his +tape to the walls in an equally incomprehensible manner. In one place +he gathered up very carefully a little pile of grey dust from the floor, +and packed it away in an envelope. Finally, he examined with his glass +the word upon the wall, going over every letter of it with the most +minute exactness. This done, he appeared to be satisfied, for he +replaced his tape and his glass in his pocket. + +They say that genius is an infinite capacity for taking pains, he +remarked with a smile. It's a very bad definition, but it does apply to +detective work. + +Gregson and Lestrade had watched the manoeuvres [9] of their amateur +companion with considerable curiosity and some contempt. They evidently +failed to appreciate the fact, which I had begun to realize, that +Sherlock Holmes' smallest actions were all directed towards some +definite and practical end. + +What do you think of it, sir? they both asked. + +It would be robbing you of the credit of the case if I was to presume +to help you, remarked my friend. You are doing so well now that it +would be a pity for anyone to interfere. There was a world of +sarcasm in his voice as he spoke. If you will let me know how your +investigations go, he continued, I shall be happy to give you any help +I can. In the meantime I should like to speak to the constable who found +the body. Can you give me his name and address? + +Lestrade glanced at his note-book. John Rance, he said. He is off +duty now. You will find him at 46, Audley Court, Kennington Park Gate. + +Holmes took a note of the address. + +Come along, Doctor, he said; we shall go and look him up. I'll tell +you one thing which may help you in the case, he continued, turning to +the two detectives. There has been murder done, and the murderer was a +man. He was more than six feet high, was in the prime of life, had +small feet for his height, wore coarse, square-toed boots and smoked a +Trichinopoly cigar. He came here with his victim in a four-wheeled cab, +which was drawn by a horse with three old shoes and one new one on his +off fore leg. In all probability the murderer had a florid face, and the +finger-nails of his right hand were remarkably long. These are only a +few indications, but they may assist you. + +Lestrade and Gregson glanced at each other with an incredulous smile. + +If this man was murdered, how was it done? asked the former. + +Poison, said Sherlock Holmes curtly, and strode off. One other thing, +Lestrade, he added, turning round at the door: Rache, is the German +for revenge; so don't lose your time looking for Miss Rachel. + +With which Parthian shot he walked away, leaving the two rivals +open-mouthed behind him. + + + + +CHAPTER IV. WHAT JOHN RANCE HAD TO TELL. + + +IT was one o'clock when we left No. 3, Lauriston Gardens. Sherlock +Holmes led me to the nearest telegraph office, whence he dispatched a +long telegram. He then hailed a cab, and ordered the driver to take us +to the address given us by Lestrade. + +There is nothing like first hand evidence, he remarked; as a matter +of fact, my mind is entirely made up upon the case, but still we may as +well learn all that is to be learned. + +You amaze me, Holmes, said I. Surely you are not as sure as you +pretend to be of all those particulars which you gave. + +There's no room for a mistake, he answered. The very first thing +which I observed on arriving there was that a cab had made two ruts with +its wheels close to the curb. Now, up to last night, we have had no rain +for a week, so that those wheels which left such a deep impression must +have been there during the night. There were the marks of the horse's +hoofs, too, the outline of one of which was far more clearly cut than +that of the other three, showing that that was a new shoe. Since the cab +was there after the rain began, and was not there at any time during the +morning--I have Gregson's word for that--it follows that it must have +been there during the night, and, therefore, that it brought those two +individuals to the house. + +That seems simple enough, said I; but how about the other man's +height? + +Why, the height of a man, in nine cases out of ten, can be told from +the length of his stride. It is a simple calculation enough, though +there is no use my boring you with figures. I had this fellow's stride +both on the clay outside and on the dust within. Then I had a way of +checking my calculation. When a man writes on a wall, his instinct leads +him to write about the level of his own eyes. Now that writing was just +over six feet from the ground. It was child's play. + +And his age? I asked. + +Well, if a man can stride four and a-half feet without the smallest +effort, he can't be quite in the sere and yellow. That was the breadth +of a puddle on the garden walk which he had evidently walked across. +Patent-leather boots had gone round, and Square-toes had hopped over. +There is no mystery about it at all. I am simply applying to ordinary +life a few of those precepts of observation and deduction which I +advocated in that article. Is there anything else that puzzles you? + +The finger nails and the Trichinopoly, I suggested. + +The writing on the wall was done with a man's forefinger dipped in +blood. My glass allowed me to observe that the plaster was slightly +scratched in doing it, which would not have been the case if the man's +nail had been trimmed. I gathered up some scattered ash from the floor. +It was dark in colour and flakey--such an ash as is only made by a +Trichinopoly. I have made a special study of cigar ashes--in fact, I +have written a monograph upon the subject. I flatter myself that I can +distinguish at a glance the ash of any known brand, either of cigar +or of tobacco. It is just in such details that the skilled detective +differs from the Gregson and Lestrade type. + +And the florid face? I asked. + +Ah, that was a more daring shot, though I have no doubt that I was +right. You must not ask me that at the present state of the affair. + +I passed my hand over my brow. My head is in a whirl, I remarked; the +more one thinks of it the more mysterious it grows. How came these two +men--if there were two men--into an empty house? What has become of the +cabman who drove them? How could one man compel another to take poison? +Where did the blood come from? What was the object of the murderer, +since robbery had no part in it? How came the woman's ring there? Above +all, why should the second man write up the German word RACHE before +decamping? I confess that I cannot see any possible way of reconciling +all these facts. + +My companion smiled approvingly. + +You sum up the difficulties of the situation succinctly and well, he +said. There is much that is still obscure, though I have quite made up +my mind on the main facts. As to poor Lestrade's discovery it was simply +a blind intended to put the police upon a wrong track, by suggesting +Socialism and secret societies. It was not done by a German. The A, if +you noticed, was printed somewhat after the German fashion. Now, a real +German invariably prints in the Latin character, so that we may safely +say that this was not written by one, but by a clumsy imitator who +overdid his part. It was simply a ruse to divert inquiry into a wrong +channel. I'm not going to tell you much more of the case, Doctor. You +know a conjuror gets no credit when once he has explained his trick, +and if I show you too much of my method of working, you will come to the +conclusion that I am a very ordinary individual after all. + +I shall never do that, I answered; you have brought detection as near +an exact science as it ever will be brought in this world. + +My companion flushed up with pleasure at my words, and the earnest way +in which I uttered them. I had already observed that he was as sensitive +to flattery on the score of his art as any girl could be of her beauty. + +I'll tell you one other thing, he said. Patent leathers [10] and +Square-toes came in the same cab, and they walked down the pathway +together as friendly as possible--arm-in-arm, in all probability. +When they got inside they walked up and down the room--or rather, +Patent-leathers stood still while Square-toes walked up and down. I +could read all that in the dust; and I could read that as he walked he +grew more and more excited. That is shown by the increased length of his +strides. He was talking all the while, and working himself up, no doubt, +into a fury. Then the tragedy occurred. I've told you all I know myself +now, for the rest is mere surmise and conjecture. We have a good working +basis, however, on which to start. We must hurry up, for I want to go to +Halle's concert to hear Norman Neruda this afternoon. + +This conversation had occurred while our cab had been threading its way +through a long succession of dingy streets and dreary by-ways. In the +dingiest and dreariest of them our driver suddenly came to a stand. +That's Audley Court in there, he said, pointing to a narrow slit in +the line of dead-coloured brick. You'll find me here when you come +back. + +Audley Court was not an attractive locality. The narrow passage led us +into a quadrangle paved with flags and lined by sordid dwellings. We +picked our way among groups of dirty children, and through lines of +discoloured linen, until we came to Number 46, the door of which +was decorated with a small slip of brass on which the name Rance was +engraved. On enquiry we found that the constable was in bed, and we were +shown into a little front parlour to await his coming. + +He appeared presently, looking a little irritable at being disturbed in +his slumbers. I made my report at the office, he said. + +Holmes took a half-sovereign from his pocket and played with it +pensively. We thought that we should like to hear it all from your own +lips, he said. + +I shall be most happy to tell you anything I can, the constable +answered with his eyes upon the little golden disk. + +Just let us hear it all in your own way as it occurred. + +Rance sat down on the horsehair sofa, and knitted his brows as though +determined not to omit anything in his narrative. + +I'll tell it ye from the beginning, he said. My time is from ten at +night to six in the morning. At eleven there was a fight at the White +Hart'; but bar that all was quiet enough on the beat. At one o'clock it +began to rain, and I met Harry Murcher--him who has the Holland Grove +beat--and we stood together at the corner of Henrietta Street a-talkin'. +Presently--maybe about two or a little after--I thought I would take +a look round and see that all was right down the Brixton Road. It was +precious dirty and lonely. Not a soul did I meet all the way down, +though a cab or two went past me. I was a strollin' down, thinkin' +between ourselves how uncommon handy a four of gin hot would be, when +suddenly the glint of a light caught my eye in the window of that same +house. Now, I knew that them two houses in Lauriston Gardens was empty +on account of him that owns them who won't have the drains seen to, +though the very last tenant what lived in one of them died o' typhoid +fever. I was knocked all in a heap therefore at seeing a light in +the window, and I suspected as something was wrong. When I got to the +door---- + +You stopped, and then walked back to the garden gate, my companion +interrupted. What did you do that for? + +Rance gave a violent jump, and stared at Sherlock Holmes with the utmost +amazement upon his features. + +Why, that's true, sir, he said; though how you come to know it, +Heaven only knows. Ye see, when I got up to the door it was so still and +so lonesome, that I thought I'd be none the worse for some one with me. +I ain't afeared of anything on this side o' the grave; but I thought +that maybe it was him that died o' the typhoid inspecting the drains +what killed him. The thought gave me a kind o' turn, and I walked back +to the gate to see if I could see Murcher's lantern, but there wasn't no +sign of him nor of anyone else. + +There was no one in the street? + +Not a livin' soul, sir, nor as much as a dog. Then I pulled myself +together and went back and pushed the door open. All was quiet inside, +so I went into the room where the light was a-burnin'. There was a +candle flickerin' on the mantelpiece--a red wax one--and by its light I +saw---- + +Yes, I know all that you saw. You walked round the room several times, +and you knelt down by the body, and then you walked through and tried +the kitchen door, and then---- + +John Rance sprang to his feet with a frightened face and suspicion in +his eyes. Where was you hid to see all that? he cried. It seems to me +that you knows a deal more than you should. + +Holmes laughed and threw his card across the table to the constable. +Don't get arresting me for the murder, he said. I am one of the +hounds and not the wolf; Mr. Gregson or Mr. Lestrade will answer for +that. Go on, though. What did you do next? + +Rance resumed his seat, without however losing his mystified expression. +I went back to the gate and sounded my whistle. That brought Murcher +and two more to the spot. + +Was the street empty then? + +Well, it was, as far as anybody that could be of any good goes. + +What do you mean? + +The constable's features broadened into a grin. I've seen many a drunk +chap in my time, he said, but never anyone so cryin' drunk as +that cove. He was at the gate when I came out, a-leanin' up agin the +railings, and a-singin' at the pitch o' his lungs about Columbine's +New-fangled Banner, or some such stuff. He couldn't stand, far less +help. + +What sort of a man was he? asked Sherlock Holmes. + +John Rance appeared to be somewhat irritated at this digression. He was +an uncommon drunk sort o' man, he said. He'd ha' found hisself in the +station if we hadn't been so took up. + +His face--his dress--didn't you notice them? Holmes broke in +impatiently. + +I should think I did notice them, seeing that I had to prop him up--me +and Murcher between us. He was a long chap, with a red face, the lower +part muffled round---- + +That will do, cried Holmes. What became of him? + +We'd enough to do without lookin' after him, the policeman said, in an +aggrieved voice. I'll wager he found his way home all right. + +How was he dressed? + +A brown overcoat. + +Had he a whip in his hand? + +A whip--no. + +He must have left it behind, muttered my companion. You didn't happen +to see or hear a cab after that? + +No. + +There's a half-sovereign for you, my companion said, standing up and +taking his hat. I am afraid, Rance, that you will never rise in the +force. That head of yours should be for use as well as ornament. You +might have gained your sergeant's stripes last night. The man whom you +held in your hands is the man who holds the clue of this mystery, and +whom we are seeking. There is no use of arguing about it now; I tell you +that it is so. Come along, Doctor. + +We started off for the cab together, leaving our informant incredulous, +but obviously uncomfortable. + +The blundering fool, Holmes said, bitterly, as we drove back to our +lodgings. Just to think of his having such an incomparable bit of good +luck, and not taking advantage of it. + +I am rather in the dark still. It is true that the description of this +man tallies with your idea of the second party in this mystery. But why +should he come back to the house after leaving it? That is not the way +of criminals. + +The ring, man, the ring: that was what he came back for. If we have no +other way of catching him, we can always bait our line with the ring. I +shall have him, Doctor--I'll lay you two to one that I have him. I must +thank you for it all. I might not have gone but for you, and so have +missed the finest study I ever came across: a study in scarlet, eh? +Why shouldn't we use a little art jargon. There's the scarlet thread of +murder running through the colourless skein of life, and our duty is +to unravel it, and isolate it, and expose every inch of it. And now +for lunch, and then for Norman Neruda. Her attack and her bowing +are splendid. What's that little thing of Chopin's she plays so +magnificently: Tra-la-la-lira-lira-lay. + +Leaning back in the cab, this amateur bloodhound carolled away like a +lark while I meditated upon the many-sidedness of the human mind. + + + + +CHAPTER V. OUR ADVERTISEMENT BRINGS A VISITOR. + + +OUR morning's exertions had been too much for my weak health, and I was +tired out in the afternoon. After Holmes' departure for the concert, I +lay down upon the sofa and endeavoured to get a couple of hours' sleep. +It was a useless attempt. My mind had been too much excited by all that +had occurred, and the strangest fancies and surmises crowded into +it. Every time that I closed my eyes I saw before me the distorted +baboon-like countenance of the murdered man. So sinister was the +impression which that face had produced upon me that I found it +difficult to feel anything but gratitude for him who had removed its +owner from the world. If ever human features bespoke vice of the most +malignant type, they were certainly those of Enoch J. Drebber, of +Cleveland. Still I recognized that justice must be done, and that the +depravity of the victim was no condonment [11] in the eyes of the law. + +The more I thought of it the more extraordinary did my companion's +hypothesis, that the man had been poisoned, appear. I remembered how he +had sniffed his lips, and had no doubt that he had detected something +which had given rise to the idea. Then, again, if not poison, what +had caused the man's death, since there was neither wound nor marks of +strangulation? But, on the other hand, whose blood was that which lay so +thickly upon the floor? There were no signs of a struggle, nor had the +victim any weapon with which he might have wounded an antagonist. As +long as all these questions were unsolved, I felt that sleep would be +no easy matter, either for Holmes or myself. His quiet self-confident +manner convinced me that he had already formed a theory which explained +all the facts, though what it was I could not for an instant conjecture. + +He was very late in returning--so late, that I knew that the concert +could not have detained him all the time. Dinner was on the table before +he appeared. + +It was magnificent, he said, as he took his seat. Do you remember +what Darwin says about music? He claims that the power of producing and +appreciating it existed among the human race long before the power of +speech was arrived at. Perhaps that is why we are so subtly influenced +by it. There are vague memories in our souls of those misty centuries +when the world was in its childhood. + +That's rather a broad idea, I remarked. + +One's ideas must be as broad as Nature if they are to interpret +Nature, he answered. What's the matter? You're not looking quite +yourself. This Brixton Road affair has upset you. + +To tell the truth, it has, I said. I ought to be more case-hardened +after my Afghan experiences. I saw my own comrades hacked to pieces at +Maiwand without losing my nerve. + +I can understand. There is a mystery about this which stimulates the +imagination; where there is no imagination there is no horror. Have you +seen the evening paper? + +No. + +It gives a fairly good account of the affair. It does not mention the +fact that when the man was raised up, a woman's wedding ring fell upon +the floor. It is just as well it does not. + +Why? + +Look at this advertisement, he answered. I had one sent to every +paper this morning immediately after the affair. + +He threw the paper across to me and I glanced at the place indicated. It +was the first announcement in the Found column. In Brixton Road, +this morning, it ran, a plain gold wedding ring, found in the roadway +between the White Hart' Tavern and Holland Grove. Apply Dr. Watson, +221B, Baker Street, between eight and nine this evening. + +Excuse my using your name, he said. If I used my own some of these +dunderheads would recognize it, and want to meddle in the affair. + +That is all right, I answered. But supposing anyone applies, I have +no ring. + +Oh yes, you have, said he, handing me one. This will do very well. It +is almost a facsimile. + +And who do you expect will answer this advertisement. + +Why, the man in the brown coat--our florid friend with the square toes. +If he does not come himself he will send an accomplice. + +Would he not consider it as too dangerous? + +Not at all. If my view of the case is correct, and I have every reason +to believe that it is, this man would rather risk anything than lose the +ring. According to my notion he dropped it while stooping over Drebber's +body, and did not miss it at the time. After leaving the house he +discovered his loss and hurried back, but found the police already in +possession, owing to his own folly in leaving the candle burning. He had +to pretend to be drunk in order to allay the suspicions which might have +been aroused by his appearance at the gate. Now put yourself in that +man's place. On thinking the matter over, it must have occurred to him +that it was possible that he had lost the ring in the road after leaving +the house. What would he do, then? He would eagerly look out for the +evening papers in the hope of seeing it among the articles found. His +eye, of course, would light upon this. He would be overjoyed. Why should +he fear a trap? There would be no reason in his eyes why the finding +of the ring should be connected with the murder. He would come. He will +come. You shall see him within an hour? + +And then? I asked. + +Oh, you can leave me to deal with him then. Have you any arms? + +I have my old service revolver and a few cartridges. + +You had better clean it and load it. He will be a desperate man, +and though I shall take him unawares, it is as well to be ready for +anything. + +I went to my bedroom and followed his advice. When I returned with +the pistol the table had been cleared, and Holmes was engaged in his +favourite occupation of scraping upon his violin. + +The plot thickens, he said, as I entered; I have just had an answer +to my American telegram. My view of the case is the correct one. + +And that is? I asked eagerly. + +My fiddle would be the better for new strings, he remarked. Put your +pistol in your pocket. When the fellow comes speak to him in an ordinary +way. Leave the rest to me. Don't frighten him by looking at him too +hard. + +It is eight o'clock now, I said, glancing at my watch. + +Yes. He will probably be here in a few minutes. Open the door slightly. +That will do. Now put the key on the inside. Thank you! This is a +queer old book I picked up at a stall yesterday--De Jure inter +Gentes'--published in Latin at Liege in the Lowlands, in 1642. Charles' +head was still firm on his shoulders when this little brown-backed +volume was struck off. + +Who is the printer? + +Philippe de Croy, whoever he may have been. On the fly-leaf, in very +faded ink, is written Ex libris Guliolmi Whyte. I wonder who William +Whyte was. Some pragmatical seventeenth century lawyer, I suppose. His +writing has a legal twist about it. Here comes our man, I think. + +As he spoke there was a sharp ring at the bell. Sherlock Holmes rose +softly and moved his chair in the direction of the door. We heard the +servant pass along the hall, and the sharp click of the latch as she +opened it. + +Does Dr. Watson live here? asked a clear but rather harsh voice. We +could not hear the servant's reply, but the door closed, and some one +began to ascend the stairs. The footfall was an uncertain and shuffling +one. A look of surprise passed over the face of my companion as he +listened to it. It came slowly along the passage, and there was a feeble +tap at the door. + +Come in, I cried. + +At my summons, instead of the man of violence whom we expected, a very +old and wrinkled woman hobbled into the apartment. She appeared to be +dazzled by the sudden blaze of light, and after dropping a curtsey, she +stood blinking at us with her bleared eyes and fumbling in her pocket +with nervous, shaky fingers. I glanced at my companion, and his face +had assumed such a disconsolate expression that it was all I could do to +keep my countenance. + +The old crone drew out an evening paper, and pointed at our +advertisement. It's this as has brought me, good gentlemen, she said, +dropping another curtsey; a gold wedding ring in the Brixton Road. It +belongs to my girl Sally, as was married only this time twelvemonth, +which her husband is steward aboard a Union boat, and what he'd say if +he come ome and found her without her ring is more than I can think, he +being short enough at the best o' times, but more especially when he +has the drink. If it please you, she went to the circus last night along +with---- + +Is that her ring? I asked. + +The Lord be thanked! cried the old woman; Sally will be a glad woman +this night. That's the ring. + +And what may your address be? I inquired, taking up a pencil. + +13, Duncan Street, Houndsditch. A weary way from here. + +The Brixton Road does not lie between any circus and Houndsditch, said +Sherlock Holmes sharply. + +The old woman faced round and looked keenly at him from her little +red-rimmed eyes. The gentleman asked me for _my_ address, she said. +Sally lives in lodgings at 3, Mayfield Place, Peckham. + +And your name is----? + +My name is Sawyer--her's is Dennis, which Tom Dennis married her--and +a smart, clean lad, too, as long as he's at sea, and no steward in the +company more thought of; but when on shore, what with the women and what +with liquor shops---- + +Here is your ring, Mrs. Sawyer, I interrupted, in obedience to a sign +from my companion; it clearly belongs to your daughter, and I am glad +to be able to restore it to the rightful owner. + +With many mumbled blessings and protestations of gratitude the old crone +packed it away in her pocket, and shuffled off down the stairs. Sherlock +Holmes sprang to his feet the moment that she was gone and rushed into +his room. He returned in a few seconds enveloped in an ulster and +a cravat. I'll follow her, he said, hurriedly; she must be an +accomplice, and will lead me to him. Wait up for me. The hall door had +hardly slammed behind our visitor before Holmes had descended the stair. +Looking through the window I could see her walking feebly along the +other side, while her pursuer dogged her some little distance behind. +Either his whole theory is incorrect, I thought to myself, or else he +will be led now to the heart of the mystery. There was no need for him +to ask me to wait up for him, for I felt that sleep was impossible until +I heard the result of his adventure. + +It was close upon nine when he set out. I had no idea how long he might +be, but I sat stolidly puffing at my pipe and skipping over the pages +of Henri Murger's Vie de Bohème. Ten o'clock passed, and I heard the +footsteps of the maid as they pattered off to bed. Eleven, and the +more stately tread of the landlady passed my door, bound for the same +destination. It was close upon twelve before I heard the sharp sound of +his latch-key. The instant he entered I saw by his face that he had not +been successful. Amusement and chagrin seemed to be struggling for the +mastery, until the former suddenly carried the day, and he burst into a +hearty laugh. + +I wouldn't have the Scotland Yarders know it for the world, he cried, +dropping into his chair; I have chaffed them so much that they would +never have let me hear the end of it. I can afford to laugh, because I +know that I will be even with them in the long run. + +What is it then? I asked. + +Oh, I don't mind telling a story against myself. That creature had +gone a little way when she began to limp and show every sign of being +foot-sore. Presently she came to a halt, and hailed a four-wheeler which +was passing. I managed to be close to her so as to hear the address, but +I need not have been so anxious, for she sang it out loud enough to +be heard at the other side of the street, Drive to 13, Duncan Street, +Houndsditch, she cried. This begins to look genuine, I thought, and +having seen her safely inside, I perched myself behind. That's an art +which every detective should be an expert at. Well, away we rattled, and +never drew rein until we reached the street in question. I hopped off +before we came to the door, and strolled down the street in an easy, +lounging way. I saw the cab pull up. The driver jumped down, and I saw +him open the door and stand expectantly. Nothing came out though. When +I reached him he was groping about frantically in the empty cab, and +giving vent to the finest assorted collection of oaths that ever I +listened to. There was no sign or trace of his passenger, and I fear it +will be some time before he gets his fare. On inquiring at Number 13 +we found that the house belonged to a respectable paperhanger, named +Keswick, and that no one of the name either of Sawyer or Dennis had ever +been heard of there. + +You don't mean to say, I cried, in amazement, that that tottering, +feeble old woman was able to get out of the cab while it was in motion, +without either you or the driver seeing her? + +Old woman be damned! said Sherlock Holmes, sharply. We were the old +women to be so taken in. It must have been a young man, and an +active one, too, besides being an incomparable actor. The get-up was +inimitable. He saw that he was followed, no doubt, and used this means +of giving me the slip. It shows that the man we are after is not as +lonely as I imagined he was, but has friends who are ready to risk +something for him. Now, Doctor, you are looking done-up. Take my advice +and turn in. + +I was certainly feeling very weary, so I obeyed his injunction. I +left Holmes seated in front of the smouldering fire, and long into the +watches of the night I heard the low, melancholy wailings of his violin, +and knew that he was still pondering over the strange problem which he +had set himself to unravel. + + + + +CHAPTER VI. TOBIAS GREGSON SHOWS WHAT HE CAN DO. + + +THE papers next day were full of the Brixton Mystery, as they termed +it. Each had a long account of the affair, and some had leaders upon it +in addition. There was some information in them which was new to me. I +still retain in my scrap-book numerous clippings and extracts bearing +upon the case. Here is a condensation of a few of them:-- + +The _Daily Telegraph_ remarked that in the history of crime there had +seldom been a tragedy which presented stranger features. The German +name of the victim, the absence of all other motive, and the sinister +inscription on the wall, all pointed to its perpetration by political +refugees and revolutionists. The Socialists had many branches in +America, and the deceased had, no doubt, infringed their unwritten laws, +and been tracked down by them. After alluding airily to the Vehmgericht, +aqua tofana, Carbonari, the Marchioness de Brinvilliers, the Darwinian +theory, the principles of Malthus, and the Ratcliff Highway murders, the +article concluded by admonishing the Government and advocating a closer +watch over foreigners in England. + +The _Standard_ commented upon the fact that lawless outrages of the sort +usually occurred under a Liberal Administration. They arose from the +unsettling of the minds of the masses, and the consequent weakening +of all authority. The deceased was an American gentleman who had +been residing for some weeks in the Metropolis. He had stayed at the +boarding-house of Madame Charpentier, in Torquay Terrace, Camberwell. +He was accompanied in his travels by his private secretary, Mr. Joseph +Stangerson. The two bade adieu to their landlady upon Tuesday, the +4th inst., and departed to Euston Station with the avowed intention of +catching the Liverpool express. They were afterwards seen together upon +the platform. Nothing more is known of them until Mr. Drebber's body +was, as recorded, discovered in an empty house in the Brixton Road, +many miles from Euston. How he came there, or how he met his fate, are +questions which are still involved in mystery. Nothing is known of the +whereabouts of Stangerson. We are glad to learn that Mr. Lestrade and +Mr. Gregson, of Scotland Yard, are both engaged upon the case, and it +is confidently anticipated that these well-known officers will speedily +throw light upon the matter. + +The _Daily News_ observed that there was no doubt as to the crime being +a political one. The despotism and hatred of Liberalism which animated +the Continental Governments had had the effect of driving to our shores +a number of men who might have made excellent citizens were they not +soured by the recollection of all that they had undergone. Among these +men there was a stringent code of honour, any infringement of which was +punished by death. Every effort should be made to find the secretary, +Stangerson, and to ascertain some particulars of the habits of the +deceased. A great step had been gained by the discovery of the address +of the house at which he had boarded--a result which was entirely due to +the acuteness and energy of Mr. Gregson of Scotland Yard. + +Sherlock Holmes and I read these notices over together at breakfast, and +they appeared to afford him considerable amusement. + +I told you that, whatever happened, Lestrade and Gregson would be sure +to score. + +That depends on how it turns out. + +Oh, bless you, it doesn't matter in the least. If the man is caught, it +will be _on account_ of their exertions; if he escapes, it will be _in +spite_ of their exertions. It's heads I win and tails you lose. Whatever +they do, they will have followers. Un sot trouve toujours un plus sot +qui l'admire. + +What on earth is this? I cried, for at this moment there came the +pattering of many steps in the hall and on the stairs, accompanied by +audible expressions of disgust upon the part of our landlady. + +It's the Baker Street division of the detective police force, said my +companion, gravely; and as he spoke there rushed into the room half a +dozen of the dirtiest and most ragged street Arabs that ever I clapped +eyes on. + +Tention! cried Holmes, in a sharp tone, and the six dirty little +scoundrels stood in a line like so many disreputable statuettes. In +future you shall send up Wiggins alone to report, and the rest of you +must wait in the street. Have you found it, Wiggins? + +No, sir, we hain't, said one of the youths. + +I hardly expected you would. You must keep on until you do. Here are +your wages. [13] He handed each of them a shilling. + +Now, off you go, and come back with a better report next time. + +He waved his hand, and they scampered away downstairs like so many rats, +and we heard their shrill voices next moment in the street. + +There's more work to be got out of one of those little beggars than +out of a dozen of the force, Holmes remarked. The mere sight of an +official-looking person seals men's lips. These youngsters, however, go +everywhere and hear everything. They are as sharp as needles, too; all +they want is organisation. + +Is it on this Brixton case that you are employing them? I asked. + +Yes; there is a point which I wish to ascertain. It is merely a matter +of time. Hullo! we are going to hear some news now with a vengeance! +Here is Gregson coming down the road with beatitude written upon every +feature of his face. Bound for us, I know. Yes, he is stopping. There he +is! + +There was a violent peal at the bell, and in a few seconds the +fair-haired detective came up the stairs, three steps at a time, and +burst into our sitting-room. + +My dear fellow, he cried, wringing Holmes' unresponsive hand, +congratulate me! I have made the whole thing as clear as day. + +A shade of anxiety seemed to me to cross my companion's expressive face. + +Do you mean that you are on the right track? he asked. + +The right track! Why, sir, we have the man under lock and key. + +And his name is? + +Arthur Charpentier, sub-lieutenant in Her Majesty's navy, cried +Gregson, pompously, rubbing his fat hands and inflating his chest. + +Sherlock Holmes gave a sigh of relief, and relaxed into a smile. + +Take a seat, and try one of these cigars, he said. We are anxious to +know how you managed it. Will you have some whiskey and water? + +I don't mind if I do, the detective answered. The tremendous +exertions which I have gone through during the last day or two have worn +me out. Not so much bodily exertion, you understand, as the strain upon +the mind. You will appreciate that, Mr. Sherlock Holmes, for we are both +brain-workers. + +You do me too much honour, said Holmes, gravely. Let us hear how you +arrived at this most gratifying result. + +The detective seated himself in the arm-chair, and puffed complacently +at his cigar. Then suddenly he slapped his thigh in a paroxysm of +amusement. + +The fun of it is, he cried, that that fool Lestrade, who thinks +himself so smart, has gone off upon the wrong track altogether. He is +after the secretary Stangerson, who had no more to do with the crime +than the babe unborn. I have no doubt that he has caught him by this +time. + +The idea tickled Gregson so much that he laughed until he choked. + +And how did you get your clue? + +Ah, I'll tell you all about it. Of course, Doctor Watson, this is +strictly between ourselves. The first difficulty which we had to contend +with was the finding of this American's antecedents. Some people would +have waited until their advertisements were answered, or until parties +came forward and volunteered information. That is not Tobias Gregson's +way of going to work. You remember the hat beside the dead man? + +Yes, said Holmes; by John Underwood and Sons, 129, Camberwell Road. + +Gregson looked quite crest-fallen. + +I had no idea that you noticed that, he said. Have you been there? + +No. + +Ha! cried Gregson, in a relieved voice; you should never neglect a +chance, however small it may seem. + +To a great mind, nothing is little, remarked Holmes, sententiously. + +Well, I went to Underwood, and asked him if he had sold a hat of that +size and description. He looked over his books, and came on it at once. +He had sent the hat to a Mr. Drebber, residing at Charpentier's Boarding +Establishment, Torquay Terrace. Thus I got at his address. + +Smart--very smart! murmured Sherlock Holmes. + +I next called upon Madame Charpentier, continued the detective. +I found her very pale and distressed. Her daughter was in the room, +too--an uncommonly fine girl she is, too; she was looking red about +the eyes and her lips trembled as I spoke to her. That didn't escape +my notice. I began to smell a rat. You know the feeling, Mr. Sherlock +Holmes, when you come upon the right scent--a kind of thrill in your +nerves. Have you heard of the mysterious death of your late boarder Mr. +Enoch J. Drebber, of Cleveland? I asked. + +The mother nodded. She didn't seem able to get out a word. The daughter +burst into tears. I felt more than ever that these people knew something +of the matter. + +At what o'clock did Mr. Drebber leave your house for the train? I +asked. + +At eight o'clock, she said, gulping in her throat to keep down her +agitation. His secretary, Mr. Stangerson, said that there were two +trains--one at 9.15 and one at 11. He was to catch the first. [14] + +And was that the last which you saw of him? + +A terrible change came over the woman's face as I asked the question. +Her features turned perfectly livid. It was some seconds before she +could get out the single word Yes'--and when it did come it was in a +husky unnatural tone. + +There was silence for a moment, and then the daughter spoke in a calm +clear voice. + +No good can ever come of falsehood, mother, she said. Let us be +frank with this gentleman. We _did_ see Mr. Drebber again. + +God forgive you! cried Madame Charpentier, throwing up her hands and +sinking back in her chair. You have murdered your brother. + +Arthur would rather that we spoke the truth, the girl answered +firmly. + +You had best tell me all about it now, I said. Half-confidences are +worse than none. Besides, you do not know how much we know of it. + +On your head be it, Alice! cried her mother; and then, turning to me, +I will tell you all, sir. Do not imagine that my agitation on behalf +of my son arises from any fear lest he should have had a hand in this +terrible affair. He is utterly innocent of it. My dread is, however, +that in your eyes and in the eyes of others he may appear to be +compromised. That however is surely impossible. His high character, his +profession, his antecedents would all forbid it. + +Your best way is to make a clean breast of the facts, I answered. +Depend upon it, if your son is innocent he will be none the worse. + +Perhaps, Alice, you had better leave us together, she said, and her +daughter withdrew. Now, sir, she continued, I had no intention of +telling you all this, but since my poor daughter has disclosed it I +have no alternative. Having once decided to speak, I will tell you all +without omitting any particular. + +It is your wisest course, said I. + +Mr. Drebber has been with us nearly three weeks. He and his secretary, +Mr. Stangerson, had been travelling on the Continent. I noticed a +Copenhagen label upon each of their trunks, showing that that had been +their last stopping place. Stangerson was a quiet reserved man, but his +employer, I am sorry to say, was far otherwise. He was coarse in his +habits and brutish in his ways. The very night of his arrival he became +very much the worse for drink, and, indeed, after twelve o'clock in the +day he could hardly ever be said to be sober. His manners towards the +maid-servants were disgustingly free and familiar. Worst of all, he +speedily assumed the same attitude towards my daughter, Alice, and spoke +to her more than once in a way which, fortunately, she is too innocent +to understand. On one occasion he actually seized her in his arms and +embraced her--an outrage which caused his own secretary to reproach him +for his unmanly conduct. + +But why did you stand all this, I asked. I suppose that you can get +rid of your boarders when you wish. + +Mrs. Charpentier blushed at my pertinent question. Would to God that +I had given him notice on the very day that he came, she said. But +it was a sore temptation. They were paying a pound a day each--fourteen +pounds a week, and this is the slack season. I am a widow, and my boy in +the Navy has cost me much. I grudged to lose the money. I acted for the +best. This last was too much, however, and I gave him notice to leave on +account of it. That was the reason of his going. + +Well? + +My heart grew light when I saw him drive away. My son is on leave +just now, but I did not tell him anything of all this, for his temper +is violent, and he is passionately fond of his sister. When I closed the +door behind them a load seemed to be lifted from my mind. Alas, in +less than an hour there was a ring at the bell, and I learned that Mr. +Drebber had returned. He was much excited, and evidently the worse for +drink. He forced his way into the room, where I was sitting with my +daughter, and made some incoherent remark about having missed his train. +He then turned to Alice, and before my very face, proposed to her that +she should fly with him. You are of age, he said, and there is no law +to stop you. I have money enough and to spare. Never mind the old girl +here, but come along with me now straight away. You shall live like a +princess. Poor Alice was so frightened that she shrunk away from him, +but he caught her by the wrist and endeavoured to draw her towards the +door. I screamed, and at that moment my son Arthur came into the room. +What happened then I do not know. I heard oaths and the confused sounds +of a scuffle. I was too terrified to raise my head. When I did look up +I saw Arthur standing in the doorway laughing, with a stick in his hand. +I don't think that fine fellow will trouble us again, he said. I will +just go after him and see what he does with himself. With those words +he took his hat and started off down the street. The next morning we +heard of Mr. Drebber's mysterious death. + +This statement came from Mrs. Charpentier's lips with many gasps and +pauses. At times she spoke so low that I could hardly catch the words. I +made shorthand notes of all that she said, however, so that there should +be no possibility of a mistake. + +It's quite exciting, said Sherlock Holmes, with a yawn. What happened +next? + +When Mrs. Charpentier paused, the detective continued, I saw that the +whole case hung upon one point. Fixing her with my eye in a way which +I always found effective with women, I asked her at what hour her son +returned. + +I do not know, she answered. + +Not know? + +No; he has a latch-key, and he let himself in. + +After you went to bed? + +Yes. + +When did you go to bed? + +About eleven. + +So your son was gone at least two hours? + +Yes. + +Possibly four or five? + +Yes. + +What was he doing during that time? + +I do not know, she answered, turning white to her very lips. + +Of course after that there was nothing more to be done. I found +out where Lieutenant Charpentier was, took two officers with me, and +arrested him. When I touched him on the shoulder and warned him to come +quietly with us, he answered us as bold as brass, I suppose you +are arresting me for being concerned in the death of that scoundrel +Drebber, he said. We had said nothing to him about it, so that his +alluding to it had a most suspicious aspect. + +Very, said Holmes. + +He still carried the heavy stick which the mother described him as +having with him when he followed Drebber. It was a stout oak cudgel. + +What is your theory, then? + +Well, my theory is that he followed Drebber as far as the Brixton Road. +When there, a fresh altercation arose between them, in the course of +which Drebber received a blow from the stick, in the pit of the stomach, +perhaps, which killed him without leaving any mark. The night was so +wet that no one was about, so Charpentier dragged the body of his victim +into the empty house. As to the candle, and the blood, and the writing +on the wall, and the ring, they may all be so many tricks to throw the +police on to the wrong scent. + +Well done! said Holmes in an encouraging voice. Really, Gregson, you +are getting along. We shall make something of you yet. + +I flatter myself that I have managed it rather neatly, the detective +answered proudly. The young man volunteered a statement, in which he +said that after following Drebber some time, the latter perceived him, +and took a cab in order to get away from him. On his way home he met an +old shipmate, and took a long walk with him. On being asked where this +old shipmate lived, he was unable to give any satisfactory reply. I +think the whole case fits together uncommonly well. What amuses me is to +think of Lestrade, who had started off upon the wrong scent. I am afraid +he won't make much of [15] Why, by Jove, here's the very man himself! + +It was indeed Lestrade, who had ascended the stairs while we were +talking, and who now entered the room. The assurance and jauntiness +which generally marked his demeanour and dress were, however, wanting. +His face was disturbed and troubled, while his clothes were disarranged +and untidy. He had evidently come with the intention of consulting +with Sherlock Holmes, for on perceiving his colleague he appeared to be +embarrassed and put out. He stood in the centre of the room, fumbling +nervously with his hat and uncertain what to do. This is a most +extraordinary case, he said at last--a most incomprehensible affair. + +Ah, you find it so, Mr. Lestrade! cried Gregson, triumphantly. I +thought you would come to that conclusion. Have you managed to find the +Secretary, Mr. Joseph Stangerson? + +The Secretary, Mr. Joseph Stangerson, said Lestrade gravely, was +murdered at Halliday's Private Hotel about six o'clock this morning. + + + + +CHAPTER VII. LIGHT IN THE DARKNESS. + + +THE intelligence with which Lestrade greeted us was so momentous and so +unexpected, that we were all three fairly dumfoundered. Gregson sprang +out of his chair and upset the remainder of his whiskey and water. I +stared in silence at Sherlock Holmes, whose lips were compressed and his +brows drawn down over his eyes. + +Stangerson too! he muttered. The plot thickens. + +It was quite thick enough before, grumbled Lestrade, taking a chair. +I seem to have dropped into a sort of council of war. + +Are you--are you sure of this piece of intelligence? stammered +Gregson. + +I have just come from his room, said Lestrade. I was the first to +discover what had occurred. + +We have been hearing Gregson's view of the matter, Holmes observed. +Would you mind letting us know what you have seen and done? + +I have no objection, Lestrade answered, seating himself. I freely +confess that I was of the opinion that Stangerson was concerned in +the death of Drebber. This fresh development has shown me that I was +completely mistaken. Full of the one idea, I set myself to find out +what had become of the Secretary. They had been seen together at Euston +Station about half-past eight on the evening of the third. At two in the +morning Drebber had been found in the Brixton Road. The question which +confronted me was to find out how Stangerson had been employed between +8.30 and the time of the crime, and what had become of him afterwards. +I telegraphed to Liverpool, giving a description of the man, and warning +them to keep a watch upon the American boats. I then set to work calling +upon all the hotels and lodging-houses in the vicinity of Euston. You +see, I argued that if Drebber and his companion had become separated, +the natural course for the latter would be to put up somewhere in the +vicinity for the night, and then to hang about the station again next +morning. + +They would be likely to agree on some meeting-place beforehand, + remarked Holmes. + +So it proved. I spent the whole of yesterday evening in making +enquiries entirely without avail. This morning I began very early, and +at eight o'clock I reached Halliday's Private Hotel, in Little George +Street. On my enquiry as to whether a Mr. Stangerson was living there, +they at once answered me in the affirmative. + +No doubt you are the gentleman whom he was expecting, they said. He +has been waiting for a gentleman for two days. + +Where is he now? I asked. + +He is upstairs in bed. He wished to be called at nine. + +I will go up and see him at once, I said. + +It seemed to me that my sudden appearance might shake his nerves and +lead him to say something unguarded. The Boots volunteered to show me +the room: it was on the second floor, and there was a small corridor +leading up to it. The Boots pointed out the door to me, and was about to +go downstairs again when I saw something that made me feel sickish, in +spite of my twenty years' experience. From under the door there curled +a little red ribbon of blood, which had meandered across the passage and +formed a little pool along the skirting at the other side. I gave a cry, +which brought the Boots back. He nearly fainted when he saw it. The door +was locked on the inside, but we put our shoulders to it, and knocked it +in. The window of the room was open, and beside the window, all huddled +up, lay the body of a man in his nightdress. He was quite dead, and had +been for some time, for his limbs were rigid and cold. When we turned +him over, the Boots recognized him at once as being the same gentleman +who had engaged the room under the name of Joseph Stangerson. The cause +of death was a deep stab in the left side, which must have penetrated +the heart. And now comes the strangest part of the affair. What do you +suppose was above the murdered man? + +I felt a creeping of the flesh, and a presentiment of coming horror, +even before Sherlock Holmes answered. + +The word RACHE, written in letters of blood, he said. + +That was it, said Lestrade, in an awe-struck voice; and we were all +silent for a while. + +There was something so methodical and so incomprehensible about the +deeds of this unknown assassin, that it imparted a fresh ghastliness to +his crimes. My nerves, which were steady enough on the field of battle +tingled as I thought of it. + +The man was seen, continued Lestrade. A milk boy, passing on his way +to the dairy, happened to walk down the lane which leads from the mews +at the back of the hotel. He noticed that a ladder, which usually lay +there, was raised against one of the windows of the second floor, which +was wide open. After passing, he looked back and saw a man descend the +ladder. He came down so quietly and openly that the boy imagined him to +be some carpenter or joiner at work in the hotel. He took no particular +notice of him, beyond thinking in his own mind that it was early for him +to be at work. He has an impression that the man was tall, had a reddish +face, and was dressed in a long, brownish coat. He must have stayed in +the room some little time after the murder, for we found blood-stained +water in the basin, where he had washed his hands, and marks on the +sheets where he had deliberately wiped his knife. + +I glanced at Holmes on hearing the description of the murderer, which +tallied so exactly with his own. There was, however, no trace of +exultation or satisfaction upon his face. + +Did you find nothing in the room which could furnish a clue to the +murderer? he asked. + +Nothing. Stangerson had Drebber's purse in his pocket, but it seems +that this was usual, as he did all the paying. There was eighty odd +pounds in it, but nothing had been taken. Whatever the motives of these +extraordinary crimes, robbery is certainly not one of them. There were +no papers or memoranda in the murdered man's pocket, except a single +telegram, dated from Cleveland about a month ago, and containing +the words, J. H. is in Europe. There was no name appended to this +message. + +And there was nothing else? Holmes asked. + +Nothing of any importance. The man's novel, with which he had read +himself to sleep was lying upon the bed, and his pipe was on a chair +beside him. There was a glass of water on the table, and on the +window-sill a small chip ointment box containing a couple of pills. + +Sherlock Holmes sprang from his chair with an exclamation of delight. + +The last link, he cried, exultantly. My case is complete. + +The two detectives stared at him in amazement. + +I have now in my hands, my companion said, confidently, all the +threads which have formed such a tangle. There are, of course, details +to be filled in, but I am as certain of all the main facts, from the +time that Drebber parted from Stangerson at the station, up to the +discovery of the body of the latter, as if I had seen them with my own +eyes. I will give you a proof of my knowledge. Could you lay your hand +upon those pills? + +I have them, said Lestrade, producing a small white box; I took them +and the purse and the telegram, intending to have them put in a place of +safety at the Police Station. It was the merest chance my taking these +pills, for I am bound to say that I do not attach any importance to +them. + +Give them here, said Holmes. Now, Doctor, turning to me, are those +ordinary pills? + +They certainly were not. They were of a pearly grey colour, small, +round, and almost transparent against the light. From their lightness +and transparency, I should imagine that they are soluble in water, I +remarked. + +Precisely so, answered Holmes. Now would you mind going down and +fetching that poor little devil of a terrier which has been bad so long, +and which the landlady wanted you to put out of its pain yesterday. + +I went downstairs and carried the dog upstair in my arms. It's laboured +breathing and glazing eye showed that it was not far from its end. +Indeed, its snow-white muzzle proclaimed that it had already exceeded +the usual term of canine existence. I placed it upon a cushion on the +rug. + +I will now cut one of these pills in two, said Holmes, and drawing his +penknife he suited the action to the word. One half we return into the +box for future purposes. The other half I will place in this wine glass, +in which is a teaspoonful of water. You perceive that our friend, the +Doctor, is right, and that it readily dissolves. + +This may be very interesting, said Lestrade, in the injured tone of +one who suspects that he is being laughed at, I cannot see, however, +what it has to do with the death of Mr. Joseph Stangerson. + +Patience, my friend, patience! You will find in time that it has +everything to do with it. I shall now add a little milk to make the +mixture palatable, and on presenting it to the dog we find that he laps +it up readily enough. + +As he spoke he turned the contents of the wine glass into a saucer and +placed it in front of the terrier, who speedily licked it dry. Sherlock +Holmes' earnest demeanour had so far convinced us that we all sat in +silence, watching the animal intently, and expecting some startling +effect. None such appeared, however. The dog continued to lie stretched +upon tho [16] cushion, breathing in a laboured way, but apparently +neither the better nor the worse for its draught. + +Holmes had taken out his watch, and as minute followed minute without +result, an expression of the utmost chagrin and disappointment appeared +upon his features. He gnawed his lip, drummed his fingers upon the +table, and showed every other symptom of acute impatience. So great +was his emotion, that I felt sincerely sorry for him, while the two +detectives smiled derisively, by no means displeased at this check which +he had met. + +It can't be a coincidence, he cried, at last springing from his chair +and pacing wildly up and down the room; it is impossible that it should +be a mere coincidence. The very pills which I suspected in the case of +Drebber are actually found after the death of Stangerson. And yet they +are inert. What can it mean? Surely my whole chain of reasoning cannot +have been false. It is impossible! And yet this wretched dog is none the +worse. Ah, I have it! I have it! With a perfect shriek of delight he +rushed to the box, cut the other pill in two, dissolved it, added milk, +and presented it to the terrier. The unfortunate creature's tongue +seemed hardly to have been moistened in it before it gave a convulsive +shiver in every limb, and lay as rigid and lifeless as if it had been +struck by lightning. + +Sherlock Holmes drew a long breath, and wiped the perspiration from his +forehead. I should have more faith, he said; I ought to know by +this time that when a fact appears to be opposed to a long train of +deductions, it invariably proves to be capable of bearing some other +interpretation. Of the two pills in that box one was of the most deadly +poison, and the other was entirely harmless. I ought to have known that +before ever I saw the box at all. + +This last statement appeared to me to be so startling, that I could +hardly believe that he was in his sober senses. There was the dead dog, +however, to prove that his conjecture had been correct. It seemed to me +that the mists in my own mind were gradually clearing away, and I began +to have a dim, vague perception of the truth. + +All this seems strange to you, continued Holmes, because you failed +at the beginning of the inquiry to grasp the importance of the single +real clue which was presented to you. I had the good fortune to seize +upon that, and everything which has occurred since then has served to +confirm my original supposition, and, indeed, was the logical sequence +of it. Hence things which have perplexed you and made the case more +obscure, have served to enlighten me and to strengthen my conclusions. +It is a mistake to confound strangeness with mystery. The most +commonplace crime is often the most mysterious because it presents no +new or special features from which deductions may be drawn. This murder +would have been infinitely more difficult to unravel had the body of +the victim been simply found lying in the roadway without any of +those _outré_ and sensational accompaniments which have rendered +it remarkable. These strange details, far from making the case more +difficult, have really had the effect of making it less so. + +Mr. Gregson, who had listened to this address with considerable +impatience, could contain himself no longer. Look here, Mr. Sherlock +Holmes, he said, we are all ready to acknowledge that you are a smart +man, and that you have your own methods of working. We want something +more than mere theory and preaching now, though. It is a case of taking +the man. I have made my case out, and it seems I was wrong. Young +Charpentier could not have been engaged in this second affair. Lestrade +went after his man, Stangerson, and it appears that he was wrong too. +You have thrown out hints here, and hints there, and seem to know more +than we do, but the time has come when we feel that we have a right to +ask you straight how much you do know of the business. Can you name the +man who did it? + +I cannot help feeling that Gregson is right, sir, remarked Lestrade. +We have both tried, and we have both failed. You have remarked more +than once since I have been in the room that you had all the evidence +which you require. Surely you will not withhold it any longer. + +Any delay in arresting the assassin, I observed, might give him time +to perpetrate some fresh atrocity. + +Thus pressed by us all, Holmes showed signs of irresolution. He +continued to walk up and down the room with his head sunk on his chest +and his brows drawn down, as was his habit when lost in thought. + +There will be no more murders, he said at last, stopping abruptly and +facing us. You can put that consideration out of the question. You have +asked me if I know the name of the assassin. I do. The mere knowing of +his name is a small thing, however, compared with the power of laying +our hands upon him. This I expect very shortly to do. I have good hopes +of managing it through my own arrangements; but it is a thing which +needs delicate handling, for we have a shrewd and desperate man to deal +with, who is supported, as I have had occasion to prove, by another who +is as clever as himself. As long as this man has no idea that anyone +can have a clue there is some chance of securing him; but if he had the +slightest suspicion, he would change his name, and vanish in an instant +among the four million inhabitants of this great city. Without meaning +to hurt either of your feelings, I am bound to say that I consider these +men to be more than a match for the official force, and that is why I +have not asked your assistance. If I fail I shall, of course, incur all +the blame due to this omission; but that I am prepared for. At present +I am ready to promise that the instant that I can communicate with you +without endangering my own combinations, I shall do so. + +Gregson and Lestrade seemed to be far from satisfied by this assurance, +or by the depreciating allusion to the detective police. The former had +flushed up to the roots of his flaxen hair, while the other's beady eyes +glistened with curiosity and resentment. Neither of them had time to +speak, however, before there was a tap at the door, and the spokesman +of the street Arabs, young Wiggins, introduced his insignificant and +unsavoury person. + +Please, sir, he said, touching his forelock, I have the cab +downstairs. + +Good boy, said Holmes, blandly. Why don't you introduce this pattern +at Scotland Yard? he continued, taking a pair of steel handcuffs from +a drawer. See how beautifully the spring works. They fasten in an +instant. + +The old pattern is good enough, remarked Lestrade, if we can only +find the man to put them on. + +Very good, very good, said Holmes, smiling. The cabman may as well +help me with my boxes. Just ask him to step up, Wiggins. + +I was surprised to find my companion speaking as though he were about +to set out on a journey, since he had not said anything to me about it. +There was a small portmanteau in the room, and this he pulled out and +began to strap. He was busily engaged at it when the cabman entered the +room. + +Just give me a help with this buckle, cabman, he said, kneeling over +his task, and never turning his head. + +The fellow came forward with a somewhat sullen, defiant air, and put +down his hands to assist. At that instant there was a sharp click, the +jangling of metal, and Sherlock Holmes sprang to his feet again. + +Gentlemen, he cried, with flashing eyes, let me introduce you to Mr. +Jefferson Hope, the murderer of Enoch Drebber and of Joseph Stangerson. + +The whole thing occurred in a moment--so quickly that I had no time +to realize it. I have a vivid recollection of that instant, of Holmes' +triumphant expression and the ring of his voice, of the cabman's +dazed, savage face, as he glared at the glittering handcuffs, which had +appeared as if by magic upon his wrists. For a second or two we might +have been a group of statues. Then, with an inarticulate roar of fury, +the prisoner wrenched himself free from Holmes's grasp, and hurled +himself through the window. Woodwork and glass gave way before him; but +before he got quite through, Gregson, Lestrade, and Holmes sprang upon +him like so many staghounds. He was dragged back into the room, and then +commenced a terrific conflict. So powerful and so fierce was he, that +the four of us were shaken off again and again. He appeared to have the +convulsive strength of a man in an epileptic fit. His face and hands +were terribly mangled by his passage through the glass, but loss of +blood had no effect in diminishing his resistance. It was not until +Lestrade succeeded in getting his hand inside his neckcloth and +half-strangling him that we made him realize that his struggles were of +no avail; and even then we felt no security until we had pinioned his +feet as well as his hands. That done, we rose to our feet breathless and +panting. + +We have his cab, said Sherlock Holmes. It will serve to take him to +Scotland Yard. And now, gentlemen, he continued, with a pleasant smile, +we have reached the end of our little mystery. You are very welcome to +put any questions that you like to me now, and there is no danger that I +will refuse to answer them. + +PART II. _The Country of the Saints._ + +CHAPTER I. ON THE GREAT ALKALI PLAIN. + +IN the central portion of the great North American Continent there lies +an arid and repulsive desert, which for many a long year served as a +barrier against the advance of civilisation. From the Sierra Nevada to +Nebraska, and from the Yellowstone River in the north to the Colorado +upon the south, is a region of desolation and silence. Nor is Nature +always in one mood throughout this grim district. It comprises +snow-capped and lofty mountains, and dark and gloomy valleys. There are +swift-flowing rivers which dash through jagged cañons; and there are +enormous plains, which in winter are white with snow, and in summer are +grey with the saline alkali dust. They all preserve, however, the common +characteristics of barrenness, inhospitality, and misery. + +There are no inhabitants of this land of despair. A band of Pawnees +or of Blackfeet may occasionally traverse it in order to reach other +hunting-grounds, but the hardiest of the braves are glad to lose sight +of those awesome plains, and to find themselves once more upon their +prairies. The coyote skulks among the scrub, the buzzard flaps heavily +through the air, and the clumsy grizzly bear lumbers through the dark +ravines, and picks up such sustenance as it can amongst the rocks. These +are the sole dwellers in the wilderness. + +In the whole world there can be no more dreary view than that from +the northern slope of the Sierra Blanco. As far as the eye can reach +stretches the great flat plain-land, all dusted over with patches of +alkali, and intersected by clumps of the dwarfish chaparral bushes. On +the extreme verge of the horizon lie a long chain of mountain peaks, +with their rugged summits flecked with snow. In this great stretch of +country there is no sign of life, nor of anything appertaining to life. +There is no bird in the steel-blue heaven, no movement upon the dull, +grey earth--above all, there is absolute silence. Listen as one may, +there is no shadow of a sound in all that mighty wilderness; nothing but +silence--complete and heart-subduing silence. + +It has been said there is nothing appertaining to life upon the broad +plain. That is hardly true. Looking down from the Sierra Blanco, one +sees a pathway traced out across the desert, which winds away and is +lost in the extreme distance. It is rutted with wheels and trodden down +by the feet of many adventurers. Here and there there are scattered +white objects which glisten in the sun, and stand out against the dull +deposit of alkali. Approach, and examine them! They are bones: some +large and coarse, others smaller and more delicate. The former have +belonged to oxen, and the latter to men. For fifteen hundred miles one +may trace this ghastly caravan route by these scattered remains of those +who had fallen by the wayside. + +Looking down on this very scene, there stood upon the fourth of May, +eighteen hundred and forty-seven, a solitary traveller. His appearance +was such that he might have been the very genius or demon of the region. +An observer would have found it difficult to say whether he was nearer +to forty or to sixty. His face was lean and haggard, and the brown +parchment-like skin was drawn tightly over the projecting bones; his +long, brown hair and beard were all flecked and dashed with white; his +eyes were sunken in his head, and burned with an unnatural lustre; while +the hand which grasped his rifle was hardly more fleshy than that of a +skeleton. As he stood, he leaned upon his weapon for support, and yet +his tall figure and the massive framework of his bones suggested a wiry +and vigorous constitution. His gaunt face, however, and his clothes, +which hung so baggily over his shrivelled limbs, proclaimed what it +was that gave him that senile and decrepit appearance. The man was +dying--dying from hunger and from thirst. + +He had toiled painfully down the ravine, and on to this little +elevation, in the vain hope of seeing some signs of water. Now the great +salt plain stretched before his eyes, and the distant belt of savage +mountains, without a sign anywhere of plant or tree, which might +indicate the presence of moisture. In all that broad landscape there +was no gleam of hope. North, and east, and west he looked with wild +questioning eyes, and then he realised that his wanderings had come to +an end, and that there, on that barren crag, he was about to die. Why +not here, as well as in a feather bed, twenty years hence, he muttered, +as he seated himself in the shelter of a boulder. + +Before sitting down, he had deposited upon the ground his useless rifle, +and also a large bundle tied up in a grey shawl, which he had carried +slung over his right shoulder. It appeared to be somewhat too heavy for +his strength, for in lowering it, it came down on the ground with some +little violence. Instantly there broke from the grey parcel a little +moaning cry, and from it there protruded a small, scared face, with very +bright brown eyes, and two little speckled, dimpled fists. + +You've hurt me! said a childish voice reproachfully. + +Have I though, the man answered penitently, I didn't go for to do +it. As he spoke he unwrapped the grey shawl and extricated a pretty +little girl of about five years of age, whose dainty shoes and smart +pink frock with its little linen apron all bespoke a mother's care. The +child was pale and wan, but her healthy arms and legs showed that she +had suffered less than her companion. + +How is it now? he answered anxiously, for she was still rubbing the +towsy golden curls which covered the back of her head. + +Kiss it and make it well, she said, with perfect gravity, shoving +[19] the injured part up to him. That's what mother used to do. Where's +mother? + +Mother's gone. I guess you'll see her before long. + +Gone, eh! said the little girl. Funny, she didn't say good-bye; she +most always did if she was just goin' over to Auntie's for tea, and now +she's been away three days. Say, it's awful dry, ain't it? Ain't there +no water, nor nothing to eat? + +No, there ain't nothing, dearie. You'll just need to be patient awhile, +and then you'll be all right. Put your head up agin me like that, and +then you'll feel bullier. It ain't easy to talk when your lips is like +leather, but I guess I'd best let you know how the cards lie. What's +that you've got? + +Pretty things! fine things! cried the little girl enthusiastically, +holding up two glittering fragments of mica. When we goes back to home +I'll give them to brother Bob. + +You'll see prettier things than them soon, said the man confidently. +You just wait a bit. I was going to tell you though--you remember when +we left the river? + +Oh, yes. + +Well, we reckoned we'd strike another river soon, d'ye see. But there +was somethin' wrong; compasses, or map, or somethin', and it didn't +turn up. Water ran out. Just except a little drop for the likes of you +and--and---- + +And you couldn't wash yourself, interrupted his companion gravely, +staring up at his grimy visage. + +No, nor drink. And Mr. Bender, he was the fust to go, and then Indian +Pete, and then Mrs. McGregor, and then Johnny Hones, and then, dearie, +your mother. + +Then mother's a deader too, cried the little girl dropping her face in +her pinafore and sobbing bitterly. + +Yes, they all went except you and me. Then I thought there was some +chance of water in this direction, so I heaved you over my shoulder and +we tramped it together. It don't seem as though we've improved matters. +There's an almighty small chance for us now! + +Do you mean that we are going to die too? asked the child, checking +her sobs, and raising her tear-stained face. + +I guess that's about the size of it. + +Why didn't you say so before? she said, laughing gleefully. You gave +me such a fright. Why, of course, now as long as we die we'll be with +mother again. + +Yes, you will, dearie. + +And you too. I'll tell her how awful good you've been. I'll bet she +meets us at the door of Heaven with a big pitcher of water, and a lot +of buckwheat cakes, hot, and toasted on both sides, like Bob and me was +fond of. How long will it be first? + +I don't know--not very long. The man's eyes were fixed upon the +northern horizon. In the blue vault of the heaven there had appeared +three little specks which increased in size every moment, so rapidly did +they approach. They speedily resolved themselves into three large brown +birds, which circled over the heads of the two wanderers, and then +settled upon some rocks which overlooked them. They were buzzards, the +vultures of the west, whose coming is the forerunner of death. + +Cocks and hens, cried the little girl gleefully, pointing at their +ill-omened forms, and clapping her hands to make them rise. Say, did +God make this country? + +In course He did, said her companion, rather startled by this +unexpected question. + +He made the country down in Illinois, and He made the Missouri, the +little girl continued. I guess somebody else made the country in these +parts. It's not nearly so well done. They forgot the water and the +trees. + +What would ye think of offering up prayer? the man asked diffidently. + +It ain't night yet, she answered. + +It don't matter. It ain't quite regular, but He won't mind that, you +bet. You say over them ones that you used to say every night in the +waggon when we was on the Plains. + +Why don't you say some yourself? the child asked, with wondering eyes. + +I disremember them, he answered. I hain't said none since I was half +the height o' that gun. I guess it's never too late. You say them out, +and I'll stand by and come in on the choruses. + +Then you'll need to kneel down, and me too, she said, laying the shawl +out for that purpose. You've got to put your hands up like this. It +makes you feel kind o' good. + +It was a strange sight had there been anything but the buzzards to see +it. Side by side on the narrow shawl knelt the two wanderers, the little +prattling child and the reckless, hardened adventurer. Her chubby face, +and his haggard, angular visage were both turned up to the cloudless +heaven in heartfelt entreaty to that dread being with whom they were +face to face, while the two voices--the one thin and clear, the other +deep and harsh--united in the entreaty for mercy and forgiveness. The +prayer finished, they resumed their seat in the shadow of the boulder +until the child fell asleep, nestling upon the broad breast of her +protector. He watched over her slumber for some time, but Nature proved +to be too strong for him. For three days and three nights he had allowed +himself neither rest nor repose. Slowly the eyelids drooped over the +tired eyes, and the head sunk lower and lower upon the breast, until the +man's grizzled beard was mixed with the gold tresses of his companion, +and both slept the same deep and dreamless slumber. + +Had the wanderer remained awake for another half hour a strange sight +would have met his eyes. Far away on the extreme verge of the alkali +plain there rose up a little spray of dust, very slight at first, and +hardly to be distinguished from the mists of the distance, but gradually +growing higher and broader until it formed a solid, well-defined cloud. +This cloud continued to increase in size until it became evident that it +could only be raised by a great multitude of moving creatures. In more +fertile spots the observer would have come to the conclusion that one +of those great herds of bisons which graze upon the prairie land was +approaching him. This was obviously impossible in these arid wilds. As +the whirl of dust drew nearer to the solitary bluff upon which the two +castaways were reposing, the canvas-covered tilts of waggons and the +figures of armed horsemen began to show up through the haze, and the +apparition revealed itself as being a great caravan upon its journey for +the West. But what a caravan! When the head of it had reached the base +of the mountains, the rear was not yet visible on the horizon. Right +across the enormous plain stretched the straggling array, waggons +and carts, men on horseback, and men on foot. Innumerable women who +staggered along under burdens, and children who toddled beside the +waggons or peeped out from under the white coverings. This was evidently +no ordinary party of immigrants, but rather some nomad people who had +been compelled from stress of circumstances to seek themselves a new +country. There rose through the clear air a confused clattering and +rumbling from this great mass of humanity, with the creaking of wheels +and the neighing of horses. Loud as it was, it was not sufficient to +rouse the two tired wayfarers above them. + +At the head of the column there rode a score or more of grave ironfaced +men, clad in sombre homespun garments and armed with rifles. On reaching +the base of the bluff they halted, and held a short council among +themselves. + +The wells are to the right, my brothers, said one, a hard-lipped, +clean-shaven man with grizzly hair. + +To the right of the Sierra Blanco--so we shall reach the Rio Grande, + said another. + +Fear not for water, cried a third. He who could draw it from the +rocks will not now abandon His own chosen people. + +Amen! Amen! responded the whole party. + +They were about to resume their journey when one of the youngest and +keenest-eyed uttered an exclamation and pointed up at the rugged crag +above them. From its summit there fluttered a little wisp of pink, +showing up hard and bright against the grey rocks behind. At the sight +there was a general reining up of horses and unslinging of guns, while +fresh horsemen came galloping up to reinforce the vanguard. The word +Redskins' was on every lip. + +There can't be any number of Injuns here, said the elderly man who +appeared to be in command. We have passed the Pawnees, and there are no +other tribes until we cross the great mountains. + +Shall I go forward and see, Brother Stangerson, asked one of the band. + +And I, and I, cried a dozen voices. + +Leave your horses below and we will await you here, the Elder +answered. In a moment the young fellows had dismounted, fastened their +horses, and were ascending the precipitous slope which led up to the +object which had excited their curiosity. They advanced rapidly and +noiselessly, with the confidence and dexterity of practised scouts. +The watchers from the plain below could see them flit from rock to rock +until their figures stood out against the skyline. The young man who had +first given the alarm was leading them. Suddenly his followers saw him +throw up his hands, as though overcome with astonishment, and on joining +him they were affected in the same way by the sight which met their +eyes. + +On the little plateau which crowned the barren hill there stood a +single giant boulder, and against this boulder there lay a tall man, +long-bearded and hard-featured, but of an excessive thinness. His placid +face and regular breathing showed that he was fast asleep. Beside him +lay a little child, with her round white arms encircling his brown +sinewy neck, and her golden haired head resting upon the breast of his +velveteen tunic. Her rosy lips were parted, showing the regular line of +snow-white teeth within, and a playful smile played over her infantile +features. Her plump little white legs terminating in white socks and +neat shoes with shining buckles, offered a strange contrast to the long +shrivelled members of her companion. On the ledge of rock above this +strange couple there stood three solemn buzzards, who, at the sight of +the new comers uttered raucous screams of disappointment and flapped +sullenly away. + +The cries of the foul birds awoke the two sleepers who stared about [20] +them in bewilderment. The man staggered to his feet and looked down upon +the plain which had been so desolate when sleep had overtaken him, and +which was now traversed by this enormous body of men and of beasts. His +face assumed an expression of incredulity as he gazed, and he passed his +boney hand over his eyes. This is what they call delirium, I guess, + he muttered. The child stood beside him, holding on to the skirt of +his coat, and said nothing but looked all round her with the wondering +questioning gaze of childhood. + +The rescuing party were speedily able to convince the two castaways that +their appearance was no delusion. One of them seized the little girl, +and hoisted her upon his shoulder, while two others supported her gaunt +companion, and assisted him towards the waggons. + +My name is John Ferrier, the wanderer explained; me and that little +un are all that's left o' twenty-one people. The rest is all dead o' +thirst and hunger away down in the south. + +Is she your child? asked someone. + +I guess she is now, the other cried, defiantly; she's mine cause I +saved her. No man will take her from me. She's Lucy Ferrier from this +day on. Who are you, though? he continued, glancing with curiosity at +his stalwart, sunburned rescuers; there seems to be a powerful lot of +ye. + +Nigh upon ten thousand, said one of the young men; we are the +persecuted children of God--the chosen of the Angel Merona. + +I never heard tell on him, said the wanderer. He appears to have +chosen a fair crowd of ye. + +Do not jest at that which is sacred, said the other sternly. We are +of those who believe in those sacred writings, drawn in Egyptian letters +on plates of beaten gold, which were handed unto the holy Joseph Smith +at Palmyra. We have come from Nauvoo, in the State of Illinois, where we +had founded our temple. We have come to seek a refuge from the violent +man and from the godless, even though it be the heart of the desert. + +The name of Nauvoo evidently recalled recollections to John Ferrier. I +see, he said, you are the Mormons. + +We are the Mormons, answered his companions with one voice. + +And where are you going? + +We do not know. The hand of God is leading us under the person of our +Prophet. You must come before him. He shall say what is to be done with +you. + +They had reached the base of the hill by this time, and were surrounded +by crowds of the pilgrims--pale-faced meek-looking women, strong +laughing children, and anxious earnest-eyed men. Many were the cries +of astonishment and of commiseration which arose from them when they +perceived the youth of one of the strangers and the destitution of the +other. Their escort did not halt, however, but pushed on, followed by +a great crowd of Mormons, until they reached a waggon, which was +conspicuous for its great size and for the gaudiness and smartness of +its appearance. Six horses were yoked to it, whereas the others were +furnished with two, or, at most, four a-piece. Beside the driver there +sat a man who could not have been more than thirty years of age, but +whose massive head and resolute expression marked him as a leader. He +was reading a brown-backed volume, but as the crowd approached he laid +it aside, and listened attentively to an account of the episode. Then he +turned to the two castaways. + +If we take you with us, he said, in solemn words, it can only be as +believers in our own creed. We shall have no wolves in our fold. Better +far that your bones should bleach in this wilderness than that you +should prove to be that little speck of decay which in time corrupts the +whole fruit. Will you come with us on these terms? + +Guess I'll come with you on any terms, said Ferrier, with such +emphasis that the grave Elders could not restrain a smile. The leader +alone retained his stern, impressive expression. + +Take him, Brother Stangerson, he said, give him food and drink, +and the child likewise. Let it be your task also to teach him our holy +creed. We have delayed long enough. Forward! On, on to Zion! + +On, on to Zion! cried the crowd of Mormons, and the words rippled down +the long caravan, passing from mouth to mouth until they died away in a +dull murmur in the far distance. With a cracking of whips and a creaking +of wheels the great waggons got into motion, and soon the whole caravan +was winding along once more. The Elder to whose care the two waifs +had been committed, led them to his waggon, where a meal was already +awaiting them. + +You shall remain here, he said. In a few days you will have recovered +from your fatigues. In the meantime, remember that now and for ever you +are of our religion. Brigham Young has said it, and he has spoken with +the voice of Joseph Smith, which is the voice of God. + + + + +CHAPTER II. THE FLOWER OF UTAH. + + +THIS is not the place to commemorate the trials and privations endured +by the immigrant Mormons before they came to their final haven. From the +shores of the Mississippi to the western slopes of the Rocky Mountains +they had struggled on with a constancy almost unparalleled in history. +The savage man, and the savage beast, hunger, thirst, fatigue, and +disease--every impediment which Nature could place in the way, had all +been overcome with Anglo-Saxon tenacity. Yet the long journey and the +accumulated terrors had shaken the hearts of the stoutest among them. +There was not one who did not sink upon his knees in heartfelt prayer +when they saw the broad valley of Utah bathed in the sunlight beneath +them, and learned from the lips of their leader that this was the +promised land, and that these virgin acres were to be theirs for +evermore. + +Young speedily proved himself to be a skilful administrator as well as a +resolute chief. Maps were drawn and charts prepared, in which the future +city was sketched out. All around farms were apportioned and allotted in +proportion to the standing of each individual. The tradesman was put +to his trade and the artisan to his calling. In the town streets and +squares sprang up, as if by magic. In the country there was draining +and hedging, planting and clearing, until the next summer saw the whole +country golden with the wheat crop. Everything prospered in the strange +settlement. Above all, the great temple which they had erected in the +centre of the city grew ever taller and larger. From the first blush of +dawn until the closing of the twilight, the clatter of the hammer +and the rasp of the saw was never absent from the monument which the +immigrants erected to Him who had led them safe through many dangers. + +The two castaways, John Ferrier and the little girl who had shared his +fortunes and had been adopted as his daughter, accompanied the Mormons +to the end of their great pilgrimage. Little Lucy Ferrier was borne +along pleasantly enough in Elder Stangerson's waggon, a retreat which +she shared with the Mormon's three wives and with his son, a headstrong +forward boy of twelve. Having rallied, with the elasticity of childhood, +from the shock caused by her mother's death, she soon became a pet +with the women, and reconciled herself to this new life in her moving +canvas-covered home. In the meantime Ferrier having recovered from his +privations, distinguished himself as a useful guide and an indefatigable +hunter. So rapidly did he gain the esteem of his new companions, that +when they reached the end of their wanderings, it was unanimously agreed +that he should be provided with as large and as fertile a tract of land +as any of the settlers, with the exception of Young himself, and of +Stangerson, Kemball, Johnston, and Drebber, who were the four principal +Elders. + +On the farm thus acquired John Ferrier built himself a substantial +log-house, which received so many additions in succeeding years that it +grew into a roomy villa. He was a man of a practical turn of mind, +keen in his dealings and skilful with his hands. His iron constitution +enabled him to work morning and evening at improving and tilling his +lands. Hence it came about that his farm and all that belonged to +him prospered exceedingly. In three years he was better off than his +neighbours, in six he was well-to-do, in nine he was rich, and in twelve +there were not half a dozen men in the whole of Salt Lake City who could +compare with him. From the great inland sea to the distant Wahsatch +Mountains there was no name better known than that of John Ferrier. + +There was one way and only one in which he offended the susceptibilities +of his co-religionists. No argument or persuasion could ever induce him +to set up a female establishment after the manner of his companions. He +never gave reasons for this persistent refusal, but contented himself by +resolutely and inflexibly adhering to his determination. There were some +who accused him of lukewarmness in his adopted religion, and others who +put it down to greed of wealth and reluctance to incur expense. Others, +again, spoke of some early love affair, and of a fair-haired girl who +had pined away on the shores of the Atlantic. Whatever the reason, +Ferrier remained strictly celibate. In every other respect he conformed +to the religion of the young settlement, and gained the name of being an +orthodox and straight-walking man. + +Lucy Ferrier grew up within the log-house, and assisted her adopted +father in all his undertakings. The keen air of the mountains and the +balsamic odour of the pine trees took the place of nurse and mother to +the young girl. As year succeeded to year she grew taller and stronger, +her cheek more rudy, and her step more elastic. Many a wayfarer upon +the high road which ran by Ferrier's farm felt long-forgotten thoughts +revive in their mind as they watched her lithe girlish figure tripping +through the wheatfields, or met her mounted upon her father's mustang, +and managing it with all the ease and grace of a true child of the West. +So the bud blossomed into a flower, and the year which saw her father +the richest of the farmers left her as fair a specimen of American +girlhood as could be found in the whole Pacific slope. + +It was not the father, however, who first discovered that the child had +developed into the woman. It seldom is in such cases. That mysterious +change is too subtle and too gradual to be measured by dates. Least of +all does the maiden herself know it until the tone of a voice or the +touch of a hand sets her heart thrilling within her, and she learns, +with a mixture of pride and of fear, that a new and a larger nature has +awoken within her. There are few who cannot recall that day and remember +the one little incident which heralded the dawn of a new life. In the +case of Lucy Ferrier the occasion was serious enough in itself, apart +from its future influence on her destiny and that of many besides. + +It was a warm June morning, and the Latter Day Saints were as busy as +the bees whose hive they have chosen for their emblem. In the fields and +in the streets rose the same hum of human industry. Down the dusty high +roads defiled long streams of heavily-laden mules, all heading to the +west, for the gold fever had broken out in California, and the Overland +Route lay through the City of the Elect. There, too, were droves of +sheep and bullocks coming in from the outlying pasture lands, and trains +of tired immigrants, men and horses equally weary of their interminable +journey. Through all this motley assemblage, threading her way with the +skill of an accomplished rider, there galloped Lucy Ferrier, her fair +face flushed with the exercise and her long chestnut hair floating out +behind her. She had a commission from her father in the City, and was +dashing in as she had done many a time before, with all the fearlessness +of youth, thinking only of her task and how it was to be performed. The +travel-stained adventurers gazed after her in astonishment, and even +the unemotional Indians, journeying in with their pelties, relaxed their +accustomed stoicism as they marvelled at the beauty of the pale-faced +maiden. + +She had reached the outskirts of the city when she found the road +blocked by a great drove of cattle, driven by a half-dozen wild-looking +herdsmen from the plains. In her impatience she endeavoured to pass this +obstacle by pushing her horse into what appeared to be a gap. Scarcely +had she got fairly into it, however, before the beasts closed in behind +her, and she found herself completely imbedded in the moving stream of +fierce-eyed, long-horned bullocks. Accustomed as she was to deal with +cattle, she was not alarmed at her situation, but took advantage of +every opportunity to urge her horse on in the hopes of pushing her way +through the cavalcade. Unfortunately the horns of one of the creatures, +either by accident or design, came in violent contact with the flank of +the mustang, and excited it to madness. In an instant it reared up upon +its hind legs with a snort of rage, and pranced and tossed in a way that +would have unseated any but a most skilful rider. The situation was full +of peril. Every plunge of the excited horse brought it against the horns +again, and goaded it to fresh madness. It was all that the girl could +do to keep herself in the saddle, yet a slip would mean a terrible death +under the hoofs of the unwieldy and terrified animals. Unaccustomed to +sudden emergencies, her head began to swim, and her grip upon the bridle +to relax. Choked by the rising cloud of dust and by the steam from the +struggling creatures, she might have abandoned her efforts in despair, +but for a kindly voice at her elbow which assured her of assistance. At +the same moment a sinewy brown hand caught the frightened horse by +the curb, and forcing a way through the drove, soon brought her to the +outskirts. + +You're not hurt, I hope, miss, said her preserver, respectfully. + +She looked up at his dark, fierce face, and laughed saucily. I'm awful +frightened, she said, naively; whoever would have thought that Poncho +would have been so scared by a lot of cows? + +Thank God you kept your seat, the other said earnestly. He was a tall, +savage-looking young fellow, mounted on a powerful roan horse, and +clad in the rough dress of a hunter, with a long rifle slung over his +shoulders. I guess you are the daughter of John Ferrier, he remarked, +I saw you ride down from his house. When you see him, ask him if he +remembers the Jefferson Hopes of St. Louis. If he's the same Ferrier, my +father and he were pretty thick. + +Hadn't you better come and ask yourself? she asked, demurely. + +The young fellow seemed pleased at the suggestion, and his dark eyes +sparkled with pleasure. I'll do so, he said, we've been in the +mountains for two months, and are not over and above in visiting +condition. He must take us as he finds us. + +He has a good deal to thank you for, and so have I, she answered, +he's awful fond of me. If those cows had jumped on me he'd have never +got over it. + +Neither would I, said her companion. + +You! Well, I don't see that it would make much matter to you, anyhow. +You ain't even a friend of ours. + +The young hunter's dark face grew so gloomy over this remark that Lucy +Ferrier laughed aloud. + +There, I didn't mean that, she said; of course, you are a friend now. +You must come and see us. Now I must push along, or father won't trust +me with his business any more. Good-bye! + +Good-bye, he answered, raising his broad sombrero, and bending over +her little hand. She wheeled her mustang round, gave it a cut with her +riding-whip, and darted away down the broad road in a rolling cloud of +dust. + +Young Jefferson Hope rode on with his companions, gloomy and taciturn. +He and they had been among the Nevada Mountains prospecting for silver, +and were returning to Salt Lake City in the hope of raising capital +enough to work some lodes which they had discovered. He had been as keen +as any of them upon the business until this sudden incident had drawn +his thoughts into another channel. The sight of the fair young girl, +as frank and wholesome as the Sierra breezes, had stirred his volcanic, +untamed heart to its very depths. When she had vanished from his sight, +he realized that a crisis had come in his life, and that neither silver +speculations nor any other questions could ever be of such importance to +him as this new and all-absorbing one. The love which had sprung up in +his heart was not the sudden, changeable fancy of a boy, but rather the +wild, fierce passion of a man of strong will and imperious temper. He +had been accustomed to succeed in all that he undertook. He swore in +his heart that he would not fail in this if human effort and human +perseverance could render him successful. + +He called on John Ferrier that night, and many times again, until +his face was a familiar one at the farm-house. John, cooped up in the +valley, and absorbed in his work, had had little chance of learning +the news of the outside world during the last twelve years. All this +Jefferson Hope was able to tell him, and in a style which interested +Lucy as well as her father. He had been a pioneer in California, and +could narrate many a strange tale of fortunes made and fortunes lost +in those wild, halcyon days. He had been a scout too, and a trapper, a +silver explorer, and a ranchman. Wherever stirring adventures were to be +had, Jefferson Hope had been there in search of them. He soon became a +favourite with the old farmer, who spoke eloquently of his virtues. On +such occasions, Lucy was silent, but her blushing cheek and her bright, +happy eyes, showed only too clearly that her young heart was no longer +her own. Her honest father may not have observed these symptoms, +but they were assuredly not thrown away upon the man who had won her +affections. + +It was a summer evening when he came galloping down the road and pulled +up at the gate. She was at the doorway, and came down to meet him. He +threw the bridle over the fence and strode up the pathway. + +I am off, Lucy, he said, taking her two hands in his, and gazing +tenderly down into her face; I won't ask you to come with me now, but +will you be ready to come when I am here again? + +And when will that be? she asked, blushing and laughing. + +A couple of months at the outside. I will come and claim you then, my +darling. There's no one who can stand between us. + +And how about father? she asked. + +He has given his consent, provided we get these mines working all +right. I have no fear on that head. + +Oh, well; of course, if you and father have arranged it all, there's +no more to be said, she whispered, with her cheek against his broad +breast. + +Thank God! he said, hoarsely, stooping and kissing her. It is +settled, then. The longer I stay, the harder it will be to go. They are +waiting for me at the cañon. Good-bye, my own darling--good-bye. In two +months you shall see me. + +He tore himself from her as he spoke, and, flinging himself upon his +horse, galloped furiously away, never even looking round, as though +afraid that his resolution might fail him if he took one glance at +what he was leaving. She stood at the gate, gazing after him until +he vanished from her sight. Then she walked back into the house, the +happiest girl in all Utah. + + + + +CHAPTER III. JOHN FERRIER TALKS WITH THE PROPHET. + + +THREE weeks had passed since Jefferson Hope and his comrades had +departed from Salt Lake City. John Ferrier's heart was sore within him +when he thought of the young man's return, and of the impending loss of +his adopted child. Yet her bright and happy face reconciled him to +the arrangement more than any argument could have done. He had always +determined, deep down in his resolute heart, that nothing would ever +induce him to allow his daughter to wed a Mormon. Such a marriage he +regarded as no marriage at all, but as a shame and a disgrace. Whatever +he might think of the Mormon doctrines, upon that one point he was +inflexible. He had to seal his mouth on the subject, however, for to +express an unorthodox opinion was a dangerous matter in those days in +the Land of the Saints. + +Yes, a dangerous matter--so dangerous that even the most saintly dared +only whisper their religious opinions with bated breath, lest something +which fell from their lips might be misconstrued, and bring down a +swift retribution upon them. The victims of persecution had now turned +persecutors on their own account, and persecutors of the most +terrible description. Not the Inquisition of Seville, nor the German +Vehm-gericht, nor the Secret Societies of Italy, were ever able to put +a more formidable machinery in motion than that which cast a cloud over +the State of Utah. + +Its invisibility, and the mystery which was attached to it, made +this organization doubly terrible. It appeared to be omniscient and +omnipotent, and yet was neither seen nor heard. The man who held out +against the Church vanished away, and none knew whither he had gone or +what had befallen him. His wife and his children awaited him at home, +but no father ever returned to tell them how he had fared at the +hands of his secret judges. A rash word or a hasty act was followed +by annihilation, and yet none knew what the nature might be of this +terrible power which was suspended over them. No wonder that men +went about in fear and trembling, and that even in the heart of the +wilderness they dared not whisper the doubts which oppressed them. + +At first this vague and terrible power was exercised only upon the +recalcitrants who, having embraced the Mormon faith, wished afterwards +to pervert or to abandon it. Soon, however, it took a wider range. The +supply of adult women was running short, and polygamy without a female +population on which to draw was a barren doctrine indeed. Strange +rumours began to be bandied about--rumours of murdered immigrants and +rifled camps in regions where Indians had never been seen. Fresh women +appeared in the harems of the Elders--women who pined and wept, and +bore upon their faces the traces of an unextinguishable horror. Belated +wanderers upon the mountains spoke of gangs of armed men, masked, +stealthy, and noiseless, who flitted by them in the darkness. These +tales and rumours took substance and shape, and were corroborated and +re-corroborated, until they resolved themselves into a definite name. +To this day, in the lonely ranches of the West, the name of the Danite +Band, or the Avenging Angels, is a sinister and an ill-omened one. + +Fuller knowledge of the organization which produced such terrible +results served to increase rather than to lessen the horror which it +inspired in the minds of men. None knew who belonged to this ruthless +society. The names of the participators in the deeds of blood and +violence done under the name of religion were kept profoundly secret. +The very friend to whom you communicated your misgivings as to the +Prophet and his mission, might be one of those who would come forth at +night with fire and sword to exact a terrible reparation. Hence every +man feared his neighbour, and none spoke of the things which were +nearest his heart. + +One fine morning, John Ferrier was about to set out to his wheatfields, +when he heard the click of the latch, and, looking through the window, +saw a stout, sandy-haired, middle-aged man coming up the pathway. His +heart leapt to his mouth, for this was none other than the great Brigham +Young himself. Full of trepidation--for he knew that such a visit boded +him little good--Ferrier ran to the door to greet the Mormon chief. The +latter, however, received his salutations coldly, and followed him with +a stern face into the sitting-room. + +Brother Ferrier, he said, taking a seat, and eyeing the farmer keenly +from under his light-coloured eyelashes, the true believers have been +good friends to you. We picked you up when you were starving in the +desert, we shared our food with you, led you safe to the Chosen Valley, +gave you a goodly share of land, and allowed you to wax rich under our +protection. Is not this so? + +It is so, answered John Ferrier. + +In return for all this we asked but one condition: that was, that you +should embrace the true faith, and conform in every way to its usages. +This you promised to do, and this, if common report says truly, you have +neglected. + +And how have I neglected it? asked Ferrier, throwing out his hands in +expostulation. Have I not given to the common fund? Have I not attended +at the Temple? Have I not----? + +Where are your wives? asked Young, looking round him. Call them in, +that I may greet them. + +It is true that I have not married, Ferrier answered. But women +were few, and there were many who had better claims than I. I was not a +lonely man: I had my daughter to attend to my wants. + +It is of that daughter that I would speak to you, said the leader +of the Mormons. She has grown to be the flower of Utah, and has found +favour in the eyes of many who are high in the land. + +John Ferrier groaned internally. + +There are stories of her which I would fain disbelieve--stories that +she is sealed to some Gentile. This must be the gossip of idle tongues. +What is the thirteenth rule in the code of the sainted Joseph Smith? +Let every maiden of the true faith marry one of the elect; for if +she wed a Gentile, she commits a grievous sin. This being so, it is +impossible that you, who profess the holy creed, should suffer your +daughter to violate it. + +John Ferrier made no answer, but he played nervously with his +riding-whip. + +Upon this one point your whole faith shall be tested--so it has been +decided in the Sacred Council of Four. The girl is young, and we would +not have her wed grey hairs, neither would we deprive her of all +choice. We Elders have many heifers, [29] but our children must also +be provided. Stangerson has a son, and Drebber has a son, and either of +them would gladly welcome your daughter to their house. Let her choose +between them. They are young and rich, and of the true faith. What say +you to that? + +Ferrier remained silent for some little time with his brows knitted. + +You will give us time, he said at last. My daughter is very +young--she is scarce of an age to marry. + +She shall have a month to choose, said Young, rising from his seat. +At the end of that time she shall give her answer. + +He was passing through the door, when he turned, with flushed face and +flashing eyes. It were better for you, John Ferrier, he thundered, +that you and she were now lying blanched skeletons upon the Sierra +Blanco, than that you should put your weak wills against the orders of +the Holy Four! + +With a threatening gesture of his hand, he turned from the door, and +Ferrier heard his heavy step scrunching along the shingly path. + +He was still sitting with his elbows upon his knees, considering how he +should broach the matter to his daughter when a soft hand was laid upon +his, and looking up, he saw her standing beside him. One glance at her +pale, frightened face showed him that she had heard what had passed. + +I could not help it, she said, in answer to his look. His voice rang +through the house. Oh, father, father, what shall we do? + +Don't you scare yourself, he answered, drawing her to him, and passing +his broad, rough hand caressingly over her chestnut hair. We'll fix it +up somehow or another. You don't find your fancy kind o' lessening for +this chap, do you? + +A sob and a squeeze of his hand was her only answer. + +No; of course not. I shouldn't care to hear you say you did. He's a +likely lad, and he's a Christian, which is more than these folk here, in +spite o' all their praying and preaching. There's a party starting for +Nevada to-morrow, and I'll manage to send him a message letting him know +the hole we are in. If I know anything o' that young man, he'll be back +here with a speed that would whip electro-telegraphs. + +Lucy laughed through her tears at her father's description. + +When he comes, he will advise us for the best. But it is for you that +I am frightened, dear. One hears--one hears such dreadful stories about +those who oppose the Prophet: something terrible always happens to +them. + +But we haven't opposed him yet, her father answered. It will be time +to look out for squalls when we do. We have a clear month before us; at +the end of that, I guess we had best shin out of Utah. + +Leave Utah! + +That's about the size of it. + +But the farm? + +We will raise as much as we can in money, and let the rest go. To tell +the truth, Lucy, it isn't the first time I have thought of doing it. I +don't care about knuckling under to any man, as these folk do to their +darned prophet. I'm a free-born American, and it's all new to me. Guess +I'm too old to learn. If he comes browsing about this farm, he might +chance to run up against a charge of buckshot travelling in the opposite +direction. + +But they won't let us leave, his daughter objected. + +Wait till Jefferson comes, and we'll soon manage that. In the meantime, +don't you fret yourself, my dearie, and don't get your eyes swelled up, +else he'll be walking into me when he sees you. There's nothing to be +afeared about, and there's no danger at all. + +John Ferrier uttered these consoling remarks in a very confident tone, +but she could not help observing that he paid unusual care to the +fastening of the doors that night, and that he carefully cleaned and +loaded the rusty old shotgun which hung upon the wall of his bedroom. + + + + +CHAPTER IV. A FLIGHT FOR LIFE. + + +ON the morning which followed his interview with the Mormon Prophet, +John Ferrier went in to Salt Lake City, and having found his +acquaintance, who was bound for the Nevada Mountains, he entrusted him +with his message to Jefferson Hope. In it he told the young man of the +imminent danger which threatened them, and how necessary it was that he +should return. Having done thus he felt easier in his mind, and returned +home with a lighter heart. + +As he approached his farm, he was surprised to see a horse hitched to +each of the posts of the gate. Still more surprised was he on entering +to find two young men in possession of his sitting-room. One, with a +long pale face, was leaning back in the rocking-chair, with his feet +cocked up upon the stove. The other, a bull-necked youth with coarse +bloated features, was standing in front of the window with his hands in +his pocket, whistling a popular hymn. Both of them nodded to Ferrier as +he entered, and the one in the rocking-chair commenced the conversation. + +Maybe you don't know us, he said. This here is the son of Elder +Drebber, and I'm Joseph Stangerson, who travelled with you in the desert +when the Lord stretched out His hand and gathered you into the true +fold. + +As He will all the nations in His own good time, said the other in a +nasal voice; He grindeth slowly but exceeding small. + +John Ferrier bowed coldly. He had guessed who his visitors were. + +We have come, continued Stangerson, at the advice of our fathers to +solicit the hand of your daughter for whichever of us may seem good to +you and to her. As I have but four wives and Brother Drebber here has +seven, it appears to me that my claim is the stronger one. + +Nay, nay, Brother Stangerson, cried the other; the question is not +how many wives we have, but how many we can keep. My father has now +given over his mills to me, and I am the richer man. + +But my prospects are better, said the other, warmly. When the +Lord removes my father, I shall have his tanning yard and his leather +factory. Then I am your elder, and am higher in the Church. + +It will be for the maiden to decide, rejoined young Drebber, smirking +at his own reflection in the glass. We will leave it all to her +decision. + +During this dialogue, John Ferrier had stood fuming in the doorway, +hardly able to keep his riding-whip from the backs of his two visitors. + +Look here, he said at last, striding up to them, when my daughter +summons you, you can come, but until then I don't want to see your faces +again. + +The two young Mormons stared at him in amazement. In their eyes this +competition between them for the maiden's hand was the highest of +honours both to her and her father. + +There are two ways out of the room, cried Ferrier; there is the door, +and there is the window. Which do you care to use? + +His brown face looked so savage, and his gaunt hands so threatening, +that his visitors sprang to their feet and beat a hurried retreat. The +old farmer followed them to the door. + +Let me know when you have settled which it is to be, he said, +sardonically. + +You shall smart for this! Stangerson cried, white with rage. You have +defied the Prophet and the Council of Four. You shall rue it to the end +of your days. + +The hand of the Lord shall be heavy upon you, cried young Drebber; He +will arise and smite you! + +Then I'll start the smiting, exclaimed Ferrier furiously, and would +have rushed upstairs for his gun had not Lucy seized him by the arm and +restrained him. Before he could escape from her, the clatter of horses' +hoofs told him that they were beyond his reach. + +The young canting rascals! he exclaimed, wiping the perspiration from +his forehead; I would sooner see you in your grave, my girl, than the +wife of either of them. + +And so should I, father, she answered, with spirit; but Jefferson +will soon be here. + +Yes. It will not be long before he comes. The sooner the better, for we +do not know what their next move may be. + +It was, indeed, high time that someone capable of giving advice and +help should come to the aid of the sturdy old farmer and his adopted +daughter. In the whole history of the settlement there had never been +such a case of rank disobedience to the authority of the Elders. If +minor errors were punished so sternly, what would be the fate of this +arch rebel. Ferrier knew that his wealth and position would be of no +avail to him. Others as well known and as rich as himself had been +spirited away before now, and their goods given over to the Church. He +was a brave man, but he trembled at the vague, shadowy terrors which +hung over him. Any known danger he could face with a firm lip, but +this suspense was unnerving. He concealed his fears from his daughter, +however, and affected to make light of the whole matter, though she, +with the keen eye of love, saw plainly that he was ill at ease. + +He expected that he would receive some message or remonstrance from +Young as to his conduct, and he was not mistaken, though it came in an +unlooked-for manner. Upon rising next morning he found, to his surprise, +a small square of paper pinned on to the coverlet of his bed just over +his chest. On it was printed, in bold straggling letters:-- + +Twenty-nine days are given you for amendment, and then---- + +The dash was more fear-inspiring than any threat could have been. How +this warning came into his room puzzled John Ferrier sorely, for his +servants slept in an outhouse, and the doors and windows had all been +secured. He crumpled the paper up and said nothing to his daughter, but +the incident struck a chill into his heart. The twenty-nine days were +evidently the balance of the month which Young had promised. What +strength or courage could avail against an enemy armed with such +mysterious powers? The hand which fastened that pin might have struck +him to the heart, and he could never have known who had slain him. + +Still more shaken was he next morning. They had sat down to their +breakfast when Lucy with a cry of surprise pointed upwards. In the +centre of the ceiling was scrawled, with a burned stick apparently, +the number 28. To his daughter it was unintelligible, and he did not +enlighten her. That night he sat up with his gun and kept watch and +ward. He saw and he heard nothing, and yet in the morning a great 27 had +been painted upon the outside of his door. + +Thus day followed day; and as sure as morning came he found that his +unseen enemies had kept their register, and had marked up in some +conspicuous position how many days were still left to him out of the +month of grace. Sometimes the fatal numbers appeared upon the walls, +sometimes upon the floors, occasionally they were on small placards +stuck upon the garden gate or the railings. With all his vigilance John +Ferrier could not discover whence these daily warnings proceeded. A +horror which was almost superstitious came upon him at the sight of +them. He became haggard and restless, and his eyes had the troubled look +of some hunted creature. He had but one hope in life now, and that was +for the arrival of the young hunter from Nevada. + +Twenty had changed to fifteen and fifteen to ten, but there was no news +of the absentee. One by one the numbers dwindled down, and still there +came no sign of him. Whenever a horseman clattered down the road, or a +driver shouted at his team, the old farmer hurried to the gate thinking +that help had arrived at last. At last, when he saw five give way to +four and that again to three, he lost heart, and abandoned all hope of +escape. Single-handed, and with his limited knowledge of the mountains +which surrounded the settlement, he knew that he was powerless. The +more-frequented roads were strictly watched and guarded, and none could +pass along them without an order from the Council. Turn which way he +would, there appeared to be no avoiding the blow which hung over him. +Yet the old man never wavered in his resolution to part with life itself +before he consented to what he regarded as his daughter's dishonour. + +He was sitting alone one evening pondering deeply over his troubles, and +searching vainly for some way out of them. That morning had shown the +figure 2 upon the wall of his house, and the next day would be the last +of the allotted time. What was to happen then? All manner of vague and +terrible fancies filled his imagination. And his daughter--what was to +become of her after he was gone? Was there no escape from the invisible +network which was drawn all round them. He sank his head upon the table +and sobbed at the thought of his own impotence. + +What was that? In the silence he heard a gentle scratching sound--low, +but very distinct in the quiet of the night. It came from the door of +the house. Ferrier crept into the hall and listened intently. There +was a pause for a few moments, and then the low insidious sound was +repeated. Someone was evidently tapping very gently upon one of the +panels of the door. Was it some midnight assassin who had come to carry +out the murderous orders of the secret tribunal? Or was it some agent +who was marking up that the last day of grace had arrived. John Ferrier +felt that instant death would be better than the suspense which shook +his nerves and chilled his heart. Springing forward he drew the bolt and +threw the door open. + +Outside all was calm and quiet. The night was fine, and the stars were +twinkling brightly overhead. The little front garden lay before the +farmer's eyes bounded by the fence and gate, but neither there nor on +the road was any human being to be seen. With a sigh of relief, Ferrier +looked to right and to left, until happening to glance straight down at +his own feet he saw to his astonishment a man lying flat upon his face +upon the ground, with arms and legs all asprawl. + +So unnerved was he at the sight that he leaned up against the wall with +his hand to his throat to stifle his inclination to call out. His first +thought was that the prostrate figure was that of some wounded or dying +man, but as he watched it he saw it writhe along the ground and into the +hall with the rapidity and noiselessness of a serpent. Once within the +house the man sprang to his feet, closed the door, and revealed to the +astonished farmer the fierce face and resolute expression of Jefferson +Hope. + +Good God! gasped John Ferrier. How you scared me! Whatever made you +come in like that. + +Give me food, the other said, hoarsely. I have had no time for bite +or sup for eight-and-forty hours. He flung himself upon the [21] cold +meat and bread which were still lying upon the table from his host's +supper, and devoured it voraciously. Does Lucy bear up well? he asked, +when he had satisfied his hunger. + +Yes. She does not know the danger, her father answered. + +That is well. The house is watched on every side. That is why I crawled +my way up to it. They may be darned sharp, but they're not quite sharp +enough to catch a Washoe hunter. + +John Ferrier felt a different man now that he realized that he had +a devoted ally. He seized the young man's leathery hand and wrung it +cordially. You're a man to be proud of, he said. There are not many +who would come to share our danger and our troubles. + +You've hit it there, pard, the young hunter answered. I have a +respect for you, but if you were alone in this business I'd think twice +before I put my head into such a hornet's nest. It's Lucy that brings me +here, and before harm comes on her I guess there will be one less o' the +Hope family in Utah. + +What are we to do? + +To-morrow is your last day, and unless you act to-night you are lost. +I have a mule and two horses waiting in the Eagle Ravine. How much money +have you? + +Two thousand dollars in gold, and five in notes. + +That will do. I have as much more to add to it. We must push for Carson +City through the mountains. You had best wake Lucy. It is as well that +the servants do not sleep in the house. + +While Ferrier was absent, preparing his daughter for the approaching +journey, Jefferson Hope packed all the eatables that he could find into +a small parcel, and filled a stoneware jar with water, for he knew by +experience that the mountain wells were few and far between. He had +hardly completed his arrangements before the farmer returned with his +daughter all dressed and ready for a start. The greeting between the +lovers was warm, but brief, for minutes were precious, and there was +much to be done. + +We must make our start at once, said Jefferson Hope, speaking in a low +but resolute voice, like one who realizes the greatness of the peril, +but has steeled his heart to meet it. The front and back entrances are +watched, but with caution we may get away through the side window and +across the fields. Once on the road we are only two miles from the +Ravine where the horses are waiting. By daybreak we should be half-way +through the mountains. + +What if we are stopped, asked Ferrier. + +Hope slapped the revolver butt which protruded from the front of his +tunic. If they are too many for us we shall take two or three of them +with us, he said with a sinister smile. + +The lights inside the house had all been extinguished, and from the +darkened window Ferrier peered over the fields which had been his own, +and which he was now about to abandon for ever. He had long nerved +himself to the sacrifice, however, and the thought of the honour and +happiness of his daughter outweighed any regret at his ruined fortunes. +All looked so peaceful and happy, the rustling trees and the broad +silent stretch of grain-land, that it was difficult to realize that +the spirit of murder lurked through it all. Yet the white face and set +expression of the young hunter showed that in his approach to the house +he had seen enough to satisfy him upon that head. + +Ferrier carried the bag of gold and notes, Jefferson Hope had the scanty +provisions and water, while Lucy had a small bundle containing a few +of her more valued possessions. Opening the window very slowly and +carefully, they waited until a dark cloud had somewhat obscured the +night, and then one by one passed through into the little garden. With +bated breath and crouching figures they stumbled across it, and gained +the shelter of the hedge, which they skirted until they came to the gap +which opened into the cornfields. They had just reached this point when +the young man seized his two companions and dragged them down into the +shadow, where they lay silent and trembling. + +It was as well that his prairie training had given Jefferson Hope the +ears of a lynx. He and his friends had hardly crouched down before the +melancholy hooting of a mountain owl was heard within a few yards +of them, which was immediately answered by another hoot at a small +distance. At the same moment a vague shadowy figure emerged from the +gap for which they had been making, and uttered the plaintive signal cry +again, on which a second man appeared out of the obscurity. + +To-morrow at midnight, said the first who appeared to be in authority. +When the Whip-poor-Will calls three times. + +It is well, returned the other. Shall I tell Brother Drebber? + +Pass it on to him, and from him to the others. Nine to seven! + +Seven to five! repeated the other, and the two figures flitted away +in different directions. Their concluding words had evidently been some +form of sign and countersign. The instant that their footsteps had died +away in the distance, Jefferson Hope sprang to his feet, and helping his +companions through the gap, led the way across the fields at the top +of his speed, supporting and half-carrying the girl when her strength +appeared to fail her. + +Hurry on! hurry on! he gasped from time to time. We are through the +line of sentinels. Everything depends on speed. Hurry on! + +Once on the high road they made rapid progress. Only once did they +meet anyone, and then they managed to slip into a field, and so avoid +recognition. Before reaching the town the hunter branched away into a +rugged and narrow footpath which led to the mountains. Two dark jagged +peaks loomed above them through the darkness, and the defile which led +between them was the Eagle Cañon in which the horses were awaiting them. +With unerring instinct Jefferson Hope picked his way among the great +boulders and along the bed of a dried-up watercourse, until he came to +the retired corner, screened with rocks, where the faithful animals had +been picketed. The girl was placed upon the mule, and old Ferrier upon +one of the horses, with his money-bag, while Jefferson Hope led the +other along the precipitous and dangerous path. + +It was a bewildering route for anyone who was not accustomed to face +Nature in her wildest moods. On the one side a great crag towered up a +thousand feet or more, black, stern, and menacing, with long basaltic +columns upon its rugged surface like the ribs of some petrified monster. +On the other hand a wild chaos of boulders and debris made all advance +impossible. Between the two ran the irregular track, so narrow in places +that they had to travel in Indian file, and so rough that only practised +riders could have traversed it at all. Yet in spite of all dangers and +difficulties, the hearts of the fugitives were light within them, +for every step increased the distance between them and the terrible +despotism from which they were flying. + +They soon had a proof, however, that they were still within the +jurisdiction of the Saints. They had reached the very wildest and most +desolate portion of the pass when the girl gave a startled cry, and +pointed upwards. On a rock which overlooked the track, showing out dark +and plain against the sky, there stood a solitary sentinel. He saw them +as soon as they perceived him, and his military challenge of Who goes +there? rang through the silent ravine. + +Travellers for Nevada, said Jefferson Hope, with his hand upon the +rifle which hung by his saddle. + +They could see the lonely watcher fingering his gun, and peering down at +them as if dissatisfied at their reply. + +By whose permission? he asked. + +The Holy Four, answered Ferrier. His Mormon experiences had taught him +that that was the highest authority to which he could refer. + +Nine from seven, cried the sentinel. + +Seven from five, returned Jefferson Hope promptly, remembering the +countersign which he had heard in the garden. + +Pass, and the Lord go with you, said the voice from above. Beyond his +post the path broadened out, and the horses were able to break into a +trot. Looking back, they could see the solitary watcher leaning upon +his gun, and knew that they had passed the outlying post of the chosen +people, and that freedom lay before them. + + + + +CHAPTER V. THE AVENGING ANGELS. + + +ALL night their course lay through intricate defiles and over irregular +and rock-strewn paths. More than once they lost their way, but Hope's +intimate knowledge of the mountains enabled them to regain the track +once more. When morning broke, a scene of marvellous though savage +beauty lay before them. In every direction the great snow-capped peaks +hemmed them in, peeping over each other's shoulders to the far horizon. +So steep were the rocky banks on either side of them, that the larch +and the pine seemed to be suspended over their heads, and to need only a +gust of wind to come hurtling down upon them. Nor was the fear entirely +an illusion, for the barren valley was thickly strewn with trees and +boulders which had fallen in a similar manner. Even as they passed, +a great rock came thundering down with a hoarse rattle which woke +the echoes in the silent gorges, and startled the weary horses into a +gallop. + +As the sun rose slowly above the eastern horizon, the caps of the great +mountains lit up one after the other, like lamps at a festival, until +they were all ruddy and glowing. The magnificent spectacle cheered the +hearts of the three fugitives and gave them fresh energy. At a wild +torrent which swept out of a ravine they called a halt and watered their +horses, while they partook of a hasty breakfast. Lucy and her father +would fain have rested longer, but Jefferson Hope was inexorable. They +will be upon our track by this time, he said. Everything depends upon +our speed. Once safe in Carson we may rest for the remainder of our +lives. + +During the whole of that day they struggled on through the defiles, and +by evening they calculated that they were more than thirty miles from +their enemies. At night-time they chose the base of a beetling crag, +where the rocks offered some protection from the chill wind, and there +huddled together for warmth, they enjoyed a few hours' sleep. Before +daybreak, however, they were up and on their way once more. They had +seen no signs of any pursuers, and Jefferson Hope began to think that +they were fairly out of the reach of the terrible organization whose +enmity they had incurred. He little knew how far that iron grasp could +reach, or how soon it was to close upon them and crush them. + +About the middle of the second day of their flight their scanty store +of provisions began to run out. This gave the hunter little uneasiness, +however, for there was game to be had among the mountains, and he had +frequently before had to depend upon his rifle for the needs of life. +Choosing a sheltered nook, he piled together a few dried branches and +made a blazing fire, at which his companions might warm themselves, for +they were now nearly five thousand feet above the sea level, and the air +was bitter and keen. Having tethered the horses, and bade Lucy adieu, +he threw his gun over his shoulder, and set out in search of whatever +chance might throw in his way. Looking back he saw the old man and the +young girl crouching over the blazing fire, while the three animals +stood motionless in the back-ground. Then the intervening rocks hid them +from his view. + +He walked for a couple of miles through one ravine after another without +success, though from the marks upon the bark of the trees, and other +indications, he judged that there were numerous bears in the vicinity. +At last, after two or three hours' fruitless search, he was thinking of +turning back in despair, when casting his eyes upwards he saw a sight +which sent a thrill of pleasure through his heart. On the edge of a +jutting pinnacle, three or four hundred feet above him, there stood a +creature somewhat resembling a sheep in appearance, but armed with a +pair of gigantic horns. The big-horn--for so it is called--was acting, +probably, as a guardian over a flock which were invisible to the hunter; +but fortunately it was heading in the opposite direction, and had not +perceived him. Lying on his face, he rested his rifle upon a rock, and +took a long and steady aim before drawing the trigger. The animal sprang +into the air, tottered for a moment upon the edge of the precipice, and +then came crashing down into the valley beneath. + +The creature was too unwieldy to lift, so the hunter contented himself +with cutting away one haunch and part of the flank. With this trophy +over his shoulder, he hastened to retrace his steps, for the evening was +already drawing in. He had hardly started, however, before he realized +the difficulty which faced him. In his eagerness he had wandered far +past the ravines which were known to him, and it was no easy matter +to pick out the path which he had taken. The valley in which he found +himself divided and sub-divided into many gorges, which were so like +each other that it was impossible to distinguish one from the other. +He followed one for a mile or more until he came to a mountain torrent +which he was sure that he had never seen before. Convinced that he had +taken the wrong turn, he tried another, but with the same result. Night +was coming on rapidly, and it was almost dark before he at last found +himself in a defile which was familiar to him. Even then it was no easy +matter to keep to the right track, for the moon had not yet risen, and +the high cliffs on either side made the obscurity more profound. Weighed +down with his burden, and weary from his exertions, he stumbled along, +keeping up his heart by the reflection that every step brought him +nearer to Lucy, and that he carried with him enough to ensure them food +for the remainder of their journey. + +He had now come to the mouth of the very defile in which he had left +them. Even in the darkness he could recognize the outline of the cliffs +which bounded it. They must, he reflected, be awaiting him anxiously, +for he had been absent nearly five hours. In the gladness of his heart +he put his hands to his mouth and made the glen re-echo to a loud halloo +as a signal that he was coming. He paused and listened for an answer. +None came save his own cry, which clattered up the dreary silent +ravines, and was borne back to his ears in countless repetitions. Again +he shouted, even louder than before, and again no whisper came back from +the friends whom he had left such a short time ago. A vague, nameless +dread came over him, and he hurried onwards frantically, dropping the +precious food in his agitation. + +When he turned the corner, he came full in sight of the spot where the +fire had been lit. There was still a glowing pile of wood ashes there, +but it had evidently not been tended since his departure. The same +dead silence still reigned all round. With his fears all changed to +convictions, he hurried on. There was no living creature near the +remains of the fire: animals, man, maiden, all were gone. It was only +too clear that some sudden and terrible disaster had occurred during +his absence--a disaster which had embraced them all, and yet had left no +traces behind it. + +Bewildered and stunned by this blow, Jefferson Hope felt his head spin +round, and had to lean upon his rifle to save himself from falling. He +was essentially a man of action, however, and speedily recovered from +his temporary impotence. Seizing a half-consumed piece of wood from the +smouldering fire, he blew it into a flame, and proceeded with its help +to examine the little camp. The ground was all stamped down by the feet +of horses, showing that a large party of mounted men had overtaken +the fugitives, and the direction of their tracks proved that they had +afterwards turned back to Salt Lake City. Had they carried back both of +his companions with them? Jefferson Hope had almost persuaded himself +that they must have done so, when his eye fell upon an object which made +every nerve of his body tingle within him. A little way on one side of +the camp was a low-lying heap of reddish soil, which had assuredly +not been there before. There was no mistaking it for anything but a +newly-dug grave. As the young hunter approached it, he perceived that a +stick had been planted on it, with a sheet of paper stuck in the cleft +fork of it. The inscription upon the paper was brief, but to the point: + + JOHN FERRIER, + FORMERLY OF SALT LAKE CITY, [22] + Died August 4th, 1860. + +The sturdy old man, whom he had left so short a time before, was gone, +then, and this was all his epitaph. Jefferson Hope looked wildly round +to see if there was a second grave, but there was no sign of one. Lucy +had been carried back by their terrible pursuers to fulfil her original +destiny, by becoming one of the harem of the Elder's son. As the young +fellow realized the certainty of her fate, and his own powerlessness to +prevent it, he wished that he, too, was lying with the old farmer in his +last silent resting-place. + +Again, however, his active spirit shook off the lethargy which springs +from despair. If there was nothing else left to him, he could at least +devote his life to revenge. With indomitable patience and perseverance, +Jefferson Hope possessed also a power of sustained vindictiveness, which +he may have learned from the Indians amongst whom he had lived. As he +stood by the desolate fire, he felt that the only one thing which could +assuage his grief would be thorough and complete retribution, brought +by his own hand upon his enemies. His strong will and untiring energy +should, he determined, be devoted to that one end. With a grim, white +face, he retraced his steps to where he had dropped the food, and having +stirred up the smouldering fire, he cooked enough to last him for a +few days. This he made up into a bundle, and, tired as he was, he +set himself to walk back through the mountains upon the track of the +avenging angels. + +For five days he toiled footsore and weary through the defiles which he +had already traversed on horseback. At night he flung himself down among +the rocks, and snatched a few hours of sleep; but before daybreak he was +always well on his way. On the sixth day, he reached the Eagle Cañon, +from which they had commenced their ill-fated flight. Thence he could +look down upon the home of the saints. Worn and exhausted, he leaned +upon his rifle and shook his gaunt hand fiercely at the silent +widespread city beneath him. As he looked at it, he observed that +there were flags in some of the principal streets, and other signs of +festivity. He was still speculating as to what this might mean when he +heard the clatter of horse's hoofs, and saw a mounted man riding towards +him. As he approached, he recognized him as a Mormon named Cowper, to +whom he had rendered services at different times. He therefore accosted +him when he got up to him, with the object of finding out what Lucy +Ferrier's fate had been. + +I am Jefferson Hope, he said. You remember me. + +The Mormon looked at him with undisguised astonishment--indeed, it was +difficult to recognize in this tattered, unkempt wanderer, with ghastly +white face and fierce, wild eyes, the spruce young hunter of former +days. Having, however, at last, satisfied himself as to his identity, +the man's surprise changed to consternation. + +You are mad to come here, he cried. It is as much as my own life is +worth to be seen talking with you. There is a warrant against you from +the Holy Four for assisting the Ferriers away. + +I don't fear them, or their warrant, Hope said, earnestly. You must +know something of this matter, Cowper. I conjure you by everything you +hold dear to answer a few questions. We have always been friends. For +God's sake, don't refuse to answer me. + +What is it? the Mormon asked uneasily. Be quick. The very rocks have +ears and the trees eyes. + +What has become of Lucy Ferrier? + +She was married yesterday to young Drebber. Hold up, man, hold up, you +have no life left in you. + +Don't mind me, said Hope faintly. He was white to the very lips, and +had sunk down on the stone against which he had been leaning. Married, +you say? + +Married yesterday--that's what those flags are for on the Endowment +House. There was some words between young Drebber and young Stangerson +as to which was to have her. They'd both been in the party that followed +them, and Stangerson had shot her father, which seemed to give him the +best claim; but when they argued it out in council, Drebber's party was +the stronger, so the Prophet gave her over to him. No one won't have +her very long though, for I saw death in her face yesterday. She is more +like a ghost than a woman. Are you off, then? + +Yes, I am off, said Jefferson Hope, who had risen from his seat. His +face might have been chiselled out of marble, so hard and set was its +expression, while its eyes glowed with a baleful light. + +Where are you going? + +Never mind, he answered; and, slinging his weapon over his shoulder, +strode off down the gorge and so away into the heart of the mountains to +the haunts of the wild beasts. Amongst them all there was none so fierce +and so dangerous as himself. + +The prediction of the Mormon was only too well fulfilled. Whether it was +the terrible death of her father or the effects of the hateful marriage +into which she had been forced, poor Lucy never held up her head again, +but pined away and died within a month. Her sottish husband, who had +married her principally for the sake of John Ferrier's property, did not +affect any great grief at his bereavement; but his other wives mourned +over her, and sat up with her the night before the burial, as is the +Mormon custom. They were grouped round the bier in the early hours of +the morning, when, to their inexpressible fear and astonishment, +the door was flung open, and a savage-looking, weather-beaten man in +tattered garments strode into the room. Without a glance or a word to +the cowering women, he walked up to the white silent figure which had +once contained the pure soul of Lucy Ferrier. Stooping over her, he +pressed his lips reverently to her cold forehead, and then, snatching +up her hand, he took the wedding-ring from her finger. She shall not be +buried in that, he cried with a fierce snarl, and before an alarm could +be raised sprang down the stairs and was gone. So strange and so brief +was the episode, that the watchers might have found it hard to believe +it themselves or persuade other people of it, had it not been for the +undeniable fact that the circlet of gold which marked her as having been +a bride had disappeared. + +For some months Jefferson Hope lingered among the mountains, leading +a strange wild life, and nursing in his heart the fierce desire for +vengeance which possessed him. Tales were told in the City of the weird +figure which was seen prowling about the suburbs, and which haunted +the lonely mountain gorges. Once a bullet whistled through Stangerson's +window and flattened itself upon the wall within a foot of him. On +another occasion, as Drebber passed under a cliff a great boulder +crashed down on him, and he only escaped a terrible death by throwing +himself upon his face. The two young Mormons were not long in +discovering the reason of these attempts upon their lives, and led +repeated expeditions into the mountains in the hope of capturing or +killing their enemy, but always without success. Then they adopted the +precaution of never going out alone or after nightfall, and of having +their houses guarded. After a time they were able to relax these +measures, for nothing was either heard or seen of their opponent, and +they hoped that time had cooled his vindictiveness. + +Far from doing so, it had, if anything, augmented it. The hunter's mind +was of a hard, unyielding nature, and the predominant idea of revenge +had taken such complete possession of it that there was no room for +any other emotion. He was, however, above all things practical. He soon +realized that even his iron constitution could not stand the incessant +strain which he was putting upon it. Exposure and want of wholesome food +were wearing him out. If he died like a dog among the mountains, what +was to become of his revenge then? And yet such a death was sure to +overtake him if he persisted. He felt that that was to play his enemy's +game, so he reluctantly returned to the old Nevada mines, there to +recruit his health and to amass money enough to allow him to pursue his +object without privation. + +His intention had been to be absent a year at the most, but a +combination of unforeseen circumstances prevented his leaving the mines +for nearly five. At the end of that time, however, his memory of +his wrongs and his craving for revenge were quite as keen as on that +memorable night when he had stood by John Ferrier's grave. Disguised, +and under an assumed name, he returned to Salt Lake City, careless +what became of his own life, as long as he obtained what he knew to +be justice. There he found evil tidings awaiting him. There had been a +schism among the Chosen People a few months before, some of the younger +members of the Church having rebelled against the authority of the +Elders, and the result had been the secession of a certain number of the +malcontents, who had left Utah and become Gentiles. Among these had been +Drebber and Stangerson; and no one knew whither they had gone. Rumour +reported that Drebber had managed to convert a large part of his +property into money, and that he had departed a wealthy man, while his +companion, Stangerson, was comparatively poor. There was no clue at all, +however, as to their whereabouts. + +Many a man, however vindictive, would have abandoned all thought of +revenge in the face of such a difficulty, but Jefferson Hope never +faltered for a moment. With the small competence he possessed, eked out +by such employment as he could pick up, he travelled from town to town +through the United States in quest of his enemies. Year passed into +year, his black hair turned grizzled, but still he wandered on, a human +bloodhound, with his mind wholly set upon the one object upon which he +had devoted his life. At last his perseverance was rewarded. It was +but a glance of a face in a window, but that one glance told him that +Cleveland in Ohio possessed the men whom he was in pursuit of. He +returned to his miserable lodgings with his plan of vengeance all +arranged. It chanced, however, that Drebber, looking from his window, +had recognized the vagrant in the street, and had read murder in +his eyes. He hurried before a justice of the peace, accompanied by +Stangerson, who had become his private secretary, and represented to him +that they were in danger of their lives from the jealousy and hatred of +an old rival. That evening Jefferson Hope was taken into custody, and +not being able to find sureties, was detained for some weeks. When at +last he was liberated, it was only to find that Drebber's house was +deserted, and that he and his secretary had departed for Europe. + +Again the avenger had been foiled, and again his concentrated hatred +urged him to continue the pursuit. Funds were wanting, however, and +for some time he had to return to work, saving every dollar for his +approaching journey. At last, having collected enough to keep life in +him, he departed for Europe, and tracked his enemies from city to +city, working his way in any menial capacity, but never overtaking the +fugitives. When he reached St. Petersburg they had departed for Paris; +and when he followed them there he learned that they had just set off +for Copenhagen. At the Danish capital he was again a few days late, for +they had journeyed on to London, where he at last succeeded in running +them to earth. As to what occurred there, we cannot do better than quote +the old hunter's own account, as duly recorded in Dr. Watson's Journal, +to which we are already under such obligations. + + + + +CHAPTER VI. A CONTINUATION OF THE REMINISCENCES OF JOHN WATSON, M.D. + + +OUR prisoner's furious resistance did not apparently indicate any +ferocity in his disposition towards ourselves, for on finding himself +powerless, he smiled in an affable manner, and expressed his hopes that +he had not hurt any of us in the scuffle. I guess you're going to take +me to the police-station, he remarked to Sherlock Holmes. My cab's at +the door. If you'll loose my legs I'll walk down to it. I'm not so light +to lift as I used to be. + +Gregson and Lestrade exchanged glances as if they thought this +proposition rather a bold one; but Holmes at once took the prisoner at +his word, and loosened the towel which we had bound round his ancles. +[23] He rose and stretched his legs, as though to assure himself that +they were free once more. I remember that I thought to myself, as I eyed +him, that I had seldom seen a more powerfully built man; and his dark +sunburned face bore an expression of determination and energy which was +as formidable as his personal strength. + +If there's a vacant place for a chief of the police, I reckon you +are the man for it, he said, gazing with undisguised admiration at my +fellow-lodger. The way you kept on my trail was a caution. + +You had better come with me, said Holmes to the two detectives. + +I can drive you, said Lestrade. + +Good! and Gregson can come inside with me. You too, Doctor, you have +taken an interest in the case and may as well stick to us. + +I assented gladly, and we all descended together. Our prisoner made no +attempt at escape, but stepped calmly into the cab which had been his, +and we followed him. Lestrade mounted the box, whipped up the horse, and +brought us in a very short time to our destination. We were ushered into +a small chamber where a police Inspector noted down our prisoner's name +and the names of the men with whose murder he had been charged. The +official was a white-faced unemotional man, who went through his +duties in a dull mechanical way. The prisoner will be put before the +magistrates in the course of the week, he said; in the mean time, Mr. +Jefferson Hope, have you anything that you wish to say? I must warn you +that your words will be taken down, and may be used against you. + +I've got a good deal to say, our prisoner said slowly. I want to tell +you gentlemen all about it. + +Hadn't you better reserve that for your trial? asked the Inspector. + +I may never be tried, he answered. You needn't look startled. It +isn't suicide I am thinking of. Are you a Doctor? He turned his fierce +dark eyes upon me as he asked this last question. + +Yes; I am, I answered. + +Then put your hand here, he said, with a smile, motioning with his +manacled wrists towards his chest. + +I did so; and became at once conscious of an extraordinary throbbing and +commotion which was going on inside. The walls of his chest seemed to +thrill and quiver as a frail building would do inside when some powerful +engine was at work. In the silence of the room I could hear a dull +humming and buzzing noise which proceeded from the same source. + +Why, I cried, you have an aortic aneurism! + +That's what they call it, he said, placidly. I went to a Doctor last +week about it, and he told me that it is bound to burst before many days +passed. It has been getting worse for years. I got it from over-exposure +and under-feeding among the Salt Lake Mountains. I've done my work now, +and I don't care how soon I go, but I should like to leave some account +of the business behind me. I don't want to be remembered as a common +cut-throat. + +The Inspector and the two detectives had a hurried discussion as to the +advisability of allowing him to tell his story. + +Do you consider, Doctor, that there is immediate danger? the former +asked, [24] + +Most certainly there is, I answered. + +In that case it is clearly our duty, in the interests of justice, to +take his statement, said the Inspector. You are at liberty, sir, to +give your account, which I again warn you will be taken down. + +I'll sit down, with your leave, the prisoner said, suiting the action +to the word. This aneurism of mine makes me easily tired, and the +tussle we had half an hour ago has not mended matters. I'm on the brink +of the grave, and I am not likely to lie to you. Every word I say is the +absolute truth, and how you use it is a matter of no consequence to me. + +With these words, Jefferson Hope leaned back in his chair and began +the following remarkable statement. He spoke in a calm and methodical +manner, as though the events which he narrated were commonplace enough. +I can vouch for the accuracy of the subjoined account, for I have had +access to Lestrade's note-book, in which the prisoner's words were taken +down exactly as they were uttered. + +It don't much matter to you why I hated these men, he said; it's +enough that they were guilty of the death of two human beings--a father +and a daughter--and that they had, therefore, forfeited their own +lives. After the lapse of time that has passed since their crime, it was +impossible for me to secure a conviction against them in any court. I +knew of their guilt though, and I determined that I should be judge, +jury, and executioner all rolled into one. You'd have done the same, if +you have any manhood in you, if you had been in my place. + +That girl that I spoke of was to have married me twenty years ago. She +was forced into marrying that same Drebber, and broke her heart over +it. I took the marriage ring from her dead finger, and I vowed that his +dying eyes should rest upon that very ring, and that his last thoughts +should be of the crime for which he was punished. I have carried +it about with me, and have followed him and his accomplice over two +continents until I caught them. They thought to tire me out, but they +could not do it. If I die to-morrow, as is likely enough, I die knowing +that my work in this world is done, and well done. They have perished, +and by my hand. There is nothing left for me to hope for, or to desire. + +They were rich and I was poor, so that it was no easy matter for me to +follow them. When I got to London my pocket was about empty, and I found +that I must turn my hand to something for my living. Driving and riding +are as natural to me as walking, so I applied at a cabowner's office, +and soon got employment. I was to bring a certain sum a week to the +owner, and whatever was over that I might keep for myself. There was +seldom much over, but I managed to scrape along somehow. The hardest job +was to learn my way about, for I reckon that of all the mazes that ever +were contrived, this city is the most confusing. I had a map beside me +though, and when once I had spotted the principal hotels and stations, I +got on pretty well. + +It was some time before I found out where my two gentlemen were living; +but I inquired and inquired until at last I dropped across them. They +were at a boarding-house at Camberwell, over on the other side of the +river. When once I found them out I knew that I had them at my mercy. I +had grown my beard, and there was no chance of their recognizing me. +I would dog them and follow them until I saw my opportunity. I was +determined that they should not escape me again. + +They were very near doing it for all that. Go where they would about +London, I was always at their heels. Sometimes I followed them on my +cab, and sometimes on foot, but the former was the best, for then they +could not get away from me. It was only early in the morning or late +at night that I could earn anything, so that I began to get behind hand +with my employer. I did not mind that, however, as long as I could lay +my hand upon the men I wanted. + +They were very cunning, though. They must have thought that there was +some chance of their being followed, for they would never go out alone, +and never after nightfall. During two weeks I drove behind them every +day, and never once saw them separate. Drebber himself was drunk half +the time, but Stangerson was not to be caught napping. I watched them +late and early, but never saw the ghost of a chance; but I was not +discouraged, for something told me that the hour had almost come. My +only fear was that this thing in my chest might burst a little too soon +and leave my work undone. + +At last, one evening I was driving up and down Torquay Terrace, as the +street was called in which they boarded, when I saw a cab drive up to +their door. Presently some luggage was brought out, and after a time +Drebber and Stangerson followed it, and drove off. I whipped up my horse +and kept within sight of them, feeling very ill at ease, for I feared +that they were going to shift their quarters. At Euston Station they +got out, and I left a boy to hold my horse, and followed them on to the +platform. I heard them ask for the Liverpool train, and the guard answer +that one had just gone and there would not be another for some hours. +Stangerson seemed to be put out at that, but Drebber was rather pleased +than otherwise. I got so close to them in the bustle that I could hear +every word that passed between them. Drebber said that he had a little +business of his own to do, and that if the other would wait for him he +would soon rejoin him. His companion remonstrated with him, and reminded +him that they had resolved to stick together. Drebber answered that the +matter was a delicate one, and that he must go alone. I could not catch +what Stangerson said to that, but the other burst out swearing, and +reminded him that he was nothing more than his paid servant, and that he +must not presume to dictate to him. On that the Secretary gave it up +as a bad job, and simply bargained with him that if he missed the last +train he should rejoin him at Halliday's Private Hotel; to which Drebber +answered that he would be back on the platform before eleven, and made +his way out of the station. + +The moment for which I had waited so long had at last come. I had my +enemies within my power. Together they could protect each other, +but singly they were at my mercy. I did not act, however, with undue +precipitation. My plans were already formed. There is no satisfaction in +vengeance unless the offender has time to realize who it is that strikes +him, and why retribution has come upon him. I had my plans arranged by +which I should have the opportunity of making the man who had wronged me +understand that his old sin had found him out. It chanced that some days +before a gentleman who had been engaged in looking over some houses in +the Brixton Road had dropped the key of one of them in my carriage. It +was claimed that same evening, and returned; but in the interval I had +taken a moulding of it, and had a duplicate constructed. By means of +this I had access to at least one spot in this great city where I could +rely upon being free from interruption. How to get Drebber to that house +was the difficult problem which I had now to solve. + +He walked down the road and went into one or two liquor shops, staying +for nearly half-an-hour in the last of them. When he came out he +staggered in his walk, and was evidently pretty well on. There was a +hansom just in front of me, and he hailed it. I followed it so close +that the nose of my horse was within a yard of his driver the whole way. +We rattled across Waterloo Bridge and through miles of streets, until, +to my astonishment, we found ourselves back in the Terrace in which he +had boarded. I could not imagine what his intention was in returning +there; but I went on and pulled up my cab a hundred yards or so from +the house. He entered it, and his hansom drove away. Give me a glass of +water, if you please. My mouth gets dry with the talking. + +I handed him the glass, and he drank it down. + +That's better, he said. Well, I waited for a quarter of an hour, or +more, when suddenly there came a noise like people struggling inside the +house. Next moment the door was flung open and two men appeared, one of +whom was Drebber, and the other was a young chap whom I had never seen +before. This fellow had Drebber by the collar, and when they came to +the head of the steps he gave him a shove and a kick which sent him half +across the road. You hound, he cried, shaking his stick at him; I'll +teach you to insult an honest girl! He was so hot that I think he would +have thrashed Drebber with his cudgel, only that the cur staggered away +down the road as fast as his legs would carry him. He ran as far as the +corner, and then, seeing my cab, he hailed me and jumped in. Drive me +to Halliday's Private Hotel, said he. + +When I had him fairly inside my cab, my heart jumped so with joy that +I feared lest at this last moment my aneurism might go wrong. I drove +along slowly, weighing in my own mind what it was best to do. I might +take him right out into the country, and there in some deserted lane +have my last interview with him. I had almost decided upon this, when he +solved the problem for me. The craze for drink had seized him again, and +he ordered me to pull up outside a gin palace. He went in, leaving word +that I should wait for him. There he remained until closing time, and +when he came out he was so far gone that I knew the game was in my own +hands. + +Don't imagine that I intended to kill him in cold blood. It would only +have been rigid justice if I had done so, but I could not bring myself +to do it. I had long determined that he should have a show for his life +if he chose to take advantage of it. Among the many billets which I +have filled in America during my wandering life, I was once janitor and +sweeper out of the laboratory at York College. One day the professor was +lecturing on poisions, [25] and he showed his students some alkaloid, +as he called it, which he had extracted from some South American arrow +poison, and which was so powerful that the least grain meant instant +death. I spotted the bottle in which this preparation was kept, and when +they were all gone, I helped myself to a little of it. I was a fairly +good dispenser, so I worked this alkaloid into small, soluble pills, and +each pill I put in a box with a similar pill made without the poison. +I determined at the time that when I had my chance, my gentlemen should +each have a draw out of one of these boxes, while I ate the pill that +remained. It would be quite as deadly, and a good deal less noisy than +firing across a handkerchief. From that day I had always my pill boxes +about with me, and the time had now come when I was to use them. + +It was nearer one than twelve, and a wild, bleak night, blowing hard +and raining in torrents. Dismal as it was outside, I was glad within--so +glad that I could have shouted out from pure exultation. If any of you +gentlemen have ever pined for a thing, and longed for it during twenty +long years, and then suddenly found it within your reach, you would +understand my feelings. I lit a cigar, and puffed at it to steady my +nerves, but my hands were trembling, and my temples throbbing with +excitement. As I drove, I could see old John Ferrier and sweet Lucy +looking at me out of the darkness and smiling at me, just as plain as I +see you all in this room. All the way they were ahead of me, one on each +side of the horse until I pulled up at the house in the Brixton Road. + +There was not a soul to be seen, nor a sound to be heard, except the +dripping of the rain. When I looked in at the window, I found Drebber +all huddled together in a drunken sleep. I shook him by the arm, It's +time to get out, I said. + +All right, cabby, said he. + +I suppose he thought we had come to the hotel that he had mentioned, +for he got out without another word, and followed me down the garden. +I had to walk beside him to keep him steady, for he was still a little +top-heavy. When we came to the door, I opened it, and led him into the +front room. I give you my word that all the way, the father and the +daughter were walking in front of us. + +It's infernally dark, said he, stamping about. + +We'll soon have a light, I said, striking a match and putting it to +a wax candle which I had brought with me. Now, Enoch Drebber, I +continued, turning to him, and holding the light to my own face, who am +I? + +He gazed at me with bleared, drunken eyes for a moment, and then I +saw a horror spring up in them, and convulse his whole features, which +showed me that he knew me. He staggered back with a livid face, and I +saw the perspiration break out upon his brow, while his teeth chattered +in his head. At the sight, I leaned my back against the door and laughed +loud and long. I had always known that vengeance would be sweet, but I +had never hoped for the contentment of soul which now possessed me. + +You dog! I said; I have hunted you from Salt Lake City to St. +Petersburg, and you have always escaped me. Now, at last your wanderings +have come to an end, for either you or I shall never see to-morrow's sun +rise. He shrunk still further away as I spoke, and I could see on his +face that he thought I was mad. So I was for the time. The pulses in my +temples beat like sledge-hammers, and I believe I would have had a fit +of some sort if the blood had not gushed from my nose and relieved me. + +What do you think of Lucy Ferrier now? I cried, locking the door, and +shaking the key in his face. Punishment has been slow in coming, but it +has overtaken you at last. I saw his coward lips tremble as I spoke. He +would have begged for his life, but he knew well that it was useless. + +Would you murder me? he stammered. + +There is no murder, I answered. Who talks of murdering a mad dog? +What mercy had you upon my poor darling, when you dragged her from her +slaughtered father, and bore her away to your accursed and shameless +harem. + +It was not I who killed her father, he cried. + +But it was you who broke her innocent heart, I shrieked, thrusting +the box before him. Let the high God judge between us. Choose and +eat. There is death in one and life in the other. I shall take what you +leave. Let us see if there is justice upon the earth, or if we are ruled +by chance. + +He cowered away with wild cries and prayers for mercy, but I drew my +knife and held it to his throat until he had obeyed me. Then I swallowed +the other, and we stood facing one another in silence for a minute or +more, waiting to see which was to live and which was to die. Shall I +ever forget the look which came over his face when the first warning +pangs told him that the poison was in his system? I laughed as I saw +it, and held Lucy's marriage ring in front of his eyes. It was but for +a moment, for the action of the alkaloid is rapid. A spasm of pain +contorted his features; he threw his hands out in front of him, +staggered, and then, with a hoarse cry, fell heavily upon the floor. I +turned him over with my foot, and placed my hand upon his heart. There +was no movement. He was dead! + +The blood had been streaming from my nose, but I had taken no notice of +it. I don't know what it was that put it into my head to write upon the +wall with it. Perhaps it was some mischievous idea of setting the police +upon a wrong track, for I felt light-hearted and cheerful. I remembered +a German being found in New York with RACHE written up above him, and it +was argued at the time in the newspapers that the secret societies must +have done it. I guessed that what puzzled the New Yorkers would puzzle +the Londoners, so I dipped my finger in my own blood and printed it on +a convenient place on the wall. Then I walked down to my cab and found +that there was nobody about, and that the night was still very wild. I +had driven some distance when I put my hand into the pocket in which +I usually kept Lucy's ring, and found that it was not there. I was +thunderstruck at this, for it was the only memento that I had of her. +Thinking that I might have dropped it when I stooped over Drebber's +body, I drove back, and leaving my cab in a side street, I went boldly +up to the house--for I was ready to dare anything rather than lose +the ring. When I arrived there, I walked right into the arms of a +police-officer who was coming out, and only managed to disarm his +suspicions by pretending to be hopelessly drunk. + +That was how Enoch Drebber came to his end. All I had to do then was +to do as much for Stangerson, and so pay off John Ferrier's debt. I knew +that he was staying at Halliday's Private Hotel, and I hung about all +day, but he never came out. [26] fancy that he suspected something when +Drebber failed to put in an appearance. He was cunning, was Stangerson, +and always on his guard. If he thought he could keep me off by staying +indoors he was very much mistaken. I soon found out which was the window +of his bedroom, and early next morning I took advantage of some ladders +which were lying in the lane behind the hotel, and so made my way into +his room in the grey of the dawn. I woke him up and told him that the +hour had come when he was to answer for the life he had taken so long +before. I described Drebber's death to him, and I gave him the same +choice of the poisoned pills. Instead of grasping at the chance of +safety which that offered him, he sprang from his bed and flew at my +throat. In self-defence I stabbed him to the heart. It would have been +the same in any case, for Providence would never have allowed his guilty +hand to pick out anything but the poison. + +I have little more to say, and it's as well, for I am about done up. +I went on cabbing it for a day or so, intending to keep at it until I +could save enough to take me back to America. I was standing in the +yard when a ragged youngster asked if there was a cabby there called +Jefferson Hope, and said that his cab was wanted by a gentleman at 221B, +Baker Street. I went round, suspecting no harm, and the next thing I +knew, this young man here had the bracelets on my wrists, and as neatly +snackled [27] as ever I saw in my life. That's the whole of my story, +gentlemen. You may consider me to be a murderer; but I hold that I am +just as much an officer of justice as you are. + +So thrilling had the man's narrative been, and his manner was so +impressive that we had sat silent and absorbed. Even the professional +detectives, _blasé_ as they were in every detail of crime, appeared to +be keenly interested in the man's story. When he finished we sat for +some minutes in a stillness which was only broken by the scratching +of Lestrade's pencil as he gave the finishing touches to his shorthand +account. + +There is only one point on which I should like a little more +information, Sherlock Holmes said at last. Who was your accomplice who +came for the ring which I advertised? + +The prisoner winked at my friend jocosely. I can tell my own secrets, + he said, but I don't get other people into trouble. I saw your +advertisement, and I thought it might be a plant, or it might be the +ring which I wanted. My friend volunteered to go and see. I think you'll +own he did it smartly. + +Not a doubt of that, said Holmes heartily. + +Now, gentlemen, the Inspector remarked gravely, the forms of the law +must be complied with. On Thursday the prisoner will be brought before +the magistrates, and your attendance will be required. Until then I will +be responsible for him. He rang the bell as he spoke, and Jefferson +Hope was led off by a couple of warders, while my friend and I made our +way out of the Station and took a cab back to Baker Street. + + + + +CHAPTER VII. THE CONCLUSION. + + +WE had all been warned to appear before the magistrates upon the +Thursday; but when the Thursday came there was no occasion for our +testimony. A higher Judge had taken the matter in hand, and Jefferson +Hope had been summoned before a tribunal where strict justice would +be meted out to him. On the very night after his capture the aneurism +burst, and he was found in the morning stretched upon the floor of the +cell, with a placid smile upon his face, as though he had been able +in his dying moments to look back upon a useful life, and on work well +done. + +Gregson and Lestrade will be wild about his death, Holmes remarked, as +we chatted it over next evening. Where will their grand advertisement +be now? + +I don't see that they had very much to do with his capture, I +answered. + +What you do in this world is a matter of no consequence, returned my +companion, bitterly. The question is, what can you make people believe +that you have done. Never mind, he continued, more brightly, after a +pause. I would not have missed the investigation for anything. There +has been no better case within my recollection. Simple as it was, there +were several most instructive points about it. + +Simple! I ejaculated. + +Well, really, it can hardly be described as otherwise, said Sherlock +Holmes, smiling at my surprise. The proof of its intrinsic simplicity +is, that without any help save a few very ordinary deductions I was able +to lay my hand upon the criminal within three days. + +That is true, said I. + +I have already explained to you that what is out of the common is +usually a guide rather than a hindrance. In solving a problem of this +sort, the grand thing is to be able to reason backwards. That is a very +useful accomplishment, and a very easy one, but people do not practise +it much. In the every-day affairs of life it is more useful to reason +forwards, and so the other comes to be neglected. There are fifty who +can reason synthetically for one who can reason analytically. + +I confess, said I, that I do not quite follow you. + +I hardly expected that you would. Let me see if I can make it clearer. +Most people, if you describe a train of events to them, will tell you +what the result would be. They can put those events together in their +minds, and argue from them that something will come to pass. There are +few people, however, who, if you told them a result, would be able to +evolve from their own inner consciousness what the steps were which led +up to that result. This power is what I mean when I talk of reasoning +backwards, or analytically. + +I understand, said I. + +Now this was a case in which you were given the result and had to +find everything else for yourself. Now let me endeavour to show you the +different steps in my reasoning. To begin at the beginning. I approached +the house, as you know, on foot, and with my mind entirely free from all +impressions. I naturally began by examining the roadway, and there, as I +have already explained to you, I saw clearly the marks of a cab, which, +I ascertained by inquiry, must have been there during the night. I +satisfied myself that it was a cab and not a private carriage by the +narrow gauge of the wheels. The ordinary London growler is considerably +less wide than a gentleman's brougham. + +This was the first point gained. I then walked slowly down the garden +path, which happened to be composed of a clay soil, peculiarly suitable +for taking impressions. No doubt it appeared to you to be a mere +trampled line of slush, but to my trained eyes every mark upon its +surface had a meaning. There is no branch of detective science which +is so important and so much neglected as the art of tracing footsteps. +Happily, I have always laid great stress upon it, and much practice +has made it second nature to me. I saw the heavy footmarks of the +constables, but I saw also the track of the two men who had first passed +through the garden. It was easy to tell that they had been before the +others, because in places their marks had been entirely obliterated by +the others coming upon the top of them. In this way my second link was +formed, which told me that the nocturnal visitors were two in number, +one remarkable for his height (as I calculated from the length of his +stride), and the other fashionably dressed, to judge from the small and +elegant impression left by his boots. + +On entering the house this last inference was confirmed. My well-booted +man lay before me. The tall one, then, had done the murder, if murder +there was. There was no wound upon the dead man's person, but the +agitated expression upon his face assured me that he had foreseen his +fate before it came upon him. Men who die from heart disease, or any +sudden natural cause, never by any chance exhibit agitation upon their +features. Having sniffed the dead man's lips I detected a slightly sour +smell, and I came to the conclusion that he had had poison forced upon +him. Again, I argued that it had been forced upon him from the hatred +and fear expressed upon his face. By the method of exclusion, I had +arrived at this result, for no other hypothesis would meet the facts. +Do not imagine that it was a very unheard of idea. The forcible +administration of poison is by no means a new thing in criminal annals. +The cases of Dolsky in Odessa, and of Leturier in Montpellier, will +occur at once to any toxicologist. + +And now came the great question as to the reason why. Robbery had not +been the object of the murder, for nothing was taken. Was it politics, +then, or was it a woman? That was the question which confronted me. +I was inclined from the first to the latter supposition. Political +assassins are only too glad to do their work and to fly. This murder +had, on the contrary, been done most deliberately, and the perpetrator +had left his tracks all over the room, showing that he had been there +all the time. It must have been a private wrong, and not a political +one, which called for such a methodical revenge. When the inscription +was discovered upon the wall I was more inclined than ever to my +opinion. The thing was too evidently a blind. When the ring was found, +however, it settled the question. Clearly the murderer had used it to +remind his victim of some dead or absent woman. It was at this point +that I asked Gregson whether he had enquired in his telegram to +Cleveland as to any particular point in Mr. Drebber's former career. He +answered, you remember, in the negative. + +I then proceeded to make a careful examination of the room, which +confirmed me in my opinion as to the murderer's height, and furnished me +with the additional details as to the Trichinopoly cigar and the length +of his nails. I had already come to the conclusion, since there were no +signs of a struggle, that the blood which covered the floor had burst +from the murderer's nose in his excitement. I could perceive that the +track of blood coincided with the track of his feet. It is seldom that +any man, unless he is very full-blooded, breaks out in this way through +emotion, so I hazarded the opinion that the criminal was probably a +robust and ruddy-faced man. Events proved that I had judged correctly. + +Having left the house, I proceeded to do what Gregson had neglected. I +telegraphed to the head of the police at Cleveland, limiting my enquiry +to the circumstances connected with the marriage of Enoch Drebber. The +answer was conclusive. It told me that Drebber had already applied for +the protection of the law against an old rival in love, named Jefferson +Hope, and that this same Hope was at present in Europe. I knew now that +I held the clue to the mystery in my hand, and all that remained was to +secure the murderer. + +I had already determined in my own mind that the man who had walked +into the house with Drebber, was none other than the man who had driven +the cab. The marks in the road showed me that the horse had wandered +on in a way which would have been impossible had there been anyone in +charge of it. Where, then, could the driver be, unless he were inside +the house? Again, it is absurd to suppose that any sane man would carry +out a deliberate crime under the very eyes, as it were, of a third +person, who was sure to betray him. Lastly, supposing one man wished +to dog another through London, what better means could he adopt than +to turn cabdriver. All these considerations led me to the irresistible +conclusion that Jefferson Hope was to be found among the jarveys of the +Metropolis. + +If he had been one there was no reason to believe that he had ceased to +be. On the contrary, from his point of view, any sudden change would be +likely to draw attention to himself. He would, probably, for a time at +least, continue to perform his duties. There was no reason to suppose +that he was going under an assumed name. Why should he change his name +in a country where no one knew his original one? I therefore organized +my Street Arab detective corps, and sent them systematically to every +cab proprietor in London until they ferreted out the man that I wanted. +How well they succeeded, and how quickly I took advantage of it, are +still fresh in your recollection. The murder of Stangerson was an +incident which was entirely unexpected, but which could hardly in +any case have been prevented. Through it, as you know, I came into +possession of the pills, the existence of which I had already surmised. +You see the whole thing is a chain of logical sequences without a break +or flaw. + +It is wonderful! I cried. Your merits should be publicly recognized. +You should publish an account of the case. If you won't, I will for +you. + +You may do what you like, Doctor, he answered. See here! he +continued, handing a paper over to me, look at this! + +It was the _Echo_ for the day, and the paragraph to which he pointed was +devoted to the case in question. + +The public, it said, have lost a sensational treat through the sudden +death of the man Hope, who was suspected of the murder of Mr. Enoch +Drebber and of Mr. Joseph Stangerson. The details of the case will +probably be never known now, though we are informed upon good authority +that the crime was the result of an old standing and romantic feud, in +which love and Mormonism bore a part. It seems that both the victims +belonged, in their younger days, to the Latter Day Saints, and Hope, the +deceased prisoner, hails also from Salt Lake City. If the case has had +no other effect, it, at least, brings out in the most striking manner +the efficiency of our detective police force, and will serve as a lesson +to all foreigners that they will do wisely to settle their feuds at +home, and not to carry them on to British soil. It is an open secret +that the credit of this smart capture belongs entirely to the well-known +Scotland Yard officials, Messrs. Lestrade and Gregson. The man was +apprehended, it appears, in the rooms of a certain Mr. Sherlock Holmes, +who has himself, as an amateur, shown some talent in the detective +line, and who, with such instructors, may hope in time to attain to some +degree of their skill. It is expected that a testimonial of some sort +will be presented to the two officers as a fitting recognition of their +services. + +Didn't I tell you so when we started? cried Sherlock Holmes with a +laugh. That's the result of all our Study in Scarlet: to get them a +testimonial! + +Never mind, I answered, I have all the facts in my journal, and the +public shall know them. In the meantime you must make yourself contented +by the consciousness of success, like the Roman miser-- + + Populus me sibilat, at mihi plaudo + Ipse domi simul ac nummos contemplor in arca. + + + diff --git a/res/Media/Aurora.jpg b/res/Media/Aurora.jpg new file mode 100644 index 0000000..611635a Binary files /dev/null and b/res/Media/Aurora.jpg differ diff --git a/res/Media/Blue.jpg b/res/Media/Blue.jpg new file mode 100644 index 0000000..64de23d Binary files /dev/null and b/res/Media/Blue.jpg differ diff --git a/res/Media/Desert.jpg b/res/Media/Desert.jpg new file mode 100644 index 0000000..6d185b7 Binary files /dev/null and b/res/Media/Desert.jpg differ diff --git a/res/Media/Flower.jpg b/res/Media/Flower.jpg new file mode 100644 index 0000000..edf6e43 Binary files /dev/null and b/res/Media/Flower.jpg differ diff --git a/res/Media/Jellyfish.jpg b/res/Media/Jellyfish.jpg new file mode 100644 index 0000000..628dbfc Binary files /dev/null and b/res/Media/Jellyfish.jpg differ diff --git a/res/Media/Licenses.txt b/res/Media/Licenses.txt new file mode 100644 index 0000000..b6a02d6 --- /dev/null +++ b/res/Media/Licenses.txt @@ -0,0 +1,45 @@ +Licensing information for the sample images: +(If you are the author of any of these images and would like them removed, please contact me) +I've adjusted all of the images to be in the 1920x1080 resolution (sorry 4K folks!), and possibly made a few more modifications. + +Flower.jpg +https://commons.wikimedia.org/wiki/File:Lotus_flower_(978659).jpg +Author Hong Zhang +This file is licensed under the Creative Commons Zero license. +https://creativecommons.org/publicdomain/zero/1.0/deed.en + +Aurora.jpg +https://unsplash.com/photos/Oz2ZQ2j8We8 +Author Johny Goerend +This file is licened under the Unsplash License. +https://unsplash.com/license + +Paint.jpg +https://unsplash.com/photos/arwTpnIUHdM +Author Paweł Czerwiński +This file is licened under the Unsplash License. +https://unsplash.com/license + +Water.jpg +https://unsplash.com/photos/IXTG1_Tw2dM +Author Dave Hoefler +This file is licened under the Unsplash License. +https://unsplash.com/license + +Blue.jpg +https://unsplash.com/photos/oGjE-6MlGEc +Author Solen Feyissa +This file is licened under the Unsplash License. +https://unsplash.com/license + +Desert.jpg +https://unsplash.com/photos/cNagAGEok9k +Author Willian Justen de Vasconcellos +This file is licened under the Unsplash License. +https://unsplash.com/license + +Jellyfish.jpg +https://unsplash.com/photos/SUwDcVdUGiY +Author Patrick Boucher +This file is licened under the Unsplash License. +https://unsplash.com/license diff --git a/res/Media/Paint.jpg b/res/Media/Paint.jpg new file mode 100755 index 0000000..16b15f3 Binary files /dev/null and b/res/Media/Paint.jpg differ diff --git a/res/Media/Shutdown Sound.wav b/res/Media/Shutdown Sound.wav new file mode 100644 index 0000000..b26bdd2 Binary files /dev/null and b/res/Media/Shutdown Sound.wav differ diff --git a/res/Media/Startup Sound.wav b/res/Media/Startup Sound.wav new file mode 100644 index 0000000..657e163 Binary files /dev/null and b/res/Media/Startup Sound.wav differ diff --git a/res/Media/Waves.jpg b/res/Media/Waves.jpg new file mode 100644 index 0000000..96f4965 Binary files /dev/null and b/res/Media/Waves.jpg differ diff --git a/res/System Configuration Template.ini b/res/System Configuration Template.ini new file mode 100644 index 0000000..47ed4a2 --- /dev/null +++ b/res/System Configuration Template.ini @@ -0,0 +1,19 @@ +; Global system configuration. + +[general] +startup_sound=0:/Essence/Media/Startup Sound.wav +fonts_path=0:/Essence/Fonts +themes_path=0:/Essence/Themes +temporary_path=0:/Essence/Temporary +settings_path=0:/Settings +default_user_documents_path=0:/ +installation_state=0 +click_chain_timeout_ms=500 + +[ui] +theme=|Themes:/Theme.dat +icon_pack=|Themes:/elementary Icons.dat +font_fallback=Inter +font_sans=Inter +font_serif=Inter +font_mono=Hack diff --git a/res/Theme Source.dat b/res/Theme Source.dat new file mode 100644 index 0000000..f4085c4 Binary files /dev/null and b/res/Theme Source.dat differ diff --git a/res/Themes/Theme.dat b/res/Themes/Theme.dat new file mode 100644 index 0000000..a632286 Binary files /dev/null and b/res/Themes/Theme.dat differ diff --git a/res/Themes/elementary Icons License.txt b/res/Themes/elementary Icons License.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/res/Themes/elementary Icons License.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/res/Themes/elementary Icons.dat b/res/Themes/elementary Icons.dat new file mode 100644 index 0000000..89c927a Binary files /dev/null and b/res/Themes/elementary Icons.dat differ diff --git a/shared/arena.cpp b/shared/arena.cpp new file mode 100644 index 0000000..f1adf68 --- /dev/null +++ b/shared/arena.cpp @@ -0,0 +1,103 @@ +struct ArenaSlot { + uintptr_t indexInBlock; + ArenaSlot *nextEmpty, **previousEmpty; +}; + +struct ArenaBlock { + struct EsArena *arena; + size_t usedSlots; + uint8_t *data; + ArenaBlock *nextBlock; +}; + +void EsArenaFree(EsArena *arena, void *pointer) { + if (!pointer) return; + + ArenaBlock **blockReference = (ArenaBlock **) &arena->firstBlock; + ArenaBlock *block = (ArenaBlock *) arena->firstBlock; + + while (true) { + if (block->data <= (uint8_t *) pointer && block->data + arena->blockSize > (uint8_t *) pointer) { + break; + } + + blockReference = &block->nextBlock; + block = block->nextBlock; + EsAssert(block); + } + + uintptr_t indexInBlock = ((uint8_t *) pointer - block->data) / arena->slotSize; + EsAssert(indexInBlock < arena->slotsPerBlock); + ArenaSlot *slot = (ArenaSlot *) (block + 1) + indexInBlock; + EsAssert(slot->indexInBlock == indexInBlock); + + slot->nextEmpty = (ArenaSlot *) arena->firstEmptySlot; + if (arena->firstEmptySlot) ((ArenaSlot *) arena->firstEmptySlot)->previousEmpty = &slot->nextEmpty; + arena->firstEmptySlot = slot; + slot->previousEmpty = (ArenaSlot **) &arena->firstEmptySlot; + + if (!(--block->usedSlots)) { + ArenaSlot *slot = (ArenaSlot *) (block + 1); + + for (uintptr_t i = 0; i < arena->slotsPerBlock; i++, slot++) { + if (slot->nextEmpty) slot->nextEmpty->previousEmpty = slot->previousEmpty; + *slot->previousEmpty = slot->nextEmpty; + } + + *blockReference = block->nextBlock; + +#ifdef KERNEL + MMFree(kernelMMSpace, block->data); + EsHeapFree(block, 0, K_FIXED); +#else + EsMemoryUnreserve(block->data); + EsHeapFree(block); +#endif + } +} + +void *EsArenaAllocate(EsArena *arena, bool zero) { + if (!arena->firstEmptySlot) { +#ifdef KERNEL + ArenaBlock *block = (ArenaBlock *) EsHeapAllocate(arena->slotsPerBlock * sizeof(ArenaSlot) + sizeof(ArenaBlock), false, K_FIXED); + block->data = (uint8_t *) MMStandardAllocate(kernelMMSpace, arena->blockSize, ES_FLAGS_DEFAULT, nullptr, true /* commitAll */); +#else + ArenaBlock *block = (ArenaBlock *) EsHeapAllocate(arena->slotsPerBlock * sizeof(ArenaSlot) + sizeof(ArenaBlock), false); + block->data = (uint8_t *) EsMemoryReserve(arena->blockSize, ES_MEMORY_PROTECTION_READ_WRITE); +#endif + + ArenaSlot *slots = (ArenaSlot *) (block + 1); + + for (uintptr_t i = 0; i < arena->slotsPerBlock; i++) { + ArenaSlot *slot = slots + i; + slot->indexInBlock = i; + slot->nextEmpty = i == arena->slotsPerBlock - 1 ? (ArenaSlot *) arena->firstEmptySlot : (slot + 1); + slot->previousEmpty = i ? &slot[-1].nextEmpty : (ArenaSlot **) &arena->firstEmptySlot; + } + + block->arena = arena; + block->usedSlots = 0; + block->nextBlock = (ArenaBlock *) arena->firstBlock; + + arena->firstEmptySlot = slots; + arena->firstBlock = block; + } + + ArenaSlot *slot = (ArenaSlot *) arena->firstEmptySlot; + arena->firstEmptySlot = slot->nextEmpty; + if (arena->firstEmptySlot) ((ArenaSlot *) arena->firstEmptySlot)->previousEmpty = (ArenaSlot **) &arena->firstEmptySlot; + EsAssert(slot->previousEmpty == (ArenaSlot **) &arena->firstEmptySlot); // Incorrect first empty slot back link. + ArenaBlock *block = (ArenaBlock *) (slot - slot->indexInBlock) - 1; + block->usedSlots++; + void *pointer = block->data + arena->slotSize * slot->indexInBlock; + if (zero) EsMemoryZero(pointer, arena->slotSize); + return pointer; +} + +void EsArenaInitialise(EsArena *arena, size_t blockSize, size_t itemSize) { + EsAssert(!arena->slotSize && itemSize); + arena->slotSize = itemSize; + arena->slotsPerBlock = blockSize / arena->slotSize; + if (arena->slotsPerBlock < 32) arena->slotsPerBlock = 32; + arena->blockSize = arena->slotsPerBlock * arena->slotSize; +} diff --git a/shared/array.cpp b/shared/array.cpp new file mode 100644 index 0000000..4599e8f --- /dev/null +++ b/shared/array.cpp @@ -0,0 +1,177 @@ +#ifndef IMPLEMENTATION + +struct _ArrayHeader { + size_t length, allocated; +}; + +bool _ArrayEnsureAllocated(void **array, size_t minimumAllocated, size_t itemSize, uint8_t additionalHeaderBytes, EsHeap *heap); +bool _ArraySetLength(void **array, size_t newLength, size_t itemSize, uint8_t additionalHeaderBytes, EsHeap *heap); +void _ArrayDelete(void *array, uintptr_t position, size_t itemSize, size_t count); +void _ArrayDeleteSwap(void *array, uintptr_t position, size_t itemSize); +void *_ArrayInsert(void **array, const void *item, size_t itemSize, ptrdiff_t position, uint8_t additionalHeaderBytes, EsHeap *heap); +void *_ArrayInsertMany(void **array, size_t itemSize, ptrdiff_t position, size_t count, EsHeap *heap); +void _ArrayFree(void **array, size_t itemSize, EsHeap *heap); + +#define ArrayHeader(array) ((_ArrayHeader *) (array) - 1) +#define ArrayLength(array) ((array) ? (ArrayHeader(array)->length) : 0) + +#ifdef KERNEL +template <class T, EsHeap *heap> +#else +template <class T, EsHeap *heap = nullptr> +#endif +struct Array { + T *array; + + inline size_t Length() { return array ? ArrayHeader(array)->length : 0; } + inline T &First() { return array[0]; } + inline T &Last() { return array[Length() - 1]; } + inline void Delete(uintptr_t position) { _ArrayDelete(array, position, sizeof(T), 1); } + inline void DeleteSwap(uintptr_t position) { _ArrayDeleteSwap(array, position, sizeof(T)); } + inline void DeleteMany(uintptr_t position, size_t count) { _ArrayDelete(array, position, sizeof(T), count); } + inline T *Add(T item) { return (T *) _ArrayInsert((void **) &array, &item, sizeof(T), -1, 0, heap); } + inline T *Add() { return (T *) _ArrayInsert((void **) &array, nullptr, sizeof(T), -1, 0, heap); } + inline T *Insert(T item, uintptr_t position) { return (T *) _ArrayInsert((void **) &array, &item, sizeof(T), position, 0, heap); } + inline T *AddPointer(const T *item) { return (T *) _ArrayInsert((void **) &(array), item, sizeof(T), -1, 0, heap); } + inline T *InsertPointer(const T *item, uintptr_t position) { return (T *) _ArrayInsert((void **) &array, item, sizeof(T), position, 0, heap); } + inline T *InsertMany(uintptr_t position, size_t count) { return (T *) _ArrayInsertMany((void **) &array, sizeof(T), position, count, heap); } + inline bool SetLength(size_t length) { return _ArraySetLength((void **) &array, length, sizeof(T), 0, heap); } + inline void Free() { _ArrayFree((void **) &array, sizeof(T), heap); } + inline T Pop() { T t = Last(); Delete(Length() - 1); return t; } + inline T &operator[](uintptr_t index) { return array[index]; } + + inline intptr_t Find(T item, bool failIfNotFound) { + for (uintptr_t i = 0; i < Length(); i++) { + if (array[i] == item) { + return i; + } + } + + if (failIfNotFound) EsPanic("Array::Find - Item not found in %x.\n", this); + return -1; + } + + inline void FindAndDelete(T item, bool failIfNotFound) { + intptr_t index = Find(item, failIfNotFound); + if (index == -1) return; + Delete(index); + } + + inline void FindAndDeleteSwap(T item, bool failIfNotFound) { + intptr_t index = Find(item, failIfNotFound); + if (index == -1) return; + DeleteSwap(index); + } + + inline void AddFast(T item) { + if (!array) { Add(item); return; } + _ArrayHeader *header = ArrayHeader(array); + if (header->length == header->allocated) { Add(item); return; } + array[header->length++] = item; + } +}; + +#else + +bool _ArrayMaybeInitialise(void **array, size_t itemSize, EsHeap *heap) { + if (*array) return true; + size_t newLength = 4; + _ArrayHeader *header = (_ArrayHeader *) EsHeapAllocate(sizeof(_ArrayHeader) + itemSize * newLength, true, heap); + if (!header) return false; + header->length = 0; + header->allocated = newLength; + *array = header + 1; + return true; +} + +bool _ArrayEnsureAllocated(void **array, size_t minimumAllocated, size_t itemSize, uint8_t additionalHeaderBytes, EsHeap *heap) { + if (!_ArrayMaybeInitialise(array, itemSize, heap)) { + return false; + } + + _ArrayHeader *oldHeader = ArrayHeader(*array); + + if (oldHeader->allocated >= minimumAllocated) { + return true; + } + + _ArrayHeader *newHeader = (_ArrayHeader *) EsHeapReallocate((uint8_t *) oldHeader - additionalHeaderBytes, + sizeof(_ArrayHeader) + additionalHeaderBytes + itemSize * minimumAllocated, false, heap); + + if (!newHeader) { + return false; + } + + newHeader->allocated = minimumAllocated; + *array = (uint8_t *) (newHeader + 1) + additionalHeaderBytes; + return true; +} + +bool _ArraySetLength(void **array, size_t newLength, size_t itemSize, uint8_t additionalHeaderBytes, EsHeap *heap) { + if (!_ArrayMaybeInitialise(array, itemSize, heap)) { + return false; + } + + _ArrayHeader *header = ArrayHeader(*array); + + if (header->allocated >= newLength) { + header->length = newLength; + return true; + } + + if (!_ArrayEnsureAllocated(array, header->allocated * 2 > newLength ? header->allocated * 2 : newLength + 16, itemSize, additionalHeaderBytes, heap)) { + return false; + } + + header = ArrayHeader(*array); + header->length = newLength; + return true; +} + +void _ArrayDelete(void *array, uintptr_t position, size_t itemSize, size_t count) { + if (!count) return; + size_t oldArrayLength = ArrayLength(array); + if (position >= oldArrayLength) EsPanic("_ArrayDelete - Position out of bounds (%d/%d).\n", position, oldArrayLength); + if (count > oldArrayLength - position) EsPanic("_ArrayDelete - Count out of bounds (%d/%d/%d).\n", position, count, oldArrayLength); + ArrayHeader(array)->length = oldArrayLength - count; + uint8_t *data = (uint8_t *) array; + EsMemoryMove(data + itemSize * (position + count), data + itemSize * oldArrayLength, ES_MEMORY_MOVE_BACKWARDS itemSize * count, false); +} + +void _ArrayDeleteSwap(void *array, uintptr_t position, size_t itemSize) { + size_t oldArrayLength = ArrayLength(array); + if (position >= oldArrayLength) EsPanic("_ArrayDeleteSwap - Position out of bounds (%d/%d).\n", position, oldArrayLength); + ArrayHeader(array)->length = oldArrayLength - 1; + uint8_t *data = (uint8_t *) array; + EsMemoryCopy(data + itemSize * position, data + itemSize * ArrayLength(array), itemSize); +} + +void *_ArrayInsert(void **array, const void *item, size_t itemSize, ptrdiff_t position, uint8_t additionalHeaderBytes, EsHeap *heap) { + size_t oldArrayLength = ArrayLength(*array); + if (position == -1) position = oldArrayLength; + if (position < 0 || (size_t) position > oldArrayLength) EsPanic("_ArrayInsert - Position out of bounds (%d/%d).\n", position, oldArrayLength); + if (!_ArraySetLength(array, oldArrayLength + 1, itemSize, additionalHeaderBytes, heap)) return nullptr; + uint8_t *data = (uint8_t *) *array; + EsMemoryMove(data + itemSize * position, data + itemSize * oldArrayLength, itemSize, false); + if (item) EsMemoryCopy(data + itemSize * position, item, itemSize); + else EsMemoryZero(data + itemSize * position, itemSize); + return data + itemSize * position; +} + +void *_ArrayInsertMany(void **array, size_t itemSize, ptrdiff_t position, size_t insertCount, EsHeap *heap) { + size_t oldArrayLength = ArrayLength(*array); + if (position == -1) position = oldArrayLength; + if (position < 0 || (size_t) position > oldArrayLength) EsPanic("_ArrayInsertMany - Position out of bounds (%d/%d).\n", position, oldArrayLength); + if (!_ArraySetLength(array, oldArrayLength + insertCount, itemSize, 0, heap)) return nullptr; + uint8_t *data = (uint8_t *) *array; + EsMemoryMove(data + itemSize * position, data + itemSize * oldArrayLength, itemSize * insertCount, false); + return data + itemSize * position; +} + +void _ArrayFree(void **array, size_t itemSize, EsHeap *heap) { + if (!(*array)) return; + EsHeapFree(ArrayHeader(*array), sizeof(_ArrayHeader) + itemSize * ArrayHeader(*array)->allocated, heap); + *array = nullptr; +} + +#endif diff --git a/shared/avl_tree.cpp b/shared/avl_tree.cpp new file mode 100644 index 0000000..2d60fac --- /dev/null +++ b/shared/avl_tree.cpp @@ -0,0 +1,401 @@ +#ifndef IMPLEMENTATION + +#ifdef DEBUG_BUILD +#define TREE_VALIDATE +#endif + +#ifdef KERNEL +#define AVLPanic KernelPanic +#else +#define AVLPanic(...) do { EsPrint(__VA_ARGS__); EsAssert(false); } while (0) +#endif + +enum TreeSearchMode { + TREE_SEARCH_EXACT, + TREE_SEARCH_SMALLEST_ABOVE_OR_EQUAL, + TREE_SEARCH_LARGEST_BELOW_OR_EQUAL, +}; + +template <class T> +struct AVLTree; + +struct AVLKey { + union { + uintptr_t shortKey; + + struct { + void *longKey; + size_t longKeyBytes; + }; + }; +}; + +inline AVLKey MakeShortKey(uintptr_t shortKey) { + AVLKey key = {}; + key.shortKey = shortKey; + return key; +} + +inline AVLKey MakeLongKey(const void *longKey, size_t longKeyBytes) { + AVLKey key = {}; + key.longKey = (void *) longKey; + key.longKeyBytes = longKeyBytes; + return key; +} + +inline AVLKey MakeCStringKey(const char *cString) { + return MakeLongKey(cString, EsCStringLength(cString) + 1); +} + +template <class T> +struct AVLItem { + T *thisItem; + AVLItem<T> *children[2], *parent; +#ifdef TREE_VALIDATE + AVLTree<T> *tree; +#endif + AVLKey key; + int height; +}; + +template <class T> +struct AVLTree { + AVLItem<T> *root; + bool modCheck; + bool longKeys; +}; + +template <class T> +void TreeRelink(AVLItem<T> *item, AVLItem<T> *newLocation) { + item->parent->children[item->parent->children[1] == item] = newLocation; + if (item->children[0]) item->children[0]->parent = newLocation; + if (item->children[1]) item->children[1]->parent = newLocation; +} + +template <class T> +void TreeSwapItems(AVLItem<T> *a, AVLItem<T> *b) { + // Set the parent of each item to point to the opposite one. + a->parent->children[a->parent->children[1] == a] = b; + b->parent->children[b->parent->children[1] == b] = a; + + // Swap the data between items. + AVLItem<T> ta = *a, tb = *b; + a->parent = tb.parent; + b->parent = ta.parent; + a->height = tb.height; + b->height = ta.height; + a->children[0] = tb.children[0]; + a->children[1] = tb.children[1]; + b->children[0] = ta.children[0]; + b->children[1] = ta.children[1]; + + // Make all the children point to the correct item. + if (a->children[0]) a->children[0]->parent = a; + if (a->children[1]) a->children[1]->parent = a; + if (b->children[0]) b->children[0]->parent = b; + if (b->children[1]) b->children[1]->parent = b; +} + +template <class T> +inline int TreeCompare(AVLTree<T> *tree, AVLKey *key1, AVLKey *key2) { + if (tree->longKeys) { + if (!key1->longKey && !key2->longKey) return 0; + if (!key2->longKey) return 1; + if (!key1->longKey) return -1; + return EsStringCompareRaw((const char *) key1->longKey, key1->longKeyBytes, (const char *) key2->longKey, key2->longKeyBytes); + } else { + if (key1->shortKey < key2->shortKey) return -1; + if (key1->shortKey > key2->shortKey) return 1; + return 0; + } +} + +template <class T> +int TreeValidate(AVLItem<T> *root, bool before, AVLTree<T> *tree, AVLItem<T> *parent = nullptr, int depth = 0) { +#ifdef TREE_VALIDATE + if (!root) return 0; + if (root->parent != parent) AVLPanic("TreeValidate - Invalid binary tree 1 (%d).\n", before); + if (root->tree != tree) AVLPanic("TreeValidate - Invalid binary tree 4 (%d).\n", before); + + AVLItem<T> *left = root->children[0]; + AVLItem<T> *right = root->children[1]; + + if (left && TreeCompare(tree, &left->key, &root->key) > 0) AVLPanic("TreeValidate - Invalid binary tree 2 (%d).\n", before); + if (right && TreeCompare(tree, &right->key, &root->key) < 0) AVLPanic("TreeValidate - Invalid binary tree 3 (%d).\n", before); + + int leftHeight = TreeValidate(left, before, tree, root, depth + 1); + int rightHeight = TreeValidate(right, before, tree, root, depth + 1); + int height = (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; + if (height != root->height) AVLPanic("TreeValidate - Invalid AVL tree 1 (%d).\n", before); + +#if 0 + static int maxSeenDepth = 0; + if (maxSeenDepth < depth) { + maxSeenDepth = depth; + EsPrint("New depth reached! %d\n", maxSeenDepth); + } +#endif + + return height; +#else + (void) root; + (void) before; + (void) tree; + (void) parent; + (void) depth; + return 0; +#endif +} + +template <class T> +AVLItem<T> *TreeRotateLeft(AVLItem<T> *x) { + AVLItem<T> *y = x->children[1], *t = y->children[0]; + y->children[0] = x, x->children[1] = t; + if (x) x->parent = y; + if (t) t->parent = x; + + int leftHeight, rightHeight, balance; + + leftHeight = x->children[0] ? x->children[0]->height : 0; + rightHeight = x->children[1] ? x->children[1]->height : 0; + balance = leftHeight - rightHeight; + x->height = (balance > 0 ? leftHeight : rightHeight) + 1; + + leftHeight = y->children[0] ? y->children[0]->height : 0; + rightHeight = y->children[1] ? y->children[1]->height : 0; + balance = leftHeight - rightHeight; + y->height = (balance > 0 ? leftHeight : rightHeight) + 1; + + return y; +} + +template <class T> +AVLItem<T> *TreeRotateRight(AVLItem<T> *y) { + AVLItem<T> *x = y->children[0], *t = x->children[1]; + x->children[1] = y, y->children[0] = t; + if (y) y->parent = x; + if (t) t->parent = y; + + int leftHeight, rightHeight, balance; + + leftHeight = y->children[0] ? y->children[0]->height : 0; + rightHeight = y->children[1] ? y->children[1]->height : 0; + balance = leftHeight - rightHeight; + y->height = (balance > 0 ? leftHeight : rightHeight) + 1; + + leftHeight = x->children[0] ? x->children[0]->height : 0; + rightHeight = x->children[1] ? x->children[1]->height : 0; + balance = leftHeight - rightHeight; + x->height = (balance > 0 ? leftHeight : rightHeight) + 1; + + return x; +} + +enum AVLDuplicateKeyPolicy { + AVL_DUPLICATE_KEYS_PANIC, + AVL_DUPLICATE_KEYS_ALLOW, + AVL_DUPLICATE_KEYS_FAIL, +}; + +template <class T> +bool TreeInsert(AVLTree<T> *tree, AVLItem<T> *item, T *thisItem, AVLKey key, AVLDuplicateKeyPolicy duplicateKeyPolicy = AVL_DUPLICATE_KEYS_PANIC) { + if (tree->modCheck) AVLPanic("TreeInsert - Concurrent modification\n"); + tree->modCheck = true; EsDefer({tree->modCheck = false;}); + + TreeValidate(tree->root, true, tree); + +#ifdef TREE_VALIDATE + if (item->tree) { + AVLPanic("TreeInsert - Item %x already in tree %x (adding to %x).\n", item, item->tree, tree); + } + + item->tree = tree; +#endif + + item->key = key; + item->children[0] = item->children[1] = nullptr; + item->thisItem = thisItem; + item->height = 1; + + AVLItem<T> **link = &tree->root, *parent = nullptr; + + while (true) { + AVLItem<T> *node = *link; + + if (!node) { + *link = item; + item->parent = parent; + break; + } + + if (TreeCompare(tree, &item->key, &node->key) == 0) { + if (duplicateKeyPolicy == AVL_DUPLICATE_KEYS_PANIC) { + AVLPanic("TreeInsertRecursive - Duplicate keys: %x and %x both have key %x.\n", item, node, node->key); + } else if (duplicateKeyPolicy == AVL_DUPLICATE_KEYS_FAIL) { + return false; + } + } + + link = node->children + (TreeCompare(tree, &item->key, &node->key) > 0); + parent = node; + } + + AVLItem<T> fakeRoot = {}; + tree->root->parent = &fakeRoot; +#ifdef TREE_VALIDATE + fakeRoot.tree = tree; +#endif + fakeRoot.key = {}; + fakeRoot.children[0] = tree->root; + + item = item->parent; + + while (item != &fakeRoot) { + int leftHeight = item->children[0] ? item->children[0]->height : 0; + int rightHeight = item->children[1] ? item->children[1]->height : 0; + int balance = leftHeight - rightHeight; + + item->height = (balance > 0 ? leftHeight : rightHeight) + 1; + AVLItem<T> *newRoot = nullptr; + AVLItem<T> *oldParent = item->parent; + + if (balance > 1 && TreeCompare(tree, &key, &item->children[0]->key) <= 0) { + oldParent->children[oldParent->children[1] == item] = newRoot = TreeRotateRight(item); + } else if (balance > 1 && TreeCompare(tree, &key, &item->children[0]->key) > 0 && item->children[0]->children[1]) { + item->children[0] = TreeRotateLeft(item->children[0]); + item->children[0]->parent = item; + oldParent->children[oldParent->children[1] == item] = newRoot = TreeRotateRight(item); + } else if (balance < -1 && TreeCompare(tree, &key, &item->children[1]->key) > 0) { + oldParent->children[oldParent->children[1] == item] = newRoot = TreeRotateLeft(item); + } else if (balance < -1 && TreeCompare(tree, &key, &item->children[1]->key) <= 0 && item->children[1]->children[0]) { + item->children[1] = TreeRotateRight(item->children[1]); + item->children[1]->parent = item; + oldParent->children[oldParent->children[1] == item] = newRoot = TreeRotateLeft(item); + } + + if (newRoot) newRoot->parent = oldParent; + item = oldParent; + } + + tree->root = fakeRoot.children[0]; + tree->root->parent = nullptr; + + TreeValidate(tree->root, false, tree); + return true; +} + +template <class T> +AVLItem<T> *TreeFindRecursive(AVLTree<T> *tree, AVLItem<T> *root, AVLKey *key, TreeSearchMode mode) { + if (!root) return nullptr; + if (TreeCompare(tree, &root->key, key) == 0) return root; + + if (mode == TREE_SEARCH_EXACT) { + return TreeFindRecursive(tree, root->children[TreeCompare(tree, &root->key, key) < 0], key, mode); + } else if (mode == TREE_SEARCH_SMALLEST_ABOVE_OR_EQUAL) { + if (TreeCompare(tree, &root->key, key) > 0) { + AVLItem<T> *item = TreeFindRecursive(tree, root->children[0], key, mode); + if (item) return item; else return root; + } else { + return TreeFindRecursive(tree, root->children[1], key, mode); + } + } else if (mode == TREE_SEARCH_LARGEST_BELOW_OR_EQUAL) { + if (TreeCompare(tree, &root->key, key) < 0) { + AVLItem<T> *item = TreeFindRecursive(tree, root->children[1], key, mode); + if (item) return item; else return root; + } else { + return TreeFindRecursive(tree, root->children[0], key, mode); + } + } else { + AVLPanic("TreeFindRecursive - Invalid search mode.\n"); + return nullptr; + } +} + +template <class T> +AVLItem<T> *TreeFind(AVLTree<T> *tree, AVLKey key, TreeSearchMode mode) { + if (tree->modCheck) AVLPanic("TreeFind - Concurrent access\n"); + + TreeValidate(tree->root, true, tree); + return TreeFindRecursive(tree, tree->root, &key, mode); +} + +template <class T> +int TreeGetBalance(AVLItem<T> *item) { + if (!item) return 0; + + int leftHeight = item->children[0] ? item->children[0]->height : 0; + int rightHeight = item->children[1] ? item->children[1]->height : 0; + return leftHeight - rightHeight; +} + +template <class T> +void TreeRemove(AVLTree<T> *tree, AVLItem<T> *item) { + if (tree->modCheck) AVLPanic("TreeRemove - Concurrent modification\n"); + tree->modCheck = true; EsDefer({tree->modCheck = false;}); + + TreeValidate(tree->root, true, tree); + +#ifdef TREE_VALIDATE + if (item->tree != tree) AVLPanic("TreeRemove - Item %x not in tree %x (in %x).\n", item, tree, item->tree); +#endif + + AVLItem<T> fakeRoot = {}; + tree->root->parent = &fakeRoot; +#ifdef TREE_VALIDATE + fakeRoot.tree = tree; +#endif + fakeRoot.key = {}; + fakeRoot.children[0] = tree->root; + + if (item->children[0] && item->children[1]) { + // Swap the item we're removing with the smallest item on its right side. + AVLKey smallest = {}; + TreeSwapItems(TreeFindRecursive(tree, item->children[1], &smallest, TREE_SEARCH_SMALLEST_ABOVE_OR_EQUAL), item); + } + + AVLItem<T> **link = item->parent->children + (item->parent->children[1] == item); + *link = item->children[0] ? item->children[0] : item->children[1]; + if (*link) (*link)->parent = item->parent; +#ifdef TREE_VALIDATE + item->tree = nullptr; +#endif + if (*link) item = *link; else item = item->parent; + + while (item != &fakeRoot) { + int leftHeight = item->children[0] ? item->children[0]->height : 0; + int rightHeight = item->children[1] ? item->children[1]->height : 0; + int balance = leftHeight - rightHeight; + + item->height = (balance > 0 ? leftHeight : rightHeight) + 1; + AVLItem<T> *newRoot = nullptr; + AVLItem<T> *oldParent = item->parent; + + if (balance > 1 && TreeGetBalance(item->children[0]) >= 0) { + oldParent->children[oldParent->children[1] == item] = newRoot = TreeRotateRight(item); + } else if (balance > 1 && TreeGetBalance(item->children[0]) < 0) { + item->children[0] = TreeRotateLeft(item->children[0]); + item->children[0]->parent = item; + oldParent->children[oldParent->children[1] == item] = newRoot = TreeRotateRight(item); + } else if (balance < -1 && TreeGetBalance(item->children[1]) <= 0) { + oldParent->children[oldParent->children[1] == item] = newRoot = TreeRotateLeft(item); + } else if (balance < -1 && TreeGetBalance(item->children[1]) > 0) { + item->children[1] = TreeRotateRight(item->children[1]); + item->children[1]->parent = item; + oldParent->children[oldParent->children[1] == item] = newRoot = TreeRotateLeft(item); + } + + if (newRoot) newRoot->parent = oldParent; + item = oldParent; + } + + tree->root = fakeRoot.children[0]; + + if (tree->root) { + if (tree->root->parent != &fakeRoot) AVLPanic("TreeRemove - Incorrect root parent.\n"); + tree->root->parent = nullptr; + } + + TreeValidate(tree->root, false, tree); +} + +#endif diff --git a/shared/bitset.cpp b/shared/bitset.cpp new file mode 100644 index 0000000..55b3a8e --- /dev/null +++ b/shared/bitset.cpp @@ -0,0 +1,182 @@ +#ifndef IMPLEMENTATION + +struct Bitset { + void Initialise(size_t count, bool mapAll = false); + void PutAll(); + uintptr_t Get(size_t count = 1, uintptr_t align = 1, uintptr_t below = 0); + void Put(uintptr_t index); + void Take(uintptr_t index); + bool Read(uintptr_t index); + +#define BITSET_GROUP_SIZE (4096) + uint32_t *singleUsage; + uint16_t *groupUsage; + + size_t singleCount; + size_t groupCount; + + bool modCheck; +}; + +#else + +void Bitset::Initialise(size_t count, bool mapAll) { + singleCount = (count + 31) & ~31; + groupCount = singleCount / BITSET_GROUP_SIZE + 1; + + singleUsage = (uint32_t *) MMStandardAllocate(kernelMMSpace, (singleCount >> 3) + (groupCount * 2), mapAll ? MM_REGION_FIXED : 0); + groupUsage = (uint16_t *) singleUsage + (singleCount >> 4); +} + +void Bitset::PutAll() { + for (uintptr_t i = 0; i < singleCount; i += 32) { + groupUsage[i / BITSET_GROUP_SIZE] += 32; + singleUsage[i / 32] |= 0xFFFFFFFF; + } +} + +uintptr_t Bitset::Get(size_t count, uintptr_t align, uintptr_t below) { + if (modCheck) KernelPanic("Bitset::Allocate - Concurrent modification.\n"); + modCheck = true; EsDefer({modCheck = false;}); + + uintptr_t returnValue = (uintptr_t) -1; + + if (below) { + if (below < count) goto done; + below -= count; + } + + if (count == 1 && align == 1) { + for (uintptr_t i = 0; i < groupCount; i++) { + if (groupUsage[i]) { + for (uintptr_t j = 0; j < BITSET_GROUP_SIZE; j++) { + uintptr_t index = i * BITSET_GROUP_SIZE + j; + if (below && index >= below) goto done; + + if (singleUsage[index >> 5] & (1 << (index & 31))) { + singleUsage[index >> 5] &= ~(1 << (index & 31)); + groupUsage[i]--; + returnValue = index; + goto done; + } + } + } + } + } else if (count == 16 && align == 16) { + for (uintptr_t i = 0; i < groupCount; i++) { + if (groupUsage[i] >= 16) { + for (uintptr_t j = 0; j < BITSET_GROUP_SIZE; j += 16) { + uintptr_t index = i * BITSET_GROUP_SIZE + j; + if (below && index >= below) goto done; + + if (((uint16_t *) singleUsage)[index >> 4] == (uint16_t) (-1)) { + ((uint16_t *) singleUsage)[index >> 4] = 0; + groupUsage[i] -= 16; + returnValue = index; + goto done; + } + } + } + } + } else if (count == 32 && align == 32) { + for (uintptr_t i = 0; i < groupCount; i++) { + if (groupUsage[i] >= 32) { + for (uintptr_t j = 0; j < BITSET_GROUP_SIZE; j += 32) { + uintptr_t index = i * BITSET_GROUP_SIZE + j; + if (below && index >= below) goto done; + + if (singleUsage[index >> 5] == (uint32_t) (-1)) { + singleUsage[index >> 5] = 0; + groupUsage[i] -= 32; + returnValue = index; + goto done; + } + } + } + } + } else { + // TODO Optimise this? + + size_t found = 0; + uintptr_t start = 0; + + for (uintptr_t i = 0; i < groupCount; i++) { + if (!groupUsage[i]) { + found = 0; + continue; + } + + for (uintptr_t j = 0; j < BITSET_GROUP_SIZE; j++) { + uintptr_t index = i * BITSET_GROUP_SIZE + j; + + if (singleUsage[index >> 5] & (1 << (index & 31))) { + if (!found) { + if (index >= below && below) goto done; + if (index % align) continue; + + start = index; + } + + found++; + } else { + found = 0; + } + + if (found == count) { + returnValue = start; + + for (uintptr_t i = 0; i < count; i++) { + uintptr_t index = start + i; + singleUsage[index >> 5] &= ~(1 << (index & 31)); + } + + goto done; + } + } + } + } + + done:; + return returnValue; +} + +bool Bitset::Read(uintptr_t index) { + // We don't want to set modCheck, + // since we allow other bits to be modified while this bit is being read, + // and we allow multiple readers of this bit. + return singleUsage[index >> 5] & (1 << (index & 31)); +} + +void Bitset::Take(uintptr_t index) { + if (modCheck) KernelPanic("Bitset::Take - Concurrent modification.\n"); + modCheck = true; EsDefer({modCheck = false;}); + + uintptr_t group = index / BITSET_GROUP_SIZE; + + if (!(singleUsage[index >> 5] & (1 << (index & 31)))) { + KernelPanic("Bitset::Take - Attempting to take a entry that has already been taken.\n"); + } + + groupUsage[group]--; + singleUsage[index >> 5] &= ~(1 << (index & 31)); +} + +void Bitset::Put(uintptr_t index) { + if (modCheck) KernelPanic("Bitset::Put - Concurrent modification.\n"); + modCheck = true; EsDefer({modCheck = false;}); + + if (index > singleCount) { + KernelPanic("Bitset::Put - Index greater than single code.\n"); + } + + if (singleUsage[index >> 5] & (1 << (index & 31))) { + KernelPanic("Bitset::Put - Duplicate entry.\n"); + } + + { + singleUsage[index >> 5] |= 1 << (index & 31); + groupUsage[index / BITSET_GROUP_SIZE]++; + } +} + +#endif diff --git a/shared/common.cpp b/shared/common.cpp new file mode 100644 index 0000000..207045c --- /dev/null +++ b/shared/common.cpp @@ -0,0 +1,2615 @@ +#ifdef SHARED_COMMON_WANT_ALL +#define SHARED_COMMON_WANT_RECTANGLES +#define SHARED_COMMON_WANT_RENDERING +#define SHARED_COMMON_WANT_STRINGS +#define SHARED_COMMON_WANT_MEMORY +#define SHARED_COMMON_WANT_AUDIO +#define SHARED_COMMON_WANT_PRINTING +#define SHARED_COMMON_WANT_TIMING +#define SHARED_COMMON_WANT_RANDOM +#define SHARED_COMMON_WANT_ALGORITHMS +#define SHARED_COMMON_WANT_MISCELLANEOUS +#define SHARED_COMMON_WANT_SYNC +#define SHARED_COMMON_WANT_BYTE_SWAP +#define SHARED_COMMON_WANT_CSTDLIB +#define SHARED_COMMON_WANT_BUFFERS +#define SHARED_COMMON_WANT_AUDIO +#endif + +///////////////////////////////// +// EsRectangle utility functions. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_RECTANGLES + +struct Corners8 { int8_t tl, tr, bl, br; }; +struct Corners32 { int32_t tl, tr, bl, br; }; +struct Rectangle8 { int8_t l, r, t, b; }; +struct Rectangle16 { int16_t l, r, t, b; }; +struct Rectangle32 { int32_t l, r, t, b; }; + +#define RECT16_TO_RECT(x) ((EsRectangle) { (x).l, (x).r, (x).t, (x).b }) + +inline int Width(EsRectangle rectangle) { + return rectangle.r - rectangle.l; +} + +inline int Height(EsRectangle rectangle) { + return rectangle.b - rectangle.t; +} + +EsRectangle Translate(EsRectangle rectangle, int x, int y) { + return EsRectangleAdd(rectangle, ES_RECT_2(x, y)); +} + +bool EsRectangleClip(EsRectangle parent, EsRectangle rectangle, EsRectangle *output) { + EsRectangle current = parent; + EsRectangle intersection; + + if (!((current.l > rectangle.r && current.r > rectangle.l) + || (current.t > rectangle.b && current.b > rectangle.t))) { + intersection.l = current.l > rectangle.l ? current.l : rectangle.l; + intersection.t = current.t > rectangle.t ? current.t : rectangle.t; + intersection.r = current.r < rectangle.r ? current.r : rectangle.r; + intersection.b = current.b < rectangle.b ? current.b : rectangle.b; + } else { + intersection = ES_RECT_4(0, 0, 0, 0); + } + + if (output) { + *output = intersection; + } + + return intersection.l < intersection.r && intersection.t < intersection.b; +} + +EsRectangle EsRectangleAddBorder(EsRectangle rectangle, EsRectangle border) { + rectangle.l += border.l; + rectangle.r -= border.r; + rectangle.t += border.t; + rectangle.b -= border.b; + return rectangle; +} + +EsRectangle EsRectangleAdd(EsRectangle a, EsRectangle b) { + a.l += b.l; + a.t += b.t; + a.r += b.r; + a.b += b.b; + return a; +} + +EsRectangle EsRectangleTranslate(EsRectangle a, EsRectangle b) { + a.l += b.l; + a.t += b.t; + a.r += b.l; + a.b += b.t; + return a; +} + +EsRectangle EsRectangleSubtract(EsRectangle a, EsRectangle b) { + a.l -= b.l; + a.t -= b.t; + a.r -= b.r; + a.b -= b.b; + return a; +} + +EsRectangle EsRectangleBounding(EsRectangle a, EsRectangle b) { + if (a.l > b.l) a.l = b.l; + if (a.t > b.t) a.t = b.t; + if (a.r < b.r) a.r = b.r; + if (a.b < b.b) a.b = b.b; + return a; +} + +EsRectangle EsRectangleIntersection(EsRectangle a, EsRectangle b) { + if (a.l < b.l) a.l = b.l; + if (a.t < b.t) a.t = b.t; + if (a.r > b.r) a.r = b.r; + if (a.b > b.b) a.b = b.b; + return a; +} + +EsRectangle EsRectangleCenter(EsRectangle parent, EsRectangle child) { + int childWidth = Width(child), childHeight = Height(child); + int parentWidth = Width(parent), parentHeight = Height(parent); + child.l = parentWidth / 2 - childWidth / 2 + parent.l, child.r = child.l + childWidth; + child.t = parentHeight / 2 - childHeight / 2 + parent.t, child.b = child.t + childHeight; + return child; +} + +EsRectangle EsRectangleFit(EsRectangle parent, EsRectangle child, bool allowScalingUp) { + int childWidth = Width(child), childHeight = Height(child); + int parentWidth = Width(parent), parentHeight = Height(parent); + + if (childWidth < parentWidth && childHeight < parentHeight && !allowScalingUp) { + return EsRectangleCenter(parent, child); + } + + float childAspectRatio = (float) childWidth / childHeight; + int childMaximumWidth = parentHeight * childAspectRatio; + int childMaximumHeight = parentWidth / childAspectRatio; + + if (childMaximumWidth > parentWidth) { + return EsRectangleCenter(parent, ES_RECT_2S(parentWidth, childMaximumHeight)); + } else { + return EsRectangleCenter(parent, ES_RECT_2S(childMaximumWidth, parentHeight)); + } +} + +bool EsRectangleEquals(EsRectangle a, EsRectangle b) { + return a.l == b.l && a.r == b.r && a.t == b.t && a.b == b.b; +} + +bool EsRectangleContains(EsRectangle a, int32_t x, int32_t y) { + return ES_RECT_VALID(a) && a.l <= x && a.r > x && a.t <= y && a.b > y; +} + +EsRectangle EsRectangleSplit(EsRectangle *a, int32_t amount, char side, int32_t gap) { + EsRectangle b = *a; + if (side == 'l') a->l += amount + gap, b.r = a->l - gap; + if (side == 'r') a->r -= amount + gap, b.l = a->r + gap; + if (side == 't') a->t += amount + gap, b.b = a->t - gap; + if (side == 'b') a->b -= amount + gap, b.t = a->b + gap; + return b; +} + +EsRectangle EsRectangleCut(EsRectangle a, int32_t amount, char side) { + return EsRectangleSplit(&a, amount, side, 0); +} + +#endif + +///////////////////////////////// +// Rendering. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_RENDERING + +__attribute__((optimize("-O3"))) +void BlendPixel(uint32_t *destinationPixel, uint32_t modified, bool fullAlpha) { + if ((modified & 0xFF000000) == 0xFF000000) { + *destinationPixel = modified; + return; + } else if ((modified & 0xFF000000) == 0x00000000) { + return; + } + + uint32_t m1, m2, a; + uint32_t original = *destinationPixel; + + if ((*destinationPixel & 0xFF000000) != 0xFF000000 && fullAlpha) { + uint32_t alpha1 = (modified & 0xFF000000) >> 24; + uint32_t alpha2 = 255 - alpha1; + uint32_t alphaD = (original & 0xFF000000) >> 24; + uint32_t alphaD2 = alphaD * alpha2; + uint32_t alphaOut = alpha1 + (alphaD2 >> 8); + + if (!alphaOut) { + return; + } + + m2 = alphaD2 / alphaOut; + m1 = (alpha1 << 8) / alphaOut; + if (m2 == 0x100) m2--; + if (m1 == 0x100) m1--; + a = alphaOut << 24; + } else { + m1 = (modified & 0xFF000000) >> 24; + m2 = 255 - m1; + a = 0xFF000000; + } + + uint32_t r2 = m2 * (original & 0x00FF00FF); + uint32_t g2 = m2 * (original & 0x0000FF00); + uint32_t r1 = m1 * (modified & 0x00FF00FF); + uint32_t g1 = m1 * (modified & 0x0000FF00); + uint32_t result = a | (0x0000FF00 & ((g1 + g2) >> 8)) | (0x00FF00FF & ((r1 + r2) >> 8)); + *destinationPixel = result; +} + +uint32_t EsColorBlend(uint32_t under, uint32_t over, bool fullAlpha) { + BlendPixel(&under, over, fullAlpha); + return under; +} + +struct EsPaintTarget { + void *bits; + uint32_t width, height, stride; + bool fullAlpha, readOnly, fromBitmap, forWindowManager; +}; + +void EsDrawInvert(EsPainter *painter, EsRectangle bounds) { + EsPaintTarget *target = painter->target; + + if (!EsRectangleClip(bounds, painter->clip, &bounds)) { + return; + } + + uintptr_t stride = target->stride / 4; + uint32_t *lineStart = (uint32_t *) target->bits + bounds.t * stride + bounds.l; + + __m128i mask = _mm_set_epi32(0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF); + + for (int i = 0; i < bounds.b - bounds.t; i++, lineStart += stride) { + uint32_t *destination = lineStart; + int j = bounds.r - bounds.l; + + while (j >= 4) { + *(__m128i *) destination = _mm_xor_si128(*(__m128i *) destination, mask); + destination += 4; + j -= 4; + } + + while (j > 0) { + *destination ^= 0xFFFFFF; + destination++; + j--; + } + } +} + +void EsDrawClear(EsPainter *painter, EsRectangle bounds) { + EsPaintTarget *target = painter->target; + + if (!EsRectangleClip(bounds, painter->clip, &bounds)) { + return; + } + + uintptr_t stride = target->stride / 4; + uint32_t *lineStart = (uint32_t *) target->bits + bounds.t * stride + bounds.l; + + __m128i zero = {}; + + for (int i = 0; i < bounds.b - bounds.t; i++, lineStart += stride) { + uint32_t *destination = lineStart; + int j = bounds.r - bounds.l; + + while (j >= 4) { + _mm_storeu_si128((__m128i *) destination, zero); + destination += 4; + j -= 4; + } + + while (j > 0) { + *destination = 0; + destination++; + j--; + } + } +} + +void _DrawBlock(uintptr_t stride, void *bits, EsRectangle bounds, uint32_t color, bool fullAlpha) { + stride /= 4; + uint32_t *lineStart = (uint32_t *) bits + bounds.t * stride + bounds.l; + + __m128i color4 = _mm_set_epi32(color, color, color, color); + + for (int i = 0; i < bounds.b - bounds.t; i++, lineStart += stride) { + uint32_t *destination = lineStart; + int j = bounds.r - bounds.l; + + if ((color & 0xFF000000) != 0xFF000000) { + do { + BlendPixel(destination, color, fullAlpha); + destination++; + } while (--j); + } else { + while (j >= 4) { + _mm_storeu_si128((__m128i *) destination, color4); + destination += 4; + j -= 4; + } + + while (j > 0) { + *destination = color; + destination++; + j--; + } + } + } +} + +void EsDrawBlock(EsPainter *painter, EsRectangle bounds, uint32_t color) { + if (!(color & 0xFF000000)) { + return; + } + + EsPaintTarget *target = painter->target; + + if (!EsRectangleClip(bounds, painter->clip, &bounds)) { + return; + } + + _DrawBlock(target->stride, target->bits, bounds, color, target->fullAlpha); +} + +void EsDrawBitmap(EsPainter *painter, EsRectangle region, uint32_t *sourceBits, uintptr_t sourceStride, uint16_t mode) { + EsPaintTarget *target = painter->target; + EsRectangle bounds; + + if (!EsRectangleClip(region, painter->clip, &bounds)) { + return; + } + + sourceStride /= 4; + uintptr_t stride = target->stride / 4; + uint32_t *lineStart = (uint32_t *) target->bits + bounds.t * stride + bounds.l; + uint32_t *sourceLineStart = sourceBits + (bounds.l - region.l) + sourceStride * (bounds.t - region.t); + + for (int i = 0; i < bounds.b - bounds.t; i++, lineStart += stride, sourceLineStart += sourceStride) { + uint32_t *destination = lineStart; + uint32_t *source = sourceLineStart; + int j = bounds.r - bounds.l; + + if (mode == 0xFF) { + do { + BlendPixel(destination, *source, target->fullAlpha); + destination++; + source++; + } while (--j); + } else if (mode <= 0xFF) { + do { + uint32_t modified = *source; + modified = (modified & 0xFFFFFF) | (((((modified & 0xFF000000) >> 24) * mode) << 16) & 0xFF000000); + BlendPixel(destination, modified, target->fullAlpha); + destination++; + source++; + } while (--j); + } else if (mode == ES_DRAW_BITMAP_XOR) { + while (j >= 4) { + __m128i *_destination = (__m128i *) destination; + _mm_storeu_si128(_destination, _mm_xor_si128(_mm_loadu_si128((__m128i *) source), _mm_loadu_si128(_destination))); + destination += 4; + source += 4; + j -= 4; + } + + while (j > 0) { + *destination ^= *source; + destination++; + source++; + j--; + } + } else if (mode == ES_DRAW_BITMAP_OPAQUE) { + while (j >= 4) { + _mm_storeu_si128((__m128i *) destination, _mm_loadu_si128((__m128i *) source)); + destination += 4; + source += 4; + j -= 4; + } + + while (j > 0) { + *destination = *source; + destination++; + source++; + j--; + } + } + } +} + +void EsDrawRectangle(EsPainter *painter, EsRectangle r, uint32_t mainColor, uint32_t borderColor, EsRectangle borderSize) { + EsDrawBlock(painter, ES_RECT_4(r.l, r.r, r.t, r.t + borderSize.t), borderColor); + EsDrawBlock(painter, ES_RECT_4(r.l, r.l + borderSize.l, r.t + borderSize.t, r.b - borderSize.b), borderColor); + EsDrawBlock(painter, ES_RECT_4(r.r - borderSize.r, r.r, r.t + borderSize.t, r.b - borderSize.b), borderColor); + EsDrawBlock(painter, ES_RECT_4(r.l, r.r, r.b - borderSize.b, r.b), borderColor); + EsDrawBlock(painter, ES_RECT_4(r.l + borderSize.l, r.r - borderSize.r, r.t + borderSize.t, r.b - borderSize.b), mainColor); +} + +void ImageDraw(uint32_t *destinationBits, uint32_t destinationWidth, uint32_t destinationHeight, size_t destinationStride, + uint32_t *sourceBits, uint32_t sourceWidth, uint32_t sourceHeight, size_t sourceStride, + EsRectangle destinationRegion, EsRectangle sourceRegion, uint16_t alpha, bool fullAlpha) { + if (sourceRegion.l < 0 || sourceRegion.t < 0 + || sourceRegion.r < 0 || sourceRegion.b < 0 + || sourceRegion.r > (int32_t) sourceWidth || sourceRegion.b > (int32_t) sourceHeight + || sourceRegion.l >= sourceRegion.r || sourceRegion.t >= sourceRegion.b) { + return; + } + + EsRectangle clipRegion = ES_RECT_4(0, destinationWidth, 0, destinationHeight); + EsRectangle sourceBorderRegion = sourceRegion; + + clipRegion = EsRectangleIntersection(clipRegion, destinationRegion); + if (clipRegion.r <= clipRegion.l || clipRegion.b <= clipRegion.t) return; + sourceRegion = EsRectangleAdd(sourceRegion, EsRectangleSubtract(clipRegion, destinationRegion)); + int borderWidth = Width(sourceBorderRegion), borderHeight = Height(sourceBorderRegion); + if (sourceRegion.l > sourceBorderRegion.l) sourceRegion.l = sourceBorderRegion.l + (clipRegion.l - destinationRegion.l) * borderWidth / Width(destinationRegion); + if (sourceRegion.r < sourceBorderRegion.r) sourceRegion.r = sourceBorderRegion.r + (clipRegion.r - destinationRegion.r) * borderWidth / Width(destinationRegion); + if (sourceRegion.t > sourceBorderRegion.t) sourceRegion.t = sourceBorderRegion.t + (clipRegion.t - destinationRegion.t) * borderHeight / Height(destinationRegion); + if (sourceRegion.b < sourceBorderRegion.b) sourceRegion.b = sourceBorderRegion.b + (clipRegion.b - destinationRegion.b) * borderHeight / Height(destinationRegion); + destinationRegion = clipRegion; + + for (intptr_t y = destinationRegion.t; y < destinationRegion.b; y++) { + intptr_t sy = y - destinationRegion.t + sourceRegion.t; + + intptr_t sourceBorderSize = sourceRegion.b - sourceRegion.t; + intptr_t destinationBorderSize = destinationRegion.b - destinationRegion.t; + sy = (y - destinationRegion.t) * sourceBorderSize / destinationBorderSize + sourceRegion.t; + + for (intptr_t x = destinationRegion.l; x < destinationRegion.r; x++) { + intptr_t sx = x - destinationRegion.l + sourceRegion.l; + + intptr_t sourceBorderSize = sourceRegion.r - sourceRegion.l; + intptr_t destinationBorderSize = destinationRegion.r - destinationRegion.l; + sx = (x - destinationRegion.l) * sourceBorderSize / destinationBorderSize + sourceRegion.l; + + uint32_t *destinationPixel = destinationBits + x + y * destinationStride / 4; + uint32_t *sourcePixel = sourceBits + sx + sy * sourceStride / 4; + uint32_t modified = *sourcePixel; + + if (alpha == 0xFFFF) { + *destinationPixel = modified; + } else { + if (alpha != 0xFF) { + modified = (modified & 0xFFFFFF) | (((((modified & 0xFF000000) >> 24) * alpha) << 16) & 0xFF000000); + } + + BlendPixel(destinationPixel, modified, fullAlpha); + } + } + } +} + +void EsDrawBitmapScaled(EsPainter *painter, EsRectangle destinationRegion, EsRectangle sourceRegion, uint32_t *bits, uintptr_t stride, uint16_t alpha) { + ImageDraw((uint32_t *) painter->target->bits, painter->target->width, painter->target->height, painter->target->stride, + bits, Width(sourceRegion), Height(sourceRegion), stride, + destinationRegion, sourceRegion, alpha, painter->target->fullAlpha); +} + +void EsDrawPaintTarget(EsPainter *painter, EsPaintTarget *source, EsRectangle destinationRegion, EsRectangle sourceRegion, uint8_t alpha) { + bool scale = !(Width(destinationRegion) == Width(sourceRegion) && Height(destinationRegion) == Height(sourceRegion)); + + if (scale) { + ImageDraw((uint32_t *) painter->target->bits, painter->target->width, painter->target->height, painter->target->stride, + (uint32_t *) source->bits, source->width, source->height, source->stride, + destinationRegion, sourceRegion, alpha, painter->target->fullAlpha); + } else { + EsDrawBitmap(painter, destinationRegion, + (uint32_t *) source->bits + sourceRegion.l + sourceRegion.t * source->stride / 4, + source->stride, source->fullAlpha ? alpha : 0xFFFF); + } +} + +#endif + +///////////////////////////////// +// String utility functions. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_STRINGS + +size_t EsCStringLength(const char *string) { + if (!string) { + return 0; + } + + size_t size = 0; + + while (true) { + if (*string) { + size++; + string++; + } else { + return size; + } + } +} + +size_t EsStringLength(const char *string, uint8_t end) { + if (!string) { + return 0; + } + + size_t size = 0; + + while (true) { + if (*string != end) { + size++; + string++; + } else { + return size; + } + } +} + +typedef void (*FormatCallback)(int character, void *data); + +void _FormatInteger(FormatCallback callback, void *callbackData, long value, int pad = 0, bool simple = false) { + char buffer[32]; + + if (value < 0) { + callback('-', callbackData); + } else if (value == 0) { + for (int i = 0; i < (pad ?: 1); i++) { + callback('0', callbackData); + } + + return; + } + + int bp = 0; + + while (value) { + int digit = (value % 10); + if (digit < 0) digit = -digit; + buffer[bp++] = '0' + digit; + value /= 10; + } + + int cr = bp % 3; + + for (int i = 0; i < pad - bp; i++) { + callback('0', callbackData); + } + + for (int i = bp - 1; i >= 0; i--, cr--) { + if (!cr && !pad) { + if (i != bp - 1 && !simple) callback(',', callbackData); + cr = 3; + } + + callback(buffer[i], callbackData); + } +} + +void WriteCStringToCallback(FormatCallback callback, void *callbackData, const char *cString) { + while (cString && *cString) { + callback(utf8_value(cString), callbackData); + cString = utf8_advance(cString); + } +} + +void _StringFormat(FormatCallback callback, void *callbackData, const char *format, va_list arguments) { + int c; + int pad = 0; + uint32_t flags = 0; + + char buffer[32]; + const char *hexChars = "0123456789ABCDEF"; + + while ((c = utf8_value((char *) format))) { + if (c == '%') { + repeat:; + format = utf8_advance((char *) format); + c = utf8_value((char *) format); + + switch (c) { + case 'd': { + long value = va_arg(arguments, long); + _FormatInteger(callback, callbackData, value, pad, flags & ES_STRING_FORMAT_SIMPLE); + } break; + + case 'i': { + int value = va_arg(arguments, int); + _FormatInteger(callback, callbackData, value, pad, flags & ES_STRING_FORMAT_SIMPLE); + } break; + + case 'D': { + long value = va_arg(arguments, long); + + if (value == 0) { + WriteCStringToCallback(callback, callbackData, "empty"); + } else if (value < 1000) { + _FormatInteger(callback, callbackData, value, pad); + WriteCStringToCallback(callback, callbackData, " B"); + } else if (value < 1000000) { + _FormatInteger(callback, callbackData, value / 1000, pad); + callback('.', callbackData); + _FormatInteger(callback, callbackData, (value / 100) % 10, pad); + WriteCStringToCallback(callback, callbackData, " KB"); + } else if (value < 1000000000) { + _FormatInteger(callback, callbackData, value / 1000000, pad); + callback('.', callbackData); + _FormatInteger(callback, callbackData, (value / 100000) % 10, pad); + WriteCStringToCallback(callback, callbackData, " MB"); + } else { + _FormatInteger(callback, callbackData, value / 1000000000, pad); + callback('.', callbackData); + _FormatInteger(callback, callbackData, (value / 100000000) % 10, pad); + WriteCStringToCallback(callback, callbackData, " GB"); + } + } break; + + case 'R': { + EsRectangle value = va_arg(arguments, EsRectangle); + callback('{', callbackData); + _FormatInteger(callback, callbackData, value.l); + callback('-', callbackData); + callback('>', callbackData); + _FormatInteger(callback, callbackData, value.r); + callback(';', callbackData); + _FormatInteger(callback, callbackData, value.t); + callback('-', callbackData); + callback('>', callbackData); + _FormatInteger(callback, callbackData, value.b); + callback('}', callbackData); + } break; + + case 'X': { + uintptr_t value = va_arg(arguments, uintptr_t); + callback(hexChars[(value & 0xF0) >> 4], callbackData); + callback(hexChars[(value & 0xF)], callbackData); + } break; + + case 'W': { + uintptr_t value = va_arg(arguments, uintptr_t); + callback(hexChars[(value & 0xF000) >> 12], callbackData); + callback(hexChars[(value & 0xF00) >> 8], callbackData); + callback(hexChars[(value & 0xF0) >> 4], callbackData); + callback(hexChars[(value & 0xF)], callbackData); + } break; + + case 'x': { + uintptr_t value = va_arg(arguments, uintptr_t); + bool simple = flags & ES_STRING_FORMAT_SIMPLE; + if (!simple) callback('0', callbackData); + if (!simple) callback('x', callbackData); + int bp = 0; + while (value) { + buffer[bp++] = hexChars[value % 16]; + value /= 16; + } + int j = 0, k = 0; + for (int i = 0; i < 16 - bp; i++) { + callback('0', callbackData); + j++;k++;if (k != 16 && j == 4 && !simple) { callback('_',callbackData); } j&=3; + } + for (int i = bp - 1; i >= 0; i--) { + callback(buffer[i], callbackData); + j++;k++;if (k != 16 && j == 4 && !simple) { callback('_',callbackData); } j&=3; + } + } break; + + case 'c': { + callback(va_arg(arguments, int), callbackData); + } break; + + case '%': { + callback('%', callbackData); + } break; + + case 's': { + size_t length = va_arg(arguments, size_t); + char *string = va_arg(arguments, char *); + char *position = string; + + while (position < string + length) { + callback(utf8_value(position), callbackData); + position = utf8_advance(position); + } + } break; + + case 'z': { + const char *string = va_arg(arguments, const char *); + if (!string) string = "[null]"; + WriteCStringToCallback(callback, callbackData, string); + } break; + + case 'F': { + double number = va_arg(arguments, double); + + if (__builtin_isnan(number)) { + WriteCStringToCallback(callback, callbackData, "NaN"); + break; + } else if (__builtin_isinf(number)) { + if (number < 0) callback('-', callbackData); + WriteCStringToCallback(callback, callbackData, "inf"); + break; + } + + if (number < 0) { + callback('-', callbackData); + number = -number; + } + + int digits[32]; + size_t digitCount = 0; + const size_t maximumDigits = 12; + + int64_t integer = number; + number -= integer; + // number is now in the range [0,1). + + while (number && digitCount <= maximumDigits) { + // Extract the fractional digits. + number *= 10; + int digit = number; + number -= digit; + digits[digitCount++] = digit; + } + + if (digitCount > maximumDigits) { + if (digits[maximumDigits] >= 5) { + // Round up. + for (intptr_t i = digitCount - 2; i >= -1; i--) { + if (i == -1) { + integer++; + } else { + digits[i]++; + + if (digits[i] == 10) { + digits[i] = 0; + } else { + break; + } + } + } + } + + // Hide the last digit. + digitCount = maximumDigits; + } + + // Trim trailing zeroes. + while (digitCount) { + if (!digits[digitCount - 1]) { + digitCount--; + } else { + break; + } + } + + // Integer digits. + _FormatInteger(callback, callbackData, integer, pad, flags & ES_STRING_FORMAT_SIMPLE); + + // Decimal separator. + if (digitCount) { + callback('.', callbackData); + } + + // Fractional digits. + for (uintptr_t i = 0; i < digitCount; i++) { + callback('0' + digits[i], callbackData); + } + } break; + + case '*': { + pad = va_arg(arguments, int); + goto repeat; + } break; + + case 'f': { + flags = va_arg(arguments, uint32_t); + goto repeat; + } break; + } + + pad = 0; + flags = 0; + } else { + callback(c, callbackData); + } + + format = utf8_advance((char *) format); + } +} + +typedef struct { + char *buffer; + size_t bytesRemaining, bytesWritten; + bool full; +} EsStringFormatInformation; + +void StringFormatCallback(int character, void *_fsi) { + EsStringFormatInformation *fsi = (EsStringFormatInformation *) _fsi; + + if (fsi->full) { + return; + } + + char data[4]; + size_t bytes = utf8_encode(character, data); + + if (fsi->buffer) { + if (fsi->bytesRemaining < bytes && fsi->bytesRemaining != ES_STRING_FORMAT_ENOUGH_SPACE) { + fsi->full = true; + return; + } else { + utf8_encode(character, fsi->buffer); + fsi->buffer += bytes; + fsi->bytesWritten += bytes; + if (fsi->bytesRemaining != ES_STRING_FORMAT_ENOUGH_SPACE) fsi->bytesRemaining -= bytes; + } + } +} + +ptrdiff_t EsStringFormat(char *buffer, size_t bufferLength, const char *format, ...) { + EsStringFormatInformation fsi = {buffer, bufferLength, 0}; + va_list arguments; + va_start(arguments, format); + _StringFormat(StringFormatCallback, &fsi, format, arguments); + va_end(arguments); + return fsi.bytesWritten; +} + +ptrdiff_t EsStringFormatV(char *buffer, size_t bufferLength, const char *format, va_list arguments) { + EsStringFormatInformation fsi = {buffer, bufferLength, 0}; + _StringFormat(StringFormatCallback, &fsi, format, arguments); + return fsi.bytesWritten; +} + +void StringFormatCallback2(int character, void *_buffer) { + EsBuffer *buffer = (EsBuffer *) _buffer; + char data[4]; + size_t bytes = utf8_encode(character, data); + EsBufferWrite(buffer, data, bytes); +} + +void EsBufferFormat(EsBuffer *buffer, EsCString format, ...) { + va_list arguments; + va_start(arguments, format); + if (!buffer->error) _StringFormat(StringFormatCallback2, buffer, format, arguments); + va_end(arguments); +} + +void EsBufferFormatV(EsBuffer *buffer, EsCString format, va_list arguments) { + if (!buffer->error) _StringFormat(StringFormatCallback2, buffer, format, arguments); +} + +#ifndef KERNEL +char *EsCStringDuplicate(const char *string) { + size_t length = EsCStringLength(string); + char *buffer = (char *) EsHeapAllocate(length + 1, false); + if (!buffer) return nullptr; + EsMemoryCopy(buffer, string, length); + buffer[length] = 0; + return buffer; +} + +char *EsStringZeroTerminate(const char *string, ptrdiff_t stringBytes) { + if (stringBytes == -1) stringBytes = EsCStringLength(string); + char *result = (char *) EsHeapAllocate(stringBytes + 1, false); + if (!result) return nullptr; + result[stringBytes] = 0; + EsMemoryCopy(result, string, stringBytes); + return result; +} + +char *EsStringAllocateAndFormatV(size_t *bytes, const char *format, va_list arguments1) { + size_t needed = 0; + + va_list arguments2; + va_copy(arguments2, arguments1); + + _StringFormat([] (int character, void *data) { + size_t *needed = (size_t *) data; + *needed = *needed + utf8_encode(character, nullptr); + }, &needed, format, arguments1); + + if (bytes) *bytes = needed; + char *buffer = (char *) EsHeapAllocate(needed + 1, false); + char *position = buffer; + buffer[needed] = 0; + + _StringFormat([] (int character, void *data) { + char **position = (char **) data; + *position = *position + utf8_encode(character, *position); + }, &position, format, arguments2); + + va_end(arguments2); + + return buffer; +} + +char *EsStringAllocateAndFormat(size_t *bytes, const char *format, ...) { + va_list arguments; + va_start(arguments, format); + char *buffer = EsStringAllocateAndFormatV(bytes, format, arguments); + va_end(arguments); + return buffer; +} + +const char *EsStringFormatTemporary(const char *format, ...) { + EsMessageMutexCheck(); + static char *buffer = nullptr; + EsHeapFree(buffer); + va_list arguments; + va_start(arguments, format); + size_t bytes = 0; + buffer = EsStringAllocateAndFormatV(&bytes, format, arguments); + va_end(arguments); + return buffer; +} +#endif + +int64_t EsStringParseInteger(const char **string, size_t *length, int base) { + int64_t value = 0; + bool overflow = false; + + while (*length) { + char c = (*string)[0]; + + int64_t digit = 0; + + if (c >= 'a' && c <= 'z') { + digit = c - 'a' + 10; + } else if (c >= 'A' && c <= 'Z') { + digit = c - 'A' + 10; + } else if (c >= '0' && c <= '9') { + digit = c - '0'; + } else { + break; + } + + if (digit >= base) { + break; + } + + int64_t oldValue = value; + + value *= base; + value += digit; + + if (value / base != oldValue) { + overflow = true; + } + + (*string)++; + (*length)--; + } + + if (overflow) value = LONG_MAX; + return value; +} + +int EsStringCompareRaw(const char *s1, ptrdiff_t length1, const char *s2, ptrdiff_t length2) { + if (length1 == -1) length1 = EsCStringLength(s1); + if (length2 == -1) length2 = EsCStringLength(s2); + + while (length1 || length2) { + if (!length1) return -1; + if (!length2) return 1; + + char c1 = *s1; + char c2 = *s2; + + if (c1 != c2) { + return c1 - c2; + } + + length1--; + length2--; + s1++; + s2++; + } + + return 0; +} + +int EsStringCompare(const char *s1, ptrdiff_t _length1, const char *s2, ptrdiff_t _length2) { + if (_length1 == -1) _length1 = EsCStringLength(s1); + if (_length2 == -1) _length2 = EsCStringLength(s2); + size_t length1 = _length1, length2 = _length2; + + while (length1 || length2) { + if (!length1) return -1; + if (!length2) return 1; + + char c1 = *s1; + char c2 = *s2; + + if (c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9') { + int64_t n1 = EsStringParseInteger(&s1, &length1, 10); + int64_t n2 = EsStringParseInteger(&s2, &length2, 10); + + if (n1 != n2) { + if (n1 > n2) return 1; + if (n1 < n2) return -1; + } + } else { + if (c1 >= 'a' && c1 <= 'z') c1 = c1 - 'a' + 'A'; + if (c2 >= 'a' && c2 <= 'z') c2 = c2 - 'a' + 'A'; + if (c1 == '.') c1 = ' '; else if (c1 == ' ') c1 = '.'; + if (c2 == '.') c2 = ' '; else if (c2 == ' ') c2 = '.'; + + if (c1 != c2) { + if (c1 > c2) return 1; + if (c1 < c2) return -1; + } + + length1--; + length2--; + s1++; + s2++; + } + } + + return 0; +} + +bool EsStringStartsWith(const char *string, intptr_t _stringBytes, const char *prefix, intptr_t _prefixBytes, bool caseInsensitive) { + if (_stringBytes == -1) _stringBytes = EsCStringLength(string); + if (_prefixBytes == -1) _prefixBytes = EsCStringLength(prefix); + size_t stringBytes = _stringBytes, prefixBytes = _prefixBytes; + + while (true) { + if (!prefixBytes) return true; + if (!stringBytes) return false; + + char c1 = *string; + char c2 = *prefix; + + if (caseInsensitive) { + if (c1 >= 'a' && c1 <= 'z') c1 = c1 - 'a' + 'A'; + if (c2 >= 'a' && c2 <= 'z') c2 = c2 - 'a' + 'A'; + } + + if (c1 != c2) return false; + + stringBytes--; + prefixBytes--; + string++; + prefix++; + } +} + +bool EsStringEndsWith(const char *string, intptr_t _stringBytes, const char *prefix, intptr_t _prefixBytes, bool caseInsensitive) { + if (_stringBytes == -1) _stringBytes = EsCStringLength(string); + if (_prefixBytes == -1) _prefixBytes = EsCStringLength(prefix); + size_t stringBytes = _stringBytes, prefixBytes = _prefixBytes; + string += stringBytes - 1; + prefix += prefixBytes - 1; + + while (true) { + if (!prefixBytes) return true; + if (!stringBytes) return false; + + char c1 = *string; + char c2 = *prefix; + + if (caseInsensitive) { + if (c1 >= 'a' && c1 <= 'z') c1 = c1 - 'a' + 'A'; + if (c2 >= 'a' && c2 <= 'z') c2 = c2 - 'a' + 'A'; + } + + if (c1 != c2) return false; + + stringBytes--; + prefixBytes--; + string--; + prefix--; + } +} + +uint32_t EsColorParse(const char *string, ptrdiff_t bytes) { + if (bytes == -1) { + bytes = EsCStringLength(string); + } + + int digits[8], digitCount = 0; + ptrdiff_t position = 0; + + while (position != bytes && !EsCRTisxdigit(string[position])) { + position++; + } + + for (int i = 0; i < 8 && position != bytes; i++) { + char c = string[position++]; + + if (EsCRTisxdigit(c)) { + digits[digitCount++] = EsCRTisdigit(c) ? (c - '0') : EsCRTisupper(c) ? (c - 'A' + 10) : (c - 'a' + 10); + } else { + break; + } + } + + uint32_t color = 0; + + if (digitCount == 3) { + color = 0xFF000000 | (digits[0] << 20) | (digits[0] << 16) | (digits[1] << 12) | (digits[1] << 8) | (digits[2] << 4) | (digits[2] << 0); + } else if (digitCount == 4) { + color = (digits[0] << 28 | digits[0] << 24) | (digits[1] << 20) | (digits[1] << 16) + | (digits[2] << 12) | (digits[2] << 8) | (digits[3] << 4) | (digits[3] << 0); + } else if (digitCount == 5) { + color = (digits[0] << 28 | digits[1] << 24) | (digits[2] << 20) | (digits[2] << 16) + | (digits[3] << 12) | (digits[3] << 8) | (digits[4] << 4) | (digits[4] << 0); + } else if (digitCount == 6) { + color = 0xFF000000 | (digits[0] << 20) | (digits[1] << 16) | (digits[2] << 12) | (digits[3] << 8) | (digits[4] << 4) | (digits[5] << 0); + } else if (digitCount == 8) { + color = (digits[0] << 28) | (digits[1] << 24) | (digits[2] << 20) | (digits[3] << 16) + | (digits[4] << 12) | (digits[5] << 8) | (digits[6] << 4) | (digits[7] << 0); + } + + return color; +} + +static int64_t ConvertCharacterToDigit(int character, int base) { + int64_t result = -1; + + if (character >= '0' && character <= '9') { + result = character - '0'; + } else if (character >= 'A' && character <= 'Z') { + result = character - 'A' + 10; + } else if (character >= 'a' && character <= 'z') { + result = character - 'a' + 10; + } + + if (result >= base) { + result = -1; + } + + return result; +} + +int64_t EsIntegerParse(const char *text, ptrdiff_t bytes) { + if (bytes == -1) bytes = EsCStringLength(text); + + int base = 10; + + if (bytes > 2 && text[0] == '0' && text[1] == 'x') { + text += 2, bytes -= 2; + base = 16; + } + + const char *end = text + bytes; + + bool negative = false; + int64_t result = 0; + + while (text < end) { + char c = *text; + + if (c == '-') { + negative = true; + } + + if (c >= '0' && c <= '9') { + result *= base; + result += c - '0'; + } else if (c >= 'A' && c <= 'F' && base == 16) { + result *= base; + result += c - 'A' + 10; + } else if (c >= 'a' && c <= 'f' && base == 16) { + result *= base; + result += c - 'a' + 10; + } + + text++; + } + + return negative ? -result : result; +} + +bool EsStringFormatAppendV(char *buffer, size_t bufferLength, size_t *bufferPosition, const char *format, va_list arguments) { + buffer += *bufferPosition; + bufferLength -= *bufferPosition; + EsStringFormatInformation fsi = {buffer, bufferLength, 0}; + _StringFormat(StringFormatCallback, &fsi, format, arguments); + *bufferPosition += fsi.bytesWritten; + return !fsi.full; +} + +bool EsStringFormatAppend(char *buffer, size_t bufferLength, size_t *bufferPosition, const char *format, ...) { + va_list arguments; + va_start(arguments, format); + bool result = EsStringFormatAppendV(buffer, bufferLength, bufferPosition, format, arguments); + va_end(arguments); + return result; +} + +double EsDoubleParse(const char *nptr, ptrdiff_t maxBytes, char **endptr) { + if (maxBytes == -1) maxBytes = EsCStringLength(nptr); + const char *end = nptr + maxBytes; + if (nptr == end) return 0; + + while (nptr != end && EsCRTisspace(*nptr)) { + nptr++; + } + + if (nptr == end) return 0; + + bool positive = true; + + if (*nptr == '+') { + positive = true; + nptr++; + } else if (*nptr == '-') { + positive = false; + nptr++; + } + + if (nptr == end) return 0; + + double value = 0, scale = 0.1; + bool seenDecimalPoint = false; + + while (nptr != end) { + char c = *nptr; + + if (c == '.' && !seenDecimalPoint) { + seenDecimalPoint = true; + } else if (c >= '0' && c <= '9') { + if (seenDecimalPoint) { + value += scale * (c - '0'); + scale *= 0.1; + } else { + value = value * 10; + value += c - '0'; + } + } else if (c == ',') { + } else { + break; + } + + nptr++; + } + + if (!positive) { + value = -value; + } + + if (endptr) *endptr = (char *) nptr; + return value; +} + +#endif + +///////////////////////////////// +// Memory utility functions. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_MEMORY + +void EsMemoryCopy(void *_destination, const void *_source, size_t bytes) { + // TODO Prevent this from being optimised out in the kernel. + + if (!bytes) { + return; + } + + uint8_t *destination = (uint8_t *) _destination; + uint8_t *source = (uint8_t *) _source; + +#ifdef ARCH_X86_64 + while (bytes >= 16) { + _mm_storeu_si128((__m128i *) destination, + _mm_loadu_si128((__m128i *) source)); + + source += 16; + destination += 16; + bytes -= 16; + } +#endif + + while (bytes >= 1) { + ((uint8_t *) destination)[0] = ((uint8_t *) source)[0]; + + source += 1; + destination += 1; + bytes -= 1; + } +} + +void EsMemoryCopyReverse(void *_destination, void *_source, size_t bytes) { + // TODO Prevent this from being optimised out in the kernel. + + if (!bytes) { + return; + } + + uint8_t *destination = (uint8_t *) _destination; + uint8_t *source = (uint8_t *) _source; + + destination += bytes - 1; + source += bytes - 1; + + while (bytes >= 1) { + ((uint8_t *) destination)[0] = ((uint8_t *) source)[0]; + + source -= 1; + destination -= 1; + bytes -= 1; + } +} + +void EsMemoryZero(void *destination, size_t bytes) { + // TODO Prevent this from being optimised out in the kernel. + + if (!bytes) { + return; + } + + for (uintptr_t i = 0; i < bytes; i++) { + ((uint8_t *) destination)[i] = 0; + } +} + +void EsMemoryMove(void *_start, void *_end, intptr_t amount, bool zeroEmptySpace) { + // TODO Prevent this from being optimised out in the kernel./ + + uint8_t *start = (uint8_t *) _start; + uint8_t *end = (uint8_t *) _end; + + if (end < start) { + EsPrint("MemoryMove end < start: %x %x %x %d\n", start, end, amount, zeroEmptySpace); + return; + } + + if (amount > 0) { + EsMemoryCopyReverse(start + amount, start, end - start); + + if (zeroEmptySpace) { + EsMemoryZero(start, amount); + } + } else if (amount < 0) { + EsMemoryCopy(start + amount, start, end - start); + + if (zeroEmptySpace) { + EsMemoryZero(end + amount, -amount); + } + } +} + +int EsMemoryCompare(const void *a, const void *b, size_t bytes) { + if (!bytes) { + return 0; + } + + const uint8_t *x = (const uint8_t *) a; + const uint8_t *y = (const uint8_t *) b; + + for (uintptr_t i = 0; i < bytes; i++) { + if (x[i] < y[i]) { + return -1; + } else if (x[i] > y[i]) { + return 1; + } + } + + return 0; +} + +uint8_t EsMemorySumBytes(uint8_t *source, size_t bytes) { + if (!bytes) { + return 0; + } + + uint8_t total = 0; + + for (uintptr_t i = 0; i < bytes; i++) { + total += source[i]; + } + + return total; +} + +void EsMemoryFill(void *from, void *to, uint8_t byte) { + uint8_t *a = (uint8_t *) from; + uint8_t *b = (uint8_t *) to; + while (a != b) *a = byte, a++; +} + +#endif + +///////////////////////////////// +// Printing. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_PRINTING + +#ifdef USE_STB_SPRINTF +#define STB_SPRINTF_IMPLEMENTATION +#include "stb_sprintf.h" +#endif + +#ifndef KERNEL + +static struct { + EsMutex mutex; + +#define PRINT_BUFFER_SIZE (1024) + char buffer[PRINT_BUFFER_SIZE]; + uintptr_t bufferPosition; +} printing; + +void PrintCallback(int character, void *) { + if (printing.bufferPosition >= PRINT_BUFFER_SIZE - 16) { + EsSyscall(ES_SYSCALL_PRINT, (uintptr_t) printing.buffer, printing.bufferPosition, 0, 0); + printing.bufferPosition = 0; + } + + printing.bufferPosition += utf8_encode(character, printing.buffer + printing.bufferPosition); +} + +void EsPrint(const char *format, ...) { + EsMutexAcquire(&printing.mutex); + va_list arguments; + va_start(arguments, format); + _StringFormat(PrintCallback, nullptr, format, arguments); + va_end(arguments); + EsSyscall(ES_SYSCALL_PRINT, (uintptr_t) printing.buffer, printing.bufferPosition, 0, 0); + printing.bufferPosition = 0; + EsMutexRelease(&printing.mutex); +} + +void EsPrintDirect(const char *string, ptrdiff_t stringLength) { + if (stringLength == -1) stringLength = EsCStringLength(string); + EsSyscall(ES_SYSCALL_PRINT, (uintptr_t) string, stringLength, 0, 0); +} + +void EsPrintHelloWorld() { + EsPrint("Hello, world.\n"); +} + +#endif + +#endif + +///////////////////////////////// +// Timing utility functions. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_TIMING + +#ifdef KERNEL + +#if 0 +int __tsi = 1; +#define TS(...) for (int i = 0; i < __tsi; i++) EsPrint("] "); EsPrint(__VA_ARGS__); uint64_t __ts = KGetTimeInMs(); __tsi++; \ + EsDefer({__tsi--; for (int i = 0; i < __tsi; i++) EsPrint("] "); \ + EsPrint("> %d ms\n", (KGetTimeInMs() - __ts)); \ + for (int i = 0; i < __tsi; i++) EsPrint("] "); EsPrint("\n");}) +#define TSP(...) for (int i = 0; i < __tsi; i++) EsPrint("] "); EsPrint(__VA_ARGS__, (KGetTimeInMs() - __ts)); +#else +#define TS(...) +#define TSP(...) +#endif + +#else + +#if 0 +int __tsi = 1; +#define TS(...) for (int i = 0; i < __tsi; i++) EsPrint("| "); EsPrint(__VA_ARGS__); uint64_t __ts = EsTimeStamp(); __tsi++; \ + EsDefer({__tsi--; for (int i = 0; i < __tsi; i++) EsPrint("| "); \ + EsPrint("> %d ms (%d mcs)\n", (EsTimeStamp() - __ts) / (api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] * 1000 + 1), (EsTimeStamp() - __ts) / (api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] + 1)); \ + for (int i = 0; i < __tsi; i++) EsPrint("| "); EsPrint("\n");}) +#define TSP(...) for (int i = 0; i < __tsi; i++) EsPrint("| "); EsPrint(__VA_ARGS__, (EsTimeStamp() - __ts) / \ + (api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] * 1000 + 1)); +#else +#define TS(...) +#define TSP(...) +#endif + +#endif + +#endif + +///////////////////////////////// +// Random number generator. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_RANDOM + +struct RNGState { + uint64_t s[4]; + EsSpinlock lock; +}; + +RNGState rngState; + +void EsRandomAddEntropy(uint64_t x) { + EsSpinlockAcquire(&rngState.lock); + + for (uintptr_t i = 0; i < 4; i++) { + x += 0x9E3779B97F4A7C15; + + uint64_t result = x; + result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9; + result = (result ^ (result >> 27)) * 0x94D049BB133111EB; + rngState.s[i] ^= result ^ (result >> 31); + } + + EsSpinlockRelease(&rngState.lock); +} + +void EsRandomSeed(uint64_t x) { + EsSpinlockAcquire(&rngState.lock); + + rngState.s[0] = rngState.s[1] = rngState.s[2] = rngState.s[3] = 0; + + for (uintptr_t i = 0; i < 4; i++) { + x += 0x9E3779B97F4A7C15; + + uint64_t result = x; + result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9; + result = (result ^ (result >> 27)) * 0x94D049BB133111EB; + rngState.s[i] = result ^ (result >> 31); + } + + EsSpinlockRelease(&rngState.lock); +} + +uint64_t EsRandomU64() { + EsSpinlockAcquire(&rngState.lock); + + uint64_t result = rngState.s[1] * 5; + result = ((result << 7) | (result >> 57)) * 9; + + uint64_t t = rngState.s[1] << 17; + rngState.s[2] ^= rngState.s[0]; + rngState.s[3] ^= rngState.s[1]; + rngState.s[1] ^= rngState.s[2]; + rngState.s[0] ^= rngState.s[3]; + rngState.s[2] ^= t; + rngState.s[3] = (rngState.s[3] << 45) | (rngState.s[3] >> 19); + + EsSpinlockRelease(&rngState.lock); + + return result; +} + +uint8_t EsRandomU8() { + return (uint8_t) EsRandomU64(); +} + +#endif + +///////////////////////////////// +// Standard algorithms. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_ALGORITHMS + +void EsSortWithSwapCallback(void *_base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, EsGeneric), + EsGeneric argument, void (*swap)(const void *, const void *, EsGeneric)) { + if (nmemb <= 1) return; + uint8_t *base = (uint8_t *) _base; + intptr_t i = -1, j = nmemb; + + while (true) { + while (compar(base + ++i * size, base, argument) < 0); + while (compar(base + --j * size, base, argument) > 0); + if (i >= j) break; + swap(base + i * size, base + j * size, argument); + } + + EsSortWithSwapCallback(base, ++j, size, compar, argument, swap); + EsSortWithSwapCallback(base + j * size, nmemb - j, size, compar, argument, swap); +} + +void EsSort(void *_base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, EsGeneric), EsGeneric argument) { + if (nmemb <= 1) return; + + uint8_t *base = (uint8_t *) _base; + uint8_t *swap = (uint8_t *) alloca(size); + + intptr_t i = -1, j = nmemb; + + while (true) { + while (compar(base + ++i * size, base, argument) < 0); + while (compar(base + --j * size, base, argument) > 0); + + if (i >= j) break; + + EsMemoryCopy(swap, base + i * size, size); + EsMemoryCopy(base + i * size, base + j * size, size); + EsMemoryCopy(base + j * size, swap, size); + } + + EsSort(base, ++j, size, compar, argument); + EsSort(base + j * size, nmemb - j, size, compar, argument); +} + +#endif + +///////////////////////////////// +// Miscellaneous. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_MISCELLANEOUS + +void EnterDebugger() { + // Do nothing. +} + +#ifndef KERNEL +size_t EsPathFindUniqueName(char *buffer, size_t originalBytes, size_t bufferBytes) { + // TODO Check that this runs in a reasonable amount of time when all files are already present. + + size_t extensionPoint = originalBytes; + + for (uintptr_t i = 0; i < originalBytes; i++) { + if (buffer[i] == '.') { + extensionPoint = i; + } + } + + if (!EsPathExists(buffer, originalBytes)) { + return originalBytes; + } + + char *buffer2 = (char *) EsHeapAllocate(bufferBytes, false); + EsDefer(EsHeapFree(buffer2)); + + uintptr_t attempt = 2; + + while (attempt < 1000) { + size_t length = EsStringFormat(buffer2, bufferBytes, "%s %d%s", extensionPoint, buffer, + attempt, originalBytes - extensionPoint, buffer + extensionPoint); + + if (!EsPathExists(buffer2, length)) { + EsMemoryCopy(buffer, buffer2, length); + return length; + } else { + attempt++; + } + } + + return 0; +} + +uint8_t *EsImageLoad(const void *file, size_t fileSize, uint32_t *imageX, uint32_t *imageY, int imageChannels) { +#ifdef USE_STB_IMAGE + int unused; + uint32_t *image = (uint32_t *) stbi_load_from_memory((uint8_t *) file, fileSize, (int *) imageX, (int *) imageY, &unused, imageChannels); + + for (uintptr_t j = 0; j < *imageY; j++) { + for (uintptr_t i = 0; i < *imageX; i++) { + uint32_t in = image[i + j * *imageX]; + uint32_t red = ((in & 0xFF) << 16), green = (in & 0xFF00FF00), blue = ((in & 0xFF0000) >> 16); + image[i + j * *imageX] = red | green | blue; + } + } + + return (uint8_t *) image; +#else + (void) imageChannels; + PNGReader reader = {}; + reader.buffer = file; + reader.bytes = fileSize; + uint32_t *bits; + bool success = PNGParse(&reader, &bits, imageX, imageY, [] (size_t s) { return EsHeapAllocate(s, false); }, [] (void *p) { EsHeapFree(p); }); + return success ? (uint8_t *) bits : nullptr; +#endif +} + +void LoadImage(const void *path, ptrdiff_t pathBytes, void *destination, int destinationWidth, int destinationHeight, bool fromMemory) { + int width = 0, height = 0; + uint32_t *image = nullptr; + + if (!fromMemory) { + size_t fileSize; + void *file = EsFileReadAll((const char *) path, pathBytes, &fileSize); + + if (file) { + image = (uint32_t *) EsImageLoad((uint8_t *) file, fileSize, (uint32_t *) &width, (uint32_t *) &height, 4); + EsHeapFree(file); + } + } else { + image = (uint32_t *) EsImageLoad((uint8_t *) path, pathBytes, (uint32_t *) &width, (uint32_t *) &height, 4); + } + + int cx = destinationWidth / 2 - width / 2, cy = destinationHeight / 2 - height / 2; + + for (int j = 0; j < destinationHeight; j++) { + uint32_t *pixel = (uint32_t *) ((uint8_t *) destination + j * destinationWidth * 4); + + for (int i = 0; i < destinationWidth; i++, pixel++) { + if (i - cx < 0 || i - cx >= width || j - cy < 0 || j - cy >= height) { + *pixel = 0x738393; + } else { + *pixel = image[i - cx + (j - cy) * width]; + } + } + } + + EsHeapFree(image); +} +#endif + +#endif + +///////////////////////////////// +// Synchronisation. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_SYNC + +void EsSpinlockAcquire(EsSpinlock *spinlock) { + __sync_synchronize(); + while (__sync_val_compare_and_swap(&spinlock->state, 0, 1)); + __sync_synchronize(); +} + +void EsSpinlockRelease(EsSpinlock *spinlock) { + __sync_synchronize(); + + if (!spinlock->state) { + EsPanic("EsSpinlockRelease - Spinlock %x not acquired.\n", spinlock); + } + + spinlock->state = 0; + __sync_synchronize(); +} + +#ifndef KERNEL + +void EsMutexAcquire(EsMutex *mutex) { + bool acquired = false; + + while (true) { + EsSpinlockAcquire(&mutex->spinlock); + + if (mutex->event == ES_INVALID_HANDLE) { + mutex->event = EsEventCreate(false); + } + + if (mutex->state == 0) { + acquired = true; + mutex->state = 1; + } + + if (acquired) { + // TODO Test this. + EsSpinlockRelease(&mutex->spinlock); + return; + } + + __sync_fetch_and_add(&mutex->queued, 1); + EsEventReset(mutex->event); + EsSpinlockRelease(&mutex->spinlock); + EsWaitSingle(mutex->event); + __sync_fetch_and_sub(&mutex->queued, 1); + } +} + +void EsMutexRelease(EsMutex *mutex) { + volatile bool queued = false; + + EsSpinlockAcquire(&mutex->spinlock); + + if (!mutex->state) { + EsPanic("EsMutexRelease - Mutex not acquired."); + } + + mutex->state = 0; + + if (mutex->queued) { + queued = true; + EsEventSet(mutex->event); + } + + EsSpinlockRelease(&mutex->spinlock); + + if (queued) { + EsSchedulerYield(); + } +} + +void EsMutexDestroy(EsMutex *mutex) { + EsAssert(!mutex->state && !mutex->queued && !mutex->spinlock.state); + + if (mutex->event != ES_INVALID_HANDLE) { + EsHandleClose(mutex->event); + mutex->event = ES_INVALID_HANDLE; + } +} + +#endif + +#endif + +///////////////////////////////// +// Byte swapping. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_BYTE_SWAP + +uint16_t ByteSwap16(uint16_t x) { + return (x << 8) | (x >> 8); +} + +uint32_t ByteSwap32(uint32_t x) { + return ((x & 0xFF000000) >> 24) + | ((x & 0x000000FF) << 24) + | ((x & 0x00FF0000) >> 8) + | ((x & 0x0000FF00) << 8); +} + +uint16_t SwapBigEndian16(uint16_t x) { + return ByteSwap16(x); +} + +uint32_t SwapBigEndian32(uint32_t x) { + return ByteSwap32(x); +} + +#endif + +///////////////////////////////// +// C standard library. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_CSTDLIB + +void *EsCRTmemset(void *s, int c, size_t n) { + uint8_t *s8 = (uint8_t *) s; + for (uintptr_t i = 0; i < n; i++) { + s8[i] = (uint8_t) c; + } + return s; +} + +void *EsCRTmemcpy(void *dest, const void *src, size_t n) { + uint8_t *dest8 = (uint8_t *) dest; + const uint8_t *src8 = (const uint8_t *) src; + for (uintptr_t i = 0; i < n; i++) { + dest8[i] = src8[i]; + } + return dest; +} + +void *EsCRTmemmove(void *dest, const void *src, size_t n) { + if ((uintptr_t) dest < (uintptr_t) src) { + return EsCRTmemcpy(dest, src, n); + } else { + uint8_t *dest8 = (uint8_t *) dest; + const uint8_t *src8 = (const uint8_t *) src; + for (uintptr_t i = n; i; i--) { + dest8[i - 1] = src8[i - 1]; + } + return dest; + } +} + +char *EsCRTstrdup(const char *string) { + if (!string) return nullptr; + size_t length = EsCRTstrlen(string) + 1; + char *memory = (char *) EsCRTmalloc(length); + if (!memory) return nullptr; + EsCRTmemcpy(memory, string, length); + return memory; +} + +size_t EsCRTstrlen(const char *s) { + size_t n = 0; + while (s[n]) n++; + return n; +} + +size_t EsCRTstrnlen(const char *s, size_t maxlen) { + size_t n = 0; + while (s[n] && maxlen--) n++; + return n; +} + +int EsCRTabs(int n) { + if (n < 0) return 0 - n; + else return n; +} + +#ifndef KERNEL +void *EsCRTmalloc(size_t size) { + void *x = EsHeapAllocate(size, false); + return x; +} + +void *EsCRTcalloc(size_t num, size_t size) { + return EsHeapAllocate(num * size, true); +} + +void EsCRTfree(void *ptr) { + EsHeapFree(ptr); +} + +void *EsCRTrealloc(void *ptr, size_t size) { + return EsHeapReallocate(ptr, size, false); +} +#else +void *EsHeapAllocate(size_t size, bool zeroMemory, EsHeap *heap); +void EsHeapFree(void *address, size_t expectedSize, EsHeap *heap); +void *EsHeapReallocate(void *oldAddress, size_t newAllocationSize, bool zeroNewSpace, EsHeap *heap); + +void *EsCRTmalloc(size_t size) { + void *x = EsHeapAllocate(size, false, K_FIXED); + return x; +} + +void *EsCRTcalloc(size_t num, size_t size) { + return EsHeapAllocate(num * size, true, K_FIXED); +} + +void EsCRTfree(void *ptr) { + EsHeapFree(ptr, 0, K_FIXED); +} + +void *EsCRTrealloc(void *ptr, size_t size) { + return EsHeapReallocate(ptr, size, false, K_FIXED); +} +#endif + +char *EsCRTgetenv(const char *name) { + (void) name; + return nullptr; +} + +int EsCRTtoupper(int c) { + if (c >= 'a' && c <= 'z') { + return c - 'a' + 'A'; + } else { + return c; + } +} + +int EsCRTtolower(int c) { + if (c >= 'A' && c <= 'Z') { + return c - 'A' + 'a'; + } else { + return c; + } +} + +int EsCRTstrcasecmp(const char *s1, const char *s2) { + while (true) { + if (*s1 != *s2 && EsCRTtolower(*s1) != EsCRTtolower(*s2)) { + if (*s1 == 0) return -1; + else if (*s2 == 0) return 1; + return *s1 - *s2; + } + + if (*s1 == 0) { + return 0; + } + + s1++; + s2++; + } +} + +int EsCRTstrncasecmp(const char *s1, const char *s2, size_t n) { + while (n--) { + if (*s1 != *s2 && EsCRTtolower(*s1) != EsCRTtolower(*s2)) { + if (*s1 == 0) return -1; + else if (*s2 == 0) return 1; + return *s1 - *s2; + } + + if (*s1 == 0) { + return 0; + } + + s1++; + s2++; + } + + return 0; +} + +int EsCRTstrcmp(const char *s1, const char *s2) { + while (true) { + if (*s1 != *s2) { + if (*s1 == 0) return -1; + else if (*s2 == 0) return 1; + return *s1 - *s2; + } + + if (*s1 == 0) { + return 0; + } + + s1++; + s2++; + } +} + +int EsCRTstrncmp(const char *s1, const char *s2, size_t n) { + while (n--) { + if (*s1 != *s2) { + if (*s1 == 0) return -1; + else if (*s2 == 0) return 1; + return *s1 - *s2; + } + + if (*s1 == 0) { + return 0; + } + + s1++; + s2++; + } + + return 0; +} + +int EsCRTisspace(int c) { + if (c == ' ') return 1; + if (c == '\f') return 1; + if (c == '\n') return 1; + if (c == '\r') return 1; + if (c == '\t') return 1; + if (c == '\v') return 1; + + return 0; +} + +uint64_t EsCRTstrtoul(const char *nptr, char **endptr, int base) { + // TODO errno + + if (base > 36) return 0; + + while (EsCRTisspace(*nptr)) { + nptr++; + } + + if (*nptr == '+') { + nptr++; + } else if (*nptr == '-') { + nptr++; + } + + if (base == 0) { + if (nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X')) { + base = 16; + nptr += 2; + } else if (nptr[0] == '0') { + EsPrint("WARNING: strtoul with base=0, detected octal\n"); + base = 8; // Why?!? + nptr++; + } else { + base = 10; + } + } + + uint64_t value = 0; + bool overflow = false; + + while (true) { + int64_t digit = ConvertCharacterToDigit(*nptr, base); + + if (digit != -1) { + nptr++; + + uint64_t x = value; + value *= base; + value += (uint64_t) digit; + + if (value / base != x) { + overflow = true; + } + } else { + break; + } + } + + if (overflow) { + value = ULONG_MAX; + } + + if (endptr) { + *endptr = (char *) nptr; + } + + return value; +} + +size_t EsCRTstrcspn(const char *s, const char *reject) { + size_t count = 0; + + while (true) { + char character = *s; + if (!character) return count; + + const char *search = reject; + + while (true) { + char c = *search; + + if (!c) { + goto match; + } else if (character == c) { + break; + } + + search++; + } + + return count; + + match:; + count++; + s++; + } +} + +char *EsCRTstrsep(char **stringp, const char *delim) { + char *string = *stringp; + + if (!string) { + return NULL; + } + + size_t tokenLength = EsCRTstrcspn(string, delim); + + if (string[tokenLength] == 0) { + *stringp = NULL; + } else { + string[tokenLength] = 0; + *stringp = string + tokenLength + 1; + } + + return string; +} + +char *EsCRTstrcat(char *dest, const char *src) { + char *o = dest; + dest += EsCRTstrlen(dest); + + while (*src) { + *dest = *src; + src++; + dest++; + } + + *dest = 0; + + return o; +} + +long int EsCRTstrtol(const char *nptr, char **endptr, int base) { + // TODO errno + + if (base > 36) return 0; + + while (EsCRTisspace(*nptr)) { + nptr++; + } + + bool positive = true; + + if (*nptr == '+') { + positive = true; + nptr++; + } else if (*nptr == '-') { + positive = false; + nptr++; + } + + if (base == 0) { + if (nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X')) { + base = 16; + nptr += 2; + } else if (nptr[0] == '0') { + EsPrint("WARNING: strtol with base=0, detected octal\n"); + base = 8; // Why?!? + nptr++; + } else { + base = 10; + } + } + + int64_t value = 0; + bool overflow = false; + + while (true) { + int64_t digit = ConvertCharacterToDigit(*nptr, base); + + if (digit != -1) { + nptr++; + + int64_t x = value; + value *= base; + value += digit; + + if (value / base != x) { + overflow = true; + } + } else { + break; + } + } + + if (!positive) { + value = -value; + } + + if (overflow) { + value = positive ? LONG_MAX : LONG_MIN; + } + + if (endptr) { + *endptr = (char *) nptr; + } + + return value; +} + +int EsCRTatoi(const char *nptr) { + return (int) EsCRTstrtol(nptr, NULL, 10); +} + +char *EsCRTstrstr(const char *haystack, const char *needle) { + size_t haystackLength = EsCRTstrlen(haystack); + size_t needleLength = EsCRTstrlen(needle); + + if (haystackLength < needleLength) { + return nullptr; + } + + for (uintptr_t i = 0; i <= haystackLength - needleLength; i++) { + for (uintptr_t j = 0; j < needleLength; j++) { + if (haystack[i + j] != needle[j]) { + goto tryNext; + } + } + + return (char *) haystack + i; + + tryNext:; + } + + return nullptr; +} + +void EsCRTqsort(void *_base, size_t nmemb, size_t size, EsCRTComparisonCallback compar) { + if (nmemb <= 1) return; + + uint8_t *base = (uint8_t *) _base; + uint8_t *swap = (uint8_t *) alloca(size); + + intptr_t i = -1, j = nmemb; + + while (true) { + while (compar(base + ++i * size, base) < 0); + while (compar(base + --j * size, base) > 0); + + if (i >= j) break; + + EsCRTmemcpy(swap, base + i * size, size); + EsCRTmemcpy(base + i * size, base + j * size, size); + EsCRTmemcpy(base + j * size, swap, size); + } + + EsCRTqsort(base, ++j, size, compar); + EsCRTqsort(base + j * size, nmemb - j, size, compar); +} + +void *EsCRTbsearch(const void *key, const void *base, size_t num, size_t size, EsCRTComparisonCallback compar) { + if (!num) return nullptr; + + intptr_t low = 0; + intptr_t high = num - 1; + + while (low <= high) { + uintptr_t index = ((high - low) >> 1) + low; + int result = compar(key, (uint8_t *) base + size * index); + + if (result < 0) { + high = index - 1; + } else if (result > 0) { + low = index + 1; + } else { + return (uint8_t *) base + size * index; + } + } + + return nullptr; +} + +char *EsCRTstrcpy(char *dest, const char *src) { + size_t stringLength = EsCRTstrlen(src); + EsCRTmemcpy(dest, src, stringLength + 1); + return dest; +} + +char *EsCRTstpcpy(char *dest, const char *src) { + size_t stringLength = EsCRTstrlen(src); + EsCRTmemcpy(dest, src, stringLength + 1); + return dest + stringLength; +} + +size_t EsCRTstrspn(const char *s, const char *accept) { + size_t count = 0; + + while (true) { + char character = *s; + + const char *search = accept; + + while (true) { + char c = *search; + + if (!c) { + break; + } else if (character == c) { + goto match; + } + + search++; + } + + return count; + + match:; + count++; + s++; + } +} + +char *EsCRTstrrchr(const char *s, int c) { + const char *start = s; + if (!s[0]) return NULL; + s += EsCRTstrlen(s) - 1; + + while (true) { + if (*s == c) { + return (char *) s; + } + + if (s == start) { + return NULL; + } + + s--; + } +} + +char *EsCRTstrchr(const char *s, int c) { + while (true) { + if (*s == c) { + return (char *) s; + } + + if (*s == 0) { + return NULL; + } + + s++; + } +} + +char *EsCRTstrncpy(char *dest, const char *src, size_t n) { + size_t i; + + for (i = 0; i < n && src[i]; i++) { + dest[i] = src[i]; + } + + for (; i < n; i++) { + dest[i] = 0; + } + + return dest; +} + +char *EsCRTstrlcpy(char *dest, const char *src, size_t n) { + size_t i; + + for (i = 0; i < n - 1 && src[i]; i++) { + dest[i] = src[i]; + } + + for (; i < n; i++) { + dest[i] = 0; + } + + return dest; +} + +int EsCRTmemcmp(const void *s1, const void *s2, size_t n) { + return EsMemoryCompare((void *) s1, (void *) s2, n); +} + +void *EsCRTmemchr(const void *_s, int _c, size_t n) { + uint8_t *s = (uint8_t *) _s; + uint8_t c = (uint8_t) _c; + + for (uintptr_t i = 0; i < n; i++) { + if (s[i] == c) { + return s + i; + } + } + + return nullptr; +} + +int EsCRTisalpha(int c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +int EsCRTisdigit(int c) { + return (c >= '0' && c <= '9'); +} + +int EsCRTrand() { + uint8_t a = EsRandomU8(); + uint8_t b = EsRandomU8(); + uint8_t c = EsRandomU8(); + return (a << 16) | (b << 8) | (c << 0); +} + +int EsCRTisalnum(int c) { + return EsCRTisalpha(c) || EsCRTisdigit(c); +} + +int EsCRTiscntrl(int c) { + return c < 0x20 || c == 0x7F; +} + +int EsCRTisgraph(int c) { + return c > ' ' && c < 0x7F; +} + +int EsCRTislower(int c) { + return c >= 'a' && c <= 'z'; +} + +int EsCRTisprint(int c) { + return c >= ' ' && c < 127; +} + +int EsCRTispunct(int c) { + return c != ' ' && !EsCRTisalnum(c); +} + +int EsCRTisupper(int c) { + return c >= 'A' && c <= 'Z'; +} + +int EsCRTisxdigit(int c) { + return EsCRTisdigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +char *EsCRTsetlocale(int category, const char *locale) { + (void) category; + (void) locale; + return nullptr; +} + +void EsCRTsrand(unsigned int seed) { + EsRandomSeed(seed); +} + +#ifndef KERNEL +void EsCRTexit(int status) { + EsProcessTerminate(ES_CURRENT_PROCESS, status); +} + +void EsCRTabort() { + EsPanic("EsCRTabort called.\n"); +} +#endif + +int EsCRTstrcoll(const char *s1, const char *s2) { + return EsStringCompare(s1, EsCStringLength(s1), s2, EsCStringLength(s2)); +} + +char *EsCRTstrerror(int errnum) { + (void) errnum; + return (char*) "unknown operation failure"; +} + +char *EsCRTstrpbrk(const char *s, const char *accept) { + size_t l1 = EsCStringLength(s), l2 = EsCStringLength(accept); + + for (uintptr_t i = 0; i < l1; i++) { + char c = s[i]; + + for (uintptr_t j = 0; j < l2; j++) { + if (accept[j] == c) { + return (char *) (i + s); + } + } + } + + return nullptr; +} + +#ifdef USE_STB_SPRINTF +int EsCRTsprintf(char *buffer, const char *format, ...) { + va_list arguments; + va_start(arguments, format); + int length = stbsp_vsprintf(buffer, format, arguments); + va_end(arguments); + return length; +} + +int EsCRTsnprintf(char *buffer, size_t bufferSize, const char *format, ...) { + va_list arguments; + va_start(arguments, format); + int length = stbsp_vsnprintf(buffer, bufferSize, format, arguments); + va_end(arguments); + return length; +} + +int EsCRTvsnprintf(char *buffer, size_t bufferSize, const char *format, va_list arguments) { + return stbsp_vsnprintf(buffer, bufferSize, format, arguments); +} +#endif + +#endif + +///////////////////////////////// +// Memory buffers. +///////////////////////////////// + +#ifdef SHARED_COMMON_WANT_BUFFERS + +const void *EsBufferRead(EsBuffer *buffer, size_t readBytes) { + if (!readBytes && buffer->position == buffer->bytes) { + return buffer->in + buffer->position; + } else if (buffer->position >= buffer->bytes || buffer->bytes - buffer->position < readBytes || buffer->error) { + buffer->error = true; + return NULL; + } else { + const void *pointer = buffer->in + buffer->position; + buffer->position += readBytes; + return pointer; + } +} + +const void *EsBufferReadMany(EsBuffer *buffer, size_t a, size_t b) { + size_t c; + + if (__builtin_mul_overflow(a, b, &c)) { + buffer->error = true; + return NULL; + } else { + return EsBufferRead(buffer, c); + } +} + +float EsBufferReadFloat(EsBuffer *buffer) { + const float *p = (const float *) EsBufferRead(buffer, sizeof(float)); + return p ? *p : 0; +} + +uint8_t EsBufferReadByte(EsBuffer *buffer) { + const uint8_t *p = (const uint8_t *) EsBufferRead(buffer, sizeof(uint8_t)); + return p ? *p : 0; +} + +uint32_t EsBufferReadInt(EsBuffer *buffer) { + const uint32_t *p = (const uint32_t *) EsBufferRead(buffer, sizeof(uint32_t)); + return p ? *p : 0; +} + +void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writeBytes) { +#ifdef ES_API + tryAgain:; +#endif + + if (buffer->error) { + return NULL; + } else if (buffer->bytes - buffer->position < writeBytes) { +#ifdef ES_API + if (buffer->canGrow) { + size_t newBytes = buffer->bytes * 2 + 16; + + if (newBytes < writeBytes + buffer->position) { + newBytes = writeBytes + buffer->position + 16; + } + + char *newOut = (char *) EsHeapReallocate(buffer->out, newBytes, false); + + if (!newOut) { + buffer->error = true; + } else { + buffer->bytes = newBytes; + buffer->out = (uint8_t *) newOut; + goto tryAgain; + } + } else { + buffer->error = true; + } +#else + buffer->error = true; +#endif + + return NULL; + } else { + void *pointer = buffer->out + buffer->position; + buffer->position += writeBytes; + + if (source) { + EsMemoryCopy(pointer, source, writeBytes); + } else { + EsMemoryZero(pointer, writeBytes); + } + + return pointer; + } +} + +#endif diff --git a/shared/hash.cpp b/shared/hash.cpp new file mode 100644 index 0000000..47ea388 --- /dev/null +++ b/shared/hash.cpp @@ -0,0 +1,110 @@ +// TODO Replace with FNV1a, as used in hash_table.cpp? +// Currently used for: EsFS, theme constants, build core configuration hash, make bundle. + +#ifdef __cplusplus +constexpr static uint32_t crc32Table[] = { +#else +static uint32_t crc32Table[] = { +#endif + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; + +#ifdef __cplusplus +constexpr static uint64_t crc64Table[] = { +#else +static uint64_t crc64Table[] = { +#endif + 0x0000000000000000UL, 0x7AD870C830358979UL, 0xF5B0E190606B12F2UL, 0x8F689158505E9B8BUL, 0xC038E5739841B68FUL, 0xBAE095BBA8743FF6UL, 0x358804E3F82AA47DUL, 0x4F50742BC81F2D04UL, + 0xAB28ECB46814FE75UL, 0xD1F09C7C5821770CUL, 0x5E980D24087FEC87UL, 0x24407DEC384A65FEUL, 0x6B1009C7F05548FAUL, 0x11C8790FC060C183UL, 0x9EA0E857903E5A08UL, 0xE478989FA00BD371UL, + 0x7D08FF3B88BE6F81UL, 0x07D08FF3B88BE6F8UL, 0x88B81EABE8D57D73UL, 0xF2606E63D8E0F40AUL, 0xBD301A4810FFD90EUL, 0xC7E86A8020CA5077UL, 0x4880FBD87094CBFCUL, 0x32588B1040A14285UL, + 0xD620138FE0AA91F4UL, 0xACF86347D09F188DUL, 0x2390F21F80C18306UL, 0x594882D7B0F40A7FUL, 0x1618F6FC78EB277BUL, 0x6CC0863448DEAE02UL, 0xE3A8176C18803589UL, 0x997067A428B5BCF0UL, + 0xFA11FE77117CDF02UL, 0x80C98EBF2149567BUL, 0x0FA11FE77117CDF0UL, 0x75796F2F41224489UL, 0x3A291B04893D698DUL, 0x40F16BCCB908E0F4UL, 0xCF99FA94E9567B7FUL, 0xB5418A5CD963F206UL, + 0x513912C379682177UL, 0x2BE1620B495DA80EUL, 0xA489F35319033385UL, 0xDE51839B2936BAFCUL, 0x9101F7B0E12997F8UL, 0xEBD98778D11C1E81UL, 0x64B116208142850AUL, 0x1E6966E8B1770C73UL, + 0x8719014C99C2B083UL, 0xFDC17184A9F739FAUL, 0x72A9E0DCF9A9A271UL, 0x08719014C99C2B08UL, 0x4721E43F0183060CUL, 0x3DF994F731B68F75UL, 0xB29105AF61E814FEUL, 0xC849756751DD9D87UL, + 0x2C31EDF8F1D64EF6UL, 0x56E99D30C1E3C78FUL, 0xD9810C6891BD5C04UL, 0xA3597CA0A188D57DUL, 0xEC09088B6997F879UL, 0x96D1784359A27100UL, 0x19B9E91B09FCEA8BUL, 0x636199D339C963F2UL, + 0xDF7ADABD7A6E2D6FUL, 0xA5A2AA754A5BA416UL, 0x2ACA3B2D1A053F9DUL, 0x50124BE52A30B6E4UL, 0x1F423FCEE22F9BE0UL, 0x659A4F06D21A1299UL, 0xEAF2DE5E82448912UL, 0x902AAE96B271006BUL, + 0x74523609127AD31AUL, 0x0E8A46C1224F5A63UL, 0x81E2D7997211C1E8UL, 0xFB3AA75142244891UL, 0xB46AD37A8A3B6595UL, 0xCEB2A3B2BA0EECECUL, 0x41DA32EAEA507767UL, 0x3B024222DA65FE1EUL, + 0xA2722586F2D042EEUL, 0xD8AA554EC2E5CB97UL, 0x57C2C41692BB501CUL, 0x2D1AB4DEA28ED965UL, 0x624AC0F56A91F461UL, 0x1892B03D5AA47D18UL, 0x97FA21650AFAE693UL, 0xED2251AD3ACF6FEAUL, + 0x095AC9329AC4BC9BUL, 0x7382B9FAAAF135E2UL, 0xFCEA28A2FAAFAE69UL, 0x8632586ACA9A2710UL, 0xC9622C4102850A14UL, 0xB3BA5C8932B0836DUL, 0x3CD2CDD162EE18E6UL, 0x460ABD1952DB919FUL, + 0x256B24CA6B12F26DUL, 0x5FB354025B277B14UL, 0xD0DBC55A0B79E09FUL, 0xAA03B5923B4C69E6UL, 0xE553C1B9F35344E2UL, 0x9F8BB171C366CD9BUL, 0x10E3202993385610UL, 0x6A3B50E1A30DDF69UL, + 0x8E43C87E03060C18UL, 0xF49BB8B633338561UL, 0x7BF329EE636D1EEAUL, 0x012B592653589793UL, 0x4E7B2D0D9B47BA97UL, 0x34A35DC5AB7233EEUL, 0xBBCBCC9DFB2CA865UL, 0xC113BC55CB19211CUL, + 0x5863DBF1E3AC9DECUL, 0x22BBAB39D3991495UL, 0xADD33A6183C78F1EUL, 0xD70B4AA9B3F20667UL, 0x985B3E827BED2B63UL, 0xE2834E4A4BD8A21AUL, 0x6DEBDF121B863991UL, 0x1733AFDA2BB3B0E8UL, + 0xF34B37458BB86399UL, 0x8993478DBB8DEAE0UL, 0x06FBD6D5EBD3716BUL, 0x7C23A61DDBE6F812UL, 0x3373D23613F9D516UL, 0x49ABA2FE23CC5C6FUL, 0xC6C333A67392C7E4UL, 0xBC1B436E43A74E9DUL, + 0x95AC9329AC4BC9B5UL, 0xEF74E3E19C7E40CCUL, 0x601C72B9CC20DB47UL, 0x1AC40271FC15523EUL, 0x5594765A340A7F3AUL, 0x2F4C0692043FF643UL, 0xA02497CA54616DC8UL, 0xDAFCE7026454E4B1UL, + 0x3E847F9DC45F37C0UL, 0x445C0F55F46ABEB9UL, 0xCB349E0DA4342532UL, 0xB1ECEEC59401AC4BUL, 0xFEBC9AEE5C1E814FUL, 0x8464EA266C2B0836UL, 0x0B0C7B7E3C7593BDUL, 0x71D40BB60C401AC4UL, + 0xE8A46C1224F5A634UL, 0x927C1CDA14C02F4DUL, 0x1D148D82449EB4C6UL, 0x67CCFD4A74AB3DBFUL, 0x289C8961BCB410BBUL, 0x5244F9A98C8199C2UL, 0xDD2C68F1DCDF0249UL, 0xA7F41839ECEA8B30UL, + 0x438C80A64CE15841UL, 0x3954F06E7CD4D138UL, 0xB63C61362C8A4AB3UL, 0xCCE411FE1CBFC3CAUL, 0x83B465D5D4A0EECEUL, 0xF96C151DE49567B7UL, 0x76048445B4CBFC3CUL, 0x0CDCF48D84FE7545UL, + 0x6FBD6D5EBD3716B7UL, 0x15651D968D029FCEUL, 0x9A0D8CCEDD5C0445UL, 0xE0D5FC06ED698D3CUL, 0xAF85882D2576A038UL, 0xD55DF8E515432941UL, 0x5A3569BD451DB2CAUL, 0x20ED197575283BB3UL, + 0xC49581EAD523E8C2UL, 0xBE4DF122E51661BBUL, 0x3125607AB548FA30UL, 0x4BFD10B2857D7349UL, 0x04AD64994D625E4DUL, 0x7E7514517D57D734UL, 0xF11D85092D094CBFUL, 0x8BC5F5C11D3CC5C6UL, + 0x12B5926535897936UL, 0x686DE2AD05BCF04FUL, 0xE70573F555E26BC4UL, 0x9DDD033D65D7E2BDUL, 0xD28D7716ADC8CFB9UL, 0xA85507DE9DFD46C0UL, 0x273D9686CDA3DD4BUL, 0x5DE5E64EFD965432UL, + 0xB99D7ED15D9D8743UL, 0xC3450E196DA80E3AUL, 0x4C2D9F413DF695B1UL, 0x36F5EF890DC31CC8UL, 0x79A59BA2C5DC31CCUL, 0x037DEB6AF5E9B8B5UL, 0x8C157A32A5B7233EUL, 0xF6CD0AFA9582AA47UL, + 0x4AD64994D625E4DAUL, 0x300E395CE6106DA3UL, 0xBF66A804B64EF628UL, 0xC5BED8CC867B7F51UL, 0x8AEEACE74E645255UL, 0xF036DC2F7E51DB2CUL, 0x7F5E4D772E0F40A7UL, 0x05863DBF1E3AC9DEUL, + 0xE1FEA520BE311AAFUL, 0x9B26D5E88E0493D6UL, 0x144E44B0DE5A085DUL, 0x6E963478EE6F8124UL, 0x21C640532670AC20UL, 0x5B1E309B16452559UL, 0xD476A1C3461BBED2UL, 0xAEAED10B762E37ABUL, + 0x37DEB6AF5E9B8B5BUL, 0x4D06C6676EAE0222UL, 0xC26E573F3EF099A9UL, 0xB8B627F70EC510D0UL, 0xF7E653DCC6DA3DD4UL, 0x8D3E2314F6EFB4ADUL, 0x0256B24CA6B12F26UL, 0x788EC2849684A65FUL, + 0x9CF65A1B368F752EUL, 0xE62E2AD306BAFC57UL, 0x6946BB8B56E467DCUL, 0x139ECB4366D1EEA5UL, 0x5CCEBF68AECEC3A1UL, 0x2616CFA09EFB4AD8UL, 0xA97E5EF8CEA5D153UL, 0xD3A62E30FE90582AUL, + 0xB0C7B7E3C7593BD8UL, 0xCA1FC72BF76CB2A1UL, 0x45775673A732292AUL, 0x3FAF26BB9707A053UL, 0x70FF52905F188D57UL, 0x0A2722586F2D042EUL, 0x854FB3003F739FA5UL, 0xFF97C3C80F4616DCUL, + 0x1BEF5B57AF4DC5ADUL, 0x61372B9F9F784CD4UL, 0xEE5FBAC7CF26D75FUL, 0x9487CA0FFF135E26UL, 0xDBD7BE24370C7322UL, 0xA10FCEEC0739FA5BUL, 0x2E675FB4576761D0UL, 0x54BF2F7C6752E8A9UL, + 0xCDCF48D84FE75459UL, 0xB71738107FD2DD20UL, 0x387FA9482F8C46ABUL, 0x42A7D9801FB9CFD2UL, 0x0DF7ADABD7A6E2D6UL, 0x772FDD63E7936BAFUL, 0xF8474C3BB7CDF024UL, 0x829F3CF387F8795DUL, + 0x66E7A46C27F3AA2CUL, 0x1C3FD4A417C62355UL, 0x935745FC4798B8DEUL, 0xE98F353477AD31A7UL, 0xA6DF411FBFB21CA3UL, 0xDC0731D78F8795DAUL, 0x536FA08FDFD90E51UL, 0x29B7D047EFEC8728UL, +}; + +#ifdef __cplusplus +constexpr static uint32_t CalculateCRC32(const void *_buffer, size_t length, uint32_t carry = 0) { +#else +static uint32_t CalculateCRC32(const void *_buffer, size_t length, uint32_t carry) { +#endif + const uint8_t *buffer = (const uint8_t *) _buffer; + uint32_t x = ~carry; + + for (uintptr_t i = 0; i < length; i++) { + x = crc32Table[(x ^ (uint32_t) buffer[i]) & 0xFF] ^ (x >> 8); + } + + return ~x; +} + +#ifdef __cplusplus +constexpr static uint64_t CalculateCRC64(const void *_buffer, size_t length, uint64_t carry = 0) { +#else +static uint64_t CalculateCRC64(const void *_buffer, size_t length, uint64_t carry) { +#endif + const uint8_t *buffer = (const uint8_t *) _buffer; + uint64_t x = ~carry; + + for (uintptr_t i = 0; i < length; i++) { + x = crc64Table[(x ^ (uint64_t) buffer[i]) & 0xFF] ^ (x >> 8); + } + + return ~x; +} diff --git a/shared/hash_table.cpp b/shared/hash_table.cpp new file mode 100644 index 0000000..5a08f80 --- /dev/null +++ b/shared/hash_table.cpp @@ -0,0 +1,520 @@ +// TODO Test deleting values in hash stores with variable length keys. + +#include <stdint.h> +#include <stddef.h> + +#ifndef OS_ESSENCE +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#define EsHeapAllocate(a, b) ((b) ? calloc(1, (a)) : malloc((a))) +#define EsHeapReallocate(a, b, c) ((c) ? (assert(false), nullptr) : realloc((a), (b))) +#define EsHeapFree free +#define EsMemoryCopy memcpy +#define EsMemoryCompare memcmp +#define EsAssert assert +#endif + +////////////////////////////////////////// + +struct HashTableKey { + union { + uintptr_t shortKey; + void *longKey; + }; + + uint32_t longKeyBytes; + uint16_t longKeyHash16; + uint8_t used, tombstone; +}; + +struct HashTableSlot { + HashTableKey key; + void *value; +}; + +struct HashTable { + size_t itemCount; + size_t slotCount; + HashTableSlot *slots; + uint8_t *storage; +}; + +struct HashStoreOptions { + size_t keyBytes; + size_t valueBytes; +}; + +uint64_t HashTableFNV1a(const void *key, size_t keyBytes) { + uint64_t hash = 0xCBF29CE484222325; + + for (uintptr_t i = 0; i < keyBytes; i++) { + hash = (hash ^ ((uint8_t *) key)[i]) * 0x100000001B3; + } + + return hash; +} + +HashTableSlot *_HashTableGetSlot(HashTable *table, HashTableKey *key, bool useLongKeys) { + uint64_t hash; + + if (useLongKeys) { + hash = HashTableFNV1a(key->longKey, key->longKeyBytes); + key->longKeyHash16 = (uint16_t) (hash >> 48); + } else { + hash = HashTableFNV1a(&key->shortKey, sizeof(key->shortKey)); + } + + uintptr_t slot = hash & (table->slotCount - 1); + HashTableSlot *firstTombstone = nullptr; + + for (uintptr_t probe = 0; probe < table->slotCount; probe++) { + uintptr_t index = slot + probe; + if (index >= table->slotCount) index -= table->slotCount; + HashTableSlot *s = table->slots + index; + + if (!s->key.used && !s->key.tombstone) { + return firstTombstone ?: s; + } + + if (s->key.tombstone) { + if (!firstTombstone) { + firstTombstone = s; + } + + continue; + } + + if (useLongKeys) { + if (s->key.longKeyHash16 == key->longKeyHash16 + && s->key.longKeyBytes == key->longKeyBytes + && 0 == EsMemoryCompare(s->key.longKey, key->longKey, key->longKeyBytes)) { + return s; + } + } else { + if (s->key.shortKey == key->shortKey) { + return s; + } + } + } + + EsAssert(false); + return nullptr; +} + +HashTableSlot *HashTableGetSlot(HashTable *table, HashTableKey key, bool useLongKeys) { + if (!table->itemCount) return nullptr; + HashTableSlot *slot = _HashTableGetSlot(table, &key, useLongKeys); + return slot->key.used ? slot : nullptr; +} + +void *HashTableGet(HashTable *table, HashTableKey key, bool useLongKeys) { + HashTableSlot *slot = HashTableGetSlot(table, key, useLongKeys); + return slot ? slot->value : nullptr; +} + +bool _HashTableResize(HashTable *table, size_t newSlotCount, bool useLongKeys); + +bool _HashTablePutSlot(HashTable *table, HashTableSlot *slot, HashTableKey key, void *value, bool useLongKeys, bool duplicateLongKeys) { + if (slot->key.used) { + if (!duplicateLongKeys) { + slot->key = key; + slot->key.tombstone = false; + slot->key.used = true; + } + + slot->value = value; + } else { + if (useLongKeys && duplicateLongKeys) { + void *keyCopy = EsHeapAllocate(key.longKeyBytes, false); + if (!keyCopy) return false; + EsMemoryCopy(keyCopy, key.longKey, key.longKeyBytes); + key.longKey = keyCopy; + } + + slot->key = key; + slot->key.tombstone = false; + slot->key.used = true; + slot->value = value; + table->itemCount++; + } + + return true; +} + +bool _HashTableEnsureSpaceAvailable(HashTable *table, bool useLongKeys) { + if (!table->slotCount) { + table->slotCount = 16; + table->slots = (HashTableSlot *) EsHeapAllocate(sizeof(HashTableSlot) * table->slotCount, true); + + if (!table->slots) { + return false; + } + } + + if (table->itemCount > table->slotCount / 2) { + if (!_HashTableResize(table, table->slotCount * 2, useLongKeys)) { + return false; + } + } + + return true; +} + +bool HashTablePut(HashTable *table, HashTableKey key, void *value, bool useLongKeys, bool duplicateLongKeys = true) { + if (!_HashTableEnsureSpaceAvailable(table, useLongKeys)) return false; + HashTableSlot *slot = _HashTableGetSlot(table, &key, useLongKeys); + return _HashTablePutSlot(table, slot, key, value, useLongKeys, duplicateLongKeys); +} + +bool _HashTableResize(HashTable *table, size_t newSlotCount, bool useLongKeys) { + HashTable copy = *table; + copy.slotCount = newSlotCount; + copy.slots = (HashTableSlot *) EsHeapAllocate(newSlotCount * sizeof(HashTableSlot), true); + copy.itemCount = 0; + + if (!copy.slots) { + return false; + } + + for (uintptr_t i = 0; i < table->slotCount; i++) { + if (table->slots[i].key.used) { + bool success = HashTablePut(©, table->slots[i].key, table->slots[i].value, useLongKeys, false); + EsAssert(success); + } + } + + EsAssert(table->itemCount == copy.itemCount); + EsHeapFree(table->slots); + *table = copy; + return true; +} + +bool HashTableDelete(HashTable *table, HashTableKey key, bool useLongKeys) { + HashTableSlot *slot = HashTableGetSlot(table, key, useLongKeys); + if (!slot) return false; + slot->key.used = false; + slot->key.tombstone = true; + table->itemCount--; + + if (table->itemCount < table->slotCount / 8 && table->itemCount > 16) { + _HashTableResize(table, table->slotCount / 2, useLongKeys); + } + + return true; +} + +void HashTableFree(HashTable *table, bool freeLongKeys) { + if (freeLongKeys) { + for (uintptr_t i = 0; i < table->slotCount; i++) { + if (table->slots[i].key.used) { + table->itemCount--; + EsHeapFree(table->slots[i].key.longKey); + } + } + + EsAssert(!table->itemCount); + } + + EsHeapFree(table->slots); + if (table->storage) EsHeapFree(table->storage - sizeof(size_t)); + table->itemCount = 0; + table->slotCount = 0; + table->slots = nullptr; +} + +////////////////////////////////////////// + +void *HashTableGetLong(HashTable *table, const void *key, size_t keyBytes) { + HashTableKey k; + k.longKey = (void *) key, k.longKeyBytes = keyBytes; + return HashTableGet(table, k, true); +} + +void *HashTableGetShort(HashTable *table, uintptr_t key) { + HashTableKey k; + k.shortKey = key; + return HashTableGet(table, k, false); +} + +bool HashTablePutLong(HashTable *table, const void *key, size_t keyBytes, void *value, bool duplicateKey = true) { + HashTableKey k; + k.longKey = (void *) key, k.longKeyBytes = keyBytes; + return HashTablePut(table, k, value, true, duplicateKey); +} + +bool HashTablePutShort(HashTable *table, uintptr_t key, void *value) { + HashTableKey k; + k.shortKey = key; + return HashTablePut(table, k, value, false); +} + +bool HashTableDeleteLong(HashTable *table, const void *key, size_t keyBytes) { + HashTableKey k; + k.longKey = (void *) key, k.longKeyBytes = keyBytes; + return HashTableDelete(table, k, true); +} + +bool HashTableDeleteShort(HashTable *table, uintptr_t key) { + HashTableKey k; + k.shortKey = key; + return HashTableDelete(table, k, false); +} + +////////////////////////////////////////// + +void *HashStoreGet(HashTable *table, HashStoreOptions *options, const void *key, size_t keyBytes = 0) { + return HashTableGetLong(table, key, options->keyBytes ?: keyBytes); +} + +void *HashStorePut(HashTable *table, HashStoreOptions *options, const void *key, size_t keyBytes = 0) { + if (!_HashTableEnsureSpaceAvailable(table, true)) return nullptr; + bool variableLengthKeys = keyBytes; + if (!keyBytes) keyBytes = options->keyBytes; + + HashTableKey k; + k.longKey = (void *) key, k.longKeyBytes = keyBytes; + HashTableSlot *slot = _HashTableGetSlot(table, &k, true); + + if (!slot->key.used) { + if (!table->storage) { + table->storage = (uint8_t *) EsHeapAllocate( + (options->keyBytes + options->valueBytes) * 16 + sizeof(size_t), true); + if (!table->storage) return nullptr; + table->storage += sizeof(size_t); + ((size_t *) table->storage)[-1] = 16; + } + + size_t storageAllocated = ((size_t *) table->storage)[-1]; + + if (table->itemCount == storageAllocated) { + uint8_t *newStorage = (uint8_t *) EsHeapReallocate(table->storage - sizeof(size_t), + (options->keyBytes + options->valueBytes) * storageAllocated * 2 + sizeof(size_t), true); + if (!newStorage) return nullptr; + newStorage += sizeof(size_t); + + if (newStorage != table->storage) { + for (uintptr_t i = 0; i < table->slotCount; i++) { + if (!table->slots[i].key.used) continue; + + if (!variableLengthKeys) { + table->slots[i].key.longKey = (uint8_t *) table->slots[i].key.longKey - table->storage + newStorage; + } + + table->slots[i].value = (uint8_t *) table->slots[i].value - table->storage + newStorage; + } + } + + table->storage = newStorage; + ((size_t *) table->storage)[-1] = storageAllocated * 2; + } + + uintptr_t index = table->itemCount; + uint8_t *value = table->storage + index * (options->keyBytes + options->valueBytes); + uint8_t *keyDestination = value + options->valueBytes; + + if (!variableLengthKeys) { + EsMemoryCopy(keyDestination, key, keyBytes); + k.longKey = keyDestination; + } + + if (!_HashTablePutSlot(table, slot, k, value, true, variableLengthKeys)) { + return nullptr; + } + + if (variableLengthKeys) { + EsAssert(options->keyBytes == sizeof(void *)); + EsMemoryCopy(keyDestination, slot->key.longKey, sizeof(void *)); + } + } + + return slot->value; +} + +bool HashStoreDelete(HashTable *table, HashStoreOptions *options, const void *key, size_t keyBytes = 0) { + if (!keyBytes) keyBytes = options->keyBytes; + uint8_t *value = (uint8_t *) HashTableGetLong(table, key, keyBytes); + if (!value) return false; + bool success = HashTableDeleteLong(table, key, keyBytes); + EsAssert(success); + uint8_t *end = table->storage + (options->keyBytes + options->valueBytes) * table->itemCount; + if (value == end) return true; + EsMemoryCopy(value, end, options->keyBytes + options->valueBytes); + HashTableKey k; + k.longKey = value + options->valueBytes, k.longKeyBytes = keyBytes; + success = HashTablePut(table, k, value, true, false); + EsAssert(success); + return true; +} + +////////////////////////////////////////// + +template <class K /* set to char * for long keys */, class V> +struct HashStore { + HashTable table; + + inline size_t Count() { + return table.itemCount; + } + + inline V &operator[](uintptr_t index) { + uintptr_t keyBytes = sizeof(K) == 1 ? sizeof(void *) : sizeof(K); + return *(V *) (table.storage + (sizeof(V) + keyBytes) * index); + } + + inline K KeyAtIndex(uintptr_t index) { + uintptr_t keyBytes = sizeof(K) == 1 ? sizeof(void *) : sizeof(K); + return *(K *) (table.storage + (sizeof(V) + keyBytes) * index + sizeof(V)); + } + + inline V *Get(const K *k, size_t bytes = 0) { + HashStoreOptions options = { sizeof(K), sizeof(V) }; + if (options.keyBytes == 1) options.keyBytes = 0; + return (V *) HashStoreGet(&table, &options, k, bytes); + } + + inline V Get1(const K *k, size_t bytes = 0) { + HashStoreOptions options = { sizeof(K), sizeof(V) }; + if (options.keyBytes == 1) options.keyBytes = 0; + V *v = (V *) HashStoreGet(&table, &options, k, bytes); + if (v) return *v; + else return {}; + } + + inline V *Put(const K *k, size_t bytes = 0) { + HashStoreOptions options = { sizeof(K), sizeof(V) }; + if (options.keyBytes == 1) options.keyBytes = sizeof(void *); + return (V *) HashStorePut(&table, &options, k, bytes); + } + + inline bool Delete(const K *k, size_t bytes = 0) { + HashStoreOptions options = { sizeof(K), sizeof(V) }; + if (options.keyBytes == 1) options.keyBytes = sizeof(void *); + return HashStoreDelete(&table, &options, k, bytes); + } + + inline void Free(bool variableLengthKeys) { + HashTableFree(&table, variableLengthKeys); + } +}; + +////////////////////////////////////////// + +#ifndef OS_ESSENCE + +#include <stdio.h> +#include "stb_ds.h" + +struct TestItem { + int key, value; +}; + +TestItem *testItems; +HashTable table; + +void TestGet(int key) { + int value1 = hmget(testItems, key); + int value2 = (intptr_t) HashTableGetShort(&table, key); + assert(value1 == value2); +} + +void TestCompare() { + for (int i = 0; i < 256; i++) { + TestGet(i); + } + + assert(hmlenu(testItems) == table.itemCount); +} + +void TestPut(int key, int value) { + hmput(testItems, key, value); + HashTablePutShort(&table, key, (void *) (intptr_t) value); + TestCompare(); +} + +void TestDelete(int key) { + TestGet(key); + hmdel(testItems, key); + HashTableDeleteShort(&table, key); + TestCompare(); +} + +int main() { + { + HashTable store = {}; + HashStoreOptions options = { .keyBytes = sizeof(uint64_t), .valueBytes = sizeof(float) }; + uint64_t key; + + key = 1; + *(float *) HashStorePut(&store, &options, &key) = 5.3f; + assert(*(float *) HashStoreGet(&store, &options, &key) == 5.3f); + key = 2; + assert(!HashStoreGet(&store, &options, &key)); + + for (uintptr_t i = 0; i < 100; i++) { + key = i; + *(float *) HashStorePut(&store, &options, &key) = i; + } + + for (uintptr_t i = 0; i < 100; i++) { + key = i; + assert(*(float *) HashStoreGet(&store, &options, &key) == i); + } + + for (uintptr_t i = 1; i < 100; i += 2) { + key = i; + assert(HashStoreDelete(&store, &options, &key)); + } + + for (uintptr_t i = 0; i < 100; i += 2) { + key = i; + assert(*(float *) HashStoreGet(&store, &options, &key) == i); + } + + for (uintptr_t i = 1; i < 100; i += 2) { + key = i; + assert(!HashStoreGet(&store, &options, &key)); + } + + for (uintptr_t i = 0; i < 100; i += 2) { + key = i; + assert(HashStoreDelete(&store, &options, &key)); + } + + for (uintptr_t i = 0; i < 100; i++) { + key = i; + assert(!HashStoreGet(&store, &options, &key)); + } + + HashTableFree(&store, true); + } + +#if 0 + for (int i = 0; i < 127; i++) { + TestPut(i, rand() % 255); + } + + for (int i = 0; i < 127; i++) { + TestDelete(i); + } + + for (uintptr_t i = 0; i < 1000; i++) { + if (rand() & 1) { + for (uintptr_t i = 0; i < 100; i++) { + TestPut(rand() % 255, rand() % 255); + } + } else { + for (uintptr_t i = 0; i < 100; i++) { + TestDelete(rand() % 127); + } + } + } + + hmfree(testItems); + HashTableFree(&table, false); +#endif + + return 0; +} + +#endif diff --git a/shared/heap.cpp b/shared/heap.cpp new file mode 100644 index 0000000..57270dd --- /dev/null +++ b/shared/heap.cpp @@ -0,0 +1,542 @@ +// TODO Rewrite. Make faster! +// TODO EsHeapAllocateNearby. +// TODO Larger heap blocks. Due to alignment, we can shift offset values a few bits right. + +#ifdef DEBUG_BUILD +#define MAYBE_VALIDATE_HEAP() HeapValidate(&heap) +#else +#define MAYBE_VALIDATE_HEAP() +#endif + +#define LARGE_ALLOCATION_THRESHOLD (32768) +#define USED_HEAP_REGION_MAGIC (0xABCD) + +struct HeapRegion { + union { + uint16_t next; + uint16_t size; + }; + + uint16_t previous; + uint16_t offset; + uint16_t used; + + union { + uintptr_t allocationSize; + + // Valid if the region is not in use. + HeapRegion *regionListNext; + }; + + // Free regions only: + HeapRegion **regionListReference; +#define USED_HEAP_REGION_HEADER_SIZE (sizeof(HeapRegion) - sizeof(HeapRegion **)) +#define FREE_HEAP_REGION_HEADER_SIZE (sizeof(HeapRegion)) +}; + +static uintptr_t HeapCalculateIndex(uintptr_t size) { + int x = __builtin_clz(size); + uintptr_t msb = sizeof(unsigned int) * 8 - x - 1; + return msb - 4; +} + +struct EsHeap { +#ifdef KERNEL + KMutex mutex; +#else + EsMutex mutex; +#endif + + HeapRegion *regions[12]; + volatile size_t allocationsCount, size, blockCount; + void *blocks[16]; + + bool cannotValidate; +}; + +// TODO Better heap panic messages. +#define HEAP_PANIC(n, x, y) EsPanic("Heap panic (%d/%x/%x).\n", n, x, y) + +#ifdef KERNEL +EsHeap heapCore, heapFixed; +#define HEAP_ACQUIRE_MUTEX(a) KMutexAcquire(&(a)) +#define HEAP_RELEASE_MUTEX(a) KMutexRelease(&(a)) +#define HEAP_ALLOCATE_CALL(x) MMStandardAllocate(_heap == &heapCore ? coreMMSpace : kernelMMSpace, x, MM_REGION_FIXED) +#define HEAP_FREE_CALL(x) MMFree(_heap == &heapCore ? coreMMSpace : kernelMMSpace, x) +#else +EsHeap heap; +#define HEAP_ACQUIRE_MUTEX(a) EsMutexAcquire(&(a)) +#define HEAP_RELEASE_MUTEX(a) EsMutexRelease(&(a)) +#define HEAP_ALLOCATE_CALL(x) EsMemoryReserve(x) +#define HEAP_FREE_CALL(x) EsMemoryUnreserve(x) +#endif + +#define HEAP_REGION_HEADER(region) ((HeapRegion *) ((uint8_t *) region - USED_HEAP_REGION_HEADER_SIZE)) +#define HEAP_REGION_DATA(region) ((uint8_t *) region + USED_HEAP_REGION_HEADER_SIZE) +#define HEAP_REGION_NEXT(region) ((HeapRegion *) ((uint8_t *) region + region->next)) +#define HEAP_REGION_PREVIOUS(region) (region->previous ? ((HeapRegion *) ((uint8_t *) region - region->previous)) : nullptr) + +#ifdef USE_PLATFORM_HEAP +void *PlatformHeapAllocate(size_t size, bool zero); +void PlatformHeapFree(void *address); +void *PlatformHeapReallocate(void *oldAddress, size_t newAllocationSize, bool zeroNewSpace); +#endif + +static void HeapRemoveFreeRegion(HeapRegion *region) { + if (!region->regionListReference || region->used) { + HEAP_PANIC(50, region, 0); + } + + *region->regionListReference = region->regionListNext; + + if (region->regionListNext) { + region->regionListNext->regionListReference = region->regionListReference; + } + + region->regionListReference = nullptr; +} + +static void HeapAddFreeRegion(HeapRegion *region, HeapRegion **heapRegions) { + if (region->used || region->size < 32) { + HEAP_PANIC(1, region, heapRegions); + } + + int index = HeapCalculateIndex(region->size); + region->regionListNext = heapRegions[index]; + if (region->regionListNext) region->regionListNext->regionListReference = ®ion->regionListNext; + heapRegions[index] = region; + region->regionListReference = heapRegions + index; +} + +static void HeapValidate(EsHeap *heap) { + if (heap->cannotValidate) return; + + for (uintptr_t i = 0; i < heap->blockCount; i++) { + HeapRegion *start = (HeapRegion *) heap->blocks[i]; + if (!start) continue; + + HeapRegion *end = (HeapRegion *) ((uint8_t *) heap->blocks[i] + 65536); + HeapRegion *previous = nullptr; + HeapRegion *region = start; + + while (region < end) { + if (previous && previous != HEAP_REGION_PREVIOUS(region)) { + HEAP_PANIC(21, previous, region); + } + + if (!previous && region->previous) { + HEAP_PANIC(23, previous, region); + } + + if (region->size & 31) { + HEAP_PANIC(51, region, start); + } + + if ((char *) region - (char *) start != region->offset) { + HEAP_PANIC(22, region, start); + } + + if (region->used != USED_HEAP_REGION_MAGIC && region->used != 0x0000) { + HEAP_PANIC(24, region, region->used); + } + + if (region->used == 0x0000 && !region->regionListReference) { + HEAP_PANIC(25, region, region->regionListReference); + } + + if (region->used == 0x0000 && region->regionListNext && region->regionListNext->regionListReference != ®ion->regionListNext) { + HEAP_PANIC(26, region->regionListNext, region); + } + + previous = region; + region = HEAP_REGION_NEXT(region); + } + + if (region != end) { + HEAP_PANIC(20, region, end); + } + } +} + +static void HeapPrintAllocatedRegions(EsHeap *heap) { + EsPrint("--- Heap (%d allocations, %d bytes, %d blocks) ---\n", heap->allocationsCount, heap->size, heap->blockCount); + HeapValidate(heap); + if (heap->cannotValidate) return; + + for (uintptr_t i = 0; i < heap->blockCount; i++) { + HeapRegion *start = (HeapRegion *) heap->blocks[i]; + if (!start) continue; + + HeapRegion *end = (HeapRegion *) ((uint8_t *) heap->blocks[i] + 65536); + HeapRegion *region = start; + + while (region < end) { + if (region->used == USED_HEAP_REGION_MAGIC) { + EsPrint("%x %d\n", HEAP_REGION_DATA(region), region->size); + } + + region = HEAP_REGION_NEXT(region); + } + } +} + +void *EsHeapAllocate(size_t size, bool zeroMemory, EsHeap *_heap) { +#ifndef KERNEL + if (!_heap) _heap = &heap; +#endif + EsHeap &heap = *(EsHeap *) _heap; + if (!size) return nullptr; + +#ifdef USE_PLATFORM_HEAP + return PlatformHeapAllocate(size, zeroMemory); +#endif + + size_t largeAllocationThreshold = LARGE_ALLOCATION_THRESHOLD; + +#ifndef KERNEL + // EsPrint("Allocate: %d\n", size); +#else + // EsPrint("%z: %d\n", mmvmm ? "CORE" : "KERN", size); +#endif + + size_t originalSize = size; + + if ((ptrdiff_t) size < 0) { + HEAP_PANIC(0, 0, 0); + } + + size += USED_HEAP_REGION_HEADER_SIZE; // Region metadata. + size = (size + 0x1F) & ~0x1F; // Allocation granularity: 32 bytes. + + if (size >= largeAllocationThreshold) { + // This is a very large allocation, so allocate it by itself. + // We don't need to zero this memory. (It'll be done by the PMM). + HeapRegion *region = (HeapRegion *) HEAP_ALLOCATE_CALL(size); + if (!region) return nullptr; + region->used = USED_HEAP_REGION_MAGIC; + region->size = 0; + region->allocationSize = originalSize; + __sync_fetch_and_add(&heap.size, originalSize); + return HEAP_REGION_DATA(region); + } + + HEAP_ACQUIRE_MUTEX(heap.mutex); + + MAYBE_VALIDATE_HEAP(); + + HeapRegion *region = nullptr; + + for (int i = HeapCalculateIndex(size); i < 12; i++) { + if (heap.regions[i] == nullptr || heap.regions[i]->size < size) { + continue; + } + + region = heap.regions[i]; + HeapRemoveFreeRegion(region); + goto foundRegion; + } + + region = (HeapRegion *) HEAP_ALLOCATE_CALL(65536); + if (heap.blockCount < 16) heap.blocks[heap.blockCount] = region; + else heap.cannotValidate = true; + heap.blockCount++; + if (!region) { + HEAP_RELEASE_MUTEX(heap.mutex); + return nullptr; + } + region->size = 65536 - 32; + + // Prevent EsHeapFree trying to merge off the end of the block. + { + HeapRegion *endRegion = HEAP_REGION_NEXT(region); + endRegion->used = USED_HEAP_REGION_MAGIC; + endRegion->offset = 65536 - 32; + endRegion->next = 32; + *((EsHeap **) HEAP_REGION_DATA(endRegion)) = &heap; + } + + foundRegion: + + if (region->used || region->size < size) { + HEAP_PANIC(4, region, size); + } + + heap.allocationsCount++; + __sync_fetch_and_add(&heap.size, size); + + if (region->size == size) { + // If the size of this region is equal to the size of the region we're trying to allocate, + // return this region immediately. + region->used = USED_HEAP_REGION_MAGIC; + region->allocationSize = originalSize; + HEAP_RELEASE_MUTEX(heap.mutex); + uint8_t *address = (uint8_t *) HEAP_REGION_DATA(region); + if (zeroMemory) EsMemoryZero(address, originalSize); +#ifdef DEBUG_BUILD + else EsMemoryFill(address, (uint8_t *) address + originalSize, 0xA1); +#endif + return address; + } + + // Split the region into 2 parts. + + HeapRegion *allocatedRegion = region; + size_t oldSize = allocatedRegion->size; + allocatedRegion->size = size; + allocatedRegion->used = USED_HEAP_REGION_MAGIC; + + HeapRegion *freeRegion = HEAP_REGION_NEXT(allocatedRegion); + freeRegion->size = oldSize - size; + freeRegion->previous = size; + freeRegion->offset = allocatedRegion->offset + size; + freeRegion->used = false; + HeapAddFreeRegion(freeRegion, heap.regions); + + HeapRegion *nextRegion = HEAP_REGION_NEXT(freeRegion); + nextRegion->previous = freeRegion->size; + + MAYBE_VALIDATE_HEAP(); + + region->allocationSize = originalSize; + + HEAP_RELEASE_MUTEX(heap.mutex); + + void *address = HEAP_REGION_DATA(region); + + if (zeroMemory) EsMemoryZero(address, originalSize); +#ifdef DEBUG_BUILD + else EsMemoryFill(address, (uint8_t *) address + originalSize, 0xA1); +#endif + + return address; +} + +void EsHeapFree(void *address, size_t expectedSize, EsHeap *_heap) { +#ifndef KERNEL + if (!_heap) _heap = &heap; +#endif + EsHeap &heap = *(EsHeap *) _heap; + + if (!address && expectedSize) HEAP_PANIC(10, address, expectedSize); + if (!address) return; + +#ifdef USE_PLATFORM_HEAP + PlatformHeapFree(address); + return; +#endif + + HeapRegion *region = HEAP_REGION_HEADER(address); + if (region->used != USED_HEAP_REGION_MAGIC) HEAP_PANIC(region->used, region, nullptr); + if (expectedSize && region->allocationSize != expectedSize) HEAP_PANIC(6, region, expectedSize); + + if (!region->size) { + // The region was allocated by itself. + __sync_fetch_and_sub(&heap.size, region->allocationSize); + HEAP_FREE_CALL(region); + return; + } + +#ifdef DEBUG_BUILD + EsMemoryFill(address, (uint8_t *) address + region->allocationSize, 0xB1); +#endif + + // Check this is the correct heap. + + if (*(EsHeap **) HEAP_REGION_DATA((uint8_t *) region - region->offset + 65536 - 32) != &heap) { + HEAP_PANIC(52, address, 0); + } + + HEAP_ACQUIRE_MUTEX(heap.mutex); + + MAYBE_VALIDATE_HEAP(); + + region->used = false; + + if (region->offset < region->previous) { + HEAP_PANIC(31, address, 0); + } + + heap.allocationsCount--; + __sync_fetch_and_sub(&heap.size, region->size); + + // Attempt to merge with the next region. + + HeapRegion *nextRegion = HEAP_REGION_NEXT(region); + + if (nextRegion && !nextRegion->used) { + HeapRemoveFreeRegion(nextRegion); + + // Merge the regions. + region->size += nextRegion->size; + HEAP_REGION_NEXT(nextRegion)->previous = region->size; + } + + // Attempt to merge with the previous region. + + HeapRegion *previousRegion = HEAP_REGION_PREVIOUS(region); + + if (previousRegion && !previousRegion->used) { + HeapRemoveFreeRegion(previousRegion); + + // Merge the regions. + previousRegion->size += region->size; + HEAP_REGION_NEXT(region)->previous = previousRegion->size; + region = previousRegion; + } + + if (region->size == 65536 - 32) { + if (region->offset) HEAP_PANIC(7, region, region->offset); + + // The memory block is empty. + heap.blockCount--; + + if (!heap.cannotValidate) { + bool found = false; + + for (uintptr_t i = 0; i <= heap.blockCount; i++) { + if (heap.blocks[i] == region) { + heap.blocks[i] = heap.blocks[heap.blockCount]; + found = true; + break; + } + } + + EsAssert(found); + } + + HEAP_FREE_CALL(region); + HEAP_RELEASE_MUTEX(heap.mutex); + return; + } + + // Put the free region in the region list. + HeapAddFreeRegion(region, heap.regions); + + MAYBE_VALIDATE_HEAP(); + + HEAP_RELEASE_MUTEX(heap.mutex); +} + +void *EsHeapReallocate(void *oldAddress, size_t newAllocationSize, bool zeroNewSpace, EsHeap *_heap) { +#ifndef KERNEL + if (!_heap) _heap = &heap; +#endif + EsHeap &heap = *(EsHeap *) _heap; + + /* + Test with: + void *a = EsHeapReallocate(nullptr, 128, true); + a = EsHeapReallocate(a, 256, true); + a = EsHeapReallocate(a, 128, true); + a = EsHeapReallocate(a, 65536, true); + a = EsHeapReallocate(a, 128, true); + a = EsHeapReallocate(a, 128, true); + void *b = EsHeapReallocate(nullptr, 64, true); + void *c = EsHeapReallocate(nullptr, 64, true); + EsHeapReallocate(b, 0, true); + a = EsHeapReallocate(a, 128 + 88, true); + a = EsHeapReallocate(a, 128, true); + EsHeapReallocate(a, 0, true); + EsHeapReallocate(c, 0, true); + */ + + if (!oldAddress) { + return EsHeapAllocate(newAllocationSize, zeroNewSpace, _heap); + } else if (!newAllocationSize) { + EsHeapFree(oldAddress, 0, _heap); + return nullptr; + } + +#ifdef USE_PLATFORM_HEAP + return PlatformHeapReallocate(oldAddress, newAllocationSize, zeroNewSpace); +#endif + + HeapRegion *region = HEAP_REGION_HEADER(oldAddress); + + if (region->used != USED_HEAP_REGION_MAGIC) { + HEAP_PANIC(region->used, region, nullptr); + } + + size_t oldAllocationSize = region->allocationSize; + size_t oldRegionSize = region->size; + size_t newRegionSize = (newAllocationSize + USED_HEAP_REGION_HEADER_SIZE + 0x1F) & ~0x1F; + void *newAddress = oldAddress; + bool inHeapBlock = region->size; + bool canMerge = true; + + if (inHeapBlock) { + HEAP_ACQUIRE_MUTEX(heap.mutex); + MAYBE_VALIDATE_HEAP(); + + HeapRegion *adjacent = HEAP_REGION_NEXT(region); + + if (oldRegionSize < newRegionSize) { + if (!adjacent->used && newRegionSize < oldRegionSize + adjacent->size - FREE_HEAP_REGION_HEADER_SIZE) { + HeapRegion *post = HEAP_REGION_NEXT(adjacent); + HeapRemoveFreeRegion(adjacent); + region->size = newRegionSize; + adjacent = HEAP_REGION_NEXT(region); + adjacent->next = (uint8_t *) post - (uint8_t *) adjacent; + adjacent->used = 0; + adjacent->offset = region->offset + region->size; + post->previous = adjacent->next; + adjacent->previous = region->next; + HeapAddFreeRegion(adjacent, heap.regions); + } else if (!adjacent->used && newRegionSize <= oldRegionSize + adjacent->size) { + HeapRegion *post = HEAP_REGION_NEXT(adjacent); + HeapRemoveFreeRegion(adjacent); + region->size = newRegionSize; + post->previous = region->next; + } else { + canMerge = false; + } + } else if (newRegionSize < oldRegionSize) { + if (!adjacent->used) { + HeapRegion *post = HEAP_REGION_NEXT(adjacent); + HeapRemoveFreeRegion(adjacent); + region->size = newRegionSize; + adjacent = HEAP_REGION_NEXT(region); + adjacent->next = (uint8_t *) post - (uint8_t *) adjacent; + adjacent->used = 0; + adjacent->offset = region->offset + region->size; + post->previous = adjacent->next; + adjacent->previous = region->next; + HeapAddFreeRegion(adjacent, heap.regions); + } else if (newRegionSize + USED_HEAP_REGION_HEADER_SIZE <= oldRegionSize) { + region->size = newRegionSize; + HeapRegion *middle = HEAP_REGION_NEXT(region); + middle->size = oldRegionSize - newRegionSize; + middle->used = 0; + middle->previous = region->size; + middle->offset = region->offset + region->size; + adjacent->previous = middle->size; + HeapAddFreeRegion(middle, heap.regions); + } + } + + MAYBE_VALIDATE_HEAP(); + HEAP_RELEASE_MUTEX(heap.mutex); + } else { + canMerge = false; + } + + if (!canMerge) { + newAddress = EsHeapAllocate(newAllocationSize, false, _heap); + EsMemoryCopy(newAddress, oldAddress, oldAllocationSize > newAllocationSize ? newAllocationSize : oldAllocationSize); + EsHeapFree(oldAddress, 0, _heap); + } else { + HEAP_REGION_HEADER(newAddress)->allocationSize = newAllocationSize; + __sync_fetch_and_add(&heap.size, newRegionSize - oldRegionSize); + } + + if (zeroNewSpace && newAllocationSize > oldAllocationSize) { + EsMemoryZero((uint8_t *) newAddress + oldAllocationSize, newAllocationSize - oldAllocationSize); + } + return newAddress; +} + +#ifndef KERNEL +void EsHeapValidate() { + HeapValidate(&heap); +} +#endif diff --git a/shared/ini.h b/shared/ini.h new file mode 100644 index 0000000..c0ca8f4 --- /dev/null +++ b/shared/ini.h @@ -0,0 +1,75 @@ +bool EsINIParse(EsINIState *s) { +#define INI_READ(destination, counter, c1, c2) \ + s->destination = s->buffer, s->counter = 0; \ + while (s->bytes && *s->buffer != c1 && *s->buffer != c2) s->counter++, s->buffer++, s->bytes--; \ + if (s->bytes && *s->buffer == c1) s->buffer++, s->bytes--; + + while (s->bytes) { + char c = *s->buffer; + + if (c == ' ' || c == '\n' || c == '\r') { + s->buffer++, s->bytes--; + continue; + } else if (c == ';') { + s->valueBytes = 0; + INI_READ(key, keyBytes, '\n', 0); + } else if (c == '[') { + s->sectionClassBytes = s->keyBytes = s->valueBytes = 0; + s->buffer++, s->bytes--; + + if (s->bytes && *s->buffer == '@') { + s->buffer++, s->bytes--; + INI_READ(sectionClass, sectionClassBytes, ' ', ']'); + } + + INI_READ(section, sectionBytes, ']', 0); + } else { + INI_READ(key, keyBytes, '=', '\n'); + INI_READ(value, valueBytes, '\n', 0); + } + + return true; + } + + return false; +} + +bool EsINIPeek(EsINIState *s) { + char *oldBuffer = s->buffer; + size_t oldBytes = s->bytes; + bool result = EsINIParse(s); + s->buffer = oldBuffer; + s->bytes = oldBytes; + return result; +} + +size_t EsINIFormat(EsINIState *s, char *buffer, size_t bytes) { +#define INI_WRITE(x, b) for (uintptr_t i = 0; i < b; i++) if (bytes) *buffer = x[i], buffer++, bytes-- + + char *start = buffer; + + if (s->keyBytes || s->valueBytes) { + if (s->key[0] == '[') return 0; + INI_WRITE(s->key, s->keyBytes); + if (s->key[0] != ';') INI_WRITE("=", 1); + INI_WRITE(s->value, s->valueBytes); + INI_WRITE("\n", 1); + } else { + INI_WRITE("\n[", 2); + if (s->sectionClassBytes) INI_WRITE("@", 1); + INI_WRITE(s->sectionClass, s->sectionClassBytes); + if (s->sectionClassBytes && s->sectionBytes) INI_WRITE(" ", 1); + INI_WRITE(s->section, s->sectionBytes); + INI_WRITE("]\n", 2); + } + + return buffer - start; +} + +void EsINIZeroTerminate(EsINIState *s) { + static char emptyString = 0; + if (s->sectionClassBytes) s->sectionClass[s->sectionClassBytes] = 0; else s->sectionClass = &emptyString; + if (s->sectionBytes) s->section[s->sectionBytes] = 0; else s->section = &emptyString; + if (s->keyBytes) s->key[s->keyBytes] = 0; else s->key = &emptyString; + if (s->valueBytes) s->value[s->valueBytes] = 0; else s->value = &emptyString; +} diff --git a/shared/linked_list.cpp b/shared/linked_list.cpp new file mode 100644 index 0000000..1387327 --- /dev/null +++ b/shared/linked_list.cpp @@ -0,0 +1,258 @@ +template <class T> +struct LinkedList; + +template <class T> +struct LinkedItem { + void RemoveFromList(); + + LinkedItem<T> *previousItem; + LinkedItem<T> *nextItem; + + // TODO Separate these out? + struct LinkedList<T> *list; + T *thisItem; +}; + +template <class T> +struct LinkedList { + void InsertStart(LinkedItem<T> *item); + void InsertEnd(LinkedItem<T> *item); + void InsertBefore(LinkedItem<T> *newItem, LinkedItem<T> *beforeItem); + void Remove(LinkedItem<T> *item); + + void Validate(int from); + + LinkedItem<T> *firstItem; + LinkedItem<T> *lastItem; + + size_t count; + +#ifdef DEBUG_BUILD + bool modCheck; +#endif +}; + +struct SimpleList { + void Insert(SimpleList *link, bool start); + void Remove(); + + union { SimpleList *previous, *last; }; + union { SimpleList *next, *first; }; +}; + +#ifndef SHARED_DEFINITIONS_ONLY + +template <class T> +void LinkedItem<T>::RemoveFromList() { + if (!list) { + EsPanic("LinkedItem::RemoveFromList - Item not in list.\n"); + } + + list->Remove(this); +} + +template <class T> +void LinkedList<T>::InsertStart(LinkedItem<T> *item) { +#ifdef DEBUG_BUILD + if (modCheck) EsPanic("LinkedList::InsertStart - Concurrent modification\n"); + modCheck = true; EsDefer({modCheck = false;}); +#endif + + if (item->list == this) EsPanic("LinkedList::InsertStart - Inserting an item that is already in this list\n"); + if (item->list) EsPanic("LinkedList::InsertStart - Inserting an item that is already in a list\n"); + + if (firstItem) { + item->nextItem = firstItem; + item->previousItem = nullptr; + firstItem->previousItem = item; + firstItem = item; + } else { + firstItem = lastItem = item; + item->previousItem = item->nextItem = nullptr; + } + + count++; + item->list = this; + Validate(0); +} + +template <class T> +void LinkedList<T>::InsertEnd(LinkedItem<T> *item) { +#ifdef DEBUG_BUILD + if (modCheck) EsPanic("LinkedList::InsertEnd - Concurrent modification\n"); + modCheck = true; EsDefer({modCheck = false;}); +#endif + + if (item->list == this) EsPanic("LinkedList::InsertEnd - Inserting a item that is already in this list\n"); + if (item->list) EsPanic("LinkedList::InsertEnd - Inserting a item that is already in a list\n"); + + if (lastItem) { + item->previousItem = lastItem; + item->nextItem = nullptr; + lastItem->nextItem = item; + lastItem = item; + } else { + firstItem = lastItem = item; + item->previousItem = item->nextItem = nullptr; + } + + count++; + item->list = this; + Validate(1); +} + +template <class T> +void LinkedList<T>::InsertBefore(LinkedItem<T> *item, LinkedItem<T> *before) { +#ifdef DEBUG_BUILD + if (modCheck) EsPanic("LinkedList::InsertBefore - Concurrent modification\n"); + modCheck = true; EsDefer({modCheck = false;}); +#endif + + if (item->list == this) EsPanic("LinkedList::InsertBefore - Inserting a item that is already in this list\n"); + if (item->list) EsPanic("LinkedList::InsertBefore - Inserting a item that is already in a list\n"); + + if (before != firstItem) { + item->previousItem = before->previousItem; + item->previousItem->nextItem = item; + } else { + firstItem = item; + item->previousItem = nullptr; + } + + item->nextItem = before; + before->previousItem = item; + + count++; + item->list = this; + Validate(3); +} + +template <class T> +void LinkedList<T>::Remove(LinkedItem<T> *item) { +#ifdef DEBUG_BUILD + if (modCheck) EsPanic("LinkedList::Remove - Concurrent modification\n"); + modCheck = true; EsDefer({modCheck = false;}); +#endif + + if (!item->list) EsPanic("LinkedList::Remove - Removing an item that has already been removed\n"); + if (item->list != this) EsPanic("LinkedList::Remove - Removing an item from a different list (list = %x, this = %x)\n", item->list, this); + + if (item->previousItem) { + item->previousItem->nextItem = item->nextItem; + } else { + firstItem = item->nextItem; + } + + if (item->nextItem) { + item->nextItem->previousItem = item->previousItem; + } else { + lastItem = item->previousItem; + } + + item->previousItem = item->nextItem = nullptr; + item->list = nullptr; + count--; + Validate(2); +} + +template <class T> +void LinkedList<T>::Validate(int from) { +#ifdef DEBUG_BUILD + if (count == 0) { + if (firstItem || lastItem) { + EsPanic("LinkedList::Validate (%d) - Invalid list (1)\n", from); + } + } else if (count == 1) { + if (firstItem != lastItem + || firstItem->previousItem + || firstItem->nextItem + || firstItem->list != this + || !firstItem->thisItem) { + EsPanic("LinkedList::Validate (%d) - Invalid list (2)\n", from); + } + } else { + if (firstItem == lastItem + || firstItem->previousItem + || lastItem->nextItem) { + EsPanic("LinkedList::Validate (%d) - Invalid list (3) %x %x %x %x\n", from, firstItem, lastItem, firstItem->previousItem, lastItem->nextItem); + } + + { + LinkedItem<T> *item = firstItem; + size_t index = count; + + while (--index) { + if (item->nextItem == item || item->list != this || !item->thisItem) { + EsPanic("LinkedList::Validate (%d) - Invalid list (4)\n", from); + } + + item = item->nextItem; + } + + if (item != lastItem) { + EsPanic("LinkedList::Validate (%d) - Invalid list (5)\n", from); + } + } + + { + LinkedItem<T> *item = lastItem; + size_t index = count; + + while (--index) { + if (item->previousItem == item) { + EsPanic("LinkedList::Validate (%d) - Invalid list (6)\n", from); + } + + item = item->previousItem; + } + + if (item != firstItem) { + EsPanic("LinkedList::Validate (%d) - Invalid list (7)\n", from); + } + } + } +#else + (void) from; +#endif +} + +void SimpleList::Insert(SimpleList *item, bool start) { + if (item->previous || item->next) { + EsPanic("SimpleList::Insert - Bad links in %x.\n", this); + } + + if (!first && !last) { + item->previous = this; + item->next = this; + first = item; + last = item; + } else if (start) { + item->previous = this; + item->next = first; + first->previous = item; + first = item; + } else { + item->previous = last; + item->next = this; + last->next = item; + last = item; + } +} + +void SimpleList::Remove() { + if (previous->next != this || next->previous != this) { + EsPanic("SimpleList::Remove - Bad links in %x.\n", this); + } + + if (previous == next) { + next->first = nullptr; + next->last = nullptr; + } else { + previous->next = next; + next->previous = previous; + } + + previous = next = nullptr; +} + +#endif diff --git a/shared/math.cpp b/shared/math.cpp new file mode 100644 index 0000000..5e0827b --- /dev/null +++ b/shared/math.cpp @@ -0,0 +1,1835 @@ +///////////////////////////////// +// Basic utilities. +///////////////////////////////// + +template <class T> +T RoundDown(T value, T divisor) { + value /= divisor; + value *= divisor; + return value; +} + +template <class T> +T RoundUp(T value, T divisor) { + value += divisor - 1; + value /= divisor; + value *= divisor; + return value; +} + +inline int DistanceSquared(int x, int y) { + return x * x + y * y; +} + +inline int DistanceSquared(int x1, int y1, int x2, int y2) { + int dx = x2 - x1; + int dy = y2 - y1; + return dx * dx + dy * dy; +} + +inline int ClampInteger(int low, int high, int integer) { + if (integer < low) return low; + if (integer > high) return high; + return integer; +} + +inline intptr_t ClampIntptr(intptr_t low, intptr_t high, intptr_t integer) { + if (integer < low) return low; + if (integer > high) return high; + return integer; +} + +inline int MaximumInteger(int a, int b) { + return a > b ? a : b; +} + +#define MaximumInteger3 MaximumInteger +#define MinimumInteger3 MinimumInteger + +inline int MaximumInteger(int a, int b, int c) { + return MaximumInteger(MaximumInteger(a, b), c); +} + +inline int MaximumInteger(int a, int b, int c, int d) { + return MaximumInteger(MaximumInteger(a, b, c), d); +} + +inline int MinimumInteger(int a, int b) { + return a < b ? a : b; +} + +///////////////////////////////// +// Interpolation. +///////////////////////////////// + +#ifndef KERNEL + +float LinearMap(float inFrom, float inTo, float outFrom, float outTo, float value) { + float raw = (value - inFrom) / (inTo - inFrom); + return raw * (outTo - outFrom) + outFrom; +} + +float LinearInterpolate(float from, float to, float progress) { + return from + progress * (to - from); +} + +#ifndef KERNEL +float GammaInterpolate(float from, float to, float progress) { + from = from * from; + to = to * to; + return EsCRTsqrtf(from + progress * (to - from)); +} +#endif + +double SmoothAnimationTime(double progress) { + if (progress > 1) return 1; + progress -= 1; + return 1 + progress * progress * progress; +} + +double SmoothAnimationTimeSharp(double progress) { + if (progress > 1) return 1; + progress -= 1; + double progressSquared = progress * progress; + return 1 + progressSquared * progressSquared * progress; +} + +///////////////////////////////// +// HSV colors. +///////////////////////////////// + +uint32_t EsColorConvertToRGB(float h, float s, float v) { + float r = 0, g = 0, b = 0; + + if (!s) { + r = g = b = v; + } else { + float f = h - EsCRTfloorf(h); + float x = v * (1 - s), y = v * (1 - s * f), z = v * (1 - s * (1 - f)); + + switch ((int) h) { + case 0: r = v, g = z, b = x; break; + case 1: r = y, g = v, b = x; break; + case 2: r = x, g = v, b = z; break; + case 3: r = x, g = y, b = v; break; + case 4: r = z, g = x, b = v; break; + case 5: r = v, g = x, b = y; break; + } + } + + return (((uint32_t) (r * 255)) << 16) | (((uint32_t) (g * 255)) << 8) | (((uint32_t) (b * 255)) << 0); +} + +bool EsColorConvertToHSV(uint32_t color, float *h, float *s, float *v) { + float r = (float) ((color >> 16) & 0xFF) / 255.0f; + float g = (float) ((color >> 8) & 0xFF) / 255.0f; + float b = (float) ((color >> 0) & 0xFF) / 255.0f; + + float maximum = (r > g && r > b) ? r : (g > b ? g : b), + minimum = (r < g && r < b) ? r : (g < b ? g : b), + difference = maximum - minimum; + *v = maximum; + + if (!difference) { + *s = 0; + return false; + } else { + if (r == maximum) *h = (g - b) / difference + 0; + if (g == maximum) *h = (b - r) / difference + 2; + if (b == maximum) *h = (r - g) / difference + 4; + if (*h < 0) *h += 6; + *s = difference / maximum; + return true; + } +} + +///////////////////////////////// +// Standard mathematical functions. +///////////////////////////////// + +union ConvertFloatInteger { + float f; + uint32_t i; +}; + +union ConvertDoubleInteger { + double d; + uint64_t i; +}; + +float EsCRTfloorf(float x) { + ConvertFloatInteger convert = {x}; + uint32_t sign = convert.i & 0x80000000; + int exponent = (int) ((convert.i >> 23) & 0xFF) - 0x7F; + + if (exponent >= 23) { + // There aren't any bits representing a fractional part. + } else if (exponent >= 0) { + // Positive exponent. + uint32_t mask = 0x7FFFFF >> exponent; + if (!(mask & convert.i)) return x; // Already an integer. + if (sign) convert.i += mask; + convert.i &= ~mask; // Mask out the fractional bits. + } else if (exponent < 0) { + // Negative exponent. + return sign ? -1.0 : 0.0; + } + + return convert.f; +} + +inline float AbsoluteFloat(float f) { + return f > 0 ? f : -f; +} + +inline int AbsoluteInteger(int a) { + return a > 0 ? a : -a; +} + +inline int64_t AbsoluteInteger64(int64_t a) { + return a > 0 ? a : -a; +} + +double EsCRTfloor(double x) { + if (x == 0) return x; + + const double doubleToInteger = 1.0 / 2.22044604925031308085e-16; + + ConvertDoubleInteger convert = {x}; + uint64_t sign = convert.i & 0x8000000000000000; + int exponent = (int) ((convert.i >> 52) & 0x7FF) - 0x3FF; + + if (exponent >= 52) { + // There aren't any bits representing a fractional part. + return x; + } else if (exponent >= 0) { + // Positive exponent. + double y = sign ? (x - doubleToInteger + doubleToInteger - x) : (x + doubleToInteger - doubleToInteger - x); + return y > 0 ? x + y - 1 : x + y; + } else if (exponent < 0) { + // Negative exponent. + return sign ? -1.0 : 0.0; + } + + return 0; +} + +double EsCRTceil(double x) { + if (x == 0) return x; + + const double doubleToInteger = 1.0 / 2.22044604925031308085e-16; + + ConvertDoubleInteger convert = {x}; + uint64_t sign = convert.i & 0x8000000000000000; + int exponent = (int) ((convert.i >> 52) & 0x7FF) - 0x3FF; + + if (exponent >= 52) { + // There aren't any bits representing a fractional part. + return x; + } else if (exponent >= 0) { + // Positive exponent. + double y = sign ? (x - doubleToInteger + doubleToInteger - x) : (x + doubleToInteger - doubleToInteger - x); + return y < 0 ? x + y + 1 : x + y; + } else if (exponent < 0) { + // Negative exponent. + return sign ? -0.0 : 1.0; + } + + return 0; +} + +double EsCRTfabs(double x) { + ConvertDoubleInteger convert = {x}; + convert.i &= ~0x8000000000000000; + return convert.d; +} + +float EsCRTfabsf(float x) { + ConvertFloatInteger convert = {x}; + convert.i &= ~0x80000000; + return convert.f; +} + +float EsCRTceilf(float x) { + ConvertFloatInteger convert = {x}; + uint32_t sign = convert.i & 0x80000000; + int exponent = (int) ((convert.i >> 23) & 0xFF) - 0x7F; + + if (exponent >= 23) { + // There aren't any bits representing a fractional part. + } else if (exponent >= 0) { + // Positive exponent. + uint32_t mask = 0x7FFFFF >> exponent; + if (!(mask & convert.i)) return x; // Already an integer. + if (!sign) convert.i += mask; + convert.i &= ~mask; // Mask out the fractional bits. + } else if (exponent < 0) { + // Negative exponent. + return sign ? -0.0 : 1.0; + } + + return convert.f; +} + +#define D(x) (((ConvertDoubleInteger) { .i = (x) }).d) +#define F(x) (((ConvertFloatInteger) { .i = (x) }).f) + +double _Sine(double x) { + // Calculates sin(x) for x in [0, pi/4]. + + double x2 = x * x; + + return x * (D(0x3FF0000000000000) + x2 * (D(0xBFC5555555555540) + x2 * (D(0x3F8111111110ED80) + x2 * (D(0xBF2A01A019AE6000) + + x2 * (D(0x3EC71DE349280000) + x2 * (D(0xBE5AE5DC48000000) + x2 * D(0x3DE5D68200000000))))))); +} + +float _SineFloat(float x) { + // Calculates sin(x) for x in [0, pi/4]. + + float x2 = x * x; + + return x * (F(0x3F800000) + x2 * (F(0xBE2AAAA0) + x2 * (F(0x3C0882C0) + x2 * F(0xB94C6000)))); +} + +double _ArcSine(double x) { + // Calculates arcsin(x) for x in [0, 0.5]. + + double x2 = x * x; + + return x * (D(0x3FEFFFFFFFFFFFE6) + x2 * (D(0x3FC555555555FE00) + x2 * (D(0x3FB333333292DF90) + x2 * (D(0x3FA6DB6DFD3693A0) + + x2 * (D(0x3F9F1C608DE51900) + x2 * (D(0x3F96EA0659B9A080) + x2 * (D(0x3F91B4ABF1029100) + + x2 * (D(0x3F8DA8DAF31ECD00) + x2 * (D(0x3F81C01FD5000C00) + x2 * (D(0x3F94BDA038CF6B00) + + x2 * (D(0xBF8E849CA75B1E00) + x2 * D(0x3FA146C2D37F2C60)))))))))))); +} + +float _ArcSineFloat(float x) { + // Calculates arcsin(x) for x in [0, 0.5]. + + float x2 = x * x; + + return x * (F(0x3F800004) + x2 * (F(0x3E2AA130) + x2 * (F(0x3D9B2C28) + x2 * (F(0x3D1C1800) + x2 * F(0x3D5A97C0))))); +} + +double _ArcTangent(double x) { + // Calculates arctan(x) for x in [0, 0.5]. + + double x2 = x * x; + + return x * (D(0x3FEFFFFFFFFFFFF8) + x2 * (D(0xBFD5555555553B44) + x2 * (D(0x3FC9999999803988) + x2 * (D(0xBFC249248C882E80) + + x2 * (D(0x3FBC71C5A4E4C220) + x2 * (D(0xBFB745B3B75243F0) + x2 * (D(0x3FB3AFAE9A2939E0) + + x2 * (D(0xBFB1030C4A4A1B90) + x2 * (D(0x3FAD6F65C35579A0) + x2 * (D(0xBFA805BCFDAFEDC0) + + x2 * (D(0x3F9FC6B5E115F2C0) + x2 * D(0xBF87DCA5AB25BF80)))))))))))); +} + +float _ArcTangentFloat(float x) { + // Calculates arctan(x) for x in [0, 0.5]. + + float x2 = x * x; + + return x * (F(0x3F7FFFF8) + x2 * (F(0xBEAAA53C) + x2 * (F(0x3E4BC990) + x2 * (F(0xBE084A60) + x2 * F(0x3D8864B0))))); +} + +double _Cosine(double x) { + // Calculates cos(x) for x in [0, pi/4]. + + double x2 = x * x; + + return D(0x3FF0000000000000) + x2 * (D(0xBFDFFFFFFFFFFFA0) + x2 * (D(0x3FA555555554F7C0) + x2 * (D(0xBF56C16C16475C00) + + x2 * (D(0x3EFA019F87490000) + x2 * (D(0xBE927DF66B000000) + x2 * D(0x3E21B949E0000000)))))); +} + +float _CosineFloat(float x) { + // Calculates cos(x) for x in [0, pi/4]. + + float x2 = x * x; + + return F(0x3F800000) + x2 * (F(0xBEFFFFDA) + x2 * (F(0x3D2A9F60) + x2 * F(0xBAB22C00))); +} + +double _Tangent(double x) { + // Calculates tan(x) for x in [0, pi/4]. + + double x2 = x * x; + + return x * (D(0x3FEFFFFFFFFFFFE8) + x2 * (D(0x3FD5555555558000) + x2 * (D(0x3FC1111110FACF90) + x2 * (D(0x3FABA1BA266BFD20) + + x2 * (D(0x3F9664F30E56E580) + x2 * (D(0x3F822703B08BDC00) + x2 * (D(0x3F6D698D2E4A4C00) + + x2 * (D(0x3F57FF4F23EA4400) + x2 * (D(0x3F424F3BEC845800) + x2 * (D(0x3F34C78CA9F61000) + + x2 * (D(0xBF042089F8510000) + x2 * (D(0x3F29D7372D3A8000) + x2 * (D(0xBF19D1C5EF6F0000) + + x2 * (D(0x3F0980BDF11E8000))))))))))))))); +} + +float _TangentFloat(float x) { + // Calculates tan(x) for x in [0, pi/4]. + + float x2 = x * x; + + return x * (F(0x3F800001) + x2 * (F(0x3EAAA9AA) + x2 * (F(0x3E08ABA8) + x2 * (F(0x3D58EC90) + + x2 * (F(0x3CD24840) + x2 * (F(0x3AC3CA00) + x2 * F(0x3C272F00))))))); +} + +double EsCRTsin(double x) { + bool negate = false; + + // x in -infty, infty + + if (x < 0) { + x = -x; + negate = true; + } + + // x in 0, infty + + x -= 2 * ES_PI * EsCRTfloor(x / (2 * ES_PI)); + + // x in 0, 2*pi + + if (x < ES_PI / 2) { + } else if (x < ES_PI) { + x = ES_PI - x; + } else if (x < 3 * ES_PI / 2) { + x = x - ES_PI; + negate = !negate; + } else { + x = ES_PI * 2 - x; + negate = !negate; + } + + // x in 0, pi/2 + + double y = x < ES_PI / 4 ? _Sine(x) : _Cosine(ES_PI / 2 - x); + return negate ? -y : y; +} + +float EsCRTsinf(float x) { + bool negate = false; + + // x in -infty, infty + + if (x < 0) { + x = -x; + negate = true; + } + + // x in 0, infty + + x -= 2 * ES_PI * EsCRTfloorf(x / (2 * ES_PI)); + + // x in 0, 2*pi + + if (x < ES_PI / 2) { + } else if (x < ES_PI) { + x = ES_PI - x; + } else if (x < 3 * ES_PI / 2) { + x = x - ES_PI; + negate = !negate; + } else { + x = ES_PI * 2 - x; + negate = !negate; + } + + // x in 0, pi/2 + + float y = x < ES_PI / 4 ? _SineFloat(x) : _CosineFloat(ES_PI / 2 - x); + return negate ? -y : y; +} + +double EsCRTcos(double x) { + bool negate = false; + + // x in -infty, infty + + if (x < 0) { + x = -x; + } + + // x in 0, infty + + x -= 2 * ES_PI * EsCRTfloor(x / (2 * ES_PI)); + + // x in 0, 2*pi + + if (x < ES_PI / 2) { + } else if (x < ES_PI) { + x = ES_PI - x; + negate = !negate; + } else if (x < 3 * ES_PI / 2) { + x = x - ES_PI; + negate = !negate; + } else { + x = ES_PI * 2 - x; + } + + // x in 0, pi/2 + + double y = x < ES_PI / 4 ? _Cosine(x) : _Sine(ES_PI / 2 - x); + return negate ? -y : y; +} + +float EsCRTcosf(float x) { + bool negate = false; + + // x in -infty, infty + + if (x < 0) { + x = -x; + } + + // x in 0, infty + + x -= 2 * ES_PI * EsCRTfloorf(x / (2 * ES_PI)); + + // x in 0, 2*pi + + if (x < ES_PI / 2) { + } else if (x < ES_PI) { + x = ES_PI - x; + negate = !negate; + } else if (x < 3 * ES_PI / 2) { + x = x - ES_PI; + negate = !negate; + } else { + x = ES_PI * 2 - x; + } + + // x in 0, pi/2 + + float y = x < ES_PI / 4 ? _CosineFloat(x) : _SineFloat(ES_PI / 2 - x); + return negate ? -y : y; +} + +double EsCRTtan(double x) { + bool negate = false; + + // x in -infty, infty + + if (x < 0) { + x = -x; + negate = !negate; + } + + // x in 0, infty + + x -= ES_PI * EsCRTfloor(x / ES_PI); + + // x in 0, pi + + if (x > ES_PI / 2) { + x = ES_PI - x; + negate = !negate; + } + + // x in 0, pi/2 + + double y = x < ES_PI / 4 ? _Tangent(x) : (1.0 / _Tangent(ES_PI / 2 - x)); + return negate ? -y : y; +} + +float EsCRTtanf(float x) { + bool negate = false; + + // x in -infty, infty + + if (x < 0) { + x = -x; + negate = !negate; + } + + // x in 0, infty + + x -= ES_PI * EsCRTfloorf(x / ES_PI); + + // x in 0, pi + + if (x > ES_PI / 2) { + x = ES_PI - x; + negate = !negate; + } + + // x in 0, pi/2 + + float y = x < ES_PI / 4 ? _TangentFloat(x) : (1.0 / _TangentFloat(ES_PI / 2 - x)); + return negate ? -y : y; +} + +double EsCRTasin(double x) { + bool negate = false; + + if (x < 0) { + x = -x; + negate = true; + } + + double y; + + if (x < 0.5) { + y = _ArcSine(x); + } else { + y = ES_PI / 2 - 2 * _ArcSine(EsCRTsqrt(0.5 - 0.5 * x)); + } + + return negate ? -y : y; +} + +float EsCRTasinf(float x) { + bool negate = false; + + if (x < 0) { + x = -x; + negate = true; + } + + float y; + + if (x < 0.5) { + y = _ArcSineFloat(x); + } else { + y = ES_PI / 2 - 2 * _ArcSineFloat(EsCRTsqrtf(0.5 - 0.5 * x)); + } + + return negate ? -y : y; +} + +double EsCRTacos(double x) { + return EsCRTasin(-x) + ES_PI / 2; +} + +float EsCRTacosf(float x) { + return EsCRTasinf(-x) + ES_PI / 2; +} + +double EsCRTatan(double x) { + bool negate = false; + + if (x < 0) { + x = -x; + negate = true; + } + + bool reciprocalTaken = false; + + if (x > 1) { + x = 1 / x; + reciprocalTaken = true; + } + + double y; + + if (x < 0.5) { + y = _ArcTangent(x); + } else { + y = 0.463647609000806116 + _ArcTangent((2 * x - 1) / (2 + x)); + } + + if (reciprocalTaken) { + y = ES_PI / 2 - y; + } + + return negate ? -y : y; +} + +float EsCRTatanf(float x) { + bool negate = false; + + if (x < 0) { + x = -x; + negate = true; + } + + bool reciprocalTaken = false; + + if (x > 1) { + x = 1 / x; + reciprocalTaken = true; + } + + float y; + + if (x < 0.5f) { + y = _ArcTangentFloat(x); + } else { + y = 0.463647609000806116f + _ArcTangentFloat((2 * x - 1) / (2 + x)); + } + + if (reciprocalTaken) { + y = ES_PI / 2 - y; + } + + return negate ? -y : y; +} + +double EsCRTatan2(double y, double x) { + if (x == 0) return y > 0 ? ES_PI / 2 : -ES_PI / 2; + else if (x > 0) return EsCRTatan(y / x); + else if (y >= 0) return ES_PI + EsCRTatan(y / x); + else return -ES_PI + EsCRTatan(y / x); +} + +float EsCRTatan2f(float y, float x) { + if (x == 0) return y > 0 ? ES_PI / 2 : -ES_PI / 2; + else if (x > 0) return EsCRTatanf(y / x); + else if (y >= 0) return ES_PI + EsCRTatanf(y / x); + else return -ES_PI + EsCRTatanf(y / x); +} + +double EsCRTexp2(double x) { + double a = EsCRTfloor(x * 8); + int64_t ai = a; + + if (ai < -1024) { + return 0; + } + + double b = x - a / 8; + + double y = D(0x3FF0000000000000) + b * (D(0x3FE62E42FEFA3A00) + b * (D(0x3FCEBFBDFF829140) + + b * (D(0x3FAC6B08D73C4A40) + b * (D(0x3F83B2AB53873280) + b * (D(0x3F55D88F363C6C00) + + b * (D(0x3F242C003E4A2000) + b * D(0x3EF0B291F6C00000))))))); + + const double m[8] = { + D(0x3FF0000000000000), + D(0x3FF172B83C7D517B), + D(0x3FF306FE0A31B715), + D(0x3FF4BFDAD5362A27), + D(0x3FF6A09E667F3BCD), + D(0x3FF8ACE5422AA0DB), + D(0x3FFAE89F995AD3AD), + D(0x3FFD5818DCFBA487), + }; + + y *= m[ai & 7]; + + ConvertDoubleInteger c; + c.d = y; + c.i += (ai >> 3) << 52; + return c.d; +} + +float EsCRTexp2f(float x) { + float a = EsCRTfloorf(x); + int32_t ai = a; + + if (ai < -128) { + return 0; + } + + float b = x - a; + + float y = F(0x3F7FFFFE) + b * (F(0x3F31729A) + b * (F(0x3E75E700) + + b * (F(0x3D64D520) + b * (F(0x3C128280) + b * F(0x3AF89400))))); + + ConvertFloatInteger c; + c.f = y; + c.i += ai << 23; + return c.f; +} + +double EsCRTlog2(double x) { + ConvertDoubleInteger c; + c.d = x; + int64_t e = ((c.i >> 52) & 2047) - 0x3FF; + c.i = (c.i & ~((uint64_t) 0x7FF << 52)) + ((uint64_t) 0x3FF << 52); + x = c.d; + + double a; + + if (x < 1.125) { + a = 0; + } else if (x < 1.250) { + x *= 1.125 / 1.250; + a = D(0xBFC374D65D9E608E); + } else if (x < 1.375) { + x *= 1.125 / 1.375; + a = D(0xBFD28746C334FECB); + } else if (x < 1.500) { + x *= 1.125 / 1.500; + a = D(0xBFDA8FF971810A5E); + } else if (x < 1.625) { + x *= 1.125 / 1.625; + a = D(0xBFE0F9F9FFC8932A); + } else if (x < 1.750) { + x *= 1.125 / 1.750; + a = D(0xBFE465D36ED11B11); + } else if (x < 1.875) { + x *= 1.125 / 1.875; + a = D(0xBFE79538DEA712F5); + } else { + x *= 1.125 / 2.000; + a = D(0xBFEA8FF971810A5E); + } + + double y = D(0xC00FF8445026AD97) + x * (D(0x40287A7A02D9353F) + x * (D(0xC03711C58D55CEE2) + + x * (D(0x4040E8263C321A26) + x * (D(0xC041EB22EA691BB3) + x * (D(0x403B00FB376D1F10) + + x * (D(0xC02C416ABE857241) + x * (D(0x40138BA7FAA3523A) + x * (D(0xBFF019731AF80316) + + x * D(0x3FB7F1CD3852C200))))))))); + + return y - a + e; +} + +float EsCRTlog2f(float x) { + ConvertFloatInteger c; + c.f = x; + int32_t e = ((c.i >> 23) & 255) - 0x7F; + c.i = (c.i & ~(0xFF << 23)) + (0x7F << 23); + x = c.f; + + double y = F(0xC05B5154) + x * (F(0x410297C6) + x * (F(0xC1205CEB) + + x * (F(0x4114DF63) + x * (F(0xC0C0DBBB) + x * (F(0x402942C6) + + x * (F(0xBF3FF98A) + x * (F(0x3DFE1050) + x * F(0xBC151480)))))))); + + return y + e; +} + +double EsCRTpow(double x, double y) { + return EsCRTexp2(y * EsCRTlog2(x)); +} + +float EsCRTpowf(float x, float y) { + return EsCRTexp2f(y * EsCRTlog2f(x)); +} + +double EsCRTexp(double x) { + return EsCRTexp2(x * 1.4426950408889634073); +} + +float EsCRTexpf(float x) { + return EsCRTexp2f(x * 1.442695040f); +} + +double EsCRTfmod(double x, double y) { + return x - y * EsCRTfloor(x / y); +} + +float EsCRTfmodf(float x, float y) { + return x - y * EsCRTfloorf(x / y); +} + +bool EsCRTisnanf(float x) { + ConvertFloatInteger c; + c.f = x; + return (c.i & ~(1 << 31)) > 0x7F800000; +} + +#undef D +#undef F + +///////////////////////////////// +// High precision floats. +///////////////////////////////// + +#define MANTISSA_BITS (256) +#include <x86intrin.h> + +struct BigFloat { + uint64_t mantissa[MANTISSA_BITS / 64]; + int32_t exponent; + bool negative, zero; + +#define SET_MANTISSA_BIT(m, i, value) \ + do { \ + if ((value)) { \ + (m).mantissa[(i) >> 6] |= (uint64_t) 1 << (63 - ((i) & 63)); \ + } else { \ + (m).mantissa[(i) >> 6] &= ~((uint64_t) 1 << (63 - ((i) & 63))); \ + } \ + } while (0) + +#define GET_MANTISSA_BIT(m, i) (((m).mantissa[(i) >> 6] & ((uint64_t) 1 << (63 - ((i) & 63)))) ? 1 : 0) + + void _FromDouble(double d) { + if (d == 0) { + zero = true; + return; + } + + ConvertDoubleInteger c; + c.d = d; + + negative = false; + + if (c.i & ((uint64_t) 1 << 63)) { + negative = true; + } + + exponent = ((c.i >> 52) & 2047) - 1023; + + for (uintptr_t i = 0; i < sizeof(mantissa) / sizeof(mantissa[0]); i++) { + mantissa[i] = 0; + } + + SET_MANTISSA_BIT(*this, 0, 1); + + for (intptr_t i = 0; i < 52; i++) { + if (c.i & ((uint64_t) 1 << (51 - i))) { + SET_MANTISSA_BIT(*this, i + 1, 1); + } + } + + _Normalize(); + } + + double ToDouble() { + if (zero) return 0; + + double d = 0; + + for (intptr_t i = MANTISSA_BITS - 1; i >= 0; i--) { + if (GET_MANTISSA_BIT(*this, i)) { + ConvertDoubleInteger c; + uint64_t p = exponent - i - 1 + 1024; + c.i = p << 52; + d += c.d; + } + } + + return negative ? -d : d; + } + + void _ShiftRight(intptr_t shift) { + if (!shift) return; + +#if 0 + for (intptr_t i = MANTISSA_BITS - 1; i >= 0; i--) { + if (i < shift) { + SET_MANTISSA_BIT(*this, i, 0); + } else { + SET_MANTISSA_BIT(*this, i, GET_MANTISSA_BIT(*this, i - shift)); + } + } +#else + if (shift >= 64) { + intptr_t shift0 = shift / 64; + + for (intptr_t i = sizeof(mantissa) / sizeof(mantissa[0]) - 1; i >= 0; i--) { + if (i < shift0) { + mantissa[i] = 0; + } else { + mantissa[i] = mantissa[i - shift0]; + } + } + } + + uint64_t removed = 0; + + for (intptr_t i = 0; i < (intptr_t) (sizeof(mantissa) / sizeof(mantissa[0])); i++) { + uint64_t r = mantissa[i] & (((uint64_t) 1 << shift) - 1); + mantissa[i] = (mantissa[i] >> shift) | removed; + removed = r << (64 - shift); + } +#endif + + exponent += shift; + } + + void _ShiftLeft(intptr_t shift) { + if (!shift) return; + +#if 0 + for (intptr_t i = 0; i < MANTISSA_BITS; i++) { + if (i >= MANTISSA_BITS - shift) { + SET_MANTISSA_BIT(*this, i, 0); + } else { + SET_MANTISSA_BIT(*this, i, GET_MANTISSA_BIT(*this, i + shift)); + } + } +#else + if (shift >= 64) { + intptr_t shift0 = shift / 64; + + for (intptr_t i = 0; i < (intptr_t) (sizeof(mantissa) / sizeof(mantissa[0])); i++) { + if (i >= (intptr_t) (sizeof(mantissa) / sizeof(mantissa[0])) - shift0) { + mantissa[i] = 0; + } else { + mantissa[i] = mantissa[i + shift0]; + } + } + } + + uint64_t removed = 0; + + for (intptr_t i = sizeof(mantissa) / sizeof(mantissa[0]) - 1; i >= 0; i--) { + uint64_t r = mantissa[i] & (((1UL << shift) - 1) << (64 - shift)); + mantissa[i] = (mantissa[i] << shift) | removed; + removed = r >> (64 - shift); + } +#endif + + exponent -= shift; + } + + void _Normalize() { + // Find the first set bit. + + intptr_t shift = -1; + +#if 0 + for (intptr_t i = 0; i < MANTISSA_BITS; i++) { + if (GET_MANTISSA_BIT(*this, i)) { + shift = i; + break; + } + } +#else + for (uintptr_t i = 0; i < sizeof(mantissa) / sizeof(mantissa[0]); i++) { + if (mantissa[i]) { + shift = __builtin_clzll(mantissa[i]) + i * 64; + break; + } + } +#endif + + // If we didn't find one, then the number is zero. + + if (shift == -1) { + exponent = 0; + negative = false; + zero = true; + return; + } + + // Shift the mantissa so that the first set bit is the first bit. + + if (shift) { + _ShiftLeft(shift); + } + + zero = false; + } + + BigFloat operator+(BigFloat y) { + if (zero) return y; + if (y.zero) return *this; + + BigFloat x = *this; + + // Make sure that x has a bigger exponent. + + if (y.exponent > x.exponent) { + BigFloat swap = x; + x = y; + y = swap; + } + + // Shift y's mantissa to the right so that its exponent matches x's. + + y._ShiftRight(x.exponent - y.exponent); + + // If x and y have different signs, make sure y is the negative one. + + bool subtract = x.negative != y.negative; + + if (x.negative && !y.negative) { + BigFloat swap = x; + x = y; + y = swap; + } + + // Add/subtract y's mantissa to x's. + + if (subtract) { + for (uintptr_t i = 0; i < sizeof(mantissa) / sizeof(mantissa[0]); i++) { + y.mantissa[i] = ~y.mantissa[i]; + } + } + + uint8_t carry = subtract ? 1 : 0; + +#if 0 + for (intptr_t i = MANTISSA_BITS - 1; i >= 0; i--) { + uint8_t xi = GET_MANTISSA_BIT(x, i); + uint8_t yi = GET_MANTISSA_BIT(y, i); + uint8_t sum = xi + yi + carry; + carry = sum >> 1; + SET_MANTISSA_BIT(x, i, sum & 1); + } +#else + for (intptr_t i = sizeof(mantissa) / sizeof(mantissa[0]) - 1; i >= 0; i--) { + carry = _addcarry_u64(carry, x.mantissa[i], y.mantissa[i], (long long unsigned int *) &x.mantissa[i]); + } +#endif + + if (subtract) { + if (!carry) { + // Negate the result. + + for (uintptr_t i = 0; i < sizeof(mantissa) / sizeof(mantissa[0]); i++) { + x.mantissa[i] = ~x.mantissa[i]; + } + + uint8_t carry = 1; + +#if 0 + for (intptr_t i = MANTISSA_BITS - 1; i >= 0; i--) { + uint8_t xi = GET_MANTISSA_BIT(x, i); + uint8_t sum = xi + carry; + carry = sum >> 1; + SET_MANTISSA_BIT(x, i, sum & 1); + } +#else + for (intptr_t i = sizeof(mantissa) / sizeof(mantissa[0]) - 1; i >= 0; i--) { + carry = _addcarry_u64(carry, x.mantissa[i], 0, (long long unsigned int *) &x.mantissa[i]); + } +#endif + + x.negative = true; + } + } else { + if (carry) { + x._ShiftRight(1); + SET_MANTISSA_BIT(x, 0, 1); + } + } + + x._Normalize(); + + return x; + } + + BigFloat operator-(BigFloat y) { + y.negative = !y.negative; + return *this + y; + } + + BigFloat operator*(BigFloat y) { + // TODO Can this be done faster? + if (zero) return *this; + if (y.zero) return y; + + BigFloat accumulator = { .zero = true }; + + for (intptr_t i = MANTISSA_BITS - 1; i >= 0; i--) { + if (GET_MANTISSA_BIT(y, i)) { + BigFloat place = *this; + place.exponent = place.exponent - i + y.exponent; + accumulator = accumulator + place; + } + } + + accumulator.negative = negative != y.negative; + return accumulator; + } +}; + +struct { + BigFloat zero; + BigFloat one; + BigFloat two; + BigFloat half; + BigFloat halfPi; + BigFloat pi; + BigFloat twoPi; + BigFloat log2; + BigFloat e; + BigFloat log2E; +} bigFloatConstants; + +BigFloat BigFloatDivide(BigFloat x, BigFloat y, bool *error) { + if (x.zero) return x; + if (y.zero) { *error = true; return y; } + + BigFloat q = {}; + bool negative = x.negative != y.negative; + x.negative = y.negative = false; + + intptr_t e = x.exponent - y.exponent; + + // Loop over MANTISSA_BITS + 1. + // There will definitely be a subtraction in the first two iterations, by the initial choice of e. + // Any additions to q with exponent less than initial e - MANTISSA_BITS - 1 therefore has no effect. + + for (int i = 0; i <= MANTISSA_BITS; i++) { + BigFloat m = {}; + SET_MANTISSA_BIT(m, 0, 1); + m.exponent = e; + + BigFloat s = y; + s.exponent += e; + BigFloat x1 = x - s; + + if (!x1.negative) { + x = x1; + q = q + m; + } + + e--; + } + + q.negative = negative; + return q; +} + +BigFloat BigFloatModulo(BigFloat x, BigFloat y, bool *error) { + if (x.zero) return x; + if (y.zero) { *error = true; return y; } + + x.negative = y.negative = false; + intptr_t e = x.exponent - y.exponent; + + for (int i = 0; e >= 0; i++) { + BigFloat m = {}; + SET_MANTISSA_BIT(m, 0, 1); + m.exponent = e; + + BigFloat s = y; + s.exponent += e; + BigFloat x1 = x - s; + + if (!x1.negative) { + x = x1; + } + + e--; + } + + return x; +} + +BigFloat BigFloatRoundToNegativeInfinity(BigFloat x) { + bool decrement = false; + + intptr_t start = x.exponent + 1; + + if (start < 0) { + start = 0; + } + + for (intptr_t i = start; i < MANTISSA_BITS; i++) { + if (x.negative && !decrement && GET_MANTISSA_BIT(x, i)) { + decrement = true; + } + + SET_MANTISSA_BIT(x, i, 0); + } + + x._Normalize(); + + if (decrement) { + return x - bigFloatConstants.one; + } else { + return x; + } +} + +BigFloat BigFloatSine(BigFloat x, bool *error) { + // Get x in the range 0 to 2*pi. + + bool negate = x.negative; + x.negative = false; + x = BigFloatModulo(x, bigFloatConstants.twoPi, error); + + // Evaluate the Maclaurin series. + + if (error && *error) return x; + if (x.zero) return x; + + BigFloat x2 = x * x; + BigFloat y = {}; + y.zero = true; + + BigFloat p = x; + BigFloat k = bigFloatConstants.two; + + for (int i = 0; i < 10000; i++) { + if (p.exponent + MANTISSA_BITS < y.exponent && !y.zero) { + break; + } + + y = y + p; + p.negative = !p.negative; + p = x2 * BigFloatDivide(p, k * (k + bigFloatConstants.one), nullptr); + k = k + bigFloatConstants.two; + } + + if (negate) y.negative = !y.negative; + return y; +} + +BigFloat BigFloatCosine(BigFloat x, bool *error) { + return BigFloatSine(bigFloatConstants.halfPi - x, error); +} + +BigFloat BigFloatTangent(BigFloat x, bool *error) { + return BigFloatDivide(BigFloatSine(x, error), BigFloatCosine(x, error), error); +} + +BigFloat BigFloatLogarithm2(BigFloat x, bool *error) { + if (x.negative || x.zero) { + *error = true; + return x; + } + + BigFloat accumulator = {}; + accumulator._FromDouble(x.exponent); + x.exponent = 0; + + BigFloat m = bigFloatConstants.one; + + do { + if ((x - bigFloatConstants.one).zero) { + break; + } + + while ((x - bigFloatConstants.two).negative && accumulator.exponent - m.exponent < MANTISSA_BITS) { + x = x * x; + m.exponent--; + } + + accumulator = accumulator + m; + x.exponent--; + } while (accumulator.exponent - m.exponent < MANTISSA_BITS); + + return accumulator; +} + +BigFloat BigFloatExponential2(BigFloat x, bool *error) { + BigFloat _integer = BigFloatRoundToNegativeInfinity(x); + BigFloat fractional = x - _integer; + int32_t integer = _integer.ToDouble(); + + if (integer < -1000000 || integer > 1000000) { + *error = true; + return x; + } + + BigFloat accumulator = {}; + accumulator.zero = true; + BigFloat term = bigFloatConstants.one; + BigFloat n = bigFloatConstants.one; + + do { + accumulator = accumulator + term; + term = BigFloatDivide(term * fractional * bigFloatConstants.log2, n, error); + n = n + bigFloatConstants.one; + } while (accumulator.exponent - term.exponent < MANTISSA_BITS && !term.zero); + + accumulator.exponent += integer; + return accumulator; +} + +BigFloat BigFloatPower(BigFloat x, BigFloat y, bool *error) { + return BigFloatExponential2(y * BigFloatLogarithm2(x, error), error); +} + +BigFloat BigFloatExponential(BigFloat x, bool *error) { + return BigFloatExponential2(x * bigFloatConstants.log2E, error); +} + +BigFloat BigFloatLogarithm(BigFloat x, bool *error) { + return BigFloatDivide(BigFloatLogarithm2(x, error), bigFloatConstants.log2E, error); +} + +BigFloat BigFloatArcSine(BigFloat x, bool *error) { + BigFloat accumulator = {}; + accumulator.zero = true; + BigFloat n = {}; + n.zero = true; + BigFloat term = x; + BigFloat xm = x * x; + xm.exponent -= 2; + BigFloat three = bigFloatConstants.one + bigFloatConstants.two; + + do { + accumulator = accumulator + term; + BigFloat n2 = n; + n2.exponent++; + BigFloat s1 = n2 + bigFloatConstants.one; + BigFloat s2 = n + bigFloatConstants.one; + term = BigFloatDivide(term * xm * (n2 + bigFloatConstants.two) * s1 * s1, s2 * s2 * (n2 + three), error); + n = n + bigFloatConstants.one; + } while (accumulator.exponent - term.exponent < MANTISSA_BITS && !term.zero); + + return accumulator; +} + +BigFloat BigFloatArcCosine(BigFloat x, bool *error) { + x.negative = !x.negative; + return BigFloatArcSine(x, error) + bigFloatConstants.halfPi; +} + +BigFloat BigFloatArcTangent(BigFloat x, bool *error) { + return BigFloatArcSine(BigFloatDivide(x, BigFloatPower(bigFloatConstants.one + x * x, bigFloatConstants.half, error), error), error); +} + +BigFloat BigFloatHyperbolicSine(BigFloat x, bool *error) { + BigFloat ex = BigFloatExponential(x, error); + return bigFloatConstants.half * (ex - BigFloatDivide(bigFloatConstants.one, ex, error)); +} + +BigFloat BigFloatHyperbolicCosine(BigFloat x, bool *error) { + BigFloat ex = BigFloatExponential(x, error); + return bigFloatConstants.half * (ex + BigFloatDivide(bigFloatConstants.one, ex, error)); +} + +BigFloat BigFloatHyperbolicTangent(BigFloat x, bool *error) { + BigFloat e2x = BigFloatExponential(bigFloatConstants.two * x, error); + return BigFloatDivide(e2x - bigFloatConstants.one, e2x + bigFloatConstants.one, error); +} + +BigFloat BigFloatArcHyperbolicSine(BigFloat x, bool *error) { + return BigFloatLogarithm(x + BigFloatPower(x * x + bigFloatConstants.one, bigFloatConstants.half, error), error); +} + +BigFloat BigFloatArcHyperbolicCosine(BigFloat x, bool *error) { + return BigFloatLogarithm(x + BigFloatPower(x * x - bigFloatConstants.one, bigFloatConstants.half, error), error); +} + +BigFloat BigFloatArcHyperbolicTangent(BigFloat x, bool *error) { + return bigFloatConstants.half * BigFloatLogarithm(BigFloatDivide(bigFloatConstants.one + x, bigFloatConstants.one - x, error), error); +} + +void BigFloatInitialise() { + EsMessageMutexCheck(); + + static bool initialised = false; + + if (initialised) { + return; + } + + initialised = true; + + bigFloatConstants.zero.zero = true; + bigFloatConstants.one.mantissa[0] = (uint64_t) 1 << 63; + bigFloatConstants.one.exponent = 0; + bigFloatConstants.two.mantissa[0] = (uint64_t) 1 << 63; + bigFloatConstants.two.exponent = 1; + bigFloatConstants.half.mantissa[0] = (uint64_t) 1 << 63; + bigFloatConstants.half.exponent = -1; + + { + BigFloat term = bigFloatConstants.two; + BigFloat n = bigFloatConstants.one; + + BigFloat accumulator = {}; + accumulator.zero = true; + + while (term.exponent >= -MANTISSA_BITS) { + accumulator = accumulator + term; + term = term * BigFloatDivide(n * n, bigFloatConstants.two * n * n + n, nullptr); + n = n + bigFloatConstants.one; + } + + bigFloatConstants.pi = accumulator; + bigFloatConstants.halfPi = BigFloatDivide(accumulator, bigFloatConstants.two, nullptr); + bigFloatConstants.twoPi = bigFloatConstants.two * accumulator; + } + + { + BigFloat n = bigFloatConstants.one; + + BigFloat accumulator = {}; + accumulator.zero = true; + + for (int i = 1; i <= MANTISSA_BITS; i++) { + BigFloat d = BigFloatDivide(bigFloatConstants.one, n, nullptr); + d.exponent -= i; + accumulator = accumulator + d; + n = n + bigFloatConstants.one; + } + + bigFloatConstants.log2 = accumulator; + } + + { + BigFloat n = bigFloatConstants.one; + BigFloat term = bigFloatConstants.one; + BigFloat accumulator = bigFloatConstants.one; + + for (int i = 0; i <= MANTISSA_BITS; i++) { + accumulator = accumulator + term; + n = n + bigFloatConstants.one; + term = BigFloatDivide(term, n, nullptr); + } + + bigFloatConstants.e = accumulator; + bigFloatConstants.log2E = BigFloatLogarithm2(bigFloatConstants.e, nullptr); + } +} + +///////////////////////////////// +// Calculating expressions. +///////////////////////////////// + +namespace Calculator { + enum ValueType : uint8_t { + VALUE_ERROR, + VALUE_NUMBER, + }; + + struct Value { + ValueType type; + + union { + BigFloat number; + }; + }; + + enum TokenType : uint8_t { + TOKEN_ERROR, + TOKEN_PUNCTUATOR, + TOKEN_LITERAL, + TOKEN_IDENTIFIER, + TOKEN_EOF, + }; + + struct Token { + TokenType type; + + union { + uint16_t punctuator; + Value literal; + char *identifier; + }; + }; + + enum NodeType : uint8_t { + NODE_BINOP, + NODE_UNARYOP, + NODE_CALL, + NODE_LITERAL, + }; + + struct Node { + NodeType type; + Node *firstChild, *sibling; + Token token; + }; + + typedef Value (*Builtin)(Value *arguments, size_t argumentCount); + + struct Parser { + const char *position; + HashStore<char, Builtin> builtins; +#define CALCULATOR_PARSER_ALLOCATION_POOL_SIZE (8192) + char *allocationPool; + int allocatedBytes; + + void FreeAll() { + allocatedBytes = 0; + EsHeapFree(allocationPool); + allocationPool = nullptr; + } + + void *Allocate(size_t bytes) { + bytes = (bytes + sizeof(max_align_t) - 1) & ~(sizeof(max_align_t) - 1); + + if (bytes + allocatedBytes > CALCULATOR_PARSER_ALLOCATION_POOL_SIZE) { + return nullptr; + } + + if (!allocationPool) { + allocationPool = (char *) EsHeapAllocate(CALCULATOR_PARSER_ALLOCATION_POOL_SIZE, false); + } + + void *pointer = allocationPool + allocatedBytes; + allocatedBytes += bytes; + EsMemoryZero(pointer, bytes); + return pointer; + } + + Token PeekToken() { + const char *oldPosition = position; + Token token = NextToken(); + position = oldPosition; + return token; + } + + Token NextToken() { + Token token = {}; + + tryAgain:; + + unsigned char c = *position; + + if (c == '#') { + while (*position != '\n') position++; + goto tryAgain; + } else if (EsCRTisspace(c)) { + position++; + goto tryAgain; + } + + if ((c == '%' && position[1] == '%') || (c == '<' && position[1] == '=') || (c == '>' && position[1] == '=') + || (c == '=' && position[1] == '=') || (c == '!' && position[1] == '=') + || (c == '&' && position[1] == '&') || (c == '|' && position[1] == '|') + || (c == '/' && position[1] == '/')) { + token.type = TOKEN_PUNCTUATOR; + token.punctuator = (c << 8) + position[1]; + position += 2; + } else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == '<' || c == '>' || c == '(' || c == ')' || c == '?' + || c == ':' || c == ';' || c == ',' || c == '!' || c == '&' || c == '^') { + token.type = TOKEN_PUNCTUATOR; + token.punctuator = c; + position++; + } else if (EsCRTisalpha(c) || c == '_' || c >= 0x80) { + const char *start = position; + while (EsCRTisalpha(c) || c == '_' || EsCRTisdigit(c) || c >= 0x80) c = *(++position); + token.type = TOKEN_IDENTIFIER; + token.identifier = (char *) Allocate(position - start + 1); + if (!token.identifier) return { TOKEN_ERROR }; + EsMemoryCopy(token.identifier, start, position - start); + token.identifier[position - start] = 0; + } else if (EsCRTisdigit(c) || c == '.') { + const char *start = position; + token.literal.number._FromDouble(EsDoubleParse(start, -1, (char **) &position)); + token.type = TOKEN_LITERAL; + token.literal.type = VALUE_NUMBER; + } else if (c == 0) { + token.type = TOKEN_EOF; + } else { + token.type = TOKEN_ERROR; + } + + return token; + } + + Node *ParseExpression(int precedence = 0) { + Node *left = (Node *) Allocate(sizeof(Node)); + if (!left) return nullptr; + Token token = NextToken(); + left->token = token; + + if (token.type == TOKEN_LITERAL) { + left->type = NODE_LITERAL; + } else if (token.type == TOKEN_PUNCTUATOR) { + left->type = NODE_UNARYOP; + + if (token.punctuator == '(') { + left->firstChild = ParseExpression(); + token = NextToken(); + + if (token.type != TOKEN_PUNCTUATOR || token.punctuator != ')' || !left->firstChild) { + return nullptr; + } + } else if (token.punctuator == '!' || token.punctuator == '-' || token.punctuator == '/') { + left->firstChild = ParseExpression(1000); + + if (!left->firstChild) { + return nullptr; + } + } else { + return nullptr; + } + } else if (token.type == TOKEN_IDENTIFIER) { + Token peek = PeekToken(); + + if (peek.type == TOKEN_PUNCTUATOR && peek.punctuator == '(') { + left->type = NODE_CALL; + NextToken(); + int count = 0; + Node **link = &left->firstChild; + + while (true) { + token = PeekToken(); + + if (token.type == TOKEN_PUNCTUATOR && token.punctuator == ')') { + NextToken(); + break; + } else if (count) { + if (token.type != TOKEN_PUNCTUATOR || token.punctuator != ',') { + return nullptr; + } + + NextToken(); + } + + *link = ParseExpression(); + + if (!(*link)) { + return nullptr; + } + + link = &((*link)->sibling); + count++; + } + } else if (0 == EsCRTstrcmp(token.identifier, "\xCF\x80") || 0 == EsCRTstrcmp(token.identifier, "pi")) { + left->type = NODE_LITERAL; + left->token.literal.type = VALUE_NUMBER; + left->token.literal.number = bigFloatConstants.pi; + } else if (0 == EsCRTstrcmp(token.identifier, "\xCF\x84") || 0 == EsCRTstrcmp(token.identifier, "tau")) { + left->type = NODE_LITERAL; + left->token.literal.type = VALUE_NUMBER; + left->token.literal.number = bigFloatConstants.twoPi; + } else if (0 == EsCRTstrcmp(token.identifier, "e")) { + left->type = NODE_LITERAL; + left->token.literal.type = VALUE_NUMBER; + left->token.literal.number = bigFloatConstants.e; + } else { + return nullptr; + } + } else { + return nullptr; + } + + while (true) { + token = PeekToken(); + + if (0) { + +#define PARSE_BINOP(symb, prec) \ + } else if (token.type == TOKEN_PUNCTUATOR && token.punctuator == symb && prec > precedence) { \ + Node *node = (Node *) Allocate(sizeof(Node)); \ + if (!node) return nullptr; \ + node->type = NODE_BINOP; \ + node->token = NextToken(); \ + node->firstChild = left; \ + left->sibling = ParseExpression(prec); \ + if (!left->sibling) return nullptr; \ + left = node + + PARSE_BINOP('^', 120); + PARSE_BINOP('*', 100); + PARSE_BINOP('/', 100); + PARSE_BINOP('+', 80); + PARSE_BINOP('-', 80); + } else { + break; + } + } + + return left; + } + + Value Evaluate(Node *node, Value *arguments) { + if (node->type == NODE_LITERAL) { + return node->token.literal; + } else if (node->type == NODE_CALL) { +#define MAX_CALCULATOR_CALL_ARGUMENTS (16) + Value callArguments[MAX_CALCULATOR_CALL_ARGUMENTS]; + int argumentCount = 0; + Node *child = node->firstChild; + + while (child) { + callArguments[argumentCount] = Evaluate(child, arguments); + + if (callArguments[argumentCount].type == VALUE_ERROR) { + return {}; + } + + child = child->sibling; + argumentCount++; + if (argumentCount == MAX_CALCULATOR_CALL_ARGUMENTS) return {}; + } + + if (!builtins.Count()) LoadBuiltins(); + Builtin builtin = builtins.Get1(node->token.identifier, EsCStringLength(node->token.identifier)); + if (!builtin) return {}; + return builtin(callArguments, argumentCount); + } else if (node->type == NODE_UNARYOP) { + Value value = Evaluate(node->firstChild, arguments); + + if (node->token.punctuator == '(') { + return value; + } else if (node->token.punctuator == '!') { + if (value.type != VALUE_NUMBER) return {}; + return { VALUE_NUMBER, .number = value.number.zero ? bigFloatConstants.one : bigFloatConstants.zero }; + } else if (node->token.punctuator == '-') { + if (value.type != VALUE_NUMBER) return {}; + value.number.negative = !value.number.negative; + return value; + } else if (node->token.punctuator == '/') { + if (value.type != VALUE_NUMBER) return {}; + bool error = false; + value.number = BigFloatDivide(bigFloatConstants.one, value.number, &error); + if (error) value.type = VALUE_ERROR; + return value; + } else { + return {}; + } + } else if (node->type == NODE_BINOP) { + Value left = Evaluate(node->firstChild, arguments), + right = Evaluate(node->firstChild->sibling, arguments); + + if (0) { + +#define DO_BINOP(p, t, output, expression) \ + } else if (node->token.punctuator == p) { \ + if (left.type != t || right.type != t) return {}; \ + Value result = { t }; \ + bool error = false; \ + output = expression; \ + if (error) result.type = VALUE_ERROR; \ + return result + + DO_BINOP('+', VALUE_NUMBER, result.number, left.number + right.number); + DO_BINOP('-', VALUE_NUMBER, result.number, left.number - right.number); + DO_BINOP('*', VALUE_NUMBER, result.number, left.number * right.number); + DO_BINOP('/', VALUE_NUMBER, result.number, BigFloatDivide(left.number, right.number, &error)); + DO_BINOP('^', VALUE_NUMBER, result.number, BigFloatPower(left.number, right.number, &error)); +#undef DO_BINOP + } else { + return {}; + } + } else { + return {}; + } + } + + void LoadBuiltins() { +#define FUNCTION1(name, callback) \ + do { Builtin builtin = [] (Value *arguments, size_t argumentCount) { \ + if (argumentCount != 1 || arguments[0].type != VALUE_NUMBER) return (Value) {}; \ + Value result = { VALUE_NUMBER }; \ + BigFloat x = arguments[0].number; \ + bool error = false; \ + result.number = callback; \ + if (error) result.type = VALUE_ERROR; \ + return result; \ + }; *builtins.Put(name, EsCStringLength(name)) = builtin; } while (0) + +#define FUNCTION2(name, callback) \ + do { Builtin builtin = [] (Value *arguments, size_t argumentCount) { \ + if (argumentCount != 2 || arguments[0].type != VALUE_NUMBER || arguments[1].type != VALUE_NUMBER) return (Value) {}; \ + Value result = { VALUE_NUMBER }; \ + BigFloat x = arguments[0].number, y = arguments[1].number; \ + bool error = false; \ + result.number = callback; \ + if (error) result.type = VALUE_ERROR; \ + return result; \ + }; *builtins.Put(name, EsCStringLength(name)) = builtin; } while (0) + + FUNCTION1("sq", BigFloatPower(x, bigFloatConstants.two, &error)); + FUNCTION1("sqrt", BigFloatPower(x, bigFloatConstants.half, &error)); + FUNCTION1("ln", BigFloatLogarithm(x, &error)); + FUNCTION1("sin", BigFloatSine(x, &error)); + FUNCTION1("sinh", BigFloatHyperbolicSine(x, &error)); + FUNCTION1("cos", BigFloatCosine(x, &error)); + FUNCTION1("cosh", BigFloatHyperbolicCosine(x, &error)); + FUNCTION1("tan", BigFloatTangent(x, &error)); + FUNCTION1("tanh", BigFloatHyperbolicTangent(x, &error)); + FUNCTION1("asin", BigFloatArcSine(x, &error)); + FUNCTION1("asinh", BigFloatArcHyperbolicSine(x, &error)); + FUNCTION1("acos", BigFloatArcCosine(x, &error)); + FUNCTION1("acosh", BigFloatArcHyperbolicCosine(x, &error)); + FUNCTION1("atan", BigFloatArcTangent(x, &error)); + FUNCTION1("atanh", BigFloatArcHyperbolicTangent(x, &error)); + FUNCTION2("mod", BigFloatModulo(x, y, &error)); + FUNCTION2("rt", BigFloatPower(x, BigFloatDivide(bigFloatConstants.one, y, &error), &error)); + FUNCTION2("log", BigFloatDivide(BigFloatLogarithm2(y, &error), BigFloatLogarithm2(x, &error), &error)); + +#undef FUNCTION1 +#undef FUNCTION2 + } + }; +}; + +Calculator::Parser calculator = {}; + +EsCalculationValue EsCalculateFromUserExpression(const char *expression) { + EsMessageMutexCheck(); + + BigFloatInitialise(); + + calculator.FreeAll(); + calculator.position = expression; + Calculator::Node *node = calculator.ParseExpression(); + Calculator::Value value = {}; + if (calculator.NextToken().type != Calculator::TOKEN_EOF) node = nullptr; + if (node) value = calculator.Evaluate(node, nullptr); + + EsCalculationValue result = {}; + result.error = value.type == Calculator::VALUE_ERROR; + result.number = value.type == Calculator::VALUE_NUMBER ? value.number.ToDouble() : 0; + return result; +} + +#endif diff --git a/shared/png_decoder.cpp b/shared/png_decoder.cpp new file mode 100644 index 0000000..b57fd3f --- /dev/null +++ b/shared/png_decoder.cpp @@ -0,0 +1,485 @@ +uint32_t SwapBigEndian32(uint32_t x); + +typedef struct PNGReader { + const void *buffer; + size_t bytes; + uintptr_t position; + uintptr_t idatBytesRemaining; + const uint8_t *idatPointer; + bool error; + uint8_t zlibByte, zlibBitsRemaining; +} PNGReader; + +const void *PNGRead(PNGReader *reader, size_t bytes) { + if (bytes > reader->bytes || reader->position > reader->bytes - bytes || reader->error) { + reader->error = true; + return NULL; + } else { + reader->position += bytes; + return (const uint8_t *) reader->buffer + reader->position - bytes; + } +} + +const uint8_t *PNGReadIDATByte(PNGReader *reader) { + if (!reader->idatBytesRemaining) { + uintptr_t position = reader->position; + + while (true) { + const uint32_t *chunkSize = (const uint32_t *) PNGRead(reader, sizeof(uint32_t)); + const uint32_t *chunkType = (const uint32_t *) PNGRead(reader, sizeof(uint32_t)); + + if (!chunkSize || !chunkType) { + return NULL; + } + + const void *chunkData = PNGRead(reader, SwapBigEndian32(*chunkSize)); + const uint32_t *chunkChecksum = (const uint32_t *) PNGRead(reader, sizeof(uint32_t)); + + if (!chunkData || !chunkChecksum) { + return NULL; + } + + if (SwapBigEndian32(*chunkType) == 0x49454E44) { + reader->position = position; + break; + } else if (SwapBigEndian32(*chunkType) != 0x49444154) { + continue; + } + + reader->idatBytesRemaining = SwapBigEndian32(*chunkSize); + reader->idatPointer = (const uint8_t *) chunkData; + break; + } + } + + if (!reader->idatBytesRemaining) { + reader->error = true; + return NULL; + } + + const uint8_t *pointer = reader->idatPointer; + reader->idatPointer++; + reader->idatBytesRemaining--; + return pointer; +} + +uint32_t PNGReadZLIBBits(PNGReader *reader, uint8_t count) { + uint32_t result = 0; + uintptr_t shift = 0; + + while (count) { + if (!reader->zlibBitsRemaining) { + const uint8_t *nextByte = PNGReadIDATByte(reader); + if (!nextByte) return 0; + reader->zlibByte = *nextByte; + reader->zlibBitsRemaining = 8; + } + + result |= (reader->zlibByte & 1) << shift; + reader->zlibByte >>= 1; + reader->zlibBitsRemaining--; + count--, shift++; + } + + return result; +} + +uint32_t PNGReadHuffman(PNGReader *reader, uint32_t *tree, size_t treeEntries) { + uint16_t code = 0; + uint16_t length = 0; + + while (true) { + code <<= 1; + code |= PNGReadZLIBBits(reader, 1); + length++; + + if (code >= treeEntries) { + reader->error = true; + return 0; + } + + uint32_t entry = tree[code]; + + if ((entry >> 16) == length) { + return entry & 0xFFFF; + } + } +} + +bool PNGBuildHuffmanTree(uint16_t count, uint8_t *lengths, uint32_t *tree, size_t treeSize) { + uint16_t lengthsCount[16] = {}; + + for (uintptr_t i = 0; i < count; i++) { + lengthsCount[lengths[i]]++; + } + + uint16_t code = 0; + uint16_t nextCodes[16] = {}; + lengthsCount[0] = 0; + + for (uintptr_t length = 1; length < 16; length++) { + code = (code + lengthsCount[length - 1]) << 1; + if (lengthsCount[length]) nextCodes[length] = code; + } + + for (uintptr_t i = 0; i < count; i++) { + uint8_t length = lengths[i]; + if (!length) continue; + uint16_t code = nextCodes[length]++; + if (code >= treeSize) return false; + tree[code] = i | (length << 16); + } + + return true; +} + +typedef struct PNGImageHeader { + uint32_t width, height; + uint8_t bitDepth, colorType; + uint8_t compressionMethod, filterMethod, interlaceMethod; +} PNGImageHeader; + +const uint8_t pngExtraLengthBits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0 +}; + +const uint16_t pngExtraLengthOffsets[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, + 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258, +}; + +const uint8_t pngExtraDistanceBits[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, +}; + +const uint16_t pngExtraDistanceOffsets[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, + 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, + 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, +}; + +const uint8_t pngReorderCLCLs[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +bool PNGParse(PNGReader *reader, uint32_t **outBits, uint32_t *outWidth, uint32_t *outHeight, void *(*alloc)(size_t), void (dealloc)(void *)) { + // TODO Validate checksums. + + // Check the signature is present. + + const uint64_t *signature = (const uint64_t *) PNGRead(reader, sizeof(uint64_t)); + + if (!signature || *signature != ((uint64_t) 0x0A1A0A0D474E5089)) { + return false; + } + + // PNGRead the IHDR chunk. + + const uint32_t *ihdrSize = (const uint32_t *) PNGRead(reader, sizeof(uint32_t)); + const uint32_t *ihdrType = (const uint32_t *) PNGRead(reader, sizeof(uint32_t)); + + if (!ihdrSize || !ihdrType || SwapBigEndian32(*ihdrSize) < 13 || SwapBigEndian32(*ihdrType) != 0x49484452) { + return false; + } + + const void *ihdrData = PNGRead(reader, SwapBigEndian32(*ihdrSize)); + const uint32_t *ihdrChecksum = (const uint32_t *) PNGRead(reader, sizeof(uint32_t)); + + if (!ihdrData || !ihdrChecksum) { + return false; + } + + PNGImageHeader imageHeader = *(PNGImageHeader *) ihdrData; + + uint32_t width = SwapBigEndian32(imageHeader.width); + uint32_t height = SwapBigEndian32(imageHeader.height); + uint8_t bytesPerPixel = 0; + + // Check the image is supported. + + if (width > 16383 || height > 16383 + || imageHeader.bitDepth != 8 + || imageHeader.compressionMethod || imageHeader.filterMethod || imageHeader.interlaceMethod) { + return false; + } + + if (imageHeader.colorType == 0) { + bytesPerPixel = 1; + } else if (imageHeader.colorType == 2) { + bytesPerPixel = 3; + } else if (imageHeader.colorType == 6) { + bytesPerPixel = 4; + } else { + // TODO Support palettes. + return false; + } + + // Check the ZLIB header. + + const uint8_t *zlibCMF = (const uint8_t *) PNGReadIDATByte(reader); + const uint8_t *zlibFLG = (const uint8_t *) PNGReadIDATByte(reader); + + if (!zlibCMF || !zlibFLG + || (*zlibCMF & 0x0F) != 0x08 + || (*zlibCMF & 0xF0) > 0x70 + || (*zlibFLG & 0x20)) { + return false; + } + + // Decode the ZLIB blocks. + + size_t bufferSize = (width + 1) * height * bytesPerPixel; + uint8_t *buffer = (uint8_t *) alloc(bufferSize + 262144); + + if (!buffer) { + return false; + } + + uintptr_t bufferPosition = 0; + bool isFinalBlock = false; + + uint32_t *litTree = (uint32_t *) (buffer + bufferSize); + uint32_t *distTree = (uint32_t *) (buffer + bufferSize + 131072); + + while (!reader->error && !isFinalBlock) { + isFinalBlock = PNGReadZLIBBits(reader, 1); + uint8_t compressionType = PNGReadZLIBBits(reader, 2); + + if (compressionType == 0) { + // Uncompressed data. + + PNGReadZLIBBits(reader, reader->zlibBitsRemaining); + const uint8_t *lengthHigh = PNGReadIDATByte(reader); + const uint8_t *lengthLow = PNGReadIDATByte(reader); + if (!lengthHigh || !lengthLow) break; + uint16_t length = (*lengthHigh << 8) | *lengthLow; + PNGReadIDATByte(reader); + PNGReadIDATByte(reader); + + for (uintptr_t i = 0; i < length; i++) { + const uint8_t *byte = PNGReadIDATByte(reader); + if (!byte) break; + + if (bufferPosition == bufferSize) { + reader->error = true; + break; + } + + buffer[bufferPosition++] = *byte; + } + + continue; + } else if (compressionType == 3) { + // Invalid compression type. + + reader->error = true; + break; + } + + // Compressed data. + + EsMemoryZero(buffer + bufferSize, 262144); + + if (compressionType == 2) { + // Read the Huffman code. + + uint16_t hlit = PNGReadZLIBBits(reader, 5) + 257; + uint16_t hdist = PNGReadZLIBBits(reader, 5) + 1; + uint16_t hclen = PNGReadZLIBBits(reader, 4) + 4; + + uint32_t codeLengthTree[128] = {}; + + if (!reader->error) { + uint8_t lengths[19] = {}; + + for (uintptr_t i = 0; i < hclen && !reader->error; i++) { + uint8_t length = PNGReadZLIBBits(reader, 3); + lengths[pngReorderCLCLs[i]] = length; + } + + if (!PNGBuildHuffmanTree(19, lengths, codeLengthTree, 128)) { + reader->error = true; + } + } + + if (!reader->error) { + uint8_t lengths[286 + 32] = {}; + + for (uintptr_t i = 0; i < (hlit + hdist) && !reader->error; i++) { + uint32_t symbol = PNGReadHuffman(reader, codeLengthTree, 128); + + if (symbol < 16) { + lengths[i] = symbol; + continue; + } + + uint8_t repeatValue; + uint8_t repeatReadBits; + size_t repeat; + + if (symbol == 16) { + if (!i) { + reader->error = true; + break; + } + + repeatValue = lengths[i - 1]; + repeatReadBits = 2; + repeat = 3; + } else { + repeatValue = 0; + repeatReadBits = symbol == 17 ? 3 : 7; + repeat = symbol == 17 ? 3 : 11; + } + + repeat += PNGReadZLIBBits(reader, repeatReadBits); + + if (i + repeat > hlit + hdist) { + reader->error = true; + break; + } + + for (uintptr_t j = 0; j < repeat; j++) { + lengths[i + j] = repeatValue; + } + + i += repeat - 1; + } + + if (!PNGBuildHuffmanTree(hlit, lengths + 0, litTree, 32768) + || !PNGBuildHuffmanTree(hdist, lengths + hlit, distTree, 32768)) { + reader->error = true; + } + } + } else { + // TODO Fixed Huffman code. + reader->error = true; + break; + } + + // Decode the data. + + while (!reader->error) { + uint32_t symbol = PNGReadHuffman(reader, litTree, 32768); + + if (symbol < 256) { + if (bufferPosition == bufferSize) { + reader->error = true; + break; + } + + buffer[bufferPosition++] = symbol; + } else if (symbol == 256) { + break; + } else if (symbol < 286) { + uint32_t length = pngExtraLengthOffsets[symbol - 257] + PNGReadZLIBBits(reader, pngExtraLengthBits[symbol - 257]); + symbol = PNGReadHuffman(reader, distTree, 32768); + uint32_t distance = pngExtraDistanceOffsets[symbol] + PNGReadZLIBBits(reader, pngExtraDistanceBits[symbol]); + + if (distance > bufferPosition || !distance) { + reader->error = true; + } else { + if (bufferPosition + length > bufferSize) { + reader->error = true; + break; + } + + for (uintptr_t i = 0; i < length; i++, bufferPosition++) { + buffer[bufferPosition] = buffer[bufferPosition - distance]; + } + } + } else { + reader->error = true; + } + } + } + + if (reader->error) { + dealloc(buffer); + return false; + } + + // Defilter the image. + + for (uintptr_t i = 0; i < height; i++) { + uint8_t type = buffer[i * (width * bytesPerPixel + 1)]; + if (!type) continue; + + for (uintptr_t j = 0; j < width * bytesPerPixel; j++) { + uintptr_t k = i * (width * bytesPerPixel + 1) + j + 1; + uint32_t x = buffer[k]; + uint32_t a = j >= bytesPerPixel ? buffer[k - bytesPerPixel] : 0; + uint32_t b = i ? buffer[k - (width * bytesPerPixel + 1)] : 0; + uint32_t c = i && j >= bytesPerPixel ? buffer[k - ((width + 1) * bytesPerPixel + 1)] : 0; + + if (type == 1) { + buffer[k] = x + a; + } else if (type == 2) { + buffer[k] = x + b; + } else if (type == 3) { + buffer[k] = x + ((a + b) >> 1); + } else if (type == 4) { + int32_t p = a + b - c; + int32_t pa = p > (int32_t) a ? p - a : a - p; + int32_t pb = p > (int32_t) b ? p - b : b - p; + int32_t pc = p > (int32_t) c ? p - c : c - p; + if (pa <= pb && pa <= pc) buffer[k] = x + a; + else if (pb <= pc) buffer[k] = x + b; + else buffer[k] = x + c; + } else { + dealloc(buffer); + return false; + } + } + } + + // Convert the image to the desired format. + + uint32_t *bits = (uint32_t *) alloc(width * height * 4); + + if (!bits) { + dealloc(buffer); + return false; + } + + if (imageHeader.colorType == 0) { + for (uintptr_t i = 0; i < height; i++) { + for (uintptr_t j = 0; j < width; j++) { + uint8_t x = buffer[i * (width + 1) + j + 1]; + bits[i * width + j] = 0xFF000000 | (x << 16) | (x << 8) | x; + } + } + } else if (imageHeader.colorType == 2) { + for (uintptr_t i = 0; i < height; i++) { + for (uintptr_t j = 0; j < width; j++) { + uint8_t r = buffer[i * (width * 3 + 1) + j * 3 + 1]; + uint8_t g = buffer[i * (width * 3 + 1) + j * 3 + 2]; + uint8_t b = buffer[i * (width * 3 + 1) + j * 3 + 3]; + bits[i * width + j] = 0xFF000000 | (r << 16) | (g << 8) | b; + } + } + } else if (imageHeader.colorType == 6) { + for (uintptr_t i = 0; i < height; i++) { + for (uintptr_t j = 0; j < width; j++) { + uint8_t r = buffer[i * (width * 4 + 1) + j * 4 + 1]; + uint8_t g = buffer[i * (width * 4 + 1) + j * 4 + 2]; + uint8_t b = buffer[i * (width * 4 + 1) + j * 4 + 3]; + uint8_t a = buffer[i * (width * 4 + 1) + j * 4 + 4]; + bits[i * width + j] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + } + + dealloc(buffer); + + // Return the loaded data. + + *outBits = bits; + *outWidth = width; + *outHeight = height; + + return true; +} diff --git a/shared/range_set.cpp b/shared/range_set.cpp new file mode 100644 index 0000000..0b4be4c --- /dev/null +++ b/shared/range_set.cpp @@ -0,0 +1,404 @@ +#ifndef IMPLEMENTATION + +struct Range { + uintptr_t from, to; +}; + +struct RangeSet { + Array<Range, K_CORE> ranges; + uintptr_t contiguous; + + Range *Find(uintptr_t offset, bool touching); + bool Contains(uintptr_t offset); + void Validate(); + bool Normalize(); + + bool Set(uintptr_t from, uintptr_t to, intptr_t *delta, bool modify); + bool Clear(uintptr_t from, uintptr_t to, intptr_t *delta, bool modify); +}; + +#else + +Range *RangeSet::Find(uintptr_t offset, bool touching) { + if (!ranges.Length()) return nullptr; + + intptr_t low = 0, high = ranges.Length() - 1; + + while (low <= high) { + intptr_t i = low + (high - low) / 2; + Range *range = &ranges[i]; + + if (range->from <= offset && (offset < range->to || (touching && offset <= range->to))) { + return range; + } else if (range->from <= offset) { + low = i + 1; + } else { + high = i - 1; + } + } + + return nullptr; +} + +bool RangeSet::Contains(uintptr_t offset) { + if (ranges.Length()) { + return Find(offset, false); + } else { + return offset < contiguous; + } +} + +void RangeSet::Validate() { +#ifdef DEBUG_BUILD + uintptr_t previousTo = 0; + + if (!ranges.Length()) return; + + for (uintptr_t i = 0; i < ranges.Length(); i++) { + Range *range = &ranges[i]; + + if (previousTo && range->from <= previousTo) { + KernelPanic("RangeSet::Validate - Range %d in set %x is not placed after the prior range.\n", i, this); + } + + if (range->from >= range->to) { + KernelPanic("RangeSet::Validate - Range %d in set %x is invalid.\n", i, this); + } + + previousTo = range->to; + } +#endif + +#if 0 + for (uintptr_t i = 0; i < sizeof(check); i++) { + if (check[i]) { + assert(Find(set, i, false)); + } else { + assert(!Find(set, i, false)); + } + } +#endif +} + +bool RangeSet::Normalize() { + KernelLog(LOG_INFO, "RangeSet", "normalize", "Normalizing range set %x...\n", this); + + if (contiguous) { + uintptr_t oldContiguous = contiguous; + contiguous = 0; + + if (!Set(0, oldContiguous, nullptr, true)) { + return false; + } + } + + return true; +} + +bool RangeSet::Set(uintptr_t from, uintptr_t to, intptr_t *delta, bool modify) { +#if 0 + for (uintptr_t i = from; i < to; i++) { + check[i] = true; + } +#endif + + if (to <= from) { + KernelPanic("RangeSet::Set - Invalid range %x to %x.\n", from, to); + } + + // Can we store this as a single contiguous range? + + if (!ranges.Length()) { + if (delta) { + if (from >= contiguous) { + *delta = to - from; + } else if (to >= contiguous) { + *delta = to - contiguous; + } else { + *delta = 0; + } + } + + if (!modify) { + return true; + } + + if (from <= contiguous) { + if (to > contiguous) { + contiguous = to; + } + + return true; + } + + if (!Normalize()) { + return false; + } + } + + // Calculate the contiguous range covered. + + Range newRange = {}; + + { + Range *left = Find(from, true); + Range *right = Find(to, true); + + newRange.from = left ? left->from : from; + newRange.to = right ? right->to : to; + } + + // Insert the new range. + + uintptr_t i = 0; + + for (; i <= ranges.Length(); i++) { + if (i == ranges.Length() || ranges[i].to > newRange.from) { + if (modify) { + if (!ranges.Insert(newRange, i)) { + return false; + } + + i++; + } + + break; + } + } + + // Remove overlapping ranges. + + uintptr_t deleteStart = i; + size_t deleteCount = 0; + uintptr_t deleteTotal = 0; + + for (; i < ranges.Length(); i++) { + Range *range = &ranges[i]; + + bool overlap = (range->from >= newRange.from && range->from <= newRange.to) + || (range->to >= newRange.from && range->to <= newRange.to); + + if (overlap) { + deleteCount++; + deleteTotal += range->to - range->from; + } else { + break; + } + } + + if (modify) { + ranges.DeleteMany(deleteStart, deleteCount); + } + + Validate(); + + if (delta) { + *delta = newRange.to - newRange.from - deleteTotal; + } + + return true; +} + +bool RangeSet::Clear(uintptr_t from, uintptr_t to, intptr_t *delta, bool modify) { +#if 0 + for (uintptr_t i = from; i < to; i++) { + check[i] = false; + } +#endif + + if (to <= from) { + KernelPanic("RangeSet::Clear - Invalid range %x to %x.\n", from, to); + } + + if (!ranges.Length()) { + if (from < contiguous && contiguous) { + if (to < contiguous) { + if (modify) { + if (!Normalize()) return false; + } else { + if (delta) *delta = from - to; + return true; + } + } else { + if (delta) *delta = from - contiguous; + if (modify) contiguous = from; + return true; + } + } else { + if (delta) *delta = 0; + return true; + } + } + + if (!ranges.Length()) { + ranges.Free(); + if (delta) *delta = 0; + return true; + } + + if (to <= ranges.First().from || from >= ranges.Last().to) { + if (delta) *delta = 0; + return true; + } + + if (from <= ranges.First().from && to >= ranges.Last().to) { + if (delta) { + intptr_t total = 0; + + for (uintptr_t i = 0; i < ranges.Length(); i++) { + total += ranges[i].to - ranges[i].from; + } + + *delta = -total; + } + + if (modify) { + ranges.Free(); + } + + return true; + } + + // Find the first and last overlapping regions. + + uintptr_t overlapStart = ranges.Length(); + size_t overlapCount = 0; + + for (uintptr_t i = 0; i < ranges.Length(); i++) { + Range *range = &ranges[i]; + + if (range->to > from && range->from < to) { + overlapStart = i; + overlapCount = 1; + break; + } + } + + for (uintptr_t i = overlapStart + 1; i < ranges.Length(); i++) { + Range *range = &ranges[i]; + + if (range->to >= from && range->from < to) { + overlapCount++; + } else { + break; + } + } + + // Remove the overlapping sections. + + intptr_t _delta = 0; + + if (overlapCount == 1) { + Range *range = &ranges[overlapStart]; + + if (range->from < from && range->to > to) { + Range newRange = { to, range->to }; + _delta -= to - from; + + if (modify) { + if (!ranges.Insert(newRange, overlapStart + 1)) { + return false; + } + + ranges[overlapStart].to = from; + } + } else if (range->from < from) { + _delta -= range->to - from; + if (modify) range->to = from; + } else if (range->to > to) { + _delta -= to - range->from; + if (modify) range->from = to; + } else { + _delta -= range->to - range->from; + if (modify) ranges.Delete(overlapStart); + } + } else if (overlapCount > 1) { + Range *left = &ranges[overlapStart]; + Range *right = &ranges[overlapStart + overlapCount - 1]; + + if (left->from < from) { + _delta -= left->to - from; + if (modify) left->to = from; + overlapStart++, overlapCount--; + } + + if (right->to > to) { + _delta -= to - right->from; + if (modify) right->from = to; + overlapCount--; + } + + if (delta) { + for (uintptr_t i = overlapStart; i < overlapStart + overlapCount; i++) { + _delta -= ranges[i].to - ranges[i].from; + } + } + + if (modify) { + ranges.DeleteMany(overlapStart, overlapCount); + } + } + + if (delta) { + *delta = _delta; + } + + Validate(); + return true; +} + +#endif + +#if 0 +int main(int argc, char **argv) { + RangeSet set = {}; + + Set(&set, 2, 3); + Set(&set, 4, 5); + Set(&set, 0, 1); + Set(&set, 1, 2); + Set(&set, 3, 4); + Set(&set, 10, 15); + Set(&set, 4, 10); + Set(&set, 20, 30); + Set(&set, 15, 21); + Set(&set, 50, 55); + Set(&set, 60, 65); + Set(&set, 40, 70); + Set(&set, 0, 100); + + Clear(&set, 50, 60); + Clear(&set, 55, 56); + Clear(&set, 50, 55); + Clear(&set, 55, 60); + Clear(&set, 50, 60); + Clear(&set, 49, 60); + Clear(&set, 49, 61); + + Set(&set, 50, 51); + Clear(&set, 48, 62); + Set(&set, 50, 51); + Clear(&set, 48, 62); + Set(&set, 50, 51); + Set(&set, 52, 53); + Clear(&set, 48, 62); + Set(&set, 50, 51); + Set(&set, 52, 53); + Clear(&set, 47, 62); + Set(&set, 50, 51); + Set(&set, 52, 53); + Clear(&set, 47, 63); + Set(&set, 50, 51); + Set(&set, 52, 53); + Clear(&set, 46, 64); + + srand(time(NULL)); + + while (true) { + int a = rand() % 1000, b = rand() % 1000; + if (b <= a) continue; + if (rand() & 1) Set(&set, a, b); + else Clear(&set, a, b); + } +} +#endif diff --git a/shared/stb_image.h b/shared/stb_image.h new file mode 100644 index 0000000..1692bc0 --- /dev/null +++ b/shared/stb_image.h @@ -0,0 +1,7193 @@ +/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using OSCRTassert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes + Fabian "ryg" Giesen + Arseny Kapoulkine + John-Mark Allen + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson + Janez Zemva John Bartholomew Michal Cichon github:rlyeh + Jonathan Blow Ken Hamada Tero Hanninen github:romigrou + Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk + Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar + Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex + Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210 + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw + Blazej Dariusz Roszkowski Gregory Mullen github:phprus + Christian Floisand Kevin Schmidt github:poppolopoppo +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 16-bit-per-channel PNG +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - no 1-bit BMP +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy to use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// make more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// + + +#ifndef STBI_NO_STDIO +#include <stdio.h> +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); + +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include <stdarg.h> +#include <stddef.h> // ptrdiff_t on osx + +// NOTE Modified by nakst for use with OS + +#include <limits.h> + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include <math.h> // ldexp +#endif + +#ifndef STBI_NO_STDIO +#include <stdio.h> +#endif + +#ifndef STBI_ASSERT +#define STBI_ASSERT(x) EsAssert((x)) +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include <stdint.h> +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include <emmintrin.h> + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include <intrin.h> // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if 0 +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include <arm_neon.h> +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +#if 0 +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if 0 +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load = flag_true_if_should_flip; +} + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + (void)bpc; + EsCRTmemset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + EsCRTmemcpy(temp, row0, bytes_copy); + EsCRTmemcpy(row0, row1, bytes_copy); + EsCRTmemcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#ifndef STBI_NO_HDR +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_file(&s,f); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + EsCRTmemcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + EsCRTmemcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0,code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + EsCRTmemset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<<n) + 1 +static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767}; + +// combined JPEG 'receive' and JPEG 'extend', since baseline +// always extends everything it receives. +stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) +{ + unsigned int k; + int sgn; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + EsCRTmemset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + EsCRTmemset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) << 12) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + // NOTE (nakst): SSE2 must be available to run the OS + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4]; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + EsCRTmemset(sizes, 0, sizeof(sizes)); + EsCRTmemset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = old_limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + EsCRTmemset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) + c = stbi__zreceive(a,3)+3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + EsCRTmemset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + EsCRTmemcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = EsCRTabs(p-a); + int pb = EsCRTabs(p-b); + int pc = EsCRTabs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a EsCRTmemcpy here; make that explicit. + case STBI__F_none: EsCRTmemcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + EsCRTmemcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +static int stbi__shiftsigned(int v, int shift, int bits) +{ + int result; + int z=0; + + if (shift < 0) v <<= -shift; + else v >>= shift; + result = v; + + z = bits; + while (z < 8) { + result += v >> z; + z += bits; + } + return result; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = EsCRTabs((int) s->img_y); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - 14 - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - 14 - info.hsz) >> 2; + } + + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - 14 - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if(is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // else: fall-through + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fall-through + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //EsCRTmemset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; y<height; ++y) { + int packet_idx; + + for(packet_idx=0; packet_idx < num_packets; ++packet_idx) { + stbi__pic_packet *packet = &packets[packet_idx]; + stbi_uc *dest = result+y*width*4; + + switch (packet->type) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;x<width;++x, dest+=4) + if (!stbi__readval(s,packet->channel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; i<count; ++i,dest+=4) + stbi__copyval(packet->channel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;i<count;++i, dest += 4) + stbi__copyval(packet->channel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;i<count;++i, dest+=4) + if (!stbi__readval(s,packet->channel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + EsCRTmemset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out, *old_out; // output buffer (always 4 components) + int flags, bgindex, ratio, transparent, eflags, delay; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[4096]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + p = &g->out[g->cur_x + g->cur_y]; + c = &g->color_table[g->codes[code].suffix * 4]; + + if (c[3] >= 128) { + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1) +{ + int x, y; + stbi_uc *c = g->pal[g->bgindex]; + for (y = y0; y < y1; y += 4 * g->w) { + for (x = x0; x < x1; x += 4) { + stbi_uc *p = &g->out[y + x]; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = 0; + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) +{ + int i; + stbi_uc *prev_out = 0; + + if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) + return 0; // stbi__g_failure_reason set by stbi__gif_header + + if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0)) + return stbi__errpuc("too large", "GIF too large"); + + prev_out = g->out; + g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + + switch ((g->eflags & 0x1C) >> 2) { + case 0: // unspecified (also always used on 1st frame) + stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); + break; + case 1: // do not dispose + if (prev_out) EsCRTmemcpy(g->out, prev_out, 4 * g->w * g->h); + g->old_out = prev_out; + break; + case 2: // dispose to background + if (prev_out) EsCRTmemcpy(g->out, prev_out, 4 * g->w * g->h); + stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); + break; + case 3: // dispose to previous + if (g->old_out) { + for (i = g->start_y; i < g->max_y; i += 4 * g->w) + EsCRTmemcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x); + } + break; + } + + for (;;) { + switch (stbi__get8(s)) { + case 0x2C: /* Image Descriptor */ + { + int prev_trans = -1; + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + if (g->transparent >= 0 && (g->eflags & 0x01)) { + prev_trans = g->pal[g->transparent][3]; + g->pal[g->transparent][3] = 0; + } + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (o == NULL) return NULL; + + if (prev_trans != -1) + g->pal[g->transparent][3] = (stbi_uc) prev_trans; + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = stbi__get16le(s); + g->transparent = stbi__get8(s); + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) + stbi__skip(s, len); + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } + + STBI_NOTUSED(req_comp); +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + EsCRTmemset(g, 0, sizeof(*g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, g, comp, req_comp); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g->w; + *y = g->h; + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g->w, g->h); + } + else if (g->out) + STBI_FREE(g->out); + STBI_FREE(g); + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) *comp = info.ma ? 4 : 3; + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + if (stbi__get16be(s) != 8) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect OSCRTassert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named OSCRTassert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring OSCRTassert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/shared/stb_sprintf.h b/shared/stb_sprintf.h new file mode 100644 index 0000000..e3c74b3 --- /dev/null +++ b/shared/stb_sprintf.h @@ -0,0 +1,1834 @@ +// stb_sprintf - v1.05 - public domain snprintf() implementation +// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 +// http://github.com/nothings/stb +// +// allowed types: sc uidBboXx p AaGgEef n +// lengths : h ll j z t I64 I32 I +// +// Contributors: +// Fabian "ryg" Giesen (reformatting) +// +// Contributors (bugfixes): +// github:d26435 +// github:trex78 +// Jari Komppa (SI suffixes) +// Rohit Nirmal +// Marcin Wojdyr +// Leonard Ritter +// +// LICENSE: +// +// See end of file for license information. + +#ifndef STB_SPRINTF_H_INCLUDE +#define STB_SPRINTF_H_INCLUDE + +/* +Single file sprintf replacement. + +Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. +Hereby placed in public domain. + +This is a full sprintf replacement that supports everything that +the C runtime sprintfs support, including float/double, 64-bit integers, +hex floats, field parameters (%*.*d stuff), length reads backs, etc. + +Why would you need this if sprintf already exists? Well, first off, +it's *much* faster (see below). It's also much smaller than the CRT +versions code-space-wise. We've also added some simple improvements +that are super handy (commas in thousands, callbacks at buffer full, +for example). Finally, the format strings for MSVC and GCC differ +for 64-bit integers (among other small things), so this lets you use +the same format strings in cross platform code. + +It uses the standard single file trick of being both the header file +and the source itself. If you just include it normally, you just get +the header file function definitions. To get the code, you include +it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. + +It only uses va_args macros from the C runtime to do it's work. It +does cast doubles to S64s and shifts and divides U64s, which does +drag in CRT code on most platforms. + +It compiles to roughly 8K with float support, and 4K without. +As a comparison, when using MSVC static libs, calling sprintf drags +in 16K. + +API: +==== +int stbsp_sprintf( char * buf, char const * fmt, ... ) +int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) + Convert an arg list into a buffer. stbsp_snprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) +int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) + Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) + typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); + Convert into a buffer, calling back every STB_SPRINTF_MIN chars. + Your callback can then copy the chars out, print them or whatever. + This function is actually the workhorse for everything else. + The buffer you pass in must hold at least STB_SPRINTF_MIN characters. + // you return the next buffer to use or 0 to stop converting + +void stbsp_set_separators( char comma, char period ) + Set the comma and period characters to use. + +FLOATS/DOUBLES: +=============== +This code uses a internal float->ascii conversion method that uses +doubles with error correction (double-doubles, for ~105 bits of +precision). This conversion is round-trip perfect - that is, an atof +of the values output here will give you the bit-exact double back. + +One difference is that our insignificant digits will be different than +with MSVC or GCC (but they don't match each other either). We also +don't attempt to find the minimum length matching float (pre-MSVC15 +doesn't either). + +If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT +and you'll save 4K of code space. + +64-BIT INTS: +============ +This library also supports 64-bit integers and you can use MSVC style or +GCC style indicators (%I64d or %lld). It supports the C99 specifiers +for size_t and ptr_diff_t (%jd %zd) as well. + +EXTRAS: +======= +Like some GCCs, for integers and floats, you can use a ' (single quote) +specifier and commas will be inserted on the thousands: "%'d" on 12345 +would print 12,345. + +For integers and floats, you can use a "$" specifier and the number +will be converted to float and then divided to get kilo, mega, giga or +tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is +"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn +2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three +$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the +suffix, add "_" specifier: "%_$d" -> "2.53M". + +In addition to octal and hexadecimal conversions, you can print +integers in binary: "%b" for 256 would print 100. + +PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): +=================================================================== +"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) +"%24d" across all 32-bit ints (4.5x/4.2x faster) +"%x" across all 32-bit ints (4.5x/3.8x faster) +"%08x" across all 32-bit ints (4.3x/3.8x faster) +"%f" across e-10 to e+10 floats (7.3x/6.0x faster) +"%e" across e-10 to e+10 floats (8.1x/6.0x faster) +"%g" across e-10 to e+10 floats (10.0x/7.1x faster) +"%f" for values near e-300 (7.9x/6.5x faster) +"%f" for values near e+300 (10.0x/9.1x faster) +"%e" for values near e-300 (10.1x/7.0x faster) +"%e" for values near e+300 (9.2x/6.0x faster) +"%.320f" for values near e-300 (12.6x/11.2x faster) +"%a" for random values (8.6x/4.3x faster) +"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) +"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) +"%s%s%s" for 64 char strings (7.1x/7.3x faster) +"...512 char string..." ( 35.0x/32.5x faster!) +*/ + +#if defined(__has_feature) + #if __has_feature(address_sanitizer) + #define STBI__ASAN __attribute__((no_sanitize("address"))) + #endif +#endif +#ifndef STBI__ASAN +#define STBI__ASAN +#endif + +#ifdef STB_SPRINTF_STATIC +#define STBSP__PUBLICDEC static +#define STBSP__PUBLICDEF static STBI__ASAN +#else +#ifdef __cplusplus +#define STBSP__PUBLICDEC extern "C" +#define STBSP__PUBLICDEF extern "C" STBI__ASAN +#else +#define STBSP__PUBLICDEC extern +#define STBSP__PUBLICDEF STBI__ASAN +#endif +#endif + +#include <stdarg.h> // for va_list() + +#ifndef STB_SPRINTF_MIN +#define STB_SPRINTF_MIN 512 // how many characters per callback +#endif +typedef char *STBSP_SPRINTFCB(char *buf, void *user, int len); + +#ifndef STB_SPRINTF_DECORATE +#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names +#endif + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...); +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...); + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); + +#endif // STB_SPRINTF_H_INCLUDE + +#ifdef STB_SPRINTF_IMPLEMENTATION + +// #include <stdlib.h> // for va_arg() + +#define stbsp__uint32 unsigned int +#define stbsp__int32 signed int + +#ifdef _MSC_VER +#define stbsp__uint64 unsigned __int64 +#define stbsp__int64 signed __int64 +#else +#define stbsp__uint64 unsigned long long +#define stbsp__int64 signed long long +#endif +#define stbsp__uint16 unsigned short + +#ifndef stbsp__uintptr +#if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) +#define stbsp__uintptr stbsp__uint64 +#else +#define stbsp__uintptr stbsp__uint32 +#endif +#endif + +#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define STB_SPRINTF_MSVC_MODE +#endif +#endif + +#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses +#define STBSP__UNALIGNED(code) +#else +#define STBSP__UNALIGNED(code) code +#endif + +#ifndef STB_SPRINTF_NOFLOAT +// internal float utility functions +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); +#define STBSP__SPECIAL 0x7000 +#endif + +static char stbsp__period = '.'; +static char stbsp__comma = ','; +static char stbsp__digitpair[201] = + "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576" + "7778798081828384858687888990919293949596979899"; + +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) +{ + stbsp__period = pperiod; + stbsp__comma = pcomma; +} + +#define STBSP__LEFTJUST 1 +#define STBSP__LEADINGPLUS 2 +#define STBSP__LEADINGSPACE 4 +#define STBSP__LEADING_0X 8 +#define STBSP__LEADINGZERO 16 +#define STBSP__INTMAX 32 +#define STBSP__TRIPLET_COMMA 64 +#define STBSP__NEGATIVE 128 +#define STBSP__METRIC_SUFFIX 256 +#define STBSP__HALFWIDTH 512 +#define STBSP__METRIC_NOSPACE 1024 +#define STBSP__METRIC_1024 2048 +#define STBSP__METRIC_JEDEC 4096 + +static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) +{ + sign[0] = 0; + if (fl & STBSP__NEGATIVE) { + sign[0] = 1; + sign[1] = '-'; + } else if (fl & STBSP__LEADINGSPACE) { + sign[0] = 1; + sign[1] = ' '; + } else if (fl & STBSP__LEADINGPLUS) { + sign[0] = 1; + sign[1] = '+'; + } +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) +{ + static char hex[] = "0123456789abcdefxp"; + static char hexu[] = "0123456789ABCDEFXP"; + char *bf; + char const *f; + int tlen = 0; + + bf = buf; + f = fmt; + for (;;) { + stbsp__int32 fw, pr, tz; + stbsp__uint32 fl; + + // macros for the callback buffer stuff + #define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } + #define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } + #define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer + #define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } + + // fast copy everything up to the next % (or end of string) + for (;;) { + while (((stbsp__uintptr)f) & 3) { + schk1: + if (f[0] == '%') + goto scandd; + schk2: + if (f[0] == 0) + goto endfmt; + stbsp__chk_cb_buf(1); + *bf++ = f[0]; + ++f; + } + for (;;) { + // Check if the next 4 bytes contain %(0x25) or end of string. + // Using the 'hasless' trick: + // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + stbsp__uint32 v, c; + v = *(stbsp__uint32 *)f; + c = (~v) & 0x80808080; + if (((v ^ 0x25252525) - 0x01010101) & c) + goto schk1; + if ((v - 0x01010101) & c) + goto schk2; + if (callback) + if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) + goto schk1; + *(stbsp__uint32 *)bf = v; + bf += 4; + f += 4; + } + } + scandd: + + ++f; + + // ok, we have a percent, read the modifiers first + fw = 0; + pr = -1; + fl = 0; + tz = 0; + + // flags + for (;;) { + switch (f[0]) { + // if we have left justify + case '-': + fl |= STBSP__LEFTJUST; + ++f; + continue; + // if we have leading plus + case '+': + fl |= STBSP__LEADINGPLUS; + ++f; + continue; + // if we have leading space + case ' ': + fl |= STBSP__LEADINGSPACE; + ++f; + continue; + // if we have leading 0x + case '#': + fl |= STBSP__LEADING_0X; + ++f; + continue; + // if we have thousand commas + case '\'': + fl |= STBSP__TRIPLET_COMMA; + ++f; + continue; + // if we have kilo marker (none->kilo->kibi->jedec) + case '$': + if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_1024) { + fl |= STBSP__METRIC_JEDEC; + } else { + fl |= STBSP__METRIC_1024; + } + } else { + fl |= STBSP__METRIC_SUFFIX; + } + ++f; + continue; + // if we don't want space between metric suffix and number + case '_': + fl |= STBSP__METRIC_NOSPACE; + ++f; + continue; + // if we have leading zero + case '0': + fl |= STBSP__LEADINGZERO; + ++f; + goto flags_done; + default: goto flags_done; + } + } + flags_done: + + // get the field width + if (f[0] == '*') { + fw = va_arg(va, stbsp__uint32); + ++f; + } else { + while ((f[0] >= '0') && (f[0] <= '9')) { + fw = fw * 10 + f[0] - '0'; + f++; + } + } + // get the precision + if (f[0] == '.') { + ++f; + if (f[0] == '*') { + pr = va_arg(va, stbsp__uint32); + ++f; + } else { + pr = 0; + while ((f[0] >= '0') && (f[0] <= '9')) { + pr = pr * 10 + f[0] - '0'; + f++; + } + } + } + + // handle integer size overrides + switch (f[0]) { + // are we halfwidth? + case 'h': + fl |= STBSP__HALFWIDTH; + ++f; + break; + // are we 64-bit (unix style) + case 'l': + ++f; + if (f[0] == 'l') { + fl |= STBSP__INTMAX; + ++f; + } + break; + // are we 64-bit on intmax? (c99) + case 'j': + fl |= STBSP__INTMAX; + ++f; + break; + // are we 64-bit on size_t or ptrdiff_t? (c99) + case 'z': + case 't': + fl |= ((sizeof(char *) == 8) ? STBSP__INTMAX : 0); + ++f; + break; + // are we 64-bit (msft style) + case 'I': + if ((f[1] == '6') && (f[2] == '4')) { + fl |= STBSP__INTMAX; + f += 3; + } else if ((f[1] == '3') && (f[2] == '2')) { + f += 3; + } else { + fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); + ++f; + } + break; + default: break; + } + + // handle each replacement + switch (f[0]) { + #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + char num[STBSP__NUMSZ]; + char lead[8]; + char tail[8]; + char *s; + char const *h; + stbsp__uint32 l, n, cs; + stbsp__uint64 n64; +#ifndef STB_SPRINTF_NOFLOAT + double fv; +#endif + stbsp__int32 dp; + char const *sn; + + case 's': + // get the string + s = va_arg(va, char *); + if (s == 0) + s = (char *)"null"; + // get the length + sn = s; + for (;;) { + if ((((stbsp__uintptr)sn) & 3) == 0) + break; + lchk: + if (sn[0] == 0) + goto ld; + ++sn; + } + n = 0xffffffff; + if (pr >= 0) { + n = (stbsp__uint32)(sn - s); + if (n >= (stbsp__uint32)pr) + goto ld; + n = ((stbsp__uint32)(pr - n)) >> 2; + } + while (n) { + stbsp__uint32 v = *(stbsp__uint32 *)sn; + if ((v - 0x01010101) & (~v) & 0x80808080UL) + goto lchk; + sn += 4; + --n; + } + goto lchk; + ld: + + l = (stbsp__uint32)(sn - s); + // clamp to precision + if (l > (stbsp__uint32)pr) + l = pr; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + // copy the string in + goto scopy; + + case 'c': // char + // get the character + s = num + STBSP__NUMSZ - 1; + *s = (char)va_arg(va, int); + l = 1; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + + case 'n': // weird write-bytes specifier + { + int *d = va_arg(va, int *); + *d = tlen + (int)(bf - buf); + } break; + +#ifdef STB_SPRINTF_NOFLOAT + case 'A': // float + case 'a': // hex float + case 'G': // float + case 'g': // float + case 'E': // float + case 'e': // float + case 'f': // float + va_arg(va, double); // eat it + s = (char *)"No float"; + l = 8; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; +#else + case 'A': // hex float + case 'a': // hex float + h = (f[0] == 'A') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) + fl |= STBSP__NEGATIVE; + + s = num + 64; + + stbsp__lead_sign(fl, lead); + + if (dp == -1023) + dp = (n64) ? -1022 : 0; + else + n64 |= (((stbsp__uint64)1) << 52); + n64 <<= (64 - 56); + if (pr < 15) + n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); +// add leading chars + +#ifdef STB_SPRINTF_MSVC_MODE + *s++ = '0'; + *s++ = 'x'; +#else + lead[1 + lead[0]] = '0'; + lead[2 + lead[0]] = 'x'; + lead[0] += 2; +#endif + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + if (pr) + *s++ = stbsp__period; + sn = s; + + // print the bits + n = pr; + if (n > 13) + n = 13; + if (pr > (stbsp__int32)n) + tz = pr - n; + pr = 0; + while (n--) { + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + } + + // print the expo + tail[1] = h[17]; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; + n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + + dp = (int)(s - sn); + l = (int)(s - (num + 64)); + s = num + 64; + cs = 1 + (3 << 24); + goto scopy; + + case 'G': // float + case 'g': // float + h = (f[0] == 'G') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; + else if (pr == 0) + pr = 1; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) + fl |= STBSP__NEGATIVE; + + // clamp the precision and delete extra zeros after clamp + n = pr; + if (l > (stbsp__uint32)pr) + l = pr; + while ((l > 1) && (pr) && (sn[l - 1] == '0')) { + --pr; + --l; + } + + // should we use %e + if ((dp <= -4) || (dp > (stbsp__int32)n)) { + if (pr > (stbsp__int32)l) + pr = l - 1; + else if (pr) + --pr; // when using %e, there is one digit before the decimal + goto doexpfromg; + } + // this is the insane action to get the pr to match %g sematics for %f + if (dp > 0) { + pr = (dp < (stbsp__int32)l) ? l - dp : 0; + } else { + pr = -dp + ((pr > (stbsp__int32)l) ? l : pr); + } + goto dofloatfromg; + + case 'E': // float + case 'e': // float + h = (f[0] == 'E') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) + fl |= STBSP__NEGATIVE; + doexpfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + // handle leading chars + *s++ = sn[0]; + + if (pr) + *s++ = stbsp__period; + + // handle after decimal + if ((l - 1) > (stbsp__uint32)pr) + l = pr + 1; + for (n = 1; n < l; n++) + *s++ = sn[n]; + // trailing zeros + tz = pr - (l - 1); + pr = 0; + // dump expo + tail[1] = h[0xe]; + dp -= 1; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; +#ifdef STB_SPRINTF_MSVC_MODE + n = 5; +#else + n = (dp >= 100) ? 5 : 4; +#endif + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + cs = 1 + (3 << 24); // how many tens + goto flt_lead; + + case 'f': // float + fv = va_arg(va, double); + doafloat: + // do kilos + if (fl & STBSP__METRIC_SUFFIX) { + double divisor; + divisor = 1000.0f; + if (fl & STBSP__METRIC_1024) + divisor = 1024.0; + while (fl < 0x4000000) { + if ((fv < divisor) && (fv > -divisor)) + break; + fv /= divisor; + fl += 0x1000000; + } + } + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) + fl |= STBSP__NEGATIVE; + dofloatfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + + // handle the three decimal varieties + if (dp <= 0) { + stbsp__int32 i; + // handle 0.000*000xxxx + *s++ = '0'; + if (pr) + *s++ = stbsp__period; + n = -dp; + if ((stbsp__int32)n > pr) + n = pr; + i = n; + while (i) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + i -= 4; + } + while (i) { + *s++ = '0'; + --i; + } + if ((stbsp__int32)(l + n) > pr) + l = pr - n; + i = l; + while (i) { + *s++ = *sn++; + --i; + } + tz = pr - (n + l); + cs = 1 + (3 << 24); // how many tens did we write (for commas below) + } else { + cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; + if ((stbsp__uint32)dp >= l) { + // handle xxxx000*000.0 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= l) + break; + } + } + if (n < (stbsp__uint32)dp) { + n = dp - n; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --n; + } + while (n >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + n -= 4; + } + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = '0'; + --n; + } + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) { + *s++ = stbsp__period; + tz = pr; + } + } else { + // handle xxxxx.xxxx000*000 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= (stbsp__uint32)dp) + break; + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) + *s++ = stbsp__period; + if ((l - dp) > (stbsp__uint32)pr) + l = pr + dp; + while (n < l) { + *s++ = sn[n]; + ++n; + } + tz = pr - (l - dp); + } + } + pr = 0; + + // handle k,m,g,t + if (fl & STBSP__METRIC_SUFFIX) { + char idx; + idx = 1; + if (fl & STBSP__METRIC_NOSPACE) + idx = 0; + tail[0] = idx; + tail[1] = ' '; + { + if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl & STBSP__METRIC_1024) + tail[idx + 1] = "_KMGT"[fl >> 24]; + else + tail[idx + 1] = "_kMGT"[fl >> 24]; + idx++; + // If printing kibits and not in jedec, add the 'i'. + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { + tail[idx + 1] = 'i'; + idx++; + } + tail[0] = idx; + } + } + }; + + flt_lead: + // get the length that we copied + l = (stbsp__uint32)(s - (num + 64)); + s = num + 64; + goto scopy; +#endif + + case 'B': // upper binary + case 'b': // lower binary + h = (f[0] == 'B') ? hexu : hex; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[0xb]; + } + l = (8 << 4) | (1 << 8); + goto radixnum; + + case 'o': // octal + h = hexu; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 1; + lead[1] = '0'; + } + l = (3 << 4) | (3 << 8); + goto radixnum; + + case 'p': // pointer + fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; + pr = sizeof(void *) * 2; + fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros + // fall through - to X + + case 'X': // upper hex + case 'x': // lower hex + h = (f[0] == 'X') ? hexu : hex; + l = (4 << 4) | (4 << 8); + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[16]; + } + radixnum: + // get the number + if (fl & STBSP__INTMAX) + n64 = va_arg(va, stbsp__uint64); + else + n64 = va_arg(va, stbsp__uint32); + + s = num + STBSP__NUMSZ; + dp = 0; + // clear tail, and clear leading if value is zero + tail[0] = 0; + if (n64 == 0) { + lead[0] = 0; + if (pr == 0) { + l = 0; + cs = (((l >> 4) & 15)) << 24; + goto scopy; + } + } + // convert to string + for (;;) { + *--s = h[n64 & ((1 << (l >> 8)) - 1)]; + n64 >>= (l >> 8); + if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) + break; + if (fl & STBSP__TRIPLET_COMMA) { + ++l; + if ((l & 15) == ((l >> 4) & 15)) { + l &= ~15; + *--s = stbsp__comma; + } + } + }; + // get the tens and the comma pos + cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + // copy it + goto scopy; + + case 'u': // unsigned + case 'i': + case 'd': // integer + // get the integer and abs it + if (fl & STBSP__INTMAX) { + stbsp__int64 i64 = va_arg(va, stbsp__int64); + n64 = (stbsp__uint64)i64; + if ((f[0] != 'u') && (i64 < 0)) { + n64 = (stbsp__uint64)-i64; + fl |= STBSP__NEGATIVE; + } + } else { + stbsp__int32 i = va_arg(va, stbsp__int32); + n64 = (stbsp__uint32)i; + if ((f[0] != 'u') && (i < 0)) { + n64 = (stbsp__uint32)-i; + fl |= STBSP__NEGATIVE; + } + } + +#ifndef STB_SPRINTF_NOFLOAT + if (fl & STBSP__METRIC_SUFFIX) { + if (n64 < 1024) + pr = 0; + else if (pr == -1) + pr = 1; + fv = (double)(stbsp__int64)n64; + goto doafloat; + } +#endif + + // convert to string + s = num + STBSP__NUMSZ; + l = 0; + + for (;;) { + // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) + char *o = s - 8; + if (n64 >= 100000000) { + n = (stbsp__uint32)(n64 % 100000000); + n64 /= 100000000; + } else { + n = (stbsp__uint32)n64; + n64 = 0; + } + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + do { + s -= 2; + *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2]; + n /= 100; + } while (n); + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = (char)(n % 10) + '0'; + n /= 10; + } + } + if (n64 == 0) { + if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) + ++s; + break; + } + while (s != o) + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = '0'; + } + } + + tail[0] = 0; + stbsp__lead_sign(fl, lead); + + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + if (l == 0) { + *--s = '0'; + l = 1; + } + cs = l + (3 << 24); + if (pr < 0) + pr = 0; + + scopy: + // get fw=leading/trailing space, pr=leading zeros + if (pr < (stbsp__int32)l) + pr = l; + n = pr + lead[0] + tail[0] + tz; + if (fw < (stbsp__int32)n) + fw = n; + fw -= n; + pr -= l; + + // handle right justify and leading zeros + if ((fl & STBSP__LEFTJUST) == 0) { + if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr + { + pr = (fw > pr) ? fw : pr; + fw = 0; + } else { + fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas + } + } + + // copy the spaces and/or zeros + if (fw + pr) { + stbsp__int32 i; + stbsp__uint32 c; + + // copy leading spaces (or when doing %8.4d stuff) + if ((fl & STBSP__LEFTJUST) == 0) + while (fw > 0) { + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = ' '; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leader + sn = lead + 1; + while (lead[0]) { + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leading zeros + c = cs >> 24; + cs &= 0xffffff; + cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; + while (pr > 0) { + stbsp__cb_buf_clamp(i, pr); + pr -= i; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + } + while (i) { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { + cs = 0; + *bf++ = stbsp__comma; + } else + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + } + + // copy leader if there is still one + sn = lead + 1; + while (lead[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy the string + n = l; + while (n) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, n); + n -= i; + STBSP__UNALIGNED(while (i >= 4) { + *(stbsp__uint32 *)bf = *(stbsp__uint32 *)s; + bf += 4; + s += 4; + i -= 4; + }) + while (i) { + *bf++ = *s++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy trailing zeros + while (tz) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tz); + tz -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy tail if there is one + sn = tail + 1; + while (tail[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tail[0]); + tail[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // handle the left justify + if (fl & STBSP__LEFTJUST) + if (fw > 0) { + while (fw) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i--) + *bf++ = ' '; + stbsp__chk_cb_buf(1); + } + } + break; + + default: // unknown, just copy code + s = num + STBSP__NUMSZ - 1; + *s = f[0]; + l = 1; + fw = fl = 0; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + } + ++f; + } +endfmt: + + if (!callback) + *bf = 0; + else + stbsp__flush_cb(); + +done: + return tlen + (int)(bf - buf); +} + +// cleanup +#undef STBSP__LEFTJUST +#undef STBSP__LEADINGPLUS +#undef STBSP__LEADINGSPACE +#undef STBSP__LEADING_0X +#undef STBSP__LEADINGZERO +#undef STBSP__INTMAX +#undef STBSP__TRIPLET_COMMA +#undef STBSP__NEGATIVE +#undef STBSP__METRIC_SUFFIX +#undef STBSP__NUMSZ +#undef stbsp__chk_cb_bufL +#undef stbsp__chk_cb_buf +#undef stbsp__flush_cb +#undef stbsp__cb_buf_clamp + +// ============================================================================ +// wrapper functions + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); + va_end(va); + return result; +} + +typedef struct stbsp__context { + char *buf; + int count; + char tmp[STB_SPRINTF_MIN]; +} stbsp__context; + +static char *stbsp__clamp_callback(char *buf, void *user, int len) +{ + stbsp__context *c = (stbsp__context *)user; + + if (len > c->count) + len = c->count; + + if (len) { + if (buf != c->buf) { + char *s, *d, *se; + d = c->buf; + s = buf; + se = buf + len; + do { + *d++ = *s++; + } while (s < se); + } + c->buf += len; + c->count -= len; + } + + if (c->count <= 0) + return 0; + return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can +} + +static char * stbsp__count_clamp_callback( char * buf, void * user, int len ) +{ + (void) buf; + stbsp__context * c = (stbsp__context*)user; + + c->count += len; + return c->tmp; // go direct into buffer if you can +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) +{ + stbsp__context c; + int l; + + if ( (count == 0) && !buf ) + { + c.count = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); + l = c.count; + } + else + { + if ( count == 0 ) + return 0; + + c.buf = buf; + c.count = count; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); + + // zero-terminate + l = (int)( c.buf - buf ); + if ( l >= count ) // should never be greater, only equal (or less) than count + l = count - 1; + buf[l] = 0; + } + + return l; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + + result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); + va_end(va); + + return result; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) +{ + return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); +} + +// ======================================================================= +// low level float utility functions + +#ifndef STB_SPRINTF_NOFLOAT + +// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) +#define STBSP__COPYFP(dest, src) \ + { \ + int cn; \ + for (cn = 0; cn < 8; cn++) \ + ((char *)&dest)[cn] = ((char *)&src)[cn]; \ + } + +// get float info +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) +{ + double d; + stbsp__int64 b = 0; + + // load value and round at the frac_digits + d = value; + + STBSP__COPYFP(b, d); + + *bits = b & ((((stbsp__uint64)1) << 52) - 1); + *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); + + return (stbsp__int32)(b >> 63); +} + +static double const stbsp__bot[23] = { + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 +}; +static double const stbsp__negbot[22] = { + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 +}; +static double const stbsp__negboterr[22] = { + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 +}; +static double const stbsp__top[13] = { + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 +}; +static double const stbsp__negtop[13] = { + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 +}; +static double const stbsp__toperr[13] = { + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282 +}; +static double const stbsp__negtoperr[13] = { + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317 +}; + +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U +}; +#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) +#else +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; +#define stbsp__tento19th (1000000000000000000ULL) +#endif + +#define stbsp__ddmulthi(oh, ol, xh, yh) \ + { \ + double ahi = 0, alo, bhi = 0, blo; \ + stbsp__int64 bt; \ + oh = xh * yh; \ + STBSP__COPYFP(bt, xh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(ahi, bt); \ + alo = xh - ahi; \ + STBSP__COPYFP(bt, yh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(bhi, bt); \ + blo = yh - bhi; \ + ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ + } + +#define stbsp__ddtoS64(ob, xh, xl) \ + { \ + double ahi = 0, alo, vh, t; \ + ob = (stbsp__int64)ph; \ + vh = (double)ob; \ + ahi = (xh - vh); \ + t = (ahi - xh); \ + alo = (xh - (ahi - t)) - (vh + t); \ + ob += (stbsp__int64)(ahi + alo + xl); \ + } + +#define stbsp__ddrenorm(oh, ol) \ + { \ + double s; \ + s = oh + ol; \ + ol = ol - (s - oh); \ + oh = s; \ + } + +#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); + +#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); + +static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 +{ + double ph, pl; + if ((power >= 0) && (power <= 22)) { + stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); + } else { + stbsp__int32 e, et, eb; + double p2h, p2l; + + e = power; + if (power < 0) + e = -e; + et = (e * 0x2c9) >> 14; /* %23 */ + if (et > 13) + et = 13; + eb = e - (et * 23); + + ph = d; + pl = 0.0; + if (power < 0) { + if (eb) { + --eb; + stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); + stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); + ph = p2h; + pl = p2l; + } + } else { + if (eb) { + e = eb; + if (eb > 22) + eb = 22; + e -= eb; + stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); + if (e) { + stbsp__ddrenorm(ph, pl); + stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); + stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); + ph = p2h; + pl = p2l; + } + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); + ph = p2h; + pl = p2l; + } + } + } + stbsp__ddrenorm(ph, pl); + *ohi = ph; + *olo = pl; +} + +// given a float value, returns the significant bits in bits, and the position of the +// decimal point in decimal_pos. +/-INF and NAN are specified by special values +// returned in the decimal_pos parameter. +// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) +{ + double d; + stbsp__int64 bits = 0; + stbsp__int32 expo, e, ng, tens; + + d = value; + STBSP__COPYFP(bits, d); + expo = (stbsp__int32)((bits >> 52) & 2047); + ng = (stbsp__int32)(bits >> 63); + if (ng) + d = -d; + + if (expo == 2047) // is nan or inf? + { + *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; + *decimal_pos = STBSP__SPECIAL; + *len = 3; + return ng; + } + + if (expo == 0) // is zero or denormal + { + if ((bits << 1) == 0) // do zero + { + *decimal_pos = 1; + *start = out; + out[0] = '0'; + *len = 1; + return ng; + } + // find the right expo for denormals + { + stbsp__int64 v = ((stbsp__uint64)1) << 51; + while ((bits & v) == 0) { + --expo; + v >>= 1; + } + } + } + + // find the decimal exponent as well as the decimal bits of the value + { + double ph, pl; + + // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 + tens = expo - 1023; + tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); + + // move the significant bits into position and stick them into an int + stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); + + // get full as much precision from double-double as possible + stbsp__ddtoS64(bits, ph, pl); + + // check if we undershot + if (((stbsp__uint64)bits) >= stbsp__tento19th) + ++tens; + } + + // now do the rounding in integer land + frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); + if ((frac_digits < 24)) { + stbsp__uint32 dg = 1; + if ((stbsp__uint64)bits >= stbsp__powten[9]) + dg = 10; + while ((stbsp__uint64)bits >= stbsp__powten[dg]) { + ++dg; + if (dg == 20) + goto noround; + } + if (frac_digits < dg) { + stbsp__uint64 r; + // add 0.5 at the right position and round + e = dg - frac_digits; + if ((stbsp__uint32)e >= 24) + goto noround; + r = stbsp__powten[e]; + bits = bits + (r / 2); + if ((stbsp__uint64)bits >= stbsp__powten[dg]) + ++tens; + bits /= r; + } + noround:; + } + + // kill long trailing runs of zeros + if (bits) { + stbsp__uint32 n; + for (;;) { + if (bits <= 0xffffffff) + break; + if (bits % 1000) + goto donez; + bits /= 1000; + } + n = (stbsp__uint32)bits; + while ((n % 1000) == 0) + n /= 1000; + bits = n; + donez:; + } + + // convert to string + out += 64; + e = 0; + for (;;) { + stbsp__uint32 n; + char *o = out - 8; + // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) + if (bits >= 100000000) { + n = (stbsp__uint32)(bits % 100000000); + bits /= 100000000; + } else { + n = (stbsp__uint32)bits; + bits = 0; + } + while (n) { + out -= 2; + *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2]; + n /= 100; + e += 2; + } + if (bits == 0) { + if ((e) && (out[0] == '0')) { + ++out; + --e; + } + break; + } + while (out != o) { + *--out = '0'; + ++e; + } + } + + *decimal_pos = tens; + *start = out; + *len = e; + return ng; +} + +#undef stbsp__ddmulthi +#undef stbsp__ddrenorm +#undef stbsp__ddmultlo +#undef stbsp__ddmultlos +#undef STBSP__SPECIAL +#undef STBSP__COPYFP + +#endif // STB_SPRINTF_NOFLOAT + +// clean up +#undef stbsp__uint16 +#undef stbsp__uint32 +#undef stbsp__int32 +#undef stbsp__uint64 +#undef stbsp__int64 +#undef STBSP__UNALIGNED + +#endif // STB_SPRINTF_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/shared/strings.cpp b/shared/strings.cpp new file mode 100644 index 0000000..98bf7a6 --- /dev/null +++ b/shared/strings.cpp @@ -0,0 +1,216 @@ +#pragma GCC diagnostic ignored "-Wunused-variable" push + +#define DEFINE_INTERFACE_STRING(name, text) static const char *interfaceString_ ## name = text; +#define INTERFACE_STRING(name) interfaceString_ ## name, -1 + +#define ELLIPSIS "…" +#define HYPHENATION_POINT "‧" + +// Common. + +DEFINE_INTERFACE_STRING(CommonErrorTitle, "Error"); + +DEFINE_INTERFACE_STRING(CommonCancel, "Cancel"); + +DEFINE_INTERFACE_STRING(CommonUndo, "Undo"); +DEFINE_INTERFACE_STRING(CommonRedo, "Redo"); +DEFINE_INTERFACE_STRING(CommonClipboardCut, "Cut"); +DEFINE_INTERFACE_STRING(CommonClipboardCopy, "Copy"); +DEFINE_INTERFACE_STRING(CommonClipboardPaste, "Paste"); +DEFINE_INTERFACE_STRING(CommonSelectionSelectAll, "Select all"); +DEFINE_INTERFACE_STRING(CommonSelectionDelete, "Delete"); + +DEFINE_INTERFACE_STRING(CommonFormatPopup, "Format"); +DEFINE_INTERFACE_STRING(CommonFormatSize, "Text size:"); +DEFINE_INTERFACE_STRING(CommonFormatLanguage, "Language:"); +DEFINE_INTERFACE_STRING(CommonFormatPlainText, "Plain text"); + +DEFINE_INTERFACE_STRING(CommonFileMenu, "File"); +DEFINE_INTERFACE_STRING(CommonFileSave, "Save"); +DEFINE_INTERFACE_STRING(CommonFileShare, "Share"); +DEFINE_INTERFACE_STRING(CommonFileMakeCopy, "Make a copy"); +DEFINE_INTERFACE_STRING(CommonFileVersionHistory, "Version history" ELLIPSIS); +DEFINE_INTERFACE_STRING(CommonFileShowInFileManager, "Show in File Manager" ELLIPSIS); +DEFINE_INTERFACE_STRING(CommonFileMenuFileSize, "Size:"); +DEFINE_INTERFACE_STRING(CommonFileUnchanged, "(All changes saved.)"); + +DEFINE_INTERFACE_STRING(CommonSearchOpen, "Search"); +DEFINE_INTERFACE_STRING(CommonSearchNoMatches, "No matches found."); +DEFINE_INTERFACE_STRING(CommonSearchNext, "Find next"); +DEFINE_INTERFACE_STRING(CommonSearchPrevious, "Find previous"); +DEFINE_INTERFACE_STRING(CommonSearchPrompt, "Search for:"); +DEFINE_INTERFACE_STRING(CommonSearchPrompt2, "Enter text to search for."); + +DEFINE_INTERFACE_STRING(CommonItemFolder, "Folder"); +DEFINE_INTERFACE_STRING(CommonItemFile, "File"); + +DEFINE_INTERFACE_STRING(CommonSortAscending, "Sort ascending"); +DEFINE_INTERFACE_STRING(CommonSortDescending, "Sort descending"); + +DEFINE_INTERFACE_STRING(CommonDriveHDD, "Hard disk"); +DEFINE_INTERFACE_STRING(CommonDriveSSD, "SSD"); +DEFINE_INTERFACE_STRING(CommonDriveCDROM, "CD-ROM"); +DEFINE_INTERFACE_STRING(CommonDriveUSBMassStorage, "USB drive"); + +DEFINE_INTERFACE_STRING(CommonSystemBrand, "Essence Alpha v0.1"); + +DEFINE_INTERFACE_STRING(CommonListViewType, "List view"); +DEFINE_INTERFACE_STRING(CommonListViewTypeThumbnails, "Thumbnails"); +DEFINE_INTERFACE_STRING(CommonListViewTypeTiles, "Tiles"); +DEFINE_INTERFACE_STRING(CommonListViewTypeDetails, "Details"); + +DEFINE_INTERFACE_STRING(CommonAnnouncementTextCopied, "Text copied"); +DEFINE_INTERFACE_STRING(CommonAnnouncementCopyErrorResources, "There's not enough space to copy this"); +DEFINE_INTERFACE_STRING(CommonAnnouncementCopyErrorOther, "Could not copy"); + +// Desktop. + +DEFINE_INTERFACE_STRING(DesktopCloseTab, "Close tab"); +DEFINE_INTERFACE_STRING(DesktopInspectUI, "Inspect UI"); +DEFINE_INTERFACE_STRING(DesktopCenterWindow, "Center in screen"); +DEFINE_INTERFACE_STRING(DesktopNewTabTitle, "New Tab"); +DEFINE_INTERFACE_STRING(DesktopShutdownTitle, "Shutdown"); +DEFINE_INTERFACE_STRING(DesktopShutdownAction, "Shutdown"); +DEFINE_INTERFACE_STRING(DesktopRestartAction, "Restart"); +DEFINE_INTERFACE_STRING(DesktopForceQuit, "Force quit"); +DEFINE_INTERFACE_STRING(DesktopCrashedApplication, "The application has crashed. If you're a developer, more information is available in System Monitor."); +DEFINE_INTERFACE_STRING(DesktopNoSuchApplication, "The requested application could not found. It may have been uninstalled."); +DEFINE_INTERFACE_STRING(DesktopApplicationStartupError, "The requested application could not be started. Your system may be low on resources, or the application files may have been corrupted."); +DEFINE_INTERFACE_STRING(DesktopNotResponding, "The application is not responding.\nIf you choose to force quit, any unsaved data may be lost."); +DEFINE_INTERFACE_STRING(DesktopConfirmShutdown, "Are you sure you want to turn off your computer? All applications will be closed."); + +// File operations. + +DEFINE_INTERFACE_STRING(FileCannotSave, "The document was not saved."); +DEFINE_INTERFACE_STRING(FileCannotOpen, "The file could not be opened."); + +DEFINE_INTERFACE_STRING(FileSaveErrorFileDeleted, "Another application deleted the file."); +DEFINE_INTERFACE_STRING(FileSaveErrorCorrupt, "The file has been corrupted, and it cannot be modified."); +DEFINE_INTERFACE_STRING(FileSaveErrorDrive, "The drive containing the file was unable to modify it."); +DEFINE_INTERFACE_STRING(FileSaveErrorTooLarge, "The drive does not support files large enough to store this document."); +DEFINE_INTERFACE_STRING(FileSaveErrorConcurrentAccess, "Another application is modifying the file."); +DEFINE_INTERFACE_STRING(FileSaveErrorDriveFull, "The drive is full. Try deleting some files to free up space."); +DEFINE_INTERFACE_STRING(FileSaveErrorResourcesLow, "The system is low on resources. Close some applcations and try again."); +DEFINE_INTERFACE_STRING(FileSaveErrorAlreadyExists, "Too many files already have the same name."); +DEFINE_INTERFACE_STRING(FileSaveErrorUnknown, "An unknown error occurred. Please try again later."); + +DEFINE_INTERFACE_STRING(FileLoadErrorCorrupt, "The file has been corrupted, and it cannot be opened."); +DEFINE_INTERFACE_STRING(FileLoadErrorDrive, "The drive containing the file was unable to access its contents."); +DEFINE_INTERFACE_STRING(FileLoadErrorResourcesLow, "The system is low on resources. Close some applcations and try again."); +DEFINE_INTERFACE_STRING(FileLoadErrorUnknown, "An unknown error occurred. Please try again later."); + +// Image Editor. + +DEFINE_INTERFACE_STRING(ImageEditorToolBrush, "Brush"); +DEFINE_INTERFACE_STRING(ImageEditorToolFill, "Fill"); +DEFINE_INTERFACE_STRING(ImageEditorToolRectangle, "Rectangle"); +DEFINE_INTERFACE_STRING(ImageEditorToolSelect, "Select"); +DEFINE_INTERFACE_STRING(ImageEditorToolText, "Text"); + +DEFINE_INTERFACE_STRING(ImageEditorCanvasSize, "Canvas size"); + +DEFINE_INTERFACE_STRING(ImageEditorPropertyWidth, "Width:"); +DEFINE_INTERFACE_STRING(ImageEditorPropertyHeight, "Height:"); +DEFINE_INTERFACE_STRING(ImageEditorPropertyColor, "Color:"); +DEFINE_INTERFACE_STRING(ImageEditorPropertyBrushSize, "Brush size:"); + +DEFINE_INTERFACE_STRING(ImageEditorImageTransformations, "Transform image"); +DEFINE_INTERFACE_STRING(ImageEditorRotateLeft, "Rotate left"); +DEFINE_INTERFACE_STRING(ImageEditorRotateRight, "Rotate right"); +DEFINE_INTERFACE_STRING(ImageEditorFlipHorizontally, "Flip horizontally"); +DEFINE_INTERFACE_STRING(ImageEditorFlipVertically, "Flip vertically"); + +DEFINE_INTERFACE_STRING(ImageEditorImage, "Image"); +DEFINE_INTERFACE_STRING(ImageEditorPickTool, "Pick tool"); + +DEFINE_INTERFACE_STRING(ImageEditorUnsupportedFormat, "The image is in an unsupported format. Try opening it with another application."); + +DEFINE_INTERFACE_STRING(ImageEditorTitle, "Image Editor"); + +// Text Editor. + +DEFINE_INTERFACE_STRING(TextEditorTitle, "Text Editor"); +DEFINE_INTERFACE_STRING(TextEditorNewFileName, "untitled.txt"); +DEFINE_INTERFACE_STRING(TextEditorNewDocument, "New text document"); + +// Markdown Viewer. + +DEFINE_INTERFACE_STRING(MarkdownViewerTitle, "Markdown Viewer"); + +// POSIX. + +DEFINE_INTERFACE_STRING(POSIXUnavailable, "This application depends on the POSIX subsystem. To enable it, select \am]Flag.ENABLE_POSIX_SUBSYSTEM\a] in \am]config\a]."); +DEFINE_INTERFACE_STRING(POSIXTitle, "POSIX Application"); + +// Font Book. + +DEFINE_INTERFACE_STRING(FontBookTitle, "Font Book"); +DEFINE_INTERFACE_STRING(FontBookTextSize, "Text size:"); +DEFINE_INTERFACE_STRING(FontBookPreviewText, "Preview text:"); +DEFINE_INTERFACE_STRING(FontBookVariants, "Variants"); +DEFINE_INTERFACE_STRING(FontBookPreviewTextDefault, "Looking for a change of mind."); +DEFINE_INTERFACE_STRING(FontBookPreviewTextLongDefault, "Sphinx of black quartz, judge my vow."); +DEFINE_INTERFACE_STRING(FontBookOpenFont, "Open"); +DEFINE_INTERFACE_STRING(FontBookNavigationBack, "Back to all fonts"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal100, "Thin"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal200, "Extra light"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal300, "Light"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal400, "Normal"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal500, "Medium"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal600, "Semi bold"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal700, "Bold"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal800, "Extra bold"); +DEFINE_INTERFACE_STRING(FontBookVariantNormal900, "Black"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic100, "Thin (italic)"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic200, "Extra light (italic)"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic300, "Light (italic)"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic400, "Normal (italic)"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic500, "Medium (italic)"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic600, "Semi bold (italic)"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic700, "Bold (italic)"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic800, "Extra bold (italic)"); +DEFINE_INTERFACE_STRING(FontBookVariantItalic900, "Black (italic)"); + +// File Manager. + +DEFINE_INTERFACE_STRING(FileManagerOpenFolderError, "The folder could not be opened."); +DEFINE_INTERFACE_STRING(FileManagerNewFolderError, "Could not create the folder."); +DEFINE_INTERFACE_STRING(FileManagerRenameItemError, "The item could not be renamed."); +DEFINE_INTERFACE_STRING(FileManagerUnknownError, "An unknown error occurred."); +DEFINE_INTERFACE_STRING(FileManagerTitle, "File Manager"); +DEFINE_INTERFACE_STRING(FileManagerRootFolder, "Computer"); +DEFINE_INTERFACE_STRING(FileManagerColumnName, "Name"); +DEFINE_INTERFACE_STRING(FileManagerColumnType, "Type"); +DEFINE_INTERFACE_STRING(FileManagerColumnSize, "Size"); +DEFINE_INTERFACE_STRING(FileManagerOpenFolderTask, "Opening folder" ELLIPSIS); +DEFINE_INTERFACE_STRING(FileManagerOpenFileError, "The file could not be opened."); +DEFINE_INTERFACE_STRING(FileManagerNoRegisteredApplicationsForFile, "None of the applications installed on this computer can open this type of file."); +DEFINE_INTERFACE_STRING(FileManagerFolderNamePrompt, "Folder name:"); +DEFINE_INTERFACE_STRING(FileManagerNewFolderAction, "Create"); +DEFINE_INTERFACE_STRING(FileManagerNewFolderTask, "Creating folder" ELLIPSIS); +DEFINE_INTERFACE_STRING(FileManagerRenameTitle, "Rename"); +DEFINE_INTERFACE_STRING(FileManagerRenamePrompt, "Type the new name of the item:"); +DEFINE_INTERFACE_STRING(FileManagerRenameAction, "Rename"); +DEFINE_INTERFACE_STRING(FileManagerRenameTask, "Renaming item" ELLIPSIS); +DEFINE_INTERFACE_STRING(FileManagerEmptyBookmarkView, "Drag folders here to bookmark them."); +DEFINE_INTERFACE_STRING(FileManagerEmptyFolderView, "Drag items here to add them to the folder."); +DEFINE_INTERFACE_STRING(FileManagerNewFolderToolbarItem, "New folder"); +DEFINE_INTERFACE_STRING(FileManagerNewFolderName, "New folder"); +DEFINE_INTERFACE_STRING(FileManagerGenericError, "The cause of the error could not be identified."); +DEFINE_INTERFACE_STRING(FileManagerItemAlreadyExistsError, "The item already exists in the folder."); +DEFINE_INTERFACE_STRING(FileManagerItemDoesNotExistError, "The item does not exist."); +DEFINE_INTERFACE_STRING(FileManagerPermissionNotGrantedError, "You don't have permission to modify this folder."); +DEFINE_INTERFACE_STRING(FileManagerOngoingTaskDescription, "This shouldn't take long."); +DEFINE_INTERFACE_STRING(FileManagerPlacesDrives, "Drives"); +DEFINE_INTERFACE_STRING(FileManagerPlacesBookmarks, "Bookmarks"); +DEFINE_INTERFACE_STRING(FileManagerBookmarksAddHere, "Add bookmark here"); +DEFINE_INTERFACE_STRING(FileManagerBookmarksRemoveHere, "Remove bookmark here"); +DEFINE_INTERFACE_STRING(FileManagerDrivesPage, "Drives/"); +DEFINE_INTERFACE_STRING(FileManagerInvalidPath, "The current path does not lead to a folder. It may have been deleted or moved."); +DEFINE_INTERFACE_STRING(FileManagerInvalidDrive, "The drive containing this folder was disconnected."); +DEFINE_INTERFACE_STRING(FileManagerRefresh, "Refresh"); +DEFINE_INTERFACE_STRING(FileManagerListContextActions, "Actions"); + +// TODO System Monitor. + +#pragma GCC diagnostic pop diff --git a/shared/unicode.cpp b/shared/unicode.cpp new file mode 100644 index 0000000..3e3c4d5 --- /dev/null +++ b/shared/unicode.cpp @@ -0,0 +1,1116 @@ +#pragma GCC diagnostic ignored "-Wunused-function" push + +#define UTF8_LENGTH_CHAR(character, value) { \ + char first = *(character); \ + \ + if (!(first & 0x80)) \ + value = 1; \ + else if ((first & 0xE0) == 0xC0) \ + value = 2; \ + else if ((first & 0xF0) == 0xE0) \ + value = 3; \ + else if ((first & 0xF8) == 0xF0) \ + value = 4; \ + else if ((first & 0xFC) == 0xF8) \ + value = 5; \ + else if ((first & 0xFE) == 0xFC) \ + value = 6; \ + else \ + value = 0; \ +} + +static int utf8_length_char(const char *character) { + int value; + UTF8_LENGTH_CHAR(character, value); + return value; +} + +static int utf8_value(const char *character, int maximumLength, int *_length) { + if (!maximumLength) return 0; + int length; + char first = *character; + + if (!(first & 0x80)) + length = 1; + else if ((first & 0xE0) == 0xC0) + length = 2; + else if ((first & 0xF0) == 0xE0) + length = 3; + else if ((first & 0xF8) == 0xF0) + length = 4; + else if ((first & 0xFC) == 0xF8) + length = 5; + else if ((first & 0xFE) == 0xFC) + length = 6; + else + length = 0; + + if (maximumLength < length) return 0; + if (_length) *_length = length; + + if (length == 1) + return (int)first; + else if (length == 2) + return (((int)first & 0x1F) << 6) | (((int)character[1]) & 0x3F); + else if (length == 3) + return (((int)first & 0xF) << 12) | ((((int)character[1]) & 0x3F) << 6) | (((int)character[2]) & 0x3F); + else if (length == 4) + return (((int)first & 0x7) << 18) | ((((int)character[1]) & 0x3F) << 12) | ((((int)character[2]) & 0x3F) << 6) | + (((int)character[3]) & 0x3F); + else if (length == 5) + return (((int)first & 0x3) << 24) | ((((int)character[1]) & 0x3F) << 18) | ((((int)character[2]) & 0x3F) << 12) | + ((((int)character[4]) & 0x3F) << 6) | (((int)character[5]) & 0x3F); + else if (length == 6) + return (((int)first & 0x1) << 30) | ((((int)character[1]) & 0x3F) << 24) | ((((int)character[2]) & 0x3F) << 18) | + ((((int)character[4]) & 0x3F) << 12) | ((((int)character[5]) & 0x3F) << 6) | (((int)character[6]) & 0x3F); + else + return 0; // Invalid code point +} + +static int utf8_value(const char *character) { + int length; + UTF8_LENGTH_CHAR(character, length); + + char first = *character; + + int value; + + if (length == 1) + value = (int)first; + else if (length == 2) + value = (((int)first & 0x1F) << 6) | (((int)character[1]) & 0x3F); + else if (length == 3) + value = (((int)first & 0xF) << 12) | ((((int)character[1]) & 0x3F) << 6) | (((int)character[2]) & 0x3F); + else if (length == 4) + value = (((int)first & 0x7) << 18) | ((((int)character[1]) & 0x3F) << 12) | ((((int)character[2]) & 0x3F) << 6) | + (((int)character[3]) & 0x3F); + else if (length == 5) + value = (((int)first & 0x3) << 24) | ((((int)character[1]) & 0x3F) << 18) | ((((int)character[2]) & 0x3F) << 12) | + ((((int)character[4]) & 0x3F) << 6) | (((int)character[5]) & 0x3F); + else if (length == 6) + value = (((int)first & 0x1) << 30) | ((((int)character[1]) & 0x3F) << 24) | ((((int)character[2]) & 0x3F) << 18) | + ((((int)character[4]) & 0x3F) << 12) | ((((int)character[5]) & 0x3F) << 6) | (((int)character[6]) & 0x3F); + else + value = 0; // Invalid code point + + return value; +} + +static int utf8_encode(int value, char *buffer) { + if (value < (1 << 7)) { + if (buffer) { + buffer[0] = value & 0x7F; + } + + return 1; + } else if (value < (1 << 11)) { + if (buffer) { + buffer[0] = 0xC0 | ((value >> 6) & 0x1F); + buffer[1] = 0x80 | (value & 0x3F); + } + + return 2; + } else if (value < (1 << 16)) { + if (buffer) { + buffer[0] = 0xE0 | ((value >> 12) & 0xF); + buffer[1] = 0x80 | ((value >> 6) & 0x3F); + buffer[2] = 0x80 | (value & 0x3F); + } + + return 3; + } else if (value < (1 << 21)) { + if (buffer) { + buffer[0] = 0xF0 | ((value >> 18) & 0x7); + buffer[1] = 0x80 | ((value >> 12) & 0x3F); + buffer[2] = 0x80 | ((value >> 6) & 0x3F); + buffer[3] = 0x80 | (value & 0x3F); + } + + return 4; + } + + return 0; // Cannot encode character +} + +static char *utf8_advance(const char *string) { + int length; + UTF8_LENGTH_CHAR(string, length); + + if (!length) // Invalid code point + return NULL; + + return (char *) string + length; +} + +static char *utf8_retreat(const char *string) { + // Keep going backwards until we find a non continuation character + do string--; + while (((*string) & 0xC0) == 0x80); + return (char *) string; +} + +static int utf8_length(char *string, int max_bytes) { + if (!string) + return 0; + if (!(*string)) + return 0; + + if (!max_bytes) return 0; + + int length = 0; + char *limit = string + max_bytes; + + while ((max_bytes == -1 || string < limit) && *string) { + if (!string) // Invalid code point + return -1; + + length++; + string = utf8_advance(string); + } + + return length; +} + +#pragma GCC diagnostic pop + +#ifndef SHARED_DEFINITIONS_ONLY + +// --------------------------------- Line breaking algorithm. + +#ifndef KERNEL + +static const uint16_t breakGroupsL2Lookup[544] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0007, 0x0008, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0010, 0x0010, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0010, 0x0017, 0x0010, 0x0018, 0x0010, 0x0010, 0x0010, 0x0010, 0x0019, 0x0007, 0x0007, + 0x001A, 0x001B, 0x0010, 0x0010, 0x0010, 0x0010, 0x001C, 0x001D, 0x0010, 0x0010, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0024, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0024, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0025, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, +}; + +static const uint16_t breakGroupsL2[38][64] = { + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0007, 0x0006, 0x0008, 0x0008, 0x0009, 0x000A, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x000B, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0006, 0x0011, 0x0012, 0x0006, 0x0006, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0006, 0x0006, 0x0018, 0x0019, 0x001A, + }, + { + 0x001B, 0x001C, 0x001D, 0x0006, 0x0006, 0x0006, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0024, 0x0025, 0x0028, 0x0029, 0x0024, 0x0025, 0x002A, 0x002B, 0x0024, 0x0025, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, + 0x0032, 0x002F, 0x0033, 0x0034, 0x0035, 0x0025, 0x0033, 0x002D, 0x0020, 0x0036, 0x0037, 0x0038, 0x0024, 0x0006, 0x0039, 0x003A, + 0x0006, 0x003B, 0x003C, 0x0006, 0x0006, 0x0006, 0x003D, 0x0006, 0x003E, 0x003F, 0x0006, 0x0040, 0x0041, 0x0042, 0x0043, 0x0006, + }, + { + 0x0006, 0x0006, 0x0044, 0x0006, 0x003D, 0x0006, 0x0006, 0x0006, 0x0045, 0x0045, 0x0045, 0x0046, 0x0046, 0x0047, 0x0048, 0x0048, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0049, 0x004A, 0x0006, 0x0006, 0x0006, 0x0006, + 0x004B, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x004C, 0x0006, 0x0006, 0x004D, 0x004E, 0x004F, 0x0050, 0x0050, 0x0006, 0x0006, 0x0051, 0x0019, + }, + { + 0x0052, 0x0006, 0x0006, 0x0006, 0x0053, 0x0054, 0x0006, 0x0006, 0x0006, 0x0055, 0x0056, 0x0006, 0x0006, 0x0006, 0x003D, 0x0006, + 0x0057, 0x0006, 0x0006, 0x0058, 0x0059, 0x0016, 0x005A, 0x0006, 0x0032, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0006, 0x0060, + 0x0006, 0x0061, 0x0059, 0x0062, 0x0006, 0x0006, 0x0063, 0x0064, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0008, 0x0065, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0066, + }, + { + 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0070, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0071, 0x0072, 0x0073, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0074, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0075, 0x0076, 0x0006, 0x0077, 0x0006, 0x0078, 0x0079, 0x007A, 0x007B, 0x0006, 0x007C, 0x007D, 0x0006, 0x0006, 0x007E, 0x007F, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0080, 0x0006, 0x0081, 0x0082, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0083, 0x0006, 0x0006, 0x0006, 0x0084, 0x0006, 0x0006, 0x0006, 0x0008, + 0x0085, 0x0086, 0x0087, 0x0006, 0x0088, 0x0089, 0x0089, 0x008A, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x008B, 0x008C, + }, + { + 0x008D, 0x008E, 0x008F, 0x0090, 0x0091, 0x0092, 0x0090, 0x0093, 0x0094, 0x0095, 0x0089, 0x0089, 0x0096, 0x0089, 0x0089, 0x0097, + 0x0098, 0x0089, 0x0099, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + }, + { + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + }, + { + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0006, 0x0006, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + }, + { + 0x009A, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x009B, 0x0089, 0x009C, 0x0062, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x009D, 0x0019, 0x0006, 0x009E, 0x002F, 0x0006, 0x0006, 0x009F, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x00A0, 0x00A1, 0x0006, 0x00A2, 0x00A3, 0x005B, 0x00A4, 0x00A5, 0x0019, 0x00A6, 0x00A7, 0x00A8, 0x0020, 0x001E, 0x00A9, 0x003D, + 0x0006, 0x00AA, 0x00AB, 0x0006, 0x0006, 0x0006, 0x0006, 0x00AC, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00AD, + 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, + }, + { + 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, + 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, + 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, + 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, + }, + { + 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, + 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, + 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, + }, + { + 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, + 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, + 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, + 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, + }, + { + 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, + 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, + 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, + }, + { + 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, + 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, + 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, + 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B5, 0x00B6, 0x00B7, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x00B8, 0x00B9, 0x00BA, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00BB, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00BC, + 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x0006, 0x0006, 0x0006, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x0098, 0x00C7, 0x00C8, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00C9, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00CA, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x005A, 0x0006, 0x0006, 0x0006, 0x00CB, 0x00CC, 0x0006, 0x00CD, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0019, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x0006, 0x00CE, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00CC, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x00CF, 0x00D0, 0x00D1, 0x0006, 0x0006, 0x0006, 0x0006, 0x00D2, 0x0006, 0x00D3, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00D4, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00D5, 0x0006, 0x0006, 0x0006, 0x0006, 0x0018, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x005E, 0x00D6, 0x00D7, 0x00D8, 0x005E, 0x00D9, 0x00DA, 0x003D, 0x005E, 0x00DB, 0x00DC, 0x00DD, 0x005E, 0x001E, 0x00DE, 0x0006, + 0x0006, 0x00DF, 0x0006, 0x0006, 0x0006, 0x00E0, 0x0058, 0x00E1, 0x0020, 0x0036, 0x0026, 0x00E2, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x00E3, 0x00E4, 0x0006, 0x0006, 0x0016, 0x00E5, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00E6, 0x00E7, 0x0006, + 0x0006, 0x0016, 0x00E8, 0x00E9, 0x0006, 0x00EA, 0x0019, 0x0006, 0x0006, 0x00EB, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x00EC, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0019, 0x0006, 0x00ED, 0x00EE, 0x0006, 0x0006, 0x0006, 0x00EF, 0x00F0, + 0x00F1, 0x00F2, 0x00F3, 0x0006, 0x00F4, 0x00F5, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x0006, 0x0006, 0x0006, 0x00FB, 0x00FC, 0x0006, 0x00FD, 0x0019, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00FE, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x00FF, 0x0100, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0101, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0102, 0x0006, 0x0103, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0104, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0105, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0106, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0107, 0x0006, 0x0006, 0x0006, 0x0108, 0x0006, 0x0109, 0x010A, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x010B, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x010C, 0x0008, 0x010D, 0x0006, 0x0006, 0x010E, + }, + { + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x010F, + }, + { + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0110, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0098, 0x0006, 0x0111, 0x0112, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0113, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0114, 0x0020, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0115, 0x0116, 0x0117, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0118, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0119, 0x011A, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0008, 0x011B, 0x0008, 0x011C, 0x011D, 0x011E, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x011F, 0x0120, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0121, 0x0019, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0122, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0121, 0x0006, 0x0006, 0x0006, 0x0123, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0124, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, + { + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0125, 0x0006, 0x0006, 0x0125, 0x0006, 0x0126, 0x0089, 0x0127, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0128, 0x0129, 0x012A, 0x012B, + 0x0089, 0x0089, 0x012C, 0x012D, 0x012E, 0x012F, 0x0089, 0x0089, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0089, 0x0135, 0x0136, + 0x0089, 0x0089, 0x0137, 0x0138, 0x0089, 0x0139, 0x013A, 0x0089, 0x0006, 0x0006, 0x0006, 0x013B, 0x0006, 0x0006, 0x013C, 0x0089, + }, + { + 0x013D, 0x0006, 0x013E, 0x0006, 0x013F, 0x0140, 0x0089, 0x0089, 0x0141, 0x0142, 0x0089, 0x0089, 0x0089, 0x0143, 0x0144, 0x0089, + 0x0006, 0x0006, 0x013B, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x003D, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0145, + }, + { + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0145, + }, + { + 0x0146, 0x0008, 0x0008, 0x0008, 0x0006, 0x0006, 0x0006, 0x0006, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0147, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + }, +}; + +static const uint8_t breakGroupsL1[328][32] = { + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 37, 34, 34, 36, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 41, 6, 3, 12, 9, 10, 12, 3, 0, 2, 12, 9, 8, 16, 8, 7, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 8, 8, 12, 12, 12, 6, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 9, 2, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 17, 1, 12, 21, }, + { 21, 21, 21, 21, 21, 38, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 4, 0, 10, 9, 9, 9, 12, 12, 12, 12, 12, 3, 12, 17, 12, 12, 10, 9, 12, 12, 18, 12, 12, 12, 12, 12, 12, 3, 12, 12, 12, 0, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 18, 12, 12, 12, 18, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 18, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 4, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 4, 4, 4, 4, }, + { 4, 4, 4, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 8, 12, }, + { 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 8, 17, 12, 12, 12, 12, 9, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 21, }, + { 12, 21, 21, 12, 21, 21, 6, 21, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, }, + { 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 8, 8, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 6, 21, 12, 6, 6, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 11, 11, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 6, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 21, }, + { 21, 21, 21, 21, 21, 12, 12, 21, 21, 12, 21, 21, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 8, 6, 12, 12, 12, 21, 9, 9, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 12, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 12, 21, 21, 21, 12, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 12, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 21, 17, 17, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 21, 21, }, + { 21, 21, 21, 21, 21, 12, 12, 21, 21, 12, 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 10, 10, 12, 12, 12, 12, 12, 10, 12, 9, 12, 12, 21, 12, }, + { 21, 21, 21, 12, 12, 12, 12, 21, 21, 12, 12, 21, 21, 21, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 21, 21, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 12, 21, 21, 21, 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 9, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 12, 12, 21, 21, 12, 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, }, + { 21, 21, 21, 12, 12, 12, 21, 21, 21, 12, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 12, 21, 21, 21, 12, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 18, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 21, 21, 21, 18, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 12, 21, 21, }, + { 21, 21, 21, 21, 21, 12, 21, 21, 21, 12, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 12, 21, 12, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 17, 17, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 18, 18, 18, 18, 12, 18, 18, 4, 18, 18, 17, 4, 6, 6, 6, 6, 6, 4, 12, 6, 12, 12, 12, 21, 21, 12, 12, 12, 12, 12, 12, }, + { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 21, 12, 21, 12, 21, 0, 1, 0, 1, 21, 21, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, }, + { 21, 21, 21, 21, 21, 17, 21, 21, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 17, 17, }, + { 12, 12, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 18, 18, 17, 18, 12, 12, 12, 12, 12, 4, 4, 12, 12, 12, 12, 12, }, + { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, }, + { 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, }, + { 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, }, + { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, }, + { 12, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, 5, 12, 17, 12, 17, 9, 12, 12, 12, 12, }, + { 12, 12, 6, 6, 17, 17, 18, 12, 6, 6, 12, 21, 21, 21, 4, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 6, 6, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, }, + { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 17, 17, 12, 17, 17, 17, }, + { 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 17, 17, 17, 17, 17, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 21, 12, 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 21, 21, 21, 21, 21, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 18, 12, 12, }, + { 17, 17, 17, 17, 17, 17, 17, 4, 17, 17, 17, 20, 21, 31, 21, 21, 17, 4, 17, 17, 19, 12, 12, 12, 3, 3, 0, 3, 3, 3, 0, 3, }, + { 12, 12, 12, 12, 15, 15, 15, 17, 34, 34, 21, 21, 21, 21, 21, 4, 10, 10, 10, 10, 10, 10, 10, 10, 12, 3, 3, 12, 5, 5, 12, 12, }, + { 12, 12, 12, 12, 8, 0, 1, 5, 5, 5, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12, 17, 17, 17, 17, 12, 17, 17, 17, }, + { 22, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 9, 9, 9, 9, 9, 9, 9, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 9, 9, 9, 9, 10, 9, 9, 10, 9, }, + { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 10, 12, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, 9, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 12, 12, 14, 12, 14, 14, 14, 29, 14, 14, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 14, 12, 14, 14, 14, 12, 14, 14, 12, 12, 12, 14, 14, 12, 12, 14, 12, 12, 14, }, + { 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 14, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 12, 14, 14, 29, 14, 12, 12, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 12, 12, 12, 14, 14, 29, 29, 29, 29, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3, 3, 3, 3, 3, }, + { 3, 12, 6, 6, 14, 12, 12, 12, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 0, 1, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 6, 17, 17, 17, 12, 6, 17, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, }, + { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 17, 17, 17, 17, 17, 17, 17, 17, 12, 17, 0, 17, 12, 12, 3, 3, 12, 12, }, + { 3, 3, 0, 1, 0, 1, 0, 1, 0, 1, 17, 17, 17, 17, 6, 12, 17, 17, 12, 17, 17, 12, 12, 12, 12, 12, 19, 19, 17, 17, 17, 12, }, + { 17, 17, 0, 17, 17, 17, 17, 17, 17, 17, 17, 12, 17, 12, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, }, + { 17, 1, 1, 14, 14, 5, 14, 14, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 14, 14, 0, 1, 0, 1, 0, 1, 0, 1, 5, 0, 1, 1, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 21, 21, 21, 21, 21, 21, 14, 14, 14, 14, 14, 21, 14, 14, 14, 14, 14, 5, 5, 14, 14, 14, }, + { 12, 5, 14, 5, 14, 5, 14, 5, 14, 5, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 5, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 5, 14, 5, 14, 5, 14, 14, 14, 14, 14, 14, 5, 14, 14, 14, 14, 14, 14, 5, 5, 12, 12, 21, 21, 5, 5, 5, 5, 14, }, + { 5, 5, 14, 5, 14, 5, 14, 5, 14, 5, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 5, 14, 5, 14, 5, 14, 14, 14, 14, 14, 14, 5, 14, 14, 14, 14, 14, 14, 5, 5, 14, 14, 14, 14, 5, 5, 5, 5, 14, }, + { 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 5, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 6, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 12, 17, 17, 17, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 12, 12, 12, 21, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 21, 21, 21, 21, 21, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 18, 18, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 18, 12, 12, 21, }, + { 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 12, 12, 12, }, + { 21, 12, 12, 12, 12, 12, 12, 17, 17, 17, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 17, 17, 17, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 17, 17, 12, 12, 12, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 17, 21, 21, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, }, + { 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, }, + { 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, }, + { 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, }, + { 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, }, + { 24, 24, 24, 24, 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, }, + { 24, 24, 24, 24, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, }, + { 24, 24, 24, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, }, + { 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, }, + { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 21, 13, }, + { 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 13, 13, 13, 13, 13, 12, 13, 12, }, + { 13, 13, 12, 13, 13, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 1, 0, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 8, 1, 1, 8, 8, 6, 6, 0, 1, 15, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 14, 14, 14, 14, 14, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, }, + { 1, 0, 1, 0, 1, 14, 14, 0, 1, 14, 14, 14, 14, 14, 14, 14, 1, 14, 1, 12, 5, 5, 6, 6, 14, 0, 1, 0, 1, 0, 1, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 12, 14, 9, 10, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 22, }, + { 12, 6, 14, 14, 9, 10, 14, 14, 0, 1, 14, 14, 1, 14, 1, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 5, 5, 14, 14, 14, 6, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 1, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 1, 14, 0, }, + { 1, 1, 0, 1, 1, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 5, 5, }, + { 12, 12, 14, 14, 14, 14, 14, 14, 12, 12, 14, 14, 14, 14, 14, 14, 12, 12, 14, 14, 14, 14, 14, 14, 12, 12, 14, 14, 14, 12, 12, 12, }, + { 10, 9, 14, 14, 14, 9, 9, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 32, 12, 12, 12, }, + { 17, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 21, 21, 21, 12, 21, 21, 12, 12, 12, 12, 12, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 12, 12, 12, 12, 21, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, 17, 17, 17, 17, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, 17, 17, 17, 17, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, 17, 17, 17, 17, 17, }, + { 12, 12, 12, 12, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 17, 17, }, + { 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, }, + { 17, 17, 17, 17, 12, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 18, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 12, 12, 12, 12, 17, 17, 12, 17, 21, 21, 21, 21, 12, 21, 21, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 18, 12, 17, 17, 17, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 12, 17, 17, 12, 21, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 21, 12, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 17, 17, 17, 17, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 17, 17, 12, 12, 21, 12, }, + { 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 18, 17, 17, 6, 6, 12, 12, 12, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 12, 12, 12, 12, 21, 21, 12, 12, }, + { 21, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 17, 17, 17, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 12, 21, 21, 12, 12, 21, 21, 21, 21, 12, }, + { 21, 12, 21, 21, 17, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 21, 21, 21, 21, 21, 21, }, + { 21, 12, 18, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 12, 21, 21, 21, 21, 18, }, + { 12, 17, 17, 17, 17, 18, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 17, 12, 18, 18, }, + { 18, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 12, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 12, 17, 17, 17, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 18, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 12, 12, 12, 21, 12, 21, 21, 12, 21, }, + { 21, 21, 21, 21, 21, 21, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 12, 21, 21, 12, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, }, + { 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, 17, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 1, 1, 1, 12, 12, }, + { 12, 12, 1, 12, 12, 12, 0, 1, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 1, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 4, 4, 4, 4, 4, 4, 0, 1, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 17, 17, 17, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 17, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 5, 5, 5, 5, 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 5, 5, 5, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 5, 5, 5, 5, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 17, }, + { 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 12, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, }, + { 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 21, 21, 21, 21, 21, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 21, 12, 12, 17, 17, 17, 17, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, }, + { 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 21, 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 21, 21, 21, 21, 21, }, + { 21, 21, 12, 21, 21, 12, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 9, }, + { 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 0, 0, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, }, + { 14, 14, 14, 14, 14, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 14, 14, 14, 14, 14, 12, 14, 14, 14, }, + { 14, 14, 29, 29, 29, 14, 14, 29, 14, 14, 29, 29, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 30, 30, 30, 30, 30, }, + { 14, 14, 29, 29, 14, 14, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 14, 14, 14, 29, 14, 14, 14, }, + { 14, 29, 29, 29, 14, 29, 29, 29, 14, 14, 14, 14, 14, 14, 14, 29, 14, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 12, 14, 12, 14, 12, 14, 14, 14, 14, 14, 29, 14, 14, 14, 14, 12, 14, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 29, 29, 14, 14, 14, 14, 29, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 29, 14, 14, 14, 14, 29, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 29, 29, 29, 14, 14, 14, 29, 29, 29, 29, 29, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3, 3, 3, 5, 5, 5, 12, 12, 12, 12, }, + { 14, 14, 14, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 29, 29, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 29, 14, 14, 29, 14, 14, 14, 14, 14, 14, 14, 14, 29, 29, 29, 29, 29, 29, 29, 29, }, + { 14, 14, 14, 14, 14, 14, 29, 14, 14, 14, 14, 14, 14, 14, 14, 14, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 14, 14, 29, 29, 29, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 29, 29, 14, 29, 29, 14, 29, 14, 14, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 29, 29, 29, 14, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 14, 14, }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, }, + { 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, + { 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, +}; + +enum BreakClass : uint8_t { + // Handled by the pair table. + + BREAK_OP, + BREAK_CL, + BREAK_CP, + BREAK_QU, + BREAK_GL, + BREAK_NS, + BREAK_EX, + BREAK_SY, + BREAK_IS, + BREAK_PR, + BREAK_PO, + BREAK_NU, + BREAK_AL, + BREAK_HL, + BREAK_ID, + BREAK_IN, + BREAK_HY, + BREAK_BA, + BREAK_BB, + BREAK_B2, + BREAK_ZW, + BREAK_CM, + BREAK_WJ, + BREAK_H2, + BREAK_H3, + BREAK_JL, + BREAK_JV, + BREAK_JT, + BREAK_RI, + BREAK_EB, + BREAK_EM, + BREAK_ZWJ, + BREAK_CB, + + // Not handled by the pair table. + + BREAK_AI, + BREAK_BK, + BREAK_CJ, + BREAK_CR, + BREAK_LF, + BREAK_NL, + BREAK_SA, + BREAK_SG, + BREAK_SP, + BREAK_XX, +}; + +enum BreakAction : uint8_t { + BREAK_DIRECT, + BREAK_INDIRECT, + BREAK_INDIRECT_COMBINING, + BREAK_PROHIBITED, + BREAK_PROHIBITED_COMBINING, +}; + +#define BD ((BreakAction) 0) +#define BI ((BreakAction) 1) +#define BC ((BreakAction) 2) +#define PB ((BreakAction) 3) +#define PC ((BreakAction) 4) + +static const BreakAction breakPairTable[34][34] = { + { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PC, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, }, + { BD, PB, PB, BI, BI, PB, PB, PB, PB, BI, BI, BD, BD, BD, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, PB, PB, PB, PB, BI, BI, BI, BI, BI, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { PB, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, PB, BC, PB, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, PB, BC, PB, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BD, BD, BD, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BI, BD, BI, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BI, BI, BI, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BI, BI, BI, BI, BD, BI, BI, BD, BD, PB, BC, PB, BI, BI, BI, BI, BI, BD, BI, BI, BI, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BI, BI, BI, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BI, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BD, BI, PB, PB, PB, BD, BD, BI, BD, BD, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BD, BI, PB, PB, PB, BD, BD, BD, BD, BD, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, PB, BC, PB, BI, BI, BI, BI, BI, BI, BI, BI, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BD, BD, BD, BD, BD, BI, BI, BD, PB, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, PB, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, PB, BC, PB, BI, BI, BI, BI, BI, BI, BI, BI, BI, BI, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BI, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BI, BI, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BI, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BI, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BI, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BI, BI, BI, BI, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BI, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BI, BI, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BI, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BI, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BD, BD, BD, BD, BD, BD, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BI, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BI, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BI, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BI, PB, PB, PB, BD, BI, BD, BD, BD, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BI, PB, PB, BI, BI, BI, PB, PB, PB, BI, BI, BI, BI, BI, BD, BI, BI, BI, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { BD, PB, PB, BI, BI, BD, PB, PB, PB, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, BD, PB, BC, PB, BD, BD, BD, BD, BD, BD, BD, BD, BI, BD, PB, }, + { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, }, +}; + +#undef BD +#undef BI +#undef BC +#undef PB +#undef PC + +struct Break { + uintptr_t position; + bool forced; +}; + +struct BreakState { + const char *string; + size_t bytes; + uintptr_t position; + BreakClass currentClass, nextClass; + bool rule8a, rule21a, started, error; + uint8_t rule30a; + + void Jump(uintptr_t newPosition) { + rule8a = rule21a = false; + rule30a = 0; + currentClass = nextClass = (BreakClass) 33; // Prohibited breaks. + position = newPosition; + } + + BreakClass GetNextClass() { + int length = 0, character; + + if (position != bytes) { + character = utf8_value(string + position, bytes - position, &length); + + if (!length) { + error = true; + } + + position += length; + } else { + character = 0; + } + + return (BreakClass) breakGroupsL1[breakGroupsL2[breakGroupsL2Lookup[character >> 11]][(character >> 5) & 63]][character & 31]; + } + + BreakClass MapFirst(BreakClass breakClass) { + if (breakClass == BREAK_LF || breakClass == BREAK_NL) return BREAK_BK; + if (breakClass == BREAK_SP) return BREAK_WJ; + return breakClass; + } + + Break Next() { + if (!started) { + started = true; + nextClass = GetNextClass(); + if (error) return {}; + currentClass = MapFirst(nextClass); + } + + while (position < bytes) { + uintptr_t previousPosition = position; + + BreakClass lastClass = nextClass; + nextClass = GetNextClass(); + if (error) return {}; + + if (currentClass == BREAK_BK) { + currentClass = MapFirst(nextClass); + return { previousPosition, true }; + } + + bool optionalBreak = false; + + if (nextClass == BREAK_BK || nextClass == BREAK_LF || nextClass == BREAK_NL) { + currentClass = BREAK_BK; + } else if (nextClass != BREAK_SP) { + BreakAction action = breakPairTable[currentClass][nextClass]; + + if (action == BREAK_DIRECT) optionalBreak = true; + else if (action == BREAK_INDIRECT || action == BREAK_INDIRECT_COMBINING) optionalBreak = lastClass == BREAK_SP; + if ((action == BREAK_INDIRECT_COMBINING || action == BREAK_PROHIBITED_COMBINING) && lastClass != BREAK_SP) goto next; + + if (rule8a) optionalBreak = false; + if (rule21a && (currentClass == BREAK_HY || currentClass == BREAK_BA)) optionalBreak = rule21a = false; + else rule21a = currentClass == BREAK_HL; + + if (currentClass == BREAK_RI) { + rule30a++; + + if (rule30a == 2 && nextClass == BREAK_RI) { + optionalBreak = true, rule30a = 0; + } + } else rule30a = 0; + + currentClass = nextClass; + } + + next:; + rule8a = nextClass == BREAK_ZWJ; + if (optionalBreak) return { previousPosition, bytes == previousPosition }; + } + + return { bytes, true }; + } +}; + +#endif + +// --------------------------------- Validation. + +const uint64_t utf8ValidationStateTable[] = { + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, 0xDB0AA4DB6DB6D80, + 0xDB0AA4636306036, 0xDB0AA4636306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, 0xDB0AA4306306036, + 0xDB0AA4DB6DB6DB6, 0xDB0AA4DB6DB6DB6, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, + 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, + 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, + 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, + 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, + 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, + 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, + 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, 0xDB0AA4DB6DB6D86, + 0xDB0AA4DB6DB6D98, 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, + 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, + 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, + 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, 0xDB0AA4DB6DB6D8C, + 0xDB0AA4DB6DB6D9E, 0xDB0AA4DB6DB6D92, 0xDB0AA4DB6DB6D92, 0xDB0AA4DB6DB6D92, + 0xDB0AA4DB6DB6D92, 0xDB0AA4DB6DB6D92, 0xDB0AA4DB6DB6D92, 0xDB0AA4DB6DB6D92, + 0xDB0AA4DB6DB6DB6, 0xDB0AA4DB6DB6DB6, 0xDB0AA4DB6DB6DB6, 0xDB0AA4DB6DB6DB6, + 0xDB0AA4DB6DB6DB6, 0xDB0AA4DB6DB6DB6, 0xDB0AA4DB6DB6DB6, 0xDB0AA4DB6DB6DB6, +}; + +#if 0 +void BuildTable() { + for (uintptr_t c = 0; c < 256; c++) { + uint64_t row = 0; + + for (uintptr_t i = 0; i < 10; i++) { + uintptr_t state = i; + + if (state == 0) { + if (!(c & 0x80)) state = 0; + else if (c == 0xC0 || c == 0xC1) state = 9; // Overlong ASCII. + else if (c == 0xE0) state = 4; // Maybe overlong... + else if (c == 0xF0) state = 5; // Maybe overlong... + else if ((c & 0xE0) == 0xC0) state = 1; + else if ((c & 0xF0) == 0xE0) state = 2; + else if ((c & 0xF8) == 0xF0) state = 3; + else state = 9; + } else if (state == 1 || state == 2 || state == 3) { + if ((c & 0xC0) != 0x80) state = 9; + else state--; + } else if (state == 5) { + if ((c & 0xC0) != 0x80) state = 9; + else if (c == 0x80 || c == 0x81) state = 4; // Maybe overlong... + else state = 2; + } else if (state == 4) { + if ((c & 0xC0) != 0x80) state = 9; + else if (c == 0x80 || c == 0x81) state = 9; // Overlong ASCII. + else state = 1; + } + + row |= (state * 6) << (i * 6); + } + + utf8ValidationStateTable[c] = row; + printf("0x%lX,\n", row); + } +} +#endif + +bool UTF8IsValid(const uint8_t *input, const uint8_t *end) { + // NOTE Does not check for surrogate characters or overlong sequences of non-ASCII characters. + // NOTE See https://gist.github.com/pervognsen/218ea17743e1442e59bb60d29b1aa725 for an explanation of how this works. + + uint64_t state = 0; + + while (input != end) { + state = utf8ValidationStateTable[*input++] >> (state & 63); + } + + return (state & 63) == 0; +} + +bool EsUTF8IsValid(const char *input, ptrdiff_t bytes) { + if (bytes == -1) bytes = EsCStringLength(input); + return UTF8IsValid((const uint8_t *) input, (const uint8_t *) input + bytes); +} + +#endif diff --git a/shared/vga_font.cpp b/shared/vga_font.cpp new file mode 100644 index 0000000..0712716 --- /dev/null +++ b/shared/vga_font.cpp @@ -0,0 +1,40 @@ +// Taken from https://commons.wikimedia.org/wiki/File:Codepage-437.png +// Public domain. + +#define VGA_FONT_WIDTH (9) +#define VGA_FONT_HEIGHT (16) + +uint64_t vgaFont[] = { + 0x0000000000000000UL, 0x0000000000000000UL, 0xBD8181A5817E0000UL, 0x000000007E818199UL, 0xC3FFFFDBFF7E0000UL, 0x000000007EFFFFE7UL, 0x7F7F7F3600000000UL, 0x00000000081C3E7FUL, + 0x7F3E1C0800000000UL, 0x0000000000081C3EUL, 0xE7E73C3C18000000UL, 0x000000003C1818E7UL, 0xFFFF7E3C18000000UL, 0x000000003C18187EUL, 0x3C18000000000000UL, 0x000000000000183CUL, + 0xC3E7FFFFFFFFFFFFUL, 0xFFFFFFFFFFFFE7C3UL, 0x42663C0000000000UL, 0x00000000003C6642UL, 0xBD99C3FFFFFFFFFFUL, 0xFFFFFFFFFFC399BDUL, 0x331E4C5870780000UL, 0x000000001E333333UL, + 0x3C666666663C0000UL, 0x0000000018187E18UL, 0x0C0C0CFCCCFC0000UL, 0x00000000070F0E0CUL, 0xC6C6C6FEC6FE0000UL, 0x0000000367E7E6C6UL, 0xE73CDB1818000000UL, 0x000000001818DB3CUL, + 0x1F7F1F0F07030100UL, 0x000000000103070FUL, 0x7C7F7C7870604000UL, 0x0000000040607078UL, 0x1818187E3C180000UL, 0x0000000000183C7EUL, 0x6666666666660000UL, 0x0000000066660066UL, + 0xD8DEDBDBDBFE0000UL, 0x00000000D8D8D8D8UL, 0x6363361C06633E00UL, 0x0000003E63301C36UL, 0x0000000000000000UL, 0x000000007F7F7F7FUL, 0x1818187E3C180000UL, 0x000000007E183C7EUL, + 0x1818187E3C180000UL, 0x0000000018181818UL, 0x1818181818180000UL, 0x00000000183C7E18UL, 0x7F30180000000000UL, 0x0000000000001830UL, 0x7F060C0000000000UL, 0x0000000000000C06UL, + 0x0303000000000000UL, 0x0000000000007F03UL, 0xFF66240000000000UL, 0x0000000000002466UL, 0x3E1C1C0800000000UL, 0x00000000007F7F3EUL, 0x3E3E7F7F00000000UL, 0x0000000000081C1CUL, + 0x0000000000000000UL, 0x0000000000000000UL, 0x18183C3C3C180000UL, 0x0000000018180018UL, 0x0000002466666600UL, 0x0000000000000000UL, 0x36367F3636000000UL, 0x0000000036367F36UL, + 0x603E0343633E1818UL, 0x000018183E636160UL, 0x1830634300000000UL, 0x000000006163060CUL, 0x3B6E1C36361C0000UL, 0x000000006E333333UL, 0x000000060C0C0C00UL, 0x0000000000000000UL, + 0x0C0C0C0C18300000UL, 0x0000000030180C0CUL, 0x30303030180C0000UL, 0x000000000C183030UL, 0xFF3C660000000000UL, 0x000000000000663CUL, 0x7E18180000000000UL, 0x0000000000001818UL, + 0x0000000000000000UL, 0x0000000C18181800UL, 0x7F00000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL, 0x0000000018180000UL, 0x1830604000000000UL, 0x000000000103060CUL, + 0xDBDBC3C3663C0000UL, 0x000000003C66C3C3UL, 0x1818181E1C180000UL, 0x000000007E181818UL, 0x0C183060633E0000UL, 0x000000007F630306UL, 0x603C6060633E0000UL, 0x000000003E636060UL, + 0x7F33363C38300000UL, 0x0000000078303030UL, 0x603F0303037F0000UL, 0x000000003E636060UL, 0x633F0303061C0000UL, 0x000000003E636363UL, 0x18306060637F0000UL, 0x000000000C0C0C0CUL, + 0x633E6363633E0000UL, 0x000000003E636363UL, 0x607E6363633E0000UL, 0x000000001E306060UL, 0x0000181800000000UL, 0x0000000000181800UL, 0x0000181800000000UL, 0x000000000C181800UL, + 0x060C183060000000UL, 0x000000006030180CUL, 0x00007E0000000000UL, 0x000000000000007EUL, 0x6030180C06000000UL, 0x00000000060C1830UL, 0x18183063633E0000UL, 0x0000000018180018UL, + 0x7B7B63633E000000UL, 0x000000003E033B7BUL, 0x7F6363361C080000UL, 0x0000000063636363UL, 0x663E6666663F0000UL, 0x000000003F666666UL, 0x03030343663C0000UL, 0x000000003C664303UL, + 0x66666666361F0000UL, 0x000000001F366666UL, 0x161E1646667F0000UL, 0x000000007F664606UL, 0x161E1646667F0000UL, 0x000000000F060606UL, 0x7B030343663C0000UL, 0x000000005C666363UL, + 0x637F636363630000UL, 0x0000000063636363UL, 0x18181818183C0000UL, 0x000000003C181818UL, 0x3030303030780000UL, 0x000000001E333333UL, 0x1E1E366666670000UL, 0x0000000067666636UL, + 0x06060606060F0000UL, 0x000000007F664606UL, 0xC3DBFFFFE7C30000UL, 0x00000000C3C3C3C3UL, 0x737B7F6F67630000UL, 0x0000000063636363UL, 0x63636363633E0000UL, 0x000000003E636363UL, + 0x063E6666663F0000UL, 0x000000000F060606UL, 0x63636363633E0000UL, 0x000070303E7B6B63UL, 0x363E6666663F0000UL, 0x0000000067666666UL, 0x301C0663633E0000UL, 0x000000003E636360UL, + 0x18181899DBFF0000UL, 0x000000003C181818UL, 0x6363636363630000UL, 0x000000003E636363UL, 0xC3C3C3C3C3C30000UL, 0x00000000183C66C3UL, 0xDBC3C3C3C3C30000UL, 0x000000006666FFDBUL, + 0x18183C66C3C30000UL, 0x00000000C3C3663CUL, 0x183C66C3C3C30000UL, 0x000000003C181818UL, 0x0C183061C3FF0000UL, 0x00000000FFC38306UL, 0x0C0C0C0C0C3C0000UL, 0x000000003C0C0C0CUL, + 0x1C0E070301000000UL, 0x0000000040607038UL, 0x30303030303C0000UL, 0x000000003C303030UL, 0x0000000063361C08UL, 0x0000000000000000UL, 0x0000000000000000UL, 0x0000FF0000000000UL, + 0x0000000000180C0CUL, 0x0000000000000000UL, 0x3E301E0000000000UL, 0x000000006E333333UL, 0x66361E0606070000UL, 0x000000003E666666UL, 0x03633E0000000000UL, 0x000000003E630303UL, + 0x33363C3030380000UL, 0x000000006E333333UL, 0x7F633E0000000000UL, 0x000000003E630303UL, 0x060F0626361C0000UL, 0x000000000F060606UL, 0x33336E0000000000UL, 0x001E33303E333333UL, + 0x666E360606070000UL, 0x0000000067666666UL, 0x18181C0018180000UL, 0x000000003C181818UL, 0x6060700060600000UL, 0x003C666660606060UL, 0x1E36660606070000UL, 0x000000006766361EUL, + 0x18181818181C0000UL, 0x000000003C181818UL, 0xDBFF670000000000UL, 0x00000000DBDBDBDBUL, 0x66663B0000000000UL, 0x0000000066666666UL, 0x63633E0000000000UL, 0x000000003E636363UL, + 0x66663B0000000000UL, 0x000F06063E666666UL, 0x33336E0000000000UL, 0x007830303E333333UL, 0x666E3B0000000000UL, 0x000000000F060606UL, 0x06633E0000000000UL, 0x000000003E63301CUL, + 0x0C0C3F0C0C080000UL, 0x00000000386C0C0CUL, 0x3333330000000000UL, 0x000000006E333333UL, 0xC3C3C30000000000UL, 0x00000000183C66C3UL, 0xC3C3C30000000000UL, 0x0000000066FFDBDBUL, + 0x3C66C30000000000UL, 0x00000000C3663C18UL, 0x6363630000000000UL, 0x001F30607E636363UL, 0x18337F0000000000UL, 0x000000007F63060CUL, 0x180E181818700000UL, 0x0000000070181818UL, + 0x1800181818180000UL, 0x0000000018181818UL, 0x18701818180E0000UL, 0x000000000E181818UL, 0x000000003B6E0000UL, 0x0000000000000000UL, 0x63361C0800000000UL, 0x00000000007F6363UL, +}; diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..ebbe173 --- /dev/null +++ b/start.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Set the current directory to the source root. +cd "$(dirname "$0")" + +# Create the bin directory. +mkdir -p bin + +# Check that we are running on a sensible platform. +uname -o | grep Cygwin > /dev/null +if [ $? -ne 1 ]; then + echo Cygwin is not supported. Please install a modern GNU/Linux distro. + exit +fi + +# Check that the source code is valid. +md5sum util/test.txt | grep 9906c52f54b2769da1c31e77d3213d0a > /dev/null +if [ $? -ne 0 ]; then + echo "--------------------------------------------------------------------" + echo " The source has been corrupted!! " + echo " Please check that you have disabled any automatic line-ending or " + echo " encoding conversions in Git and archive extraction tools you use. " + echo "--------------------------------------------------------------------" + exit +fi + +# Check the system compiler is reasonably recent. +if [ ! -f "bin/good_compiler.txt" ]; then + echo "int main() { return __GNUC__ < 9; }" > bin/check_gcc.c + g++ -o bin/check_gcc bin/check_gcc.c + if [ $? -ne 0 ]; then + echo "GCC/G++ could not be found. Please install the latest version of GCC/G++." + exit + fi + bin/check_gcc + if [ $? -ne 0 ]; then + echo "Your system compiler is out of date. Please update to the latest version of GCC/G++." + exit + fi + rm bin/check_gcc.c bin/check_gcc + echo yes > "bin/good_compiler.txt" +fi + +# Compile and run Build. +gcc -o bin/build -g util/build.c -Wall -Wextra -Wno-format-security -Wno-format-overflow \ + -Wno-missing-field-initializers -Wno-unused-function -Wno-format-truncation -pthread -DPARALLEL_BUILD \ + && bin/build "$@" diff --git a/util/api_table.ini b/util/api_table.ini new file mode 100644 index 0000000..6af9a02 --- /dev/null +++ b/util/api_table.ini @@ -0,0 +1,417 @@ +EsBatch=0 +EsConstantBufferGetSize=1 +EsListViewSetMaximumItemsPerBand=2 +EsHandleClose=3 +EsPOSIXInitialise=4 +EsFileStoreReadAll=5 +EsPOSIXSystemCall=6 +EsINIParse=7 +EsSystemGetConstant=8 +EsTakeSystemSnapshot=9 +EsListViewFocusItem=10 +_EsInstanceCreate=11 +_EsSyscall=12 +EsCommandAddButton=13 +EsCommandByID=14 +EsCommandRegister=15 +EsCommandSetCallback=16 +EsCommandSetDisabled=17 +EsDialogClose=18 +EsDialogShow=19 +EsDialogShowAlert=20 +EsCRTrand=21 +EsCRTsnprintf=22 +EsCRTsprintf=23 +EsMessageGetInputText=24 +EsMemoryReserve=25 +EsMessageMutexAcquire=26 +EsMessageMutexCheck=27 +EsMessageMutexRelease=28 +EsMessagePost=29 +EsMessagePostRemote=30 +EsMessageSend=31 +EsMouseGetPosition=32 +EsMouseSetPosition=33 +EsPaintTargetClear=34 +EsCommandSetCheck=35 +EsTextboxGetContentsAsDouble=36 +EsListViewGetSelectedFixedItem=37 +EsListViewInsertFixedItem=38 +EsDirectoryEnumerateChildren=39 +EsPathExists=40 +EsInstanceSetClassViewer=41 +EsPathDelete=42 +EsFileReadAllFromHandle=43 +EsFileReadAll=44 +EsFileReadSync=45 +EsFileResize=46 +EsFileWriteAll=47 +EsFileWriteAllGather=48 +EsApplicationRunTemporary=49 +EsFileWriteSync=50 +EsFileMap=51 +EsPathCreate=52 +EsListViewInvalidateContent=53 +EsListViewGetIndexFromItem=54 +EsElementInsertAfter=55 +EsElementRelayout=56 +EsListViewContentChanged=57 +EsDrawLine=58 +EsProcessCreate=59 +EsTimeStamp=60 +EsProcessGetExitStatus=61 +EsProcessGetID=62 +EsProcessGetState=63 +EsProcessOpen=64 +EsProcessPause=65 +EsProcessTerminate=66 +EsProcessTerminateCurrent=67 +EsThreadCreate=68 +EsThreadGetID=69 +EsCRTstrdup=70 +EsThreadTerminate=71 +EsArenaAllocate=72 +EsArenaFree=73 +EsArenaInitialise=74 +EsConstantBufferCreate=75 +EsConstantBufferRead=76 +EsConstantBufferShare=77 +EsHeapAllocate=78 +EsHeapFree=79 +EsHeapReallocate=80 +EsHeapValidate=81 +EsMemoryCommit=82 +EsMemoryCompare=83 +EsMemoryCopy=84 +EsMemoryCopyReverse=85 +EsMemoryFill=86 +EsINIPeek=87 +EsMemoryMove=88 +EsMemoryOpen=89 +EsMemoryShare=90 +EsMemorySumBytes=91 +EsMemoryZero=92 +EsObjectMap=93 +EsAssertionFailure=94 +EsDrawInvert=95 +EsFileControl=96 +EsDoubleParse=97 +EsFileOpen=98 +EsAddressResolve=99 +EsConnectionOpen=100 +EsIntegerParse=101 +EsPrint=102 +EsPrintDirect=103 +EsPrintHelloWorld=104 +EsElementGetMetrics=105 +EsRandomAddEntropy=106 +EsRandomSeed=107 +EsInstanceSetClassEditor=108 +EsSort=109 +EsSortWithSwapCallback=110 +EsColorBlend=111 +EsColorConvertToRGB=112 +EsColorConvertToHSV=113 +EsColorParse=114 +EsDrawStandardIcon=115 +EsRectangleAdd=116 +EsRectangleAddBorder=117 +EsTextboxMoveCaretRelative=118 +EsTextboxEnsureCaretVisible=119 +EsDrawText=120 +EsUndoIsEmpty=121 +EsPainterBoundsClient=122 +EsPainterBoundsInset=123 +EsApplicationStart=124 +EsINIFormat=125 +EsINIZeroTerminate=126 +EsIconIDFromString=127 +EsEventCreate=132 +EsEventForward=133 +EsBufferFormat=134 +EsEventReset=135 +EsEventSet=136 +EsEventSinkCreate=137 +EsEventSinkPop=138 +EsEventSinkPush=139 +EsMutexAcquire=140 +EsMutexDestroy=141 +EsMutexRelease=142 +EsPerformanceTimerPush=143 +EsPerformanceTimerPop=144 +EsSchedulerYield=145 +EsSleep=146 +EsSpinlockAcquire=147 +EsSpinlockRelease=148 +EsTimerSet=150 +EsWait=151 +EsCStringLength=152 +EsStringAllocateAndFormat=153 +EsStringAllocateAndFormatV=154 +EsStringCompare=155 +EsStringCompareRaw=156 +EsTextGetLineHeight=157 +EsStringFormat=158 +EsStringFormatTemporary=159 +EsStringFormatV=160 +EsStringFormatAppend=161 +EsStringFormatAppendV=162 +EsStringLength=163 +EsSystemConfigurationReadAll=164 +EsImageLoad=165 +EsStringStartsWith=166 +EsStringZeroTerminate=167 +EsCRTabs=168 +EsCRTacosf=169 +EsCRTasinf=170 +EsClipboardAddText=171 +EsCRTatan2f=172 +EsCRTatanf=173 +EsCRTatoi=174 +EsCRTcalloc=175 +EsCRTceil=176 +EsCRTceilf=177 +EsCRTcosf=178 +EsCRTfabs=179 +EsPanelCreate=180 +EsCRTfloor=181 +EsCRTfloorf=182 +EsCRTfmodf=183 +EsCRTfree=184 +EsCRTgetenv=185 +EsCRTisalpha=186 +EsCRTisdigit=187 +EsCRTisspace=188 +EsCRTisupper=189 +EsCRTisxdigit=190 +EsCRTmalloc=191 +EsCRTmemchr=192 +EsCRTmemcmp=193 +EsCRTmemcpy=194 +EsCRTmemmove=195 +EsCRTmemset=196 +EsCRTqsort=197 +EsCRTrealloc=198 +EsCRTsinf=199 +EsTextboxSetTextStyle=200 +EsTextboxGetTextStyle=201 +EsCRTsqrt=202 +EsCRTsqrtf=203 +EsSplitterCreate=204 +EsCRTstrcat=205 +EsCRTstrchr=206 +EsCRTstrcmp=207 +EsCRTstrcpy=208 +EsCRTstrerror=209 +EsCRTstrlen=210 +EsCRTstrncmp=211 +EsCRTstrncpy=212 +EsCRTstrnlen=213 +EsCRTstrstr=214 +EsCRTstrtol=215 +EsCRTstrtoul=216 +EsCRTtolower=217 +EsTextboxSetupSyntaxHighlighting=218 +EsElementGetSize=219 +EsFileGetSize=220 +EsRectangleBounding=221 +EsPathFindUniqueName=222 +EsPathMove=223 +EsDrawClear=224 +EsRectangleIntersection=225 +EsDrawRectangle=226 +EsDrawBlock=227 +EsRectangleSubtract=228 +EsMenuShow=229 +EsMenuAddItem=230 +EsElementUpdateContentSize=231 +EsMenuAddSeparator=232 +EsMenuNextColumn=233 +EsMenuAddCommand=234 +EsMenuCloseAll=235 +EsUndoPush=236 +EsClipboardHasText=237 +EsUndoInvokeGroup=238 +EsUndoEndGroup=239 +EsElementDraw=240 +EsButtonCreate=241 +EsUndoContinueGroup=242 +EsElementFocus=243 +EsElementSetDisabled=244 +EsElementSetHidden=245 +EsElementSetCallback=246 +EsUndoPeek=247 +EsElementRepaint=248 +EsColorWellCreate=249 +EsTextDisplayCreate=250 +EsElementSetCellRange=251 +EsPanelSetBandsAll=252 +EsElementGetInsets=253 +EsElementGetInsetSize=254 +EsElementGetPreferredSize=255 +EsElementMove=256 +EsElementGetLayoutParent=257 +EsElementDestroy=258 +EsElementDestroyContents=259 +EsElementStartAnimating=260 +EsTimeStampMs=261 +EsListViewSetEmptyMessage=262 +EsDrawPaintTarget=263 +EsPaintTargetEndDirectAccess=264 +EsWindowGetBounds=265 +EsWindowGetToolbar=266 +EsWindowSetIcon=267 +EsWindowSetTitle=268 +EsMenuGetSource=269 +EsButtonSetIcon=270 +EsButtonSetCheck=271 +EsButtonGetCheck=272 +EsButtonOnCommand=273 +EsButtonSetCheckBuddy=274 +EsButtonGetCheckBuddy=275 +EsPaintTargetStartDirectAccess=276 +EsTextboxFind=277 +EsTextboxInsert=278 +EsTextboxGetContents=279 +EsTextboxGetLineLength=280 +EsTextboxGetSelection=281 +EsTextboxMoveCaret=282 +EsTextboxSetSelection=283 +EsTextboxSelectAll=284 +EsTextboxClear=285 +EsTextboxUseNumberOverlay=286 +EsTextboxUseBreadcrumbOverlay=287 +EsPanelSetBands=288 +EsPanelSwitchTo=289 +EsTextPlanGetWidth=290 +EsTextPlanGetHeight=291 +EsTextPlanGetLineCount=292 +EsTextPlanDestroy=293 +EsTextDisplaySetContents=294 +EsSystemConfigurationReadInteger=295 +EsSystemConfigurationGroupReadInteger=296 +EsSystemConfigurationReadString=297 +EsSystemConfigurationGroupReadString=298 +EsGameControllerStatePoll=299 +EsInstanceDestroy=300 +EsRandomU8=301 +EsRandomU64=302 +EsConnectionPoll=303 +EsColorWellGetRGB=304 +EsColorWellSetRGB=305 +EsColorWellSetIndeterminate=306 +EsUndoInUndo=307 +EsUndoPop=308 +EsTextboxSetUndoManager=309 +EsListViewInsertGroup=310 +EsListViewInsert=311 +EsListViewRemove=312 +EsListViewRemoveAll=313 +EsSystemShowShutdownDialog=314 +EsListViewSetColumns=315 +EsListViewSelect=316 +EsUndoClear=317 +EsMessageReceive=318 +EsMemoryUnreserve=319 +EsMemoryDecommit=320 +EsConnectionClose=321 +EsConnectionNotify=322 +EsConnectionWriteSync=323 +EsDrawBitmap=324 +EsConnectionRead=325 +EsCRTexp=326 +EsCRTexp2f=327 +EsCRTpowf=328 +EsIconDisplayCreate=329 +EsImageDisplayCreate=330 +EsListViewCreate=331 +EsTextboxCreate=332 +EsCustomElementCreate=333 +EsWindowCreate=334 +EsMenuCreate=335 +EsTextPlanReplaceStyleRenderProperties=336 +EsInstanceSetActiveUndoManager=337 +EsClipboardReadText=338 +EsListViewSelectFixedItem=339 +EsSpacerCreate=340 +EsTextPlanCreate=341 +EsStringEndsWith=342 +EsListDisplayCreate=343 +EsCRTfabsf=344 +EsCRTisnanf=345 +EsListDisplaySetCounterContinuation=346 +EsCStringDuplicate=347 +EsImageDisplayLoadBits=348 +EsImageDisplayLoadFromMemory=349 +EsTextDisplaySetupSyntaxHighlighting=350 +EsPanic=351 +EsPaintTargetCreate=352 +EsPaintTargetGetSize=353 +EsPaintTargetDestroy=354 +EsMouseIsLeftHeld=355 +EsMouseIsRightHeld=356 +EsMouseIsMiddleHeld=357 +EsUndoGetInstance=358 +EsCanvasPaneCreate=359 +EsCalculateFromUserExpression=360 +EsWindowAddSizeAlternative=361 +EsMenuAddCommandsFromToolbar=362 +EsPanelStartMovementAnimation=363 +EsElementStartTransition=364 +EsToolbarAddFileMenu=365 +EsFileWriteAllFromHandle=366 +EsFileWriteAllGatherFromHandle=367 +EsEmbeddedFileGet=368 +EsFileStoreWriteAll=369 +EsInstanceOpenComplete=370 +EsInstanceSaveComplete=371 +EsElementRepaintForScroll=372 +EsMemoryFaultRange=373 +EsDrawBitmapScaled=374 +EsRectangleCenter=375 +EsMountPointEnumerate=376 +EsMountPointGetVolumeInformation=377 +EsListViewInvalidateAll=378 +EsListViewGetFocusedItem=379 +EsInstanceGetStartupInformation=380 +EsPathQueryInformation=381 +EsListViewCreateInlineTextbox=382 +EsTextboxStartEdit=383 +_EsPathAnnouncePathMoved=384 +EsCRTbsearch=385 +EsTextDisplaySetStyledContents=386 +EsElementGetTextStyle=387 +EsWindowSwitchToolbar=388 +EsListViewChangeStyles=389 +EsRichTextParse=390 +EsDrawVectorFile=391 +EsRectangleTranslate=392 +EsRectangleCut=393 +EsRectangleSplit=394 +EsRectangleEquals=395 +EsRectangleContains=396 +EsRectangleFit=397 +EsPaintTargetCreateFromBitmap=398 +EsDrawContent=399 +EsBufferRead=400 +EsBufferReadMany=401 +EsBufferWrite=402 +EsAnnouncementShow=403 +EsElementGetWindowBounds=404 +EsUTF8IsValid=405 +EsListDisplaySetCounterStart=406 +EsListViewScrollToEnd=407 +EsPanelTableSetChildCells=408 +EsBufferFormatV=409 +EsElementGetScreenBounds=410 +EsDrawTextLayers=411 +EsListViewEnumerateVisibleItems=412 +EsKeyboardGetModifiers=413 +EsCRTvsnprintf=414 +EsFontDatabaseLookupByID=415 +EsFontDatabaseEnumerate=416 +EsPOSIXConvertPath=417 +EsFontDatabaseInsertFile=418 +EsFileStoreGetSize=419 +EsFileStoreMap=420 +EsTimerCancel=421 diff --git a/util/build.c b/util/build.c new file mode 100644 index 0000000..f8d55b8 --- /dev/null +++ b/util/build.c @@ -0,0 +1,1491 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#define WARNING_FLAGS \ + " -Wall -Wextra -Wno-missing-field-initializers -Wno-pmf-conversions -Wno-frame-address -Wno-unused-function -Wno-format-truncation -Wno-invalid-offsetof " +#define WARNING_FLAGS_C \ + " -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-function -Wno-format-truncation -Wno-unused-parameter " + +#include <stdint.h> +#include <stdarg.h> + +#define CROSS_COMPILER_INDEX (11) + +#include <stdio.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <time.h> +#include <dirent.h> +#include <ctype.h> +#include <assert.h> +#include <setjmp.h> +#include <pthread.h> +#include <sys/wait.h> +#include <spawn.h> + +#define ColorHighlight "\033[0;36m" +#define ColorNormal "\033[0m" + +bool acceptedLicense; +bool foundValidCrossCompiler; +bool coloredOutput; +bool encounteredErrors; +bool interactiveMode; +FILE *systemLog; +char compilerPath[4096]; +int argc; +char **argv; + +#include "build_common.h" + +BuildFont fonts[] = { + { "Inter", "Sans", "Latn,Grek,Cyrl", (FontFile []) { + { "1", "Inter Thin.otf" }, + { "1i", "Inter Thin Italic.otf" }, + { "2", "Inter Extra Light.otf" }, + { "2i", "Inter Extra Light Italic.otf" }, + { "3", "Inter Light.otf" }, + { "3i", "Inter Light Italic.otf" }, + { "4", "Inter Regular.otf" }, + { "4i", "Inter Regular Italic.otf" }, + { "5", "Inter Medium.otf" }, + { "5i", "Inter Medium Italic.otf" }, + { "6", "Inter Semi Bold.otf" }, + { "6i", "Inter Semi Bold Italic.otf" }, + { "7", "Inter Bold.otf" }, + { "7i", "Inter Bold Italic.otf" }, + { "8", "Inter Extra Bold.otf" }, + { "8i", "Inter Extra Bold Italic.otf" }, + { "9", "Inter Black.otf" }, + { "9i", "Inter Black Italic.otf" }, + {}, + } }, + + { "Hack", "Mono", "Latn,Grek,Cyrl", (FontFile []) { + { "4", "Hack Regular.ttf" }, + { "4i", "Hack Regular Italic.ttf" }, + { "7", "Hack Bold.ttf" }, + { "7i", "Hack Bold Italic.ttf" }, + {}, + } }, + + {}, +}; + +bool GetYes() { + char *line = NULL; + size_t pos; + getline(&line, &pos, stdin); + line[strlen(line) - 1] = 0; + bool result = 0 == strcmp(line, "yes") || 0 == strcmp(line, "y"); + free(line); + return result; +} + +int CallSystem(const char *buffer) { + struct timespec startTime, endTime; + clock_gettime(CLOCK_REALTIME, &startTime); + if (systemLog) fprintf(systemLog, "%s\n", buffer); + int result = system(buffer); + clock_gettime(CLOCK_REALTIME, &endTime); + if (systemLog) fprintf(systemLog, "%fs\n", + (double) (endTime.tv_sec - startTime.tv_sec) + + (double) (endTime.tv_nsec - startTime.tv_nsec) / 1000000000); + if (result) encounteredErrors = true; + return result; +} + +int CallSystemF(const char *format, ...) { + va_list arguments; + va_start(arguments, format); + char tempBuffer[65536]; + vsnprintf(tempBuffer, sizeof(tempBuffer), format, arguments); + int result = CallSystem(tempBuffer); + va_end(arguments); + return result; +} + +void BuildAPIDependencies() { + if (CheckDependencies("API Header")) { + CallSystem("bin/build_core headers"); + ParseDependencies("bin/api_header.d", "API Header", false); + } + + CallSystem("cp `x86_64-essence-gcc -print-file-name=\"crtbegin.o\"` bin/crtbegin.o"); + CallSystem("cp `x86_64-essence-gcc -print-file-name=\"crtend.o\"` bin/crtend.o"); + + CallSystem("ports/musl/build.sh > /dev/null"); + + CallSystem("ports/freetype/build.sh"); + CallSystem("ports/harfbuzz/build.sh"); + + CallSystem("cp -p kernel/module.h root/Applications/POSIX/include"); +} + +void OutputStartOfBuildINI(FILE *f) { + LoadOptions(); + + FILE *f2 = popen("which nasm", "r"); + char buffer[1024]; + buffer[fread(buffer, 1, sizeof(buffer), f2) - 1] = 0; + pclose(f2); + + fprintf(f, "[toolchain]\npath=%s\ntmpdir=%s\n" + "ar=%s/x86_64-essence-ar\n" + "cc=%s/x86_64-essence-gcc\n" + "cxx=%s/x86_64-essence-g++\n" + "ld=%s/x86_64-essence-ld\n" + "nm=%s/x86_64-essence-nm\n" + "strip=%s/x86_64-essence-strip\n" + "nasm=%s\n" + "convert_svg=bin/render_svg\n" + "linker_scripts=util/\n" + "crt_objects=bin/\n" + "\n[general]\nsystem_build=1\nminimal_rebuild=1\ncolored_output=%d\nthread_count=%d\nskip_header_generation=1\ncommon_compile_flags=", + compilerPath, getenv("TMPDIR") ?: "", + compilerPath, compilerPath, compilerPath, compilerPath, compilerPath, compilerPath, + buffer, coloredOutput, (int) sysconf(_SC_NPROCESSORS_CONF)); + + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + Option *option = &options[i]; + + if (!option->id || memcmp(option->id, "Flag.", 5)) { + continue; + } + + if (option->type == OPTION_TYPE_BOOL && option->state.b) { + fprintf(f, "-D%s ", option->id + 5); + } else if (option->type == OPTION_TYPE_STRING) { + fprintf(f, "-D%s=%s ", option->id + 5, option->state.s); + } + } + + fprintf(f, "\n\n"); + + fprintf(f, "[options]\n"); + + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + if (options[i].type == OPTION_TYPE_BOOL) { + fprintf(f, "%s=%s\n", options[i].id, options[i].state.b ? "1" : "0"); + } else if (options[i].type == OPTION_TYPE_STRING) { + fprintf(f, "%s=%s\n", options[i].id, options[i].state.s ?: ""); + } else { + // TODO. + } + } + + fprintf(f, "\n"); + + { + size_t kernelConfigBytes; + char *kernelConfig = (char *) LoadFile("kernel/config.ini", &kernelConfigBytes); + + EsINIState s = {}; + s.buffer = kernelConfig; + s.bytes = kernelConfigBytes; + + char *source = NULL, *name = NULL; + bool builtin = false; + + while (EsINIParse(&s)) { + EsINIZeroTerminate(&s); + + if (strcmp(s.sectionClass, "driver")) { + continue; + } + + name = s.section; + + if (0 == strcmp(s.key, "source")) source = s.value; + if (0 == strcmp(s.key, "builtin")) builtin = !!atoi(s.value); + + if (!EsINIPeek(&s) || !s.keyBytes) { + if (IsDriverEnabled(name)) { + fprintf(f, "[@driver]\nname=%s\nsource=%s\nbuiltin=%d\n\n", name, source ?: "", builtin); + } + + source = name = NULL; + builtin = false; + } + } + + free(kernelConfig); + } +} + +void BuildUtilities(); + +#define COMPILE_ENABLE_OPTIMISATIONS (1 << 0) +#define COMPILE_SKIP_COMPILE (1 << 1) +#define COMPILE_DO_BUILD (1 << 2) +#define COMPILE_FOR_EMULATOR (1 << 3) + +void Compile(uint32_t flags, int partitionSize, const char *volumeLabel) { + buildStartTimeStamp = time(NULL); + BuildUtilities(); + BuildAPIDependencies(); + + LoadOptions(); + + FILE *f = fopen("bin/build.ini", "wb"); + + OutputStartOfBuildINI(f); + fprintf(f, "[general]\nfor_emulator=%d\noptimise=%d\nskip_compile=%d\n\n", + !!(flags & COMPILE_FOR_EMULATOR), !!(flags & COMPILE_ENABLE_OPTIMISATIONS), !!(flags & COMPILE_SKIP_COMPILE)); + + uintptr_t fontIndex = 0; + + while (fonts[fontIndex].files) { + BuildFont *font = fonts + fontIndex; + fprintf(f, "[@font %s]\ncategory=%s\nscripts=%s\n", font->name, font->category, font->scripts); + uintptr_t fileIndex = 0; + + while (font->files[fileIndex].path) { + FontFile *file = font->files + fileIndex; + fprintf(f, ".%s=%s\n", file->type, file->path); + fileIndex++; + } + + fprintf(f, "\n"); + fontIndex++; + } + + if (~flags & COMPILE_SKIP_COMPILE) { + struct dirent *entry; + DIR *root = opendir("apps/"); + + while (root && (entry = readdir(root))) { + const char *manifestSuffix = ".ini"; + + if (strlen(entry->d_name) <= strlen(manifestSuffix) || strcmp(entry->d_name + strlen(entry->d_name) - strlen(manifestSuffix), manifestSuffix)) { + continue; + } + + fprintf(f, "[@application]\nmanifest=apps/%s\n\n", entry->d_name); + } + + closedir(root); + + EsINIState s = { (char *) LoadFile("bin/extra_applications.ini", &s.bytes) }; + + while (s.buffer && EsINIParse(&s)) { + if (!s.keyBytes || s.valueBytes || (s.keyBytes >= 1 && s.key[0] == ';')) continue; + fprintf(f, "[@application]\nmanifest=%.*s\n\n", (int) s.keyBytes, s.key); + } + } + + if (flags & COMPILE_DO_BUILD) { + fprintf(f, "[install]\nfile=bin/drive\npartition_size=%d\npartition_label=%s\n\n", partitionSize, volumeLabel ?: "Essence HD"); + } + + fclose(f); + + fflush(stdout); + CallSystem("bin/build_core standard bin/build.ini"); + + CallSystem("x86_64-essence-gcc -o root/Applications/POSIX/bin/hello ports/gcc/hello.c"); + + forceRebuild = false; +} + +void BuildUtilities() { + buildStartTimeStamp = time(NULL); + +#define BUILD_UTILITY(x, y, z) \ + if (CheckDependencies("Utilities." x)) { \ + if (!CallSystem("gcc -MMD util/" z x ".c -o bin/" x " -g -std=c2x " WARNING_FLAGS_C " " y)) { \ + ParseDependencies("bin/" x ".d", "Utilities." x, false); \ + } \ + } + + BUILD_UTILITY("render_svg", "-lm", ""); + BUILD_UTILITY("build_core", "-pthread -DPARALLEL_BUILD", ""); + BUILD_UTILITY("config_editor", "-lX11 -Wno-unused-parameter", ""); + BUILD_UTILITY("reflect_gen", "", "designer/"); + + if (CheckDependencies("Utilities.DesignerHeader")) { + if (!CallSystem("bin/reflect_gen util/designer/designer.rf > bin/designer.h")) { + FILE *f = fopen("bin/designer_header.d", "wb"); + fprintf(f, ": util/designer/designer.rf bin/reflect_gen\n"); + fclose(f); + ParseDependencies("bin/designer_header.d", "Utilities.DesignerHeader", false); + } + } + + //util/designer_luigi.c -lX11 -lm + + if (CheckDependencies("Utilities.Designer1") || CheckDependencies("Utilities.Designer2")) { + if (!CallSystem("gcc -MMD -o bin/designer.o -c util/designer/designer.c -g -std=c2x -fsanitize=address " WARNING_FLAGS_C) + && !CallSystem("gcc -MMD -o bin/designer_luigi.o -c util/designer/designer_luigi.c -g -std=c2x " WARNING_FLAGS_C) + && !CallSystem("gcc -o bin/designer -g bin/designer.o bin/designer_luigi.o -lX11 -lm -fsanitize=address ")) { + ParseDependencies("bin/designer.d", "Utilities.Designer1", false); + ParseDependencies("bin/designer_luigi.d", "Utilities.Designer2", false); + } + } +} + +void Build(bool enableOptimisations, bool compile) { + struct timespec startTime, endTime; + clock_gettime(CLOCK_REALTIME, &startTime); + + encounteredErrors = false; + srand(time(NULL)); + printf("Build started...\n"); + CallSystem("mkdir -p root root/Applications root/Applications/POSIX root/Applications/POSIX/bin " + "root/Applications/POSIX/lib root/Applications/POSIX/include root/Essence/Modules"); + +#if 0 + if (_installationIdentifier) { + strcpy(_installationIdentifier, installationIdentifier); + } +#endif + +#ifndef __APPLE__ + CallSystem("ctags -R " + "--exclude=old/* " + "--exclude=root/* " + "--exclude=bin/* " + "--exclude=cross/* " + "--exclude=ports/acpica/* " + "--langdef=Eshg --langmap=Eshg:.header --regex-Eshg=\"/^struct[ \\t]*([a-zA-Z0-9_]+)/\\1/s,structure/\" " + "--regex-Eshg=\"/^define[ \\t]*([a-zA-Z0-9_]+)/\\1/d,definition/\" --regex-Eshg=\"/^enum[ \\t]*([a-zA-Z0-9_]+)/\\1/e,enumeration/\" " + "--regex-Eshg=\"/^function[ \\t]*([a-zA-Z0-9_]+)[ \\t\\*]*([a-zA-Z0-9_]+)/\\2/f,function/\" ." + " &" /* don't block */); +#endif + + Compile((enableOptimisations ? COMPILE_ENABLE_OPTIMISATIONS : 0) | (compile ? 0 : COMPILE_SKIP_COMPILE) | COMPILE_DO_BUILD | COMPILE_FOR_EMULATOR, 1024, NULL); + + clock_gettime(CLOCK_REALTIME, &endTime); + + printf(ColorHighlight "%s" ColorNormal " in %.2fs.\n", encounteredErrors ? "\033[0;33mBuild failed" : "Build complete", + (double) (endTime.tv_sec - startTime.tv_sec) + (double) (endTime.tv_nsec - startTime.tv_nsec) / 1000000000); +} + +#define LOG_VERBOSE (0) +#define LOG_NORMAL (1) +#define LOG_NONE (2) +#define EMULATOR_QEMU (0) +#define EMULATOR_BOCHS (1) +#define EMULATOR_VIRTUALBOX (2) +#define DEBUG_LATER (0) +#define DEBUG_START (1) +#define DEBUG_NONE (2) + +void Run(int emulator, int memory, int cores, int log, int debug) { + LoadOptions(); + + switch (emulator) { + case EMULATOR_QEMU: { + // -serial file:out.txt + // -enable-kvm (doesn't work with GDB) + + const char *driveFlags = IsOptionEnabled("Emulator.ATA") ? "-drive file=bin/drive,format=raw,media=disk,index=0 " : + IsOptionEnabled("Emulator.AHCI") ? "-drive file=bin/drive,if=none,id=mydisk,format=raw,media=disk,index=0 " + "-device ich9-ahci,id=ahci " + "-device ide-drive,drive=mydisk,bus=ahci.0 " + : "-drive file=bin/drive,if=none,id=mydisk,format=raw " + "-device nvme,drive=mydisk,serial=1234 "; + + const char *cdromImage = GetOptionString("Emulator.CDROMImage"); + char cdromFlags[256]; + if (cdromImage && cdromImage[0]) { + if (IsOptionEnabled("Emulator.ATA")) { + snprintf(cdromFlags, sizeof(cdromFlags), " -cdrom %s ", cdromImage); + } else { + snprintf(cdromFlags, sizeof(cdromFlags), "-drive file=%s,if=none,id=mycdrom,format=raw,media=cdrom,index=1 " + "-device ide-drive,drive=mycdrom,bus=ahci.1", cdromImage); + } + } else { + cdromFlags[0] = 0; + } + + const char *usbImage = GetOptionString("Emulator.USBImage"); + char usbFlags[256]; + if (usbImage && usbImage[0]) { + snprintf(usbFlags, sizeof(usbFlags), " -drive if=none,id=stick,file=%s -device usb-storage,bus=xhci.0,drive=stick ", usbImage); + } else { + usbFlags[0] = 0; + } + + const char *usbHostVendor = GetOptionString("Emulator.USBHostVendor"); + const char *usbHostProduct = GetOptionString("Emulator.USBHostProduct"); + char usbFlags2[256]; + if (usbHostVendor && usbHostVendor[0] && usbHostProduct && usbHostProduct[0]) { + snprintf(usbFlags2, sizeof(usbFlags2), " -device usb-host,vendorid=0x%s,productid=0x%s,bus=xhci.0,id=myusb ", usbHostVendor, usbHostProduct); + } else { + usbFlags2[0] = 0; + } + + bool withAudio = IsOptionEnabled("Emulator.Audio"); + const char *audioFlags = withAudio ? "QEMU_AUDIO_DRV=wav QEMU_WAV_PATH=bin/audio.wav " : ""; + const char *audioFlags2 = withAudio ? "-soundhw pcspk,hda" : ""; + unlink("bin/audio.wav"); + + const char *logFlags = log == LOG_VERBOSE ? "-d cpu_reset,int > bin/qemu_log.txt 2>&1" + : (log == LOG_NORMAL ? " > bin/qemu_log.txt 2>&1" : " > /dev/null 2>&1"); + + CallSystemF("%s %s qemu-system-x86_64 %s %s -m %d -s %s -smp cores=%d -cpu Haswell " + " -device qemu-xhci,id=xhci -device usb-kbd,bus=xhci.0,id=mykeyboard -device usb-mouse,bus=xhci.0,id=mymouse " + " -netdev user,id=u1 -device e1000,netdev=u1 -object filter-dump,id=f1,netdev=u1,file=bin/net.dat " + " %s %s %s %s ", + audioFlags, IsOptionEnabled("Emulator.RunWithSudo") ? "sudo " : "", driveFlags, cdromFlags, memory, + debug ? (debug == DEBUG_NONE ? "-enable-kvm" : "-S") : "", + cores, audioFlags2, logFlags, usbFlags, usbFlags2); + } break; + + case EMULATOR_BOCHS: { + CallSystem("bochs -f bochs.config -q"); + } break; + + case EMULATOR_VIRTUALBOX: { + // TODO Automatically setup the Essence VM if it doesn't exist. + + CallSystem("VBoxManage storageattach Essence --storagectl AHCI --port 0 --device 0 --type hdd --medium none"); + CallSystem("VBoxManage closemedium disk bin/vbox.vdi --delete"); + + CallSystem("VBoxManage convertfromraw bin/drive bin/vbox.vdi --format VDI"); + CallSystem("VBoxManage storageattach Essence --storagectl AHCI --port 0 --device 0 --type hdd --medium bin/vbox.vdi"); + + CallSystem("VBoxManage startvm --putenv VBOX_GUI_DBG_ENABLED=true Essence"); + } break; + } +} + +bool DownloadGCC() { + printf("\nDownloading and extracting sources...\n"); + + FILE *test = fopen("bin/binutils-" BINUTILS_VERSION ".tar.xz", "r"); + if (test) fclose(test); + else { + printf("Downloading Binutils source...\n"); + if (CallSystem("curl ftp://ftp.gnu.org/gnu/binutils/binutils-" BINUTILS_VERSION ".tar.xz > bin/binutils-" BINUTILS_VERSION ".tar.xz")) goto fail; + } + printf("Extracting Binutils source...\n"); + if (CallSystem("tar -xJf bin/binutils-" BINUTILS_VERSION ".tar.xz")) goto fail; + if (CallSystem("mv binutils-" BINUTILS_VERSION " bin")) goto fail; + + test = fopen("bin/gcc-" GCC_VERSION ".tar.xz", "r"); + if (test) fclose(test); + else { + printf("Downloading GCC source...\n"); + if (CallSystem("curl ftp://ftp.gnu.org/gnu/gcc/gcc-" GCC_VERSION "/gcc-" GCC_VERSION ".tar.xz > bin/gcc-" GCC_VERSION ".tar.xz")) goto fail; + } + printf("Extracting GCC source...\n"); + if (CallSystem("tar -xJf bin/gcc-" GCC_VERSION ".tar.xz")) goto fail; + if (CallSystem("mv gcc-" GCC_VERSION " bin")) goto fail; + + return true; + fail: return false; +} + +bool PatchGCC() { + // See ports/gcc/notes.txt for how these patches are made. + // Keep in sync with ports/gcc/port.sh. + + if (CallSystem("cp ports/gcc/changes/binutils_bfd_config.bfd bin/binutils-" BINUTILS_VERSION "/bfd/config.bfd")) return false; + if (CallSystem("cp ports/gcc/changes/binutils_config.sub bin/binutils-" BINUTILS_VERSION "/config.sub")) return false; + if (CallSystem("cp ports/gcc/changes/binutils_gas_configure.tgt bin/binutils-" BINUTILS_VERSION "/gas/configure.tgt")) return false; + if (CallSystem("cp ports/gcc/changes/binutils_ld_configure.tgt bin/binutils-" BINUTILS_VERSION "/ld/configure.tgt")) return false; + + if (CallSystem("cp ports/gcc/changes/gcc_config.sub bin/gcc-" GCC_VERSION "/config.sub")) return false; + if (CallSystem("cp ports/gcc/changes/gcc_fixincludes_mkfixinc.sh bin/gcc-" GCC_VERSION "/fixincludes/mkfixinc.sh")) return false; + if (CallSystem("cp ports/gcc/changes/gcc_gcc_config_essence.h bin/gcc-" GCC_VERSION "/gcc/config/essence.h")) return false; + if (CallSystem("cp ports/gcc/changes/gcc_gcc_config_i386_t-x86_64-essence bin/gcc-" GCC_VERSION "/gcc/config/i386/t-x86_64-essence")) return false; + if (CallSystem("cp ports/gcc/changes/gcc_gcc_config.gcc bin/gcc-" GCC_VERSION "/gcc/config.gcc")) return false; + if (CallSystem("cp ports/gcc/changes/gcc_libgcc_config.host bin/gcc-" GCC_VERSION "/libgcc/config.host")) return false; + if (CallSystem("cp ports/gcc/changes/gcc_libstdc++-v3_configure bin/gcc-" GCC_VERSION "/libstdc++-v3/configure")) return false; + + return true; +} + +void BuildCrossCompiler() { + if (!CallSystem("whoami | grep root")) { + printf("Error: Build should not be run as root.\n"); + return; + } + + { + printf("\n"); + printf("A cross compiler for Essence needs to be built.\n"); + printf("- You need to be connected to the internet. ~100MB will be downloaded.\n"); + printf("- You need ~3GB of drive space available.\n"); + printf("- You need ~8GB of RAM available.\n"); + printf("- This should take ~20 minutes on a modern computer.\n"); + printf("- This does *not* require root permissions.\n"); + printf("- You must fully update your system before building.\n\n"); + + bool missingPackages = false; + if (CallSystem("g++ --version > /dev/null 2>&1")) { printf("Error: Missing GCC/G++.\n"); missingPackages = true; } + if (CallSystem("make --version > /dev/null 2>&1")) { printf("Error: Missing GNU Make.\n"); missingPackages = true; } + if (CallSystem("bison --version > /dev/null 2>&1")) { printf("Error: Missing GNU Bison.\n"); missingPackages = true; } + if (CallSystem("flex --version > /dev/null 2>&1")) { printf("Error: Missing Flex.\n"); missingPackages = true; } + if (CallSystem("curl --version > /dev/null 2>&1")) { printf("Error: Missing curl.\n"); missingPackages = true; } + if (CallSystem("nasm --version > /dev/null 2>&1")) { printf("Error: Missing nasm.\n"); missingPackages = true; } + if (CallSystem("ctags --version > /dev/null 2>&1")) { printf("Error: Missing ctags.\n"); missingPackages = true; } + if (CallSystem("xz --version > /dev/null 2>&1")) { printf("Error: Missing xz.\n"); missingPackages = true; } + if (CallSystem("gzip --version > /dev/null 2>&1")) { printf("Error: Missing gzip.\n"); missingPackages = true; } + if (CallSystem("tar --version > /dev/null 2>&1")) { printf("Error: Missing tar.\n"); missingPackages = true; } + if (CallSystem("grep --version > /dev/null 2>&1")) { printf("Error: Missing grep.\n"); missingPackages = true; } + if (CallSystem("sed --version > /dev/null 2>&1")) { printf("Error: Missing sed.\n"); missingPackages = true; } + if (CallSystem("awk --version > /dev/null 2>&1")) { printf("Error: Missing awk.\n"); missingPackages = true; } + if (CallSystem("gcc -lmpc 2>&1 | grep undefined > /dev/null")) { printf("Error: Missing GNU MPC.\n"); missingPackages = true; } + if (CallSystem("gcc -lmpfr 2>&1 | grep undefined > /dev/null")) { printf("Error: Missing GNU MPFR.\n"); missingPackages = true; } + if (CallSystem("gcc -lgmp 2>&1 | grep undefined > /dev/null")) { printf("Error: Missing GNU GMP.\n"); missingPackages = true; } + if (missingPackages) exit(0); + + char installationFolder[4096]; + char sysrootFolder[4096]; + char path[65536]; + + int processorCount = sysconf(_SC_NPROCESSORS_CONF); + if (processorCount < 1) processorCount = 1; + if (processorCount > 16) processorCount = 16; + + printf("Type 'yes' if you have updated your system.\n"); + if (!GetYes()) { printf("The build has been canceled.\n"); exit(0); } + + { + getcwd(installationFolder, 4096); + strcat(installationFolder, "/cross"); + getcwd(sysrootFolder, 4096); + strcat(sysrootFolder, "/root"); + strcpy(compilerPath, installationFolder); + strcat(compilerPath, "/bin"); + printf("\nType 'yes' to install the compiler into '%s'.\n", installationFolder); + if (!GetYes()) { printf("The build has been canceled.\n"); exit(0); } + } + + { + char *originalPath = getenv("PATH"); + if (strlen(originalPath) > 32768) { + printf("PATH too long\n"); + goto fail; + } + strcpy(path, compilerPath); + strcat(path, ":"); + strcat(path, originalPath); + setenv("PATH", path, 1); + } + + { + FILE *f = fopen("bin/running_makefiles", "r"); + + if (f) { + fclose(f); + printf("\nThe build system has detected a build was started, but was not completed.\n"); + printf("Type 'yes' to attempt to resume this build.\n"); + + if (GetYes()) { + printf("Resuming build...\n"); + StartSpinner(); + goto runMakefiles; + } + } + } + + CallSystemF("echo \"Started build of cross compiler index %d, with GCC " GCC_VERSION " and Binutils " BINUTILS_VERSION ". Using %d processors.\" > bin/build_cross.log", + CROSS_COMPILER_INDEX, processorCount); + + CallSystem("rm -rf cross bin/build-binutils bin/build-gcc bin/gcc-" GCC_VERSION " bin/binutils-" BINUTILS_VERSION); + + { + CallSystem("echo Preparing C standard library headers... >> bin/build_cross.log"); + CallSystem("mkdir -p root/Essence root/Applications/POSIX/include root/Applications/POSIX/lib root/Applications/POSIX/bin"); + CallSystem("ports/musl/build.sh >> bin/build_cross.log 2>&1"); + } + + if (!DownloadGCC()) goto fail; + if (!PatchGCC()) goto fail; + + printf("Starting build...\n"); + StartSpinner(); + + { + CallSystem("echo Running configure... >> bin/build_cross.log"); + if (CallSystem("mkdir bin/build-binutils")) goto fail; + if (CallSystem("mkdir bin/build-gcc")) goto fail; + if (chdir("bin/build-binutils")) goto fail; + if (CallSystemF("../binutils-" BINUTILS_VERSION "/configure --target=x86_64-essence --prefix=\"%s\" --with-sysroot=%s --disable-nls --disable-werror >> ../build_cross.log 2>&1", + installationFolder, sysrootFolder)) goto fail; + if (chdir("../..")) goto fail; + if (chdir("bin/build-gcc")) goto fail; + // Add --without-headers for a x86_64-elf build. + if (CallSystemF("../gcc-" GCC_VERSION "/configure --target=x86_64-essence --prefix=\"%s\" --enable-languages=c,c++ --with-sysroot=%s --disable-nls >> ../build_cross.log 2>&1", + installationFolder, sysrootFolder)) goto fail; + if (chdir("../..")) goto fail; + } + + runMakefiles:; + + { + CallSystem("touch bin/running_makefiles"); + + CallSystem("echo Building Binutils... >> bin/build_cross.log"); + if (chdir("bin/build-binutils")) goto fail; + if (CallSystemF("make -j%d >> ../build_cross.log 2>&1", processorCount)) goto fail; + if (CallSystem("make install >> ../build_cross.log 2>&1")) goto fail; + if (chdir("../..")) goto fail; + + CallSystem("echo Building GCC... >> bin/build_cross.log"); + if (chdir("bin/build-gcc")) goto fail; + if (CallSystemF("make all-gcc -j%d >> ../build_cross.log 2>&1", processorCount)) goto fail; + if (CallSystem("make all-target-libgcc >> ../build_cross.log 2>&1")) goto fail; + if (CallSystem("make install-gcc >> ../build_cross.log 2>&1")) goto fail; + if (CallSystem("make install-target-libgcc >> ../build_cross.log 2>&1")) goto fail; + if (chdir("../..")) goto fail; + } + + { + CallSystem("echo Removing debug symbols... >> bin/build_cross.log"); + CallSystemF("strip %s/bin/* >> bin/build_cross.log 2>&1", installationFolder); + CallSystemF("strip %s/libexec/gcc/x86_64-essence/" GCC_VERSION "/* >> bin/build_cross.log 2>&1", installationFolder); + } + + { + CallSystem("echo Modifying headers... >> bin/build_cross.log"); + sprintf(path, "%s/lib/gcc/x86_64-essence/" GCC_VERSION "/include/mm_malloc.h", installationFolder); + FILE *file = fopen(path, "w"); + if (!file) { + printf("Couldn't modify header files\n"); + goto fail; + } else { + fprintf(file, "/*Removed*/\n"); + fclose(file); + } + } + + StopSpinner(); + + { + BuildUtilities(); + BuildAPIDependencies(); + FILE *f = fopen("bin/build.ini", "wb"); + OutputStartOfBuildINI(f); + fclose(f); + if (CallSystem("bin/build_core standard bin/build.ini")) goto fail; + } + + StartSpinner(); + + { + if (chdir("bin/build-gcc")) goto fail; + if (CallSystemF("make -j%d all-target-libstdc++-v3 >> ../build_cross.log 2>&1", processorCount)) goto fail; + if (CallSystem("make install-target-libstdc++-v3 >> ../build_cross.log 2>&1")) goto fail; + if (chdir("../..")) goto fail; + } + + { + CallSystem("echo Cleaning up... >> bin/build_cross.log"); + // printf("\nType 'yes' to remove intermediate build files (recommended).\n"); + // if (GetYes()) { + CallSystem("rm -rf bin/binutils-" BINUTILS_VERSION "/"); + CallSystem("rm -rf bin/gcc-" GCC_VERSION "/"); + CallSystem("rm -rf bin/build-binutils"); + CallSystem("rm -rf bin/build-gcc"); + // } + CallSystem("rm bin/running_makefiles"); + } + + StopSpinner(); + + printf(ColorHighlight "\nThe cross compiler has built successfully.\n" ColorNormal); + foundValidCrossCompiler = true; + } + + return; + fail:; + StopSpinner(); + printf("\nThe build has failed. A log is available in " ColorHighlight "bin/build_cross.log" ColorNormal ".\n"); + exit(0); +} + +void SaveConfig() { + FILE *f = fopen("bin/build_config.ini", "wb"); + fprintf(f, "accepted_license=%d\ncompiler_path=%s\n" + "cross_compiler_index=%d\n", + acceptedLicense, compilerPath, + foundValidCrossCompiler ? CROSS_COMPILER_INDEX : 0); + fclose(f); +} + +const char *folders[] = { + "apps", + "desktop", + "kernel", + "shared", + "boot", + "drivers", +}; + +void Find(char *l2, char *in, bool wordOnly) { + for (uintptr_t i = 0; i < sizeof(folders) / sizeof(folders[0]); i++) { + char buffer[256]; + sprintf(buffer, "grep --color -nr '%s' -e '%s%s%s'", in ?: folders[i], wordOnly ? "\\b" : "", l2, wordOnly ? "\\b" : ""); + CallSystem(buffer); + if (in) break; + } +} + +void Replace(char *l2, char *l3, char *in) { + for (uintptr_t i = 0; i < sizeof(folders) / sizeof(folders[0]); i++) { + char buffer[256]; + sprintf(buffer, "find %s -type f -exec sed -i 's/\\b%s\\b/%s/g' {} \\;", in ?: folders[i], l2, l3); + CallSystem(buffer); + if (in) break; + } +} + +typedef struct ReplacedFieldNameError { + char *file; + int line, position; +} ReplacedFieldNameError; + +void FixReplacedFieldName(const char *oldName, const char *newName) { + CallSystem("./start.sh c 2> bin/errors.tmp"); + char *errors = (char *) LoadFile("bin/errors.tmp", NULL); + char *position = errors; + + char needle[256]; + snprintf(needle, sizeof(needle), "has no member named '%s'", oldName); + + ReplacedFieldNameError *parsedErrors = NULL; + + while (position) { + char *s = strstr(position, needle); + + if (!s) { + break; + } + + while (s != position) { + if (*s == '\n') { + break; + } + + s--; + } + + s++; + + char *fileStart = s; + char *fileEnd = strchr(fileStart, ':'); + char *lineStart = fileEnd + 1; + char *lineEnd = strchr(lineStart, ':'); + char *positionStart = lineEnd + 1; + char *positionEnd = strchr(positionStart, ':'); + + position = strchr(s, '\n'); + + *fileEnd = 0; + *lineEnd = 0; + *positionEnd = 0; + + ReplacedFieldNameError error = { fileStart, atoi(lineStart), atoi(positionStart) }; + arrput(parsedErrors, error); + printf("Parsed error: file %s, line %d, position %d.\n", error.file, error.line, error.position); + } + + while (arrlenu(parsedErrors)) { + char *path = arrlast(parsedErrors).file; + size_t fileLength; + char *file = (char *) LoadFile(path, &fileLength); + + if (!file) { + printf("Error: Could not access '%s'.\n", path); + (void) arrpop(parsedErrors); + continue; + } + + printf("Replacing errors in file %s...\n", path); + + for (uintptr_t i = 0; i < arrlenu(parsedErrors); i++) { + if (strcmp(parsedErrors[i].file, path)) { + continue; + } + + // printf("(%s:%d:%d)\n", parsedErrors[i].file, parsedErrors[i].line, parsedErrors[i].position); + + int line = 1; + char *position = file; + + while (line != parsedErrors[i].line) { + position = strchr(position, '\n'); + + if (!position) { + printf("Error: File '%s' has less lines (%d) than expected (%d).\n", path, line, parsedErrors[i].line); + goto nextError; + } + + position++; + line++; + } + + { + char *end = strchr(position, '\n'); + if (!end) end = position + strlen(position); + size_t lineLength = end - position; + + if (parsedErrors[i].position + strlen(oldName) > lineLength) { + printf("Error: Line %s:%d was shorter than expected (want to replace field at %d).\n", path, line, parsedErrors[i].position); + goto nextError; + } + + if (memcmp(parsedErrors[i].position + position - 1, oldName, strlen(oldName))) { + printf("Warning: Line %s:%d did not contain old field name at position %d.\n", + path, line, parsedErrors[i].position); + goto nextError; + } + + size_t oldFileLength = fileLength; + size_t positionOffset = position - file + parsedErrors[i].position - 1; + fileLength = oldFileLength - strlen(oldName) + strlen(newName); + if (fileLength > oldFileLength) file = (char *) realloc(file, fileLength + 1); + position = file + positionOffset; + memmove(position + strlen(newName), position + strlen(oldName), oldFileLength - positionOffset - strlen(oldName)); + memcpy(position, newName, strlen(newName)); + file[fileLength] = 0; + + for (uintptr_t j = i + 1; j < arrlenu(parsedErrors); j++) { + if (strcmp(parsedErrors[i].file, parsedErrors[j].file) + || parsedErrors[i].line != parsedErrors[j].line + || parsedErrors[i].position > parsedErrors[j].position) { + continue; + } + + if (parsedErrors[i].position == parsedErrors[j].position) { + arrdel(parsedErrors, j); + j--; + } else { + parsedErrors[j].position += strlen(newName) - strlen(oldName); + } + } + } + + nextError:; + arrdel(parsedErrors, i); + i--; + } + + FILE *f = fopen(path, "wb"); + fwrite(file, 1, fileLength, f); + fclose(f); + } + + arrfree(parsedErrors); + free(errors); + CallSystem("unlink bin/errors.tmp"); +} + +void LineCountFile(const char *folder, const char *name) { + int lineCountBefore = 0; + + { + CallSystem("paste -sd+ bin/count.tmp | bc > bin/count2.tmp"); + FILE *f = fopen("bin/count2.tmp", "rb"); + char buffer[16] = {}; + fread(buffer, 1, sizeof(buffer), f); + fclose(f); + lineCountBefore = atoi(buffer); + } + + CallSystemF("awk 'NF' \"%s%s\" | wc -l >> bin/count.tmp", folder, name); + + { + CallSystem("paste -sd+ bin/count.tmp | bc > bin/count2.tmp"); + FILE *f = fopen("bin/count2.tmp", "rb"); + char buffer[16] = {}; + fread(buffer, 1, sizeof(buffer), f); + fclose(f); + printf("%5d %s%s\n", atoi(buffer) - lineCountBefore, folder, name); + } +} + +void AddressToLine(const char *symbolFile) { + char buffer[4096]; + sprintf(buffer, "echo %s > bin/all_symbol_files.dat", symbolFile); + system(buffer); + + system("echo bin/Kernel >> bin/all_symbol_files.dat && echo bin/Desktop >> bin/all_symbol_files.dat"); + char symbolFiles[4096] = {}; + fread(symbolFiles, 1, 4096, fopen("bin/all_symbol_files.dat", "rb")); + for (int i = 0; i < 4096; i++) if (symbolFiles[i] == '\n') symbolFiles[i] = 0; + system("rm -f bin/all_symbol_files.dat"); + + char root[4096]; + getcwd(root, 4096); + + while (true) { + char *line = NULL; + size_t bytes = 0; + getline(&line, &bytes, stdin); + + for (uintptr_t i = 0; i < strlen(line); i++) { + if (line[i] == '0' && line[i + 1] == 'x') { + int si = i; + uint64_t address = 0; + i += 2; + + for (int j = 0; j < 16; j++) { + if (line[i] == '_') i++; + if (line[i] >= '0' && line[i] <= '9') address = (address * 16) + line[i++] - '0'; + else if (line[i] >= 'A' && line[i] <= 'F') address = (address * 16) + line[i++] - 'A' + 10; + else if (line[i] >= 'a' && line[i] <= 'f') address = (address * 16) + line[i++] - 'a' + 10; + else break; + } + + char *file = symbolFiles; + + while (*file) { + sprintf(buffer, "addr2line --exe=\"%s\" 0x%lx | grep -v ? >> bin/result.tmp", file, address); + system(buffer); + file += strlen(file) + 1; + } + + { + char result[4096]; + FILE *file = fopen("bin/result.tmp", "rb"); + result[fread(result, 1, 4096, file)] = 0; + for (int i = 0; i < 4096; i++) if (result[i] == '\n') result[i] = 0; + + if (result[0] == 0) { + putchar('0'); + i = si; + } else { + free(file); + fputs(strstr(result, "essence") ?: "", stdout); + system("rm -f bin/result.tmp"); + i--; + } + } + } else { + putchar(line[i]); + } + } + + free(line); + } +} + +typedef struct BuildType { + const char *name, *alias, *emulator; + bool optimise, debug, smp, noCompile; + int memory; +} BuildType; + +BuildType buildTypes[] = { + { .name = "build", .alias = "b" }, + { .name = "build-optimised", .alias = "opt", .optimise = true }, + + { .name = "debug", .alias = "d", .emulator = "qemu", .debug = true }, + { .name = "debug-without-compile", .alias = "d3", .emulator = "qemu", .debug = true, .noCompile = true }, + + { .name = "vbox", .alias = "v", .emulator = "vbox", .optimise = true }, + { .name = "vbox-without-opt", .alias = "v2", .emulator = "vbox" }, + { .name = "vbox-without-compile", .alias = "v3", .emulator = "vbox", .noCompile = true }, + + { .name = "qemu-with-opt", .alias = "t", .emulator = "qemu", .optimise = true }, + { .name = "test", .alias = "t2", .emulator = "qemu" }, + { .name = "qemu-without-compile", .alias = "t3", .emulator = "qemu", .noCompile = true }, +}; + +void DoCommand(const char *l) { + while (l && (*l == ' ' || *l == '\t')) l++; + + { + struct stat s = {}; + static time_t buildSystemTimeStamp = 0; + + if (stat("util/build.c", &s) || s.st_mtime > buildSystemTimeStamp) { + if (buildSystemTimeStamp) { + printf("\033[0;33mWarning: The build system appears to be out of date.\nPlease exit and re-run ./start.sh.\n" ColorNormal); + } else { + buildSystemTimeStamp = s.st_mtime; + } + } + } + + for (uintptr_t i = 0; i < sizeof(buildTypes) / sizeof(buildTypes[0]); i++) { + BuildType *entry = buildTypes + i; + + if (strcmp(entry->name, l) && strcmp(entry->alias, l)) { + continue; + } + + Build(entry->optimise, !entry->noCompile); + + if (encounteredErrors) { + printf("Errors were encountered during the build.\n"); + } else if (entry->emulator) { + Run(entry->emulator[0] == 'q' ? EMULATOR_QEMU : EMULATOR_VIRTUALBOX, + entry->memory ?: 1024, entry->smp ? 3 : 1, LOG_NORMAL, entry->debug); + } + + return; + } + + if (0 == strcmp(l, "exit") || 0 == strcmp(l, "x") || 0 == strcmp(l, "quit") || 0 == strcmp(l, "q")) { + exit(0); + } else if (0 == strcmp(l, "reset-config")) { + unlink("bin/build_config.ini"); + printf("Please restart the build system.\n"); + exit(0); + } else if (0 == strcmp(l, "compile") || 0 == strcmp(l, "c")) { + Compile(COMPILE_FOR_EMULATOR, 1024, NULL); + } else if (0 == strcmp(l, "build-cross")) { + BuildCrossCompiler(); + SaveConfig(); + printf("Please restart the build system.\n"); + exit(0); + } else if (0 == strcmp(l, "clean-root")) { + forceRebuild = true; + CallSystem("rm -rf root"); + CallSystem("mkdir root root/Applications root/Applications/POSIX root/Applications/POSIX/bin root/Applications/POSIX/lib " + "root/Applications/POSIX/include root/Essence root/Essence/Modules root/Essence/Fonts"); + } else if (0 == strcmp(l, "build-utilities") || 0 == strcmp(l, "u")) { + BuildUtilities(); + } else if (0 == strcmp(l, "config")) { + BuildUtilities(); + CallSystem("bin/config_editor"); + } else if (0 == strcmp(l, "designer")) { + BuildUtilities(); + CallSystem("bin/designer \"res/Theme Source.dat\" \"res/Themes/Theme.dat\" \"res/Cursors.png\" \"desktop/styles.header\""); + } else if (0 == strcmp(l, "replace-many")) { + forceRebuild = true; + printf("Enter the name of the replacement file: "); + char *l2 = NULL; + size_t pos; + getline(&l2, &pos, stdin); + l2[strlen(l2) - 1] = 0; + FILE *f = fopen(l2, "r"); + free(l2); + while (!feof(f)) { + char a[512], b[512]; + fscanf(f, "%s %s", a, b); + printf("%s -> %s\n", a, b); + Replace(a, b, NULL); + } + fclose(f); + } else if (0 == strcmp(l, "find-many")) { + forceRebuild = true; + printf("Enter the name of the find file: "); + char *l2 = NULL; + size_t pos; + getline(&l2, &pos, stdin); + l2[strlen(l2) - 1] = 0; + FILE *f = fopen(l2, "r"); + free(l2); + while (!feof(f)) { + char a[512]; + fscanf(f, "%s", a); + // Find(a); + int t = 0; + for (uintptr_t i = 0; i < sizeof(folders) / sizeof(folders[0]); i++) { + char buffer[256]; + sprintf(buffer, "grep -nr '%s' -e '%s' | wc -l", folders[i], a); + FILE *f = popen(buffer, "r"); + buffer[fread(buffer, 1, sizeof(buffer), f)] = 0; + t += atoi(buffer); + fclose(f); + } + printf("%3d %s\n", t, a); + } + fclose(f); + } else if (0 == strcmp(l, "find")) { + printf("Enter the query to be found: "); + char *l2 = NULL; + size_t pos; + getline(&l2, &pos, stdin); + l2[strlen(l2) - 1] = 0; + Find(l2, NULL, false); + free(l2); + } else if (0 == strcmp(l, "find-word")) { + printf("Enter the query to be found: "); + char *l2 = NULL; + size_t pos; + getline(&l2, &pos, stdin); + l2[strlen(l2) - 1] = 0; + Find(l2, NULL, true); + free(l2); + } else if (0 == strcmp(l, "find-in")) { + printf("Enter the folder to search in: "); + char *in = NULL; + size_t pos; + getline(&in, &pos, stdin); + in[strlen(in) - 1] = 0; + printf("Enter the query to be found: "); + char *l2 = NULL; + getline(&l2, &pos, stdin); + l2[strlen(l2) - 1] = 0; + Find(l2, in, false); + free(l2); + free(in); + } else if (0 == strcmp(l, "replace")) { + forceRebuild = true; + printf("Enter the word to be replaced: "); + char *l2 = NULL; + size_t pos; + getline(&l2, &pos, stdin); + printf("Enter the word to replace it with: "); + char *l3 = NULL; + getline(&l3, &pos, stdin); + l2[strlen(l2) - 1] = 0; + l3[strlen(l3) - 1] = 0; + Replace(l2, l3, NULL); + free(l2); + free(l3); + } else if (0 == strcmp(l, "replace-in")) { + forceRebuild = true; + printf("Enter the folder to replace in: "); + char *in = NULL; + size_t pos; + getline(&in, &pos, stdin); + in[strlen(in) - 1] = 0; + printf("Enter the word to be replaced: "); + char *l2 = NULL; + getline(&l2, &pos, stdin); + printf("Enter the word to replace it with: "); + char *l3 = NULL; + getline(&l3, &pos, stdin); + l2[strlen(l2) - 1] = 0; + l3[strlen(l3) - 1] = 0; + Replace(l2, l3, in); + free(l2); + free(l3); + free(in); + } else if (0 == strcmp(l, "fix-replaced-field-name")) { + size_t pos; + + printf(">> Please make sure you have saved a backup before running this command!! <<\n"); + printf("Do not try to rename fields from different structures at the same time.\n\n"); + + printf("Enter the old name of the field: "); + char *oldName = NULL; + getline(&oldName, &pos, stdin); + oldName[strlen(oldName) - 1] = 0; + + printf("Enter the new name of the field: "); + char *newName = NULL; + getline(&newName, &pos, stdin); + newName[strlen(newName) - 1] = 0; + + FixReplacedFieldName(oldName, newName); + + free(oldName); + free(newName); + } else if (0 == memcmp(l, "ascii ", 6)) { + const char *text = l + 6; + + while (*text) { + char c = *text; + printf("0x%.2X - %.3d - '%c'\n", c, c, c); + text++; + } + } else if (0 == strcmp(l, "ascii")) { + for (int c = 32; c < 127; c++) { + printf("0x%.2X - %.3d - '%c'", c, c, c); + if ((c & 3) == 3) printf("\n"); else printf(" "); + } + + printf("\n"); + } else if (0 == strcmp(l, "build-optional-ports")) { + DIR *directory = opendir("ports"); + struct dirent *entry; + + while ((entry = readdir(directory))) { + CallSystemF("ports/%s/port.sh", entry->d_name); + } + + closedir(directory); + } else if (0 == memcmp(l, "do ", 3)) { + CallSystem(l + 3); + } else if (0 == strcmp(l, "test-gf")) { + if (!CallSystem("g++ -g -Wall -o gf util/gf.cpp `wx-config --cxxflags --libs all` " WARNING_FLAGS)) { + CallSystem("./gf"); + } + } else if (0 == strcmp(l, "gf")) { + CallSystemF("nohup ./gf > /dev/null 2>&1 &"); + } else if (0 == memcmp(l, "live ", 5)) { + if (interactiveMode) { + fprintf(stderr, "This command cannot be used in interactive mode. Type \"quit\" and then run \"./start.sh live <...>\".\n"); + return; + } + + if (argc < 4) { + fprintf(stderr, "Usage: \"./start.sh live <iso/raw> <drive size in MB> [extra options]\".\n"); + return; + } + + bool wantISO = 0 == strcmp(argv[2], "iso"); + uint32_t flags = COMPILE_ENABLE_OPTIMISATIONS | COMPILE_DO_BUILD; + const char *label = NULL; + + for (int i = 4; i < argc; i++) { + if (0 == strcmp(argv[i], "noopt")) { + flags &= ~COMPILE_ENABLE_OPTIMISATIONS; + } else if (0 == memcmp(argv[i], "label=", 6)) { + label = argv[i] + 6; + } + } + + forceRebuild = true; + Compile(flags, atoi(argv[3]), label); + + if (encounteredErrors) { + printf("\033[0;33mBuild failed.\n" ColorNormal); + return; + } + + if (!wantISO) { + printf("You can copy the image to the device with " + ColorHighlight "sudo dd if=bin/drive of=<path to drive> bs=1024 count=%d conv=notrunc" ColorNormal "\n", + atoi(argv[3]) * 1024); + return; + } + + if (CallSystem("xorriso --version")) { + printf("\033[0;33mCould not produce iso image; xorriso not found.\n" ColorNormal); + return; + } + + char buffer[512]; + FILE *f = fopen("bin/drive", "rb"); + fseek(f, 0x102000, SEEK_SET); + fread(buffer, 1, sizeof(buffer), f); + fclose(f); + + if (memcmp(buffer, "!EssenceFS2", 11)) { + printf("\033[0;33mCould not produce iso image (1).\n" ColorNormal); + return; + } + + f = fopen("bin/appuse.txt", "wb"); + fprintf(f, "Essence::%.*s", 16, buffer + 152); + fclose(f); + + unlink("bin/essence.iso"); + + if (CallSystem("xorriso -rockridge \"off\" -outdev bin/essence.iso -blank as_needed -volid \"Essence Installation Disc\" " + "-map bin/drive /ESSENCE.DAT -boot_image any bin_path=/ESSENCE.DAT -boot_image any emul_type=hard_disk " + "-application_use bin/appuse.txt")) { + printf("\033[0;33mCould not produce iso image (2).\n" ColorNormal); + return; + } + + printf("Created " ColorHighlight "bin/essence.iso" ColorNormal ".\n"); + } else if (0 == strcmp(l, "line-count")) { + FILE *f = fopen("bin/count.tmp", "wb"); + fprintf(f, "0"); + fclose(f); + + LineCountFile("", "start.sh"); + LineCountFile("", "README.md"); + LineCountFile("", "LICENSE.md"); + LineCountFile("", "CONTRIBUTING.md"); + LineCountFile("res/", "System Configuration Template.ini"); + + const char *folders[] = { + "desktop/", "boot/x86/", "drivers/", "kernel/", "apps/", "apps/file_manager/", "shared/", "util/", "util/designer/" + }; + + for (uintptr_t i = 0; i < sizeof(folders) / sizeof(folders[0]); i++) { + const char *folder = folders[i]; + DIR *directory = opendir(folder); + struct dirent *entry; + + while ((entry = readdir(directory))) { + if (0 == strcmp(entry->d_name, "nanosvg.h")) continue; + if (0 == strcmp(entry->d_name, "nanosvgrast.h")) continue; + if (0 == strcmp(entry->d_name, "stb_ds.h")) continue; + if (0 == strcmp(entry->d_name, "stb_image.h")) continue; + if (0 == strcmp(entry->d_name, "stb_sprintf.h")) continue; + if (0 == strcmp(entry->d_name, "stb_truetype.h")) continue; + if (entry->d_type != DT_REG) continue; + + LineCountFile(folder, entry->d_name); + } + + closedir(directory); + } + + printf("\nTotal line count:" ColorHighlight "\n"); + CallSystem("paste -sd+ bin/count.tmp | bc"); + unlink("bin/count.tmp"); + unlink("bin/count2.tmp"); + printf(ColorNormal); + } else if (0 == memcmp(l, "a2l ", 4)) { + AddressToLine(l + 3); + } else if (0 == strcmp(l, "help") || 0 == strcmp(l, "h") || 0 == strcmp(l, "?")) { + printf(ColorHighlight "\n=== Common Commands ===\n" ColorNormal); + printf("(t2) test - Qemu\n"); + printf("(b ) build - Unoptimised build\n"); + printf("(c ) compile - Compile the kernel and applications.\n"); + printf("(v ) vbox - VirtualBox (optimised)\n"); + printf("(d ) debug - Qemu (GDB)\n"); + printf("( ) do - Run a system() command.\n"); + printf("( ) config - Open the local configuration editor.\n"); + + printf(ColorHighlight "\n=== Other Commands ===\n" ColorNormal); + printf("(t ) qemu-with-opt - Qemu\n"); + printf("(t3) qemu-without-compile - Qemu\n"); + printf("(x ) exit - Exit the build system.\n"); + printf("(h ) help - Show the help prompt.\n"); + printf("(u ) build-utilities - Build utility applications.\n"); + printf("(v2) vbox-without-opt - VirtualBox (unoptimised)\n"); + printf("(v3) vbox-without-compile - VirtualBox\n"); + printf("( ) find - Search the project's source code.\n"); + printf("( ) replace - Replace a word throughout the project.\n"); + } else { + printf("Unrecognised command '%s'. Enter 'help' to get a list of commands.\n", l); + } +} + +int main(int _argc, char **_argv) { + argc = _argc; + argv = _argv; + + char cwd[PATH_MAX]; + getcwd(cwd, sizeof(cwd)); + + if (strchr(cwd, ' ')) { + printf("Error: The path to your essence directory, '%s', contains spaces.\n", cwd); + return 1; + } + + sh_new_strdup(applicationDependencies); + + unlink("bin/dependencies.ini"); + + coloredOutput = isatty(STDERR_FILENO); + + char *prev = NULL; + + if (argc != 2) { + printf(ColorHighlight "Essence Build" ColorNormal "\nPress Ctrl-C to exit.\n"); + } + + systemLog = fopen("bin/system.log", "w"); + + { + EsINIState s = { (char *) LoadFile("bin/build_config.ini", &s.bytes) }; + char path[32768 + PATH_MAX + 16]; + path[0] = 0; + + while (EsINIParse(&s)) { + if (s.sectionClassBytes || s.sectionBytes) continue; + EsINIZeroTerminate(&s); + + INI_READ_BOOL(accepted_license, acceptedLicense); + INI_READ_STRING(compiler_path, path); + + if (0 == strcmp("cross_compiler_index", s.key)) { + foundValidCrossCompiler = atoi(s.value) == CROSS_COMPILER_INDEX; + } + } + + if (path[0]) { + strcpy(compilerPath, path); + strcat(path, ":"); + char *originalPath = getenv("PATH"); + + if (strlen(originalPath) < 32768) { + strcat(path, originalPath); + setenv("PATH", path, 1); + } else { + printf("Warning: PATH too long\n"); + } + } + } + + if (!acceptedLicense) { + printf("\n=== Essence License ===\n\n"); + CallSystem("cat LICENSE.md"); + printf("\nType 'yes' to acknowledge you have read the license, or press Ctrl-C to exit.\n"); + if (!GetYes()) exit(0); + acceptedLicense = true; + } + + const char *runFirstCommand = NULL; + + if (CallSystem("x86_64-essence-gcc --version > /dev/null 2>&1 ")) { + BuildCrossCompiler(); + runFirstCommand = "b"; + foundValidCrossCompiler = true; + } + + SaveConfig(); + + if (argc >= 2) { + char buffer[4096]; + buffer[0] = 0; + + for (int i = 1; i < argc; i++) { + if (strlen(argv[i]) + 1 > sizeof(buffer) - strlen(buffer)) break; + if (i > 1) strcat(buffer, " "); + strcat(buffer, argv[i]); + } + + DoCommand(buffer); + return 0; + } else { + interactiveMode = true; + } + + if (runFirstCommand) { + DoCommand(runFirstCommand); + } + + if (!foundValidCrossCompiler) { + printf("Warning: Your cross compiler appears to be out of date.\n"); + printf("Please rebuild the compiler using the command " ColorHighlight "build-cross" ColorNormal " before attempting to build the OS.\n"); + } + + { + CallSystem("x86_64-essence-gcc -mno-red-zone -print-libgcc-file-name > bin/valid_compiler.txt"); + FILE *f = fopen("bin/valid_compiler.txt", "r"); + char buffer[256]; + buffer[fread(buffer, 1, 256, f)] = 0; + fclose(f); + + if (!strstr(buffer, "no-red-zone")) { + printf("Error: Compiler built without no-red-zone support.\n"); + exit(1); + } + + unlink("bin/valid_compiler.txt"); + } + + printf("Enter 'help' to get a list of commands.\n"); + + while (true) { + char *l = NULL; + size_t pos = 0; + printf("\n> "); + printf(ColorHighlight); + getline(&l, &pos, stdin); + printf(ColorNormal); + + if (strlen(l) == 1) { + l = prev; + if (!l) { + l = (char *) malloc(5); + strcpy(l, "help"); + } + printf("(%s)\n", l); + } else { + l[strlen(l) - 1] = 0; + } + + printf(ColorNormal); + fflush(stdout); + DoCommand(l); + + if (prev != l) free(prev); + prev = l; + } + + return 0; +} diff --git a/util/build_common.h b/util/build_common.h new file mode 100644 index 0000000..6b00c14 --- /dev/null +++ b/util/build_common.h @@ -0,0 +1,407 @@ +#define BINUTILS_VERSION "2.36.1" +#define GCC_VERSION "11.1.0" + +#ifndef OS_ESSENCE + +#include <sys/stat.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> + +typedef struct EsINIState { + char *buffer, *sectionClass, *section, *key, *value; + size_t bytes, sectionClassBytes, sectionBytes, keyBytes, valueBytes; +} EsINIState; + +#include "../shared/ini.h" + +#endif + +#include "stb_ds.h" + +#define INI_READ_BOOL(x, y) if (0 == strcmp(#x, s.key)) y = !!atoi(s.value) +#define INI_READ_STRING(x, y) if (0 == strcmp(#x, s.key)) snprintf(y, sizeof(y), "%s", s.value) +#define INI_READ_STRING_PTR(x, y) if (0 == strcmp(#x, s.key)) y = s.value + +typedef struct ApplicationDependencyList { + char **files; + time_t timeStamp; + bool optimised; +} ApplicationDependencyList; + +typedef struct ApplicationDependencies { + char *key; + ApplicationDependencyList value; +} ApplicationDependencies; + +typedef struct FontFile { + const char *type; + const char *path; +} FontFile; + +typedef struct BuildFont { + const char *name; + const char *category; + const char *scripts; + FontFile *files; +} BuildFont; + +ApplicationDependencies *applicationDependencies; +time_t buildStartTimeStamp; +bool _optimisationsEnabled; +bool forceRebuild; +uint64_t configurationHash; + +void *LoadFile(const char *path, size_t *length) { +#ifdef OS_ESSENCE + size_t path2Bytes; + char *path2 = EsPOSIXConvertPath(path, &path2Bytes, true); + size_t bytes; + void *result = EsFileReadAll(path2, path2Bytes, &bytes, NULL); + EsHeapFree(path2, 0, NULL); + if (!result) return NULL; + void *buffer = malloc(bytes + 1); + memcpy(buffer, result, bytes); + EsHeapFree(result, 0, NULL); + ((uint8_t *) buffer)[bytes] = 0; + if (length) *length = bytes; + return buffer; +#else + FILE *file = fopen(path, "rb"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + size_t fileSize = ftell(file); + fseek(file, 0, SEEK_SET); + char *buffer = (char *) malloc(fileSize + 1); + buffer[fileSize] = 0; + fread(buffer, 1, fileSize, file); + fclose(file); + if (length) *length = fileSize; + return buffer; +#endif +} + +bool IsStringEqual(const char *string, size_t stringBytes, const char *cLiteral) { + return stringBytes == strlen(cLiteral) && 0 == memcmp(string, cLiteral, stringBytes); +} + +bool CheckDependencies(const char *applicationName) { +#ifdef OS_ESSENCE + // TODO. + return true; +#else + bool needsRebuild = false; + ApplicationDependencyList dependencies = shget(applicationDependencies, applicationName); + + if (!dependencies.timeStamp || dependencies.optimised != _optimisationsEnabled || forceRebuild) { + needsRebuild = true; + } + + for (int i = 0; !needsRebuild && i < arrlen(dependencies.files); i++) { + struct stat s; + + // printf("%s, %s\n", applicationName, dependencies.files[i]); + + if (stat(dependencies.files[i], &s) || s.st_mtime > dependencies.timeStamp) { + needsRebuild = true; + break; + } + } + + if (needsRebuild) { + for (int i = 0; i < arrlen(dependencies.files); i++) { + free(dependencies.files[i]); + } + + arrfree(dependencies.files); + (void) shdel(applicationDependencies, applicationName); + } + + return needsRebuild; +#endif +} + +void ParseDependencies(const char *dependencyFile, const char *applicationName, bool append) { +#ifdef OS_ESSENCE + // TODO. +#else + char *dependencies = (char *) LoadFile(dependencyFile, NULL); + + if (!dependencies) { + return; + } + + ApplicationDependencyList list = {}; + + if (append) { + list = shget(applicationDependencies, applicationName); + } + + int i = 0; + + while (dependencies[i++] != ':'); + + for (; dependencies[i]; i++) { + if (dependencies[i] == '/' || isalpha(dependencies[i])) { + int j = i; for (; dependencies[j] && !isspace(dependencies[j]); j++); + char *string = (char *) malloc(j - i + 1); + memcpy(string, dependencies + i, j - i); + string[j - i] = 0; + + if (0 == memcmp(string, "/usr", 4)) { + // Assume system header files do not change. + } else { + arrput(list.files, string); + } + + // printf("%s->%s\n", applicationName, string); + i = j - 1; + } + } + + struct stat s; + + if (stat(dependencyFile, &s) == 0) { + list.timeStamp = s.st_mtime; + if (buildStartTimeStamp < s.st_mtime) list.timeStamp = buildStartTimeStamp; + list.optimised = _optimisationsEnabled; + shput(applicationDependencies, applicationName, list); + } + + free(dependencies); +#endif +} + +void DependenciesListRead() { + EsINIState s = { .buffer = (char *) LoadFile("bin/dependencies.ini", &s.bytes) }; + char *start = s.buffer; + if (!start) return; + + char *key = NULL; + ApplicationDependencyList list = {}; + + while (EsINIParse(&s)) { + EsINIZeroTerminate(&s); + + if (0 == strcmp(s.section, "general")) { + if (0 == strcmp(s.key, "configuration_hash")) { + uint64_t previousConfigurationHash = strtoul(s.value, NULL, 10); + + if (previousConfigurationHash != configurationHash) { + shfree(applicationDependencies); + sh_new_strdup(applicationDependencies); + return; + } + } + } else if (s.keyBytes) { + key = s.section; + } + + if (0 == strcmp(s.key, "time_stamp")) { + list.timeStamp = strtoul(s.value, NULL, 10); + } else if (0 == strcmp(s.key, "file")) { + arrput(list.files, strdup(s.value)); + } + + if (!EsINIPeek(&s) || !s.keyBytes) { + if (key) { + shput(applicationDependencies, key, list); + } + + key = NULL; + memset(&list, 0, sizeof(list)); + } + } + + free(start); +} + +void DependenciesListWrite() { +#ifdef OS_ESSENCE + // TODO. +#else + FILE *f = fopen("bin/dependencies.ini", "wb"); + + fprintf(f, "[general]\nconfiguration_hash=%lu\n", configurationHash); + + for (uintptr_t i = 0; i < shlenu(applicationDependencies); i++) { + ApplicationDependencyList *list = &applicationDependencies[i].value; + + fprintf(f, "[%s]\ntime_stamp=%lu\n", applicationDependencies[i].key, list->timeStamp); + + for (uintptr_t j = 0; j < arrlenu(list->files); j++) { + fprintf(f, "file=%s\n", list->files[j]); + } + } + + fclose(f); +#endif +} + +typedef union OptionVariant { + bool b; + char *s; +} OptionVariant; + +typedef struct Option { + const char *id; +#define OPTION_TYPE_BOOL (1) +#define OPTION_TYPE_STRING (2) + int type; + OptionVariant defaultState; + OptionVariant state; + bool useDefaultState; +} Option; + +Option options[] = { + { "Driver.ACPI", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.AHCI", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.BGA", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.EssenceFS", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.Ext2", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.FAT", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.HDAudio", OPTION_TYPE_BOOL, { .b = false } }, + { "Driver.I8254x", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.IDE", OPTION_TYPE_BOOL, { .b = false } }, + { "Driver.ISO9660", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.NTFS", OPTION_TYPE_BOOL, { .b = false } }, + { "Driver.NVMe", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.Networking", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.PCI", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.PS2", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.Root", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.SVGA", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.USB", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.USBBulk", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.USBHID", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.xHCI", OPTION_TYPE_BOOL, { .b = true } }, + { "Flag.ENABLE_POSIX_SUBSYSTEM", OPTION_TYPE_BOOL, { .b = false } }, + { "Flag.DEBUG_BUILD", OPTION_TYPE_BOOL, { .b = true } }, + { "Flag.USE_SMP", OPTION_TYPE_BOOL, { .b = true } }, + { "Flag.BGA_RESOLUTION_WIDTH", OPTION_TYPE_STRING, { .s = "1600" } }, + { "Flag.BGA_RESOLUTION_HEIGHT", OPTION_TYPE_STRING, { .s = "900" } }, + { "Flag.TEST_HIGH_UI_SCALE", OPTION_TYPE_BOOL, { .b = false } }, + { "Flag.VGA_TEXT_MODE", OPTION_TYPE_BOOL, { .b = false } }, + { "Flag.CHECK_FOR_NOT_RESPONDING", OPTION_TYPE_BOOL, { .b = true } }, + { "Flag._ALWAYS_USE_VBE", OPTION_TYPE_BOOL, { .b = false } }, + { "Dependency.ACPICA", OPTION_TYPE_BOOL, { .b = true } }, + { "Dependency.stb_image", OPTION_TYPE_BOOL, { .b = true } }, + { "Dependency.stb_sprintf", OPTION_TYPE_BOOL, { .b = true } }, + { "Dependency.HarfBuzz", OPTION_TYPE_BOOL, { .b = true } }, + { "Dependency.FreeType", OPTION_TYPE_BOOL, { .b = true } }, + { "Emulator.AHCI", OPTION_TYPE_BOOL, { .b = false } }, + { "Emulator.ATA", OPTION_TYPE_BOOL, { .b = false } }, + { "Emulator.NVMe", OPTION_TYPE_BOOL, { .b = true } }, + { "Emulator.CDROMImage", OPTION_TYPE_STRING, { .s = NULL } }, + { "Emulator.USBImage", OPTION_TYPE_STRING, { .s = NULL } }, + { "Emulator.USBHostVendor", OPTION_TYPE_STRING, { .s = NULL } }, + { "Emulator.USBHostProduct", OPTION_TYPE_STRING, { .s = NULL } }, + { "Emulator.RunWithSudo", OPTION_TYPE_BOOL, { .b = false } }, + { "Emulator.Audio", OPTION_TYPE_BOOL, { .b = false } }, + { "General.first_application", OPTION_TYPE_STRING, { .s = NULL } }, + { "General.wallpaper", OPTION_TYPE_STRING, { .s = NULL } }, +}; + +char *previousOptionsBuffer; + +void LoadOptions() { + free(previousOptionsBuffer); + EsINIState s = { .buffer = (char *) LoadFile("bin/config.ini", &s.bytes) }; + previousOptionsBuffer = s.buffer; + + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + options[i].state = options[i].defaultState; + options[i].useDefaultState = true; + } + + while (s.buffer && EsINIParse(&s)) { + EsINIZeroTerminate(&s); + + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + if (options[i].id && 0 == strcmp(options[i].id, s.key)) { + if (options[i].type == OPTION_TYPE_BOOL) { + options[i].state.b = atoi(s.value); + } else if (options[i].type == OPTION_TYPE_STRING) { + options[i].state.s = strdup(s.value); + } else { + // TODO. + } + + options[i].useDefaultState = false; + break; + } + } + } +} + +bool IsOptionEnabled(const char *name) { + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + if (options[i].id && 0 == strcmp(options[i].id, name)) { + return options[i].state.b; + } + } + + return false; +} + +const char *GetOptionString(const char *name) { + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + if (options[i].id && 0 == strcmp(options[i].id, name)) { + return options[i].state.s; + } + } + + return ""; +} + +bool IsDriverEnabled(const char *name) { + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + if (options[i].id && 0 == memcmp(options[i].id, "Driver.", 7) && 0 == strcmp(options[i].id + 7, name)) { + return options[i].state.b; + } + } + + return false; +} + +#ifdef PARALLEL_BUILD + +volatile uint8_t spinnerRunning; +pthread_t spinnerThread; + +void *SpinnerThread(void *_unused) { + (void) _unused; + + char spinner[4] = { '/', '-', '\\', '|' }; + int index = 0; + + fflush(stdout); + + do { + fprintf(stderr, "\033[0;36m[%c]\033[0m Compiling...\n", spinner[index]); + index = (index + 1) % 4; + struct timespec sleepTime; + sleepTime.tv_sec = 0; + sleepTime.tv_nsec = 1000000 * 200; + nanosleep(&sleepTime, NULL); + fprintf(stderr, "\033[A"); + } while (__sync_val_compare_and_swap(&spinnerRunning, 2, 2) /* use sync function to silence thread sanitizer warning */); + + fprintf(stderr, "\033[K"); + return NULL; +} + +void StopSpinner() { + if (spinnerThread) { + __sync_fetch_and_sub(&spinnerRunning, 1); + pthread_join(spinnerThread, NULL); + spinnerThread = 0; + } +} + +void StartSpinner() { + __sync_fetch_and_add(&spinnerRunning, 1); + pthread_create(&spinnerThread, NULL, SpinnerThread, NULL); +} + +#endif diff --git a/util/build_core.c b/util/build_core.c new file mode 100644 index 0000000..e980b61 --- /dev/null +++ b/util/build_core.c @@ -0,0 +1,1597 @@ +// TODO Better configuration over what files are imported to the drive image. +// TODO Make build_core responsible for generating the header. + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifdef OS_ESSENCE + +#define ES_CRT_WITHOUT_PREFIX +#include <essence.h> +#include <bits/syscall.h> + +typedef struct File { + bool error, ready; + EsHandle handle; + EsFileOffset offset; +} File; + +#define FileSeek(file, _offset) (file.offset = _offset) +#define FileRead(file, size, buffer) (_FileRead(file.handle, &file.offset, size, buffer)) +#define FileWrite(file, size, buffer) (_FileWrite(file.handle, &file.offset, size, buffer)) +#define FileClose(file) EsHandleClose(file.handle) +#define FilePrintFormat(file, ...) (_FilePrintFormat(&file, __VA_ARGS__)) + +void Log(const char *format, ...) { + va_list arguments; + va_start(arguments, format); + char buffer[4096]; + int bytes = EsCRTvsnprintf(buffer, sizeof(buffer), format, arguments); + EsAssert(bytes < sizeof(buffer)); + va_end(arguments); + EsPOSIXSystemCall(SYS_write, (intptr_t) 1, (intptr_t) buffer, (intptr_t) bytes, 0, 0, 0); +} + +File FileOpen(const char *path, char mode) { + size_t path2Bytes; + char *path2 = EsPOSIXConvertPath(path, &path2Bytes, true); + EsFileInformation information = EsFileOpen(path2, path2Bytes, mode == 'r' ? (ES_FILE_READ | ES_NODE_FAIL_IF_NOT_FOUND) : ES_FILE_WRITE); + EsHeapFree(path2, 0, NULL); + if (information.error != ES_SUCCESS) return (File) { .error = true }; + if (mode == 'w') EsFileResize(information.handle, 0); + return (File) { .ready = true, .handle = information.handle }; +} + +EsFileOffset _FileRead(EsHandle handle, EsFileOffset *offset, size_t bytes, void *buffer) { + bytes = EsFileReadSync(handle, *offset, bytes, buffer); + if (bytes > 0) *offset += bytes; + return bytes; +} + +EsFileOffset _FileWrite(EsHandle handle, EsFileOffset *offset, size_t bytes, void *buffer) { + bytes = EsFileWriteSync(handle, *offset, bytes, buffer); + if (bytes > 0) *offset += bytes; + return bytes; +} + +void _FilePrintFormat(File *file, const char *format, ...) { + va_list arguments; + va_start(arguments, format); + char buffer[4096]; + int bytes = EsCRTvsnprintf(buffer, sizeof(buffer), format, arguments); + EsAssert(bytes < sizeof(buffer)); + va_end(arguments); + FileWrite((*file), bytes, buffer); +} + +#define _exit(x) EsPOSIXSystemCall(SYS_exit_group, (intptr_t) x, 0, 0, 0, 0, 0) +#define close(x) EsPOSIXSystemCall(SYS_close, (intptr_t) x, 0, 0, 0, 0, 0) +#define dup2(x, y) EsPOSIXSystemCall(SYS_dup2, (intptr_t) x, (intptr_t) y, 0, 0, 0, 0) +#define execve(x, y, z) EsPOSIXSystemCall(SYS_execve, (intptr_t) x, (intptr_t) y, (intptr_t) z, 0, 0, 0) +#define exit(x) EsPOSIXSystemCall(SYS_exit_group, (intptr_t) x, 0, 0, 0, 0, 0) +#define pipe(x) EsPOSIXSystemCall(SYS_pipe, (intptr_t) x, 0, 0, 0, 0, 0) +#define read(x, y, z) EsPOSIXSystemCall(SYS_read, (intptr_t) x, (intptr_t) y, (intptr_t) z, 0, 0, 0) +#define rename(x, y) EsPOSIXSystemCall(SYS_rename, (intptr_t) x, (intptr_t) y, 0, 0, 0, 0) +#define truncate(x, y) EsPOSIXSystemCall(SYS_truncate, (intptr_t) x, (intptr_t) y, 0, 0, 0, 0) +#define unlink(x) EsPOSIXSystemCall(SYS_unlink, (intptr_t) x, 0, 0, 0, 0, 0) +#define vfork() EsPOSIXSystemCall(SYS_vfork, 0, 0, 0, 0, 0, 0) +#define wait4(x, y, z, w) EsPOSIXSystemCall(SYS_wait4, (intptr_t) x, (intptr_t) y, (intptr_t) z, (intptr_t) w, 0, 0) + +typedef uint64_t pid_t; + +typedef uint64_t time_t; +time_t time(time_t *timer) { return 0; } // TODO. + +#else + +#include <assert.h> +#include <dirent.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +#ifdef PARALLEL_BUILD +#include <pthread.h> +#endif + +typedef struct File { + bool error, ready; + FILE *f; +} File; + +File FileOpen(const char *path, char mode) { + FILE *f = NULL; + if (mode == 'r') f = fopen(path, "rb"); + if (mode == 'w') f = fopen(path, "wb"); + if (mode == '+') f = fopen(path, "r+b"); + return (File) { .error = f == NULL, .ready = f != NULL, .f = f }; +} + +#define FileSeek(file, offset) (fseek(file.f, offset, SEEK_SET)) +#define FileRead(file, size, buffer) (fread(buffer, 1, size, file.f)) +#define FileWrite(file, size, buffer) (fwrite(buffer, 1, size, file.f)) +#define FileClose(file) fclose(file.f) +#define FilePrintFormat(file, ...) fprintf(file.f, __VA_ARGS__) + +#define Log(...) fprintf(stderr, __VA_ARGS__) + +#endif + +#include "../shared/hash.cpp" +#include "build_common.h" +#include "esfs2.h" +#include "header_generator.c" + +// Toolchain flags: + +char commonCompileFlags[4096] = " -Wall -Wextra -Wno-missing-field-initializers -Wno-frame-address " + "-Wno-unused-function -Wno-format-truncation -ffreestanding -fno-exceptions -g -I. "; +char cCompileFlags[4096] = ""; +char cppCompileFlags[4096] = " -std=c++14 -Wno-pmf-conversions -Wno-invalid-offsetof -fno-rtti "; +char kernelCompileFlags[4096] = " -mno-red-zone -mcmodel=kernel -fno-omit-frame-pointer "; +char applicationLinkFlags[4096] = " -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 "; +char apiLinkFlags1[4096] = " -T util/linker/api64.ld -ffreestanding -nostdlib -g -z max-page-size=0x1000 -Wl,--start-group "; +char apiLinkFlags2[4096] = " -lgcc "; +char apiLinkFlags3[4096] = " -Wl,--end-group -Lroot/Applications/POSIX/lib "; +char kernelLinkFlags[4096] = " -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 "; + +// Specific configuration options: + +bool verbose; +bool useColoredOutput; +bool forEmulator, bootUseVBE; +bool systemBuild; +bool convertFonts = true; +EsINIState *fontLines; +EsINIState *generalOptions; + +// State: + +char *builtinModules; +volatile uint8_t encounteredErrors; + +////////////////////////////////// + +#define COLOR_ERROR "\033[0;33m" +#define COLOR_HIGHLIGHT "\033[0;36m" +#define COLOR_NORMAL "\033[0m" + +const char *toolchainAR = "/Applications/POSIX/bin/ar"; +const char *toolchainCC = "/Applications/POSIX/bin/gcc"; +const char *toolchainCXX = "/Applications/POSIX/bin/g++"; +const char *toolchainLD = "/Applications/POSIX/bin/ld"; +const char *toolchainNM = "/Applications/POSIX/bin/nm"; +const char *toolchainStrip = "/Applications/POSIX/bin/strip"; +const char *toolchainNasm = "/Applications/POSIX/bin/nasm"; +const char *toolchainConvertSVG = "/Applications/POSIX/bin/render_svg"; +const char *toolchainLinkerScripts = "/Applications/POSIX/lib"; +const char *toolchainCRTObjects = "/Applications/POSIX/lib"; + +char *executeEnvironment[3] = { + (char *) "PATH=/Applications/POSIX/bin", + (char *) "TMPDIR=/Applications/POSIX/tmp", + NULL, +}; + +#define Execute(...) _Execute(NULL, __VA_ARGS__, NULL, NULL) +#define ExecuteWithOutput(...) _Execute(__VA_ARGS__, NULL, NULL) +#define ExecuteForApp(application, ...) if (!application->error && ExecuteWithOutput(&application->output, __VA_ARGS__)) application->error = true +#define ArgString(x) NULL, x + +int _Execute(char **output, const char *executable, ...) { + char *argv[64]; + va_list argList; + va_start(argList, executable); + + argv[0] = (char *) executable; + + for (uintptr_t i = 1; i <= 64; i++) { + assert(i != 64); + argv[i] = va_arg(argList, char *); + + if (!argv[i]) { + char *string = va_arg(argList, char *); + + if (!string) { + break; + } + + char *copy = (char *) malloc(strlen(string) + 2); + strcpy(copy, string); + strcat(copy, " "); + uintptr_t start = 0; + bool inQuotes = false; + + for (uintptr_t j = 0; copy[j]; j++) { + assert(i != 64); + + if ((!inQuotes && copy[j] == ' ') || !copy[j]) { + if (start != j) { + argv[i] = copy + start; + if (argv[i][0] == '"') argv[i]++; + i++; + } + + if (j && copy[j - 1] == '"') copy[j - 1] = 0; + copy[j] = 0; + start = j + 1; + } else if (copy[j] == '"') { + inQuotes = !inQuotes; + } + } + + i--; + } + } + + va_end(argList); + + if (verbose) { + for (uintptr_t i = 0; i < 64; i++) { + if (!argv[i]) break; + Log("\"%s\" ", argv[i]); + } + + Log("\n"); + } + + int stdoutPipe[2]; + + if (output) { + pipe(stdoutPipe); + } + + int status = -1; + pid_t pid = vfork(); + + if (pid == 0) { + if (output) { + dup2(stdoutPipe[1], 1); + dup2(stdoutPipe[1], 2); + close(stdoutPipe[1]); + } + + execve(executable, argv, executeEnvironment); + _exit(-1); + } else if (pid > 0) { + if (output) { + close(stdoutPipe[1]); + + while (true) { + char buffer[1024]; + intptr_t bytesRead = read(stdoutPipe[0], buffer, 1024); + + if (bytesRead <= 0) { + break; + } else { + size_t previousLength = arrlenu(*output); + arrsetlen(*output, previousLength + bytesRead); + memcpy(*output + previousLength, buffer, bytesRead); + } + } + } + + wait4(-1, &status, 0, NULL); + } else { + Log("Error: could not vfork process.\n"); + exit(1); + } + + if (output) { + close(stdoutPipe[0]); + } + + if (verbose && status) { + Log("(status = %d)\n", status); + } + + if (status) __sync_fetch_and_or(&encounteredErrors, 1); + return status; +} + +void MakeDirectory(const char *path) { +#ifdef OS_ESSENCE + EsPOSIXSystemCall(SYS_mkdir, (intptr_t) path, 0, 0, 0, 0, 0); +#else + mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +#endif +} + +void DeleteFile(const char *path) { + unlink(path); +} + +void CopyFile(const char *oldPath, const char *newPath, bool quietError) { + File source = FileOpen(oldPath, 'r'); + File destination = FileOpen(newPath, 'w'); + + if (source.error) { + if (quietError) return; + Log("Error: Could not open file '%s' as a copy source.\n", oldPath); + __sync_fetch_and_or(&encounteredErrors, 1); + return; + } + + if (destination.error) { + if (quietError) return; + Log("Error: Could not open file '%s' as a copy destination.\n", newPath); + __sync_fetch_and_or(&encounteredErrors, 1); + return; + } + + char buffer[4096]; + + while (true) { + size_t bytesRead = FileRead(source, sizeof(buffer), buffer); + if (!bytesRead) break; + FileWrite(destination, bytesRead, buffer); + } + + FileClose(source); + FileClose(destination); +} + +void MoveFile(const char *oldPath, const char *newPath) { + rename(oldPath, newPath); +} + +bool FileExists(const char *path) { +#ifdef OS_ESSENCE + size_t path2Bytes; + char *path2 = EsPOSIXConvertPath(path, &path2Bytes, true); + bool exists = EsPathExists(path2, path2Bytes, NULL); + EsHeapFree(path2, 0, NULL); + return exists; +#else + struct stat s; + return !stat(path, &s); +#endif +} + +void CreateImportNode(const char *path, ImportNode *node) { + char pathBuffer[256]; + +#ifdef OS_ESSENCE + size_t path2Bytes; + char *path2 = EsPOSIXConvertPath(path, &path2Bytes, true); + EsDirectoryChild *children; + ptrdiff_t childCount = EsDirectoryEnumerateChildren(path2, path2Bytes, &children); + EsHeapFree(path2, 0, NULL); + + for (intptr_t i = 0; i < childCount; i++) { + snprintf(pathBuffer, sizeof(pathBuffer), "%s/%.*s", path, (int) children[i].nameBytes, children[i].name); + + ImportNode child = {}; + + if (children[i].type == ES_NODE_DIRECTORY) { + CreateImportNode(pathBuffer, &child); + } else { + child.isFile = true; + } + + child.name = EsStringAllocateAndFormat(NULL, "%s", children[i].nameBytes, children[i].name); + child.path = strdup(pathBuffer); + arrput(node->children, child); + } + + EsHeapFree(children, 0, NULL); +#else + DIR *d = opendir(path); + struct dirent *dir; + + if (!d) { + return; + } + + while ((dir = readdir(d))) { + if (dir->d_name[0] == '.') { + continue; + } + + snprintf(pathBuffer, sizeof(pathBuffer), "%s/%s", path, dir->d_name); + struct stat s = {}; + lstat(pathBuffer, &s); + + ImportNode child = {}; + + if (S_ISDIR(s.st_mode)) { + CreateImportNode(pathBuffer, &child); + } else if ((s.st_mode & S_IFMT) == S_IFLNK) { + continue; + } else { + child.isFile = true; + } + + child.name = strdup(dir->d_name); + child.path = strdup(pathBuffer); + arrput(node->children, child); + } + + closedir(d); +#endif +} + +////////////////////////////////// + +typedef struct BundleInput { + const char *path; + const char *name; + uint64_t alignment; +} BundleInput; + +bool MakeBundle(const char *outputFile, BundleInput *inputFiles, size_t inputFileCount) { + File output = FileOpen(outputFile, 'w'); + + if (output.error) { + Log("Error: Could not open output file '%s'.\n", outputFile); + return false; + } + + uint32_t signature = 0x63BDAF45; + FileWrite(output, sizeof(uint32_t), &signature); + uint32_t version = 1; + FileWrite(output, sizeof(uint32_t), &version); + uint32_t fileCount = inputFileCount; + FileWrite(output, sizeof(uint32_t), &fileCount); + uint32_t zero = 0; + FileWrite(output, sizeof(uint32_t), &zero); + uint64_t mapAddress = 0; + FileWrite(output, sizeof(uint64_t), &mapAddress); + + for (uintptr_t i = 0; i < fileCount; i++) { + uint64_t zero = 0; + FileWrite(output, sizeof(uint64_t), &zero); + FileWrite(output, sizeof(uint64_t), &zero); + FileWrite(output, sizeof(uint64_t), &zero); + } + + uint64_t outputPosition = 24 + fileCount * 24; + + for (uintptr_t i = 0; i < fileCount; i++) { + FileSeek(output, 24 + i * 24); + + const char *nameString = inputFiles[i].name; + outputPosition = (outputPosition + inputFiles[i].alignment - 1) & ~(inputFiles[i].alignment - 1); + + uint64_t name = CalculateCRC64(nameString, strlen(nameString), 0); + FileWrite(output, sizeof(uint64_t), &name); + + size_t size; + void *buffer = LoadFile(inputFiles[i].path, &size); + + if (!buffer) { + Log("Error: Could not open input file '%s'.\n", inputFiles[i].path); + return false; + } + + if (size > 0xFFFFFFFF) { + Log("Error: Input file '%s' too large (max: 4GB).\n", inputFiles[i].path); + return false; + } + + FileWrite(output, sizeof(uint64_t), &size); + FileWrite(output, sizeof(uint64_t), &outputPosition); + FileSeek(output, outputPosition); + FileWrite(output, size, buffer); + outputPosition += size; + } + + FileClose(output); + return true; +} + +////////////////////////////////// + +typedef struct FileType { + const char *extension; + const char *name; + const char *icon; + int id, openID; +} FileType; + +typedef struct Handler { + const char *extension; + const char *action; + int fileTypeID; +} Handler; + +typedef struct DependencyFile { + char path[256]; + const char *name; +} DependencyFile; + +typedef struct Application { + const char *name; + const char *icon; + const char **permissions; + int id; + bool useSingleProcess, hidden; + + FileType *fileTypes; + Handler *handlers; + + bool install, builtin; + + const char **sources; + const char *compileFlags; + const char *linkFlags; + const char *customCompileCommand; + const char *manifestPath; + + DependencyFile *dependencyFiles; + char *output; + bool error, skipped; + + void (*buildCallback)(struct Application *); // Called on a build thread. + + BundleInput *bundleInputFiles; +} Application; + +int nextID = 1; +Application *applications; +const char **kernelModules; + +void BuildDesktop(Application *application) { + ExecuteForApp(application, toolchainNasm, "-felf64", "desktop/api.s", "-MD", "bin/api1.d", "-o", "bin/api1.o", "-Fdwarf"); + + ExecuteForApp(application, toolchainCXX, "-MD", "-c", "desktop/api.cpp", "-o", "bin/api2.o", ArgString(commonCompileFlags)); + ExecuteForApp(application, toolchainCXX, "-MD", "-c", "desktop/posix.cpp", "-o", "bin/api3.o", ArgString(commonCompileFlags)); + ExecuteForApp(application, toolchainCC, "-o", "bin/Desktop", "bin/crti.o", "bin/crtbegin.o", + "bin/api1.o", "bin/api2.o", "bin/api3.o", "bin/crtend.o", "bin/crtn.o", + ArgString(apiLinkFlags1), ArgString(apiLinkFlags2), ArgString(apiLinkFlags3)); + + ExecuteForApp(application, toolchainStrip, "-o", "root/Essence/Desktop.esx", "--strip-all", "bin/Desktop"); +} + +void BuildApplication(Application *application) { + if (application->customCompileCommand) { +#ifdef OS_ESSENCE + // TODO. +#else + system(application->customCompileCommand); +#endif + } else { + char symbolFile[256]; + char objectFiles[4096]; + char strippedFile[256]; + char executable[256]; + char linkerScript[256]; + char crti[256]; + char crtbegin[256]; + char crtend[256]; + char crtn[256]; + size_t objectFilesPosition = 0; + + snprintf(symbolFile, sizeof(symbolFile), "bin/%s", application->name); + snprintf(strippedFile, sizeof(strippedFile), "bin/%s.no_symbols", application->name); + snprintf(linkerScript, sizeof(linkerScript), "%s/linker/userland64.ld", toolchainLinkerScripts); + snprintf(crti, sizeof(crti), "%s/crti.o", toolchainCRTObjects); + snprintf(crtbegin, sizeof(crtbegin), "%s/crtbegin.o", toolchainCRTObjects); + snprintf(crtend, sizeof(crtend), "%s/crtend.o", toolchainCRTObjects); + snprintf(crtn, sizeof(crtn), "%s/crtn.o", toolchainCRTObjects); + + if (systemBuild) { + snprintf(executable, sizeof(executable), "root/Applications/%s.esx", application->name); + } else { + snprintf(executable, sizeof(executable), "bin/%s.esx", application->name); + } + + for (uintptr_t i = 0; i < arrlenu(application->sources); i++) { + const char *source = application->sources[i]; + size_t sourceBytes = strlen(source); + + char objectFile[256]; + snprintf(objectFile, sizeof(objectFile), "bin/%s_%d.o", application->name, (int) i); + objectFilesPosition += sprintf(objectFiles + objectFilesPosition, "\"%s\" ", objectFile); + + if (sourceBytes > 2 && source[sourceBytes - 1] == 'c' && source[sourceBytes - 2] == '.') { + ExecuteForApp(application, toolchainCC, "-MD", "-o", objectFile, "-c", source, + ArgString(cCompileFlags), ArgString(commonCompileFlags), ArgString(application->compileFlags)); + } else { + ExecuteForApp(application, toolchainCXX, "-MD", "-o", objectFile, "-c", source, + ArgString(cppCompileFlags), ArgString(commonCompileFlags), ArgString(application->compileFlags)); + } + } + + assert(objectFilesPosition < sizeof(objectFiles)); + objectFiles[objectFilesPosition] = 0; + + ExecuteForApp(application, toolchainCC, "-o", symbolFile, + "-Wl,--start-group", ArgString(application->linkFlags), crti, crtbegin, ArgString(objectFiles), crtend, crtn, "-Wl,--end-group", + ArgString(applicationLinkFlags), "-T", linkerScript); + ExecuteForApp(application, toolchainStrip, "-o", strippedFile, "--strip-all", symbolFile); + + BundleInput bundleInputFile = {}; + bundleInputFile.path = strippedFile; + bundleInputFile.name = "Executable (x86_64)"; + bundleInputFile.alignment = 0x1000; + arrput(application->bundleInputFiles, bundleInputFile); + + // Convert any files for the bundle marked with a '!'. + + for (uintptr_t i = 0; i < arrlenu(application->bundleInputFiles); i++) { + const char *path = application->bundleInputFiles[i].path; + + if (path[0] == '!') { + if (strlen(path) > 5 && 0 == memcmp(path + strlen(path) - 4, ".svg", 4)) { + char output[256]; + snprintf(output, sizeof(output), "bin/temp_%d_%d", application->id, (int) i); + ExecuteForApp(application, toolchainConvertSVG, "convert", path + 1, output); + application->bundleInputFiles[i].path = output; + } else { + char buffer[256]; + snprintf(buffer, sizeof(buffer), "Error: Unknown embed convertion file type '%s'.\n", path); + size_t previousLength = arrlenu(application->output); + arrsetlen(application->output, previousLength + strlen(buffer)); + memcpy(application->output + previousLength, buffer, strlen(buffer)); + application->error = true; + } + } + } + + MakeBundle(executable, application->bundleInputFiles, arrlenu(application->bundleInputFiles)); + } +} + +#ifdef PARALLEL_BUILD +volatile uintptr_t applicationsIndex = 0; + +void *BuildApplicationThread(void *_unused) { + while (true) { + uintptr_t i = __sync_fetch_and_add(&applicationsIndex, 1); + + if (i >= arrlenu(applications)) { + return NULL; + } + + if (applications[i].skipped) continue; + applications[i].buildCallback(&applications[i]); + } +} +#endif + +void ParseApplicationManifest(const char *manifestPath) { + EsINIState s = {}; + char *manifest = (char *) LoadFile(manifestPath, &s.bytes); + s.buffer = manifest; + + const char *require = ""; + bool disabled = false; + + Application application = {}; + application.id = nextID++; + application.manifestPath = manifestPath; + application.compileFlags = ""; + application.linkFlags = ""; + Handler *handler = NULL; + FileType *fileType = NULL; + + while (EsINIParse(&s)) { + EsINIZeroTerminate(&s); + + if (0 == strcmp(s.section, "build")) { + if (0 == strcmp("source", s.key)) { + arrput(application.sources, s.value); + } + + INI_READ_STRING_PTR(compile_flags, application.compileFlags); + INI_READ_STRING_PTR(link_flags, application.linkFlags); + INI_READ_STRING_PTR(custom_compile_command, application.customCompileCommand); + INI_READ_STRING_PTR(require, require); + } else if (0 == strcmp(s.section, "general")) { + INI_READ_STRING_PTR(name, application.name); + INI_READ_STRING_PTR(icon, application.icon); + INI_READ_BOOL(use_single_process, application.useSingleProcess); + INI_READ_BOOL(hidden, application.hidden); + INI_READ_STRING_PTR(name, application.name); + INI_READ_BOOL(disabled, disabled); + + if (0 == memcmp("permission_", s.key, 11) && atoi(s.value)) { + arrput(application.permissions, s.key); + } + } else if (0 == strcmp(s.sectionClass, "handler")) { + if (!s.keyBytes) { + Handler _handler = {}; + arrput(application.handlers, _handler); + handler = &arrlast(application.handlers); + } + + INI_READ_STRING_PTR(extension, handler->extension); + INI_READ_STRING_PTR(action, handler->action); + } else if (0 == strcmp(s.sectionClass, "file_type")) { + if (!s.keyBytes) { + FileType _fileType = {}; + _fileType.id = nextID++; + arrput(application.fileTypes, _fileType); + fileType = &arrlast(application.fileTypes); + } + + INI_READ_STRING_PTR(extension, fileType->extension); + INI_READ_STRING_PTR(name, fileType->name); + INI_READ_STRING_PTR(icon, fileType->icon); + } else if (0 == strcmp(s.section, "embed") && s.key[0] != ';' && s.value[0]) { + BundleInput input = { 0 }; + input.path = s.value; + input.name = s.key; + input.alignment = 1; + arrput(application.bundleInputFiles, input); + } + } + + if (disabled || (require[0] && !FileExists(require))) { + return; + } + + for (uintptr_t i = 0; i < arrlenu(application.sources); i++) { + DependencyFile dependencyFile = {}; + dependencyFile.name = application.name; + snprintf(dependencyFile.path, sizeof(dependencyFile.path), "bin/%s_%d.d", application.name, (int) i); + arrput(application.dependencyFiles, dependencyFile); + } + + application.buildCallback = BuildApplication; + application.install = true; + + arrput(applications, application); +} + +void OutputSystemConfiguration() { + EsINIState s = {}; + char *config = (char *) LoadFile("res/System Configuration Template.ini", &s.bytes); + s.buffer = config; + File file = FileOpen("root/Essence/System Configuration.ini", 'w'); + + while (EsINIParse(&s)) { + EsINIZeroTerminate(&s); + + char buffer[4096]; + FileWrite(file, EsINIFormat(&s, buffer, sizeof(buffer)), buffer); + + if (0 == strcmp(s.section, "general") && (!EsINIPeek(&s) || !s.keyBytes)) { + FilePrintFormat(file, "next_id=%d\n", nextID); + + for (uintptr_t i = 0; i < arrlenu(generalOptions); i++) { + FileWrite(file, EsINIFormat(generalOptions + i, buffer, sizeof(buffer)), buffer); + } + } + } + + for (uintptr_t i = 0; i < arrlenu(applications); i++) { + if (!applications[i].install) { + continue; + } + + for (uintptr_t j = 0; j < arrlenu(applications[i].handlers); j++) { + Handler *handler = applications[i].handlers + j; + int handlerID = applications[i].id; + + for (uintptr_t i = 0; i < arrlenu(applications); i++) { + for (uintptr_t j = 0; j < arrlenu(applications[i].fileTypes); j++) { + FileType *fileType = applications[i].fileTypes + j; + + if (0 == strcmp(handler->extension, fileType->extension)) { + handler->fileTypeID = fileType->id; + + if (0 == strcmp(handler->action, "open")) { + fileType->openID = handlerID; + } else { + Log("Warning: unrecognised handler action '%s'.\n", handler->action); + } + } + } + } + + if (!handler->fileTypeID) { + Log("Warning: could not find a file_type entry for handler with extension '%s' in application '%s'.\n", + handler->extension, applications[i].name); + } + } + } + + for (uintptr_t i = 0; i < arrlenu(applications); i++) { + if (!applications[i].install) { + continue; + } + + FilePrintFormat(file, "\n[@application %d]\n", applications[i].id); + FilePrintFormat(file, "name=%s\n", applications[i].name); + FilePrintFormat(file, "icon=%s\n", applications[i].icon); + FilePrintFormat(file, "use_single_process=%d\n", applications[i].useSingleProcess); + FilePrintFormat(file, "hidden=%d\n", applications[i].hidden); + FilePrintFormat(file, "executable=0:/Applications/%s.esx\n", applications[i].name); + FilePrintFormat(file, "is_file_manager=%d\n", 0 == strcmp(applications[i].name, "File Manager") ? 1 : 0); + + for (uintptr_t j = 0; j < arrlenu(applications[i].permissions); j++) { + FilePrintFormat(file, "%s=1\n", applications[i].permissions[j]); + } + + for (uintptr_t j = 0; j < arrlenu(applications[i].fileTypes); j++) { + FilePrintFormat(file, "\n[@file_type %d]\n", applications[i].fileTypes[j].id); + FilePrintFormat(file, "extension=%s\n", applications[i].fileTypes[j].extension); + FilePrintFormat(file, "name=%s\n", applications[i].fileTypes[j].name); + FilePrintFormat(file, "icon=%s\n", applications[i].fileTypes[j].icon); + FilePrintFormat(file, "open=%d\n", applications[i].fileTypes[j].openID); + } + + for (uintptr_t j = 0; j < arrlenu(applications[i].handlers); j++) { + FilePrintFormat(file, "\n[@handler]\n"); + FilePrintFormat(file, "action=%s\n", applications[i].handlers[j].action); + FilePrintFormat(file, "application=%d\n", applications[i].id); + FilePrintFormat(file, "file_type=%d\n", applications[i].handlers[j].fileTypeID); + } + } + + for (uintptr_t i = 0; i < arrlenu(fontLines); i++) { + char buffer[4096]; + + if (fontLines[i].key[0] == '.') { + if (convertFonts) { +#ifdef OS_ESSENCE + // TODO. +#else + snprintf(buffer, sizeof(buffer), "bin/designer --make-font \"res/Fonts/%s\" \"bin/%.*s.dat\"", + fontLines[i].value, (int) fontLines[i].valueBytes - 4, fontLines[i].value); + system(buffer); + FilePrintFormat(file, "%s=|Fonts:/%.*s.dat\n", fontLines[i].key, (int) fontLines[i].valueBytes - 4, fontLines[i].value); +#endif + } else { + FilePrintFormat(file, "%s=|Fonts:/%s\n", fontLines[i].key, fontLines[i].value); + } + } else { + size_t bytes = EsINIFormat(fontLines + i, buffer, sizeof(buffer)); + FileWrite(file, bytes, buffer); + } + } + + FileClose(file); +} + +void BuildModule(Application *application) { + char output[4096]; + snprintf(output, sizeof(output), "bin/%s.ekm", application->name); + + assert(arrlenu(application->sources) == 1); + ExecuteForApp(application, toolchainCXX, "-MD", "-c", application->sources[0], "-o", + output, ArgString(cppCompileFlags), ArgString(kernelCompileFlags), ArgString(commonCompileFlags), + application->builtin ? "-DBUILTIN_MODULE" : "-DKERNEL_MODULE"); + + if (!application->builtin) { + char target[4096]; + snprintf(target, sizeof(target), "root/Essence/Modules/%s.ekm", application->name); + MoveFile(output, target); + } +} + +bool IsModuleEnabled(const char *name, size_t nameBytes) { + for (uintptr_t i = 0; i < arrlenu(kernelModules); i++) { + if (IsStringEqual(name, nameBytes, kernelModules[i])) { + return true; + } + } + + return false; +} + +void ParseKernelConfiguration() { + if (!CheckDependencies("Kernel Config")) { + return; + } + + size_t kernelConfigBytes; + char *kernelConfig = (char *) LoadFile("kernel/config.ini", &kernelConfigBytes); + + File f = FileOpen("bin/kernel_config.h", 'w'); + + EsINIState s = {}; + s.buffer = (char *) kernelConfig; + s.bytes = kernelConfigBytes; + + EsINIState previous = s; + + while (EsINIParse(&s)) { + if (!IsStringEqual(s.sectionClass, s.sectionClassBytes, "driver") + || (previous.sectionBytes == s.sectionBytes && 0 == memcmp(previous.section, s.section, s.sectionBytes)) + || !IsModuleEnabled(s.section, s.sectionBytes)) { + continue; + } + + FilePrintFormat(f, "extern \"C\" KDriver driver%.*s;\n", (int) s.sectionBytes, s.section); + previous = s; + } + + FilePrintFormat(f, "#ifdef K_IN_CORE_KERNEL\n"); + FilePrintFormat(f, "KInstalledDriver builtinDrivers[] = {\n"); + + s.buffer = (char *) kernelConfig; + s.bytes = kernelConfigBytes; + + char *moduleName = NULL, *parentName = NULL, *dataStart = s.buffer; + size_t moduleNameBytes = 0, parentNameBytes = 0; + bool builtin = false; + bool foundMatchingArchitecture = false, anyArchitecturesListed = false; + + while (EsINIParse(&s)) { + if (!IsStringEqual(s.sectionClass, s.sectionClassBytes, "driver")) { + continue; + } + + moduleName = s.section; + moduleNameBytes = s.sectionBytes; + + if (IsStringEqual(s.key, s.keyBytes, "parent")) { + parentName = s.value, parentNameBytes = s.valueBytes; + } + + if (IsStringEqual(s.key, s.keyBytes, "builtin")) { + builtin = s.valueBytes && s.value[0] == '1'; + } + + if (!foundMatchingArchitecture && IsStringEqual(s.key, s.keyBytes, "arch")) { + anyArchitecturesListed = true; + + if (IsStringEqual(s.value, s.valueBytes, "x86_common") + || IsStringEqual(s.value, s.valueBytes, "x86_64")) { + foundMatchingArchitecture = true; + } + } + + char *dataEnd = s.buffer; + + if (!EsINIPeek(&s) || !s.keyBytes) { + if ((foundMatchingArchitecture || !anyArchitecturesListed) && IsModuleEnabled(moduleName, moduleNameBytes)) { + FilePrintFormat(f, "\t{\n"); + FilePrintFormat(f, "\t\t.name = (char *) \"%.*s\",\n", (int) moduleNameBytes, moduleName); + FilePrintFormat(f, "\t\t.nameBytes = %d,\n", (int) moduleNameBytes); + FilePrintFormat(f, "\t\t.parent = (char *) \"%.*s\",\n", (int) parentNameBytes, parentName); + FilePrintFormat(f, "\t\t.parentBytes = %d,\n", (int) parentNameBytes); + FilePrintFormat(f, "\t\t.config = (char *) R\"(%.*s)\",\n", (int) (dataEnd - dataStart), dataStart); + FilePrintFormat(f, "\t\t.configBytes = %d,\n", (int) (dataEnd - dataStart)); + FilePrintFormat(f, "\t\t.builtin = %d,\n", builtin); + FilePrintFormat(f, "\t\t.loadedDriver = &driver%.*s,\n", (int) moduleNameBytes, moduleName); + FilePrintFormat(f, "\t},\n"); + } + + moduleName = parentName = NULL; + moduleNameBytes = parentNameBytes = 0; + builtin = false; + foundMatchingArchitecture = anyArchitecturesListed = false; + dataStart = dataEnd; + } + } + + FilePrintFormat(f, "};\n"); + FilePrintFormat(f, "#endif"); + FileClose(f); + + f = FileOpen("bin/system_config.d", 'w'); + FilePrintFormat(f, ": kernel/config.ini\n"); + FileClose(f); + ParseDependencies("bin/system_config.d", "Kernel Config", false); + DeleteFile("bin/system_config.d"); +} + +void LinkKernel() { + arrput(builtinModules, 0); + + if (Execute(toolchainLD, "-r", "bin/kernel.o", "bin/kernel_x86_64.o", ArgString(builtinModules), "-o" "bin/kernel_all.o")) { + return; + } + + { + char *output = NULL; + + if (_Execute(&output, toolchainNM, "bin/kernel_all.o", NULL, NULL)) { + return; + } else { + File f = FileOpen("bin/kernel_symbols.h", 'w'); + uintptr_t lineStart = 0, position = 0; + + while (position < arrlenu(output)) { + if (output[position] == '\n') { + output[position] = 0; + const char *line = output + lineStart; + const char *t = strstr(line, " T "); + + if (t) { + FilePrintFormat(f, "{ (void *) 0x%.*s, \"%s\" },\n", (int) (t - line), line, t + 3); + } + + lineStart = position + 1; + } + + position++; + } + + FileClose(f); + + Execute(toolchainCXX, "-c", "kernel/symbols.cpp", "-o", "bin/kernel_symbols.o", + ArgString(cppCompileFlags), ArgString(kernelCompileFlags), ArgString(commonCompileFlags)); + } + } + + Execute(toolchainCXX, "-T", "util/linker/kernel64.ld", "-o", "bin/Kernel", "bin/kernel_symbols.o", "bin/kernel_all.o", "-mno-red-zone", ArgString(kernelLinkFlags)); + Execute(toolchainStrip, "-o", "bin/Kernel.esx", "--strip-all", "bin/Kernel"); +} + +void BuildKernel(Application *application) { + ExecuteForApp(application, toolchainNasm, "-MD", "bin/kernel2.d", "-D", "COM_OUTPUT", + "-felf64", "kernel/x86_64.s", "-o", "bin/kernel_x86_64.o", "-Fdwarf"); + ExecuteForApp(application, toolchainCXX, "-MD", "-c", "kernel/main.cpp", "-o", "bin/kernel.o", + ArgString(kernelCompileFlags), ArgString(cppCompileFlags), ArgString(commonCompileFlags)); +} + +void BuildBootloader(Application *application) { + ExecuteForApp(application, toolchainNasm, "-MD", "bin/boot1.d", "-fbin", + forEmulator ? "boot/x86/mbr.s" : "boot/x86/mbr-emu.s" , "-obin/mbr"); + ExecuteForApp(application, toolchainNasm, "-MD", "bin/boot2.d", "-fbin", + "boot/x86/esfs-stage1.s", "-obin/stage1"); + ExecuteForApp(application, toolchainNasm, "-MD", "bin/boot3.d", "-fbin", + "boot/x86/loader.s", "-obin/stage2", + "-Pboot/x86/esfs-stage2.s", (forEmulator && !bootUseVBE) ? "" : "-D BOOT_USE_VBE"); +} + +File _drive; +uint64_t _partitionOffset; + +void ReadBlock(uint64_t block, uint64_t count, void *buffer) { + FileSeek(_drive, block * blockSize + _partitionOffset); + // printf("read of block %ld\n", block); + + if (FileRead(_drive, blockSize * count, buffer) != blockSize * count) { + Log("Error: Could not read blocks %d->%d of drive.\n", (int) block, (int) (block + count)); + exit(1); + } +} + +void WriteBlock(uint64_t block, uint64_t count, void *buffer) { + FileSeek(_drive, block * blockSize + _partitionOffset); + assert(block < 4294967296); + + if (FileWrite(_drive, blockSize * count, buffer) != blockSize * count) { + Log("Error: Could not write to blocks %d->%d of drive.\n", (int) block, (int) (block + count)); + exit(1); + } +} + +void WriteBytes(uint64_t offset, uint64_t count, void *buffer) { + FileSeek(_drive, offset + _partitionOffset); + + if (FileWrite(_drive, count, buffer) != count) { + Log("Error: Could not write to bytes %d->%d of drive.\n", (int) offset, (int) (offset + count)); + exit(1); + } +} + +void Install(const char *driveFile, uint64_t partitionSize, const char *partitionLabel) { + Log("Installing...\n"); + + EsUniqueIdentifier installationIdentifier; + +#ifndef OS_ESSENCE + srand(time(NULL)); +#endif + + for (int i = 0; i < 16; i++) { + installationIdentifier.d[i] = rand(); + } + + File f = FileOpen(driveFile, 'w'); + + File mbr = FileOpen("bin/mbr", 'r'); + char mbrBuffer[446] = {}; + FileRead(mbr, 446, mbrBuffer); + FileWrite(f, 446, mbrBuffer); + FileClose(mbr); + + uint32_t partitions[16] = { 0x80 /* bootable */, 0x83 /* type */, 0x800 /* offset */, (uint32_t) ((partitionSize / 0x200) - 0x800) /* sector count */ }; + uint16_t bootSignature = 0xAA55; + + uint32_t headsPerCylinder = 256, sectorsPerTrack = 63; + uint32_t partitionOffsetCylinder = (partitions[2] / sectorsPerTrack) / headsPerCylinder; + uint32_t partitionOffsetHead = (partitions[2] / sectorsPerTrack) % headsPerCylinder; + uint32_t partitionOffsetSector = (partitions[2] % sectorsPerTrack) + 1; + uint32_t partitionSizeCylinder = (partitions[3] / sectorsPerTrack) / headsPerCylinder; + uint32_t partitionSizeHead = (partitions[3] / sectorsPerTrack) % headsPerCylinder; + uint32_t partitionSizeSector = (partitions[3] % sectorsPerTrack) + 1; + partitions[0] |= (partitionOffsetHead << 8) | (partitionOffsetSector << 16) | (partitionOffsetCylinder << 24) | ((partitionOffsetCylinder >> 8) << 16); + partitions[1] |= (partitionSizeHead << 8) | (partitionSizeSector << 16) | (partitionSizeCylinder << 24) | ((partitionSizeCylinder >> 8) << 16); + + FileWrite(f, 64, partitions); + FileWrite(f, 2, &bootSignature); + + void *blank = calloc(1, 0x800 * 0x200 - 0x200); + FileWrite(f, 0x800 * 0x200 - 0x200, blank); + free(blank); + + File stage1 = FileOpen("bin/stage1", 'r'); + char stage1Buffer[0x200] = {}; + FileRead(stage1, 0x200, stage1Buffer); + FileWrite(f, 0x200, stage1Buffer); + FileClose(stage1); + + File stage2 = FileOpen("bin/stage2", 'r'); + char stage2Buffer[0x200 * 15] = {}; + + if (sizeof(stage2Buffer) == FileRead(stage2, sizeof(stage2Buffer), stage2Buffer)) { + Log("Error: Stage 2 bootloader too large. Must fit in 7.5KB.\n"); + exit(1); + } + + FileWrite(f, sizeof(stage2Buffer), stage2Buffer); + FileClose(stage2); + + FileClose(f); + + size_t kernelBytes; + void *kernel = LoadFile("bin/Kernel.esx", &kernelBytes); + + if (truncate(driveFile, partitionSize)) { + Log("Error: Could not change the file's size to %d bytes.\n", (int) partitionSize); + exit(1); + } + + _drive = FileOpen(driveFile, '+'); + _partitionOffset = 1048576; + Format(partitionSize - _partitionOffset, partitionLabel, installationIdentifier, kernel, kernelBytes); + + Log("Copying files to the drive... "); + + ImportNode root = {}; + CreateImportNode("root", &root); + CreateImportNode("res/Themes", ImportNodeMakeDirectory(ImportNodeFindChild(&root, "Essence"), "Themes")); + CreateImportNode("res/Media", ImportNodeMakeDirectory(ImportNodeFindChild(&root, "Essence"), "Media")); + + if (convertFonts) { + ImportNode *fontsFolder = ImportNodeMakeDirectory(ImportNodeFindChild(&root, "Essence"), "Fonts"); + + for (uintptr_t i = 0; i < arrlenu(fontLines); i++) { + if (fontLines[i].key[0] == '.') { + char source[4096], destination[4096]; + snprintf(source, sizeof(source), "bin/%.*s.dat", (int) fontLines[i].valueBytes - 4, fontLines[i].value); + snprintf(destination, sizeof(destination), "%.*s.dat", (int) fontLines[i].valueBytes - 4, fontLines[i].value); + ImportNodeAddFile(fontsFolder, strdup(destination), strdup(source)); + } + } + } else { + CreateImportNode("res/Fonts", ImportNodeMakeDirectory(ImportNodeFindChild(&root, "Essence"), "Fonts")); + } + + MountVolume(); + Import(root, superblock.root); + UnmountVolume(); + Log("(%u MB)\n", (unsigned) (copiedCount / 1048576)); + + FileClose(_drive); +} + +////////////////////////////////// + +#ifdef OS_ESSENCE +int BuildCore(int argc, char **argv) { +#else +int main(int argc, char **argv) { +#endif + if (argc < 2) { + Log("Usage: build_core <mode> <options...>\n"); + return 1; + } + + char **applicationManifests = NULL; + bool skipCompile = false; + bool skipHeaderGeneration = false; + bool minimalRebuild = false; + +#ifdef PARALLEL_BUILD + size_t threadCount = 1; +#endif + + const char *driveFile = NULL; + uint64_t partitionSize = 0; + const char *partitionLabel = "New Volume"; + + char *driverSource = NULL, *driverName = NULL; + bool driverBuiltin = false; + + if (0 == strcmp(argv[1], "standard")) { + if (argc != 3) { + Log("Usage: standard <configuration>\n"); + return 1; + } + + EsINIState s = {}; + s.buffer = (char *) LoadFile(argv[2], &s.bytes); + + if (!s.buffer) { + Log("Error: could not load configuration file '%s'.\n", argv[2]); + return 1; + } + + while (EsINIParse(&s)) { + EsINIZeroTerminate(&s); + + if (0 == strcmp(s.section, "toolchain")) { + if (0 == strcmp(s.key, "path")) { + executeEnvironment[0] = (char *) malloc(5 + s.valueBytes + 1); + strcpy(executeEnvironment[0], "PATH="); + strcat(executeEnvironment[0], s.value); + } else if (0 == strcmp(s.key, "tmpdir")) { + if (s.value[0]) { + executeEnvironment[1] = (char *) malloc(7 + s.valueBytes + 1); + strcpy(executeEnvironment[1], "TMPDIR="); + strcat(executeEnvironment[1], s.value); + } else { + executeEnvironment[1] = NULL; + } + } else if (0 == strcmp(s.key, "ar")) { + toolchainAR = s.value; + } else if (0 == strcmp(s.key, "cc")) { + toolchainCC = s.value; + } else if (0 == strcmp(s.key, "cxx")) { + toolchainCXX = s.value; + } else if (0 == strcmp(s.key, "ld")) { + toolchainLD = s.value; + } else if (0 == strcmp(s.key, "nm")) { + toolchainNM = s.value; + } else if (0 == strcmp(s.key, "strip")) { + toolchainStrip = s.value; + } else if (0 == strcmp(s.key, "nasm")) { + toolchainNasm = s.value; + } else if (0 == strcmp(s.key, "convert_svg")) { + toolchainConvertSVG = s.value; + } else if (0 == strcmp(s.key, "linker_scripts")) { + toolchainLinkerScripts = s.value; + } else if (0 == strcmp(s.key, "crt_objects")) { + toolchainCRTObjects = s.value; + } + } else if (0 == strcmp(s.sectionClass, "application")) { + if (0 == strcmp(s.key, "manifest")) { + arrput(applicationManifests, s.value); + } + } else if (0 == strcmp(s.section, "options")) { + if (0 == strcmp(s.key, "Dependency.ACPICA") && atoi(s.value)) { + strcat(kernelLinkFlags, " -lacpica -Lports/acpica "); + strcat(kernelCompileFlags, " -DUSE_ACPICA "); + } else if (0 == strcmp(s.key, "Dependency.stb_image") && atoi(s.value)) { + strcat(commonCompileFlags, " -DUSE_STB_IMAGE "); + } else if (0 == strcmp(s.key, "Dependency.stb_sprintf") && atoi(s.value)) { + strcat(commonCompileFlags, " -DUSE_STB_SPRINTF "); + } else if (0 == strcmp(s.key, "Dependency.HarfBuzz") && atoi(s.value)) { + strcat(apiLinkFlags2, " -lharfbuzz "); + strcat(commonCompileFlags, " -DUSE_HARFBUZZ "); + } else if (0 == strcmp(s.key, "Dependency.FreeType") && atoi(s.value)) { + strcat(apiLinkFlags2, " -lfreetype "); + strcat(commonCompileFlags, " -DUSE_FREETYPE "); + convertFonts = false; + } else if (0 == strcmp(s.key, "Flag._ALWAYS_USE_VBE")) { + bootUseVBE = !!atoi(s.value); + } else if (0 == memcmp(s.key, "General.", 8)) { + EsINIState s2 = s; + s2.key += 8, s2.keyBytes -= 8; + arrput(generalOptions, s2); + } + } else if (0 == strcmp(s.section, "general")) { + if (0 == strcmp(s.key, "skip_compile")) { + skipCompile = !!atoi(s.value); + } else if (0 == strcmp(s.key, "skip_header_generation")) { + skipHeaderGeneration = !!atoi(s.value); + } else if (0 == strcmp(s.key, "verbose")) { + verbose = !!atoi(s.value); + } else if (0 == strcmp(s.key, "for_emulator")) { + forEmulator = !!atoi(s.value); + } else if (0 == strcmp(s.key, "system_build")) { + systemBuild = !!atoi(s.value); + } else if (0 == strcmp(s.key, "minimal_rebuild")) { + minimalRebuild = !!atoi(s.value); + } else if (0 == strcmp(s.key, "optimise")) { + if (atoi(s.value)) { + strcat(commonCompileFlags, " -O2 "); + } + } else if (0 == strcmp(s.key, "colored_output")) { + if (atoi(s.value)) { + strcat(commonCompileFlags, " -fdiagnostics-color=always "); + useColoredOutput = true; + } + } else if (0 == strcmp(s.key, "common_compile_flags")) { + strcat(commonCompileFlags, s.value); + } else if (0 == strcmp(s.key, "thread_count")) { +#ifndef PARALLEL_BUILD + Log("Warning: thread_count not supported.\n"); +#else + threadCount = atoi(s.value); + if (threadCount < 1) threadCount = 1; + if (threadCount > 100) threadCount = 100; +#endif + } + } else if (0 == strcmp(s.section, "install")) { + if (0 == strcmp(s.key, "file")) { + driveFile = s.value; + } else if (0 == strcmp(s.key, "partition_label")) { + partitionLabel = s.value; + } else if (0 == strcmp(s.key, "partition_size")) { + partitionSize = atoi(s.value) * 1048576UL; + } + } else if (0 == strcmp(s.sectionClass, "font")) { + arrput(fontLines, s); + } else if (0 == strcmp(s.sectionClass, "driver")) { + if (0 == strcmp(s.key, "name")) driverName = s.value; + if (0 == strcmp(s.key, "source")) driverSource = s.value; + if (0 == strcmp(s.key, "builtin")) driverBuiltin = !!atoi(s.value); + + if (!EsINIPeek(&s) || !s.keyBytes) { + arrput(kernelModules, driverName); + + if (driverSource && *driverSource) { + DependencyFile dependencyFile = {}; + dependencyFile.name = driverName; + snprintf(dependencyFile.path, sizeof(dependencyFile.path), "bin/%s.d", driverName); + + Application application = {}; + arrput(application.sources, driverSource); + application.name = driverName; + application.builtin = driverBuiltin; + application.buildCallback = BuildModule; + arrput(application.dependencyFiles, dependencyFile); + arrput(applications, application); + + if (driverBuiltin) { + char append[256]; + snprintf(append, sizeof(append), " bin/%s.ekm ", driverName); + size_t previousLength = arrlenu(builtinModules); + arrsetlen(builtinModules, previousLength + strlen(append)); + memcpy(builtinModules + previousLength, append, strlen(append)); + } + } + + driverSource = driverName = NULL; + driverBuiltin = false; + } + } + + if (0 != strcmp(s.section, "install")) { + configurationHash = CalculateCRC64(s.sectionClass, s.sectionClassBytes, configurationHash); + configurationHash = CalculateCRC64(s.section, s.sectionBytes, configurationHash); + configurationHash = CalculateCRC64(s.key, s.keyBytes, configurationHash); + configurationHash = CalculateCRC64(s.value, s.valueBytes, configurationHash); + } + } + } else if (0 == strcmp(argv[1], "application")) { + if (argc != 3) { + Log("Usage: application <configuration>\n"); + return 1; + } + + arrput(applicationManifests, argv[2]); + } else if (0 == strcmp(argv[1], "headers")) { + MakeDirectory("bin"); + return HeaderGeneratorMain(argc - 1, argv + 1); + } else { + Log("Error: Unsupported mode '%s'.\n", argv[1]); + return 1; + } + + buildStartTimeStamp = time(NULL); + sh_new_strdup(applicationDependencies); + + if (minimalRebuild) { + DependenciesListRead(); + } + + MakeDirectory("bin"); + + if (systemBuild) { + MakeDirectory("root"); + MakeDirectory("root/Applications"); + MakeDirectory("root/Applications/POSIX"); + MakeDirectory("root/Applications/POSIX/bin"); + MakeDirectory("root/Applications/POSIX/include"); + MakeDirectory("root/Applications/POSIX/lib"); + MakeDirectory("root/Applications/POSIX/tmp"); + MakeDirectory("root/Applications/POSIX/lib/linker"); + MakeDirectory("root/Essence"); + MakeDirectory("root/Essence/Modules"); + + if (!skipHeaderGeneration) { + HeaderGeneratorMain(1, NULL); + } + } + + if (!skipCompile) { + if (systemBuild) { + Execute(toolchainNasm, "-felf64", "desktop/crti.s", "-o", "bin/crti.o", "-Fdwarf"); + Execute(toolchainNasm, "-felf64", "desktop/crtn.s", "-o", "bin/crtn.o", "-Fdwarf"); + Execute(toolchainCC, "-c", "desktop/crt1.c", "-o", "bin/crt1.o", ArgString(cCompileFlags), ArgString(commonCompileFlags)); + Execute(toolchainCC, "-c", "desktop/crtglue.c", "-o" "bin/crtglue.o", ArgString(cCompileFlags), ArgString(commonCompileFlags)); + CopyFile("bin/crti.o", "root/Applications/POSIX/lib/crti.o", false); + CopyFile("bin/crtbegin.o", "root/Applications/POSIX/lib/crtbegin.o", false); + CopyFile("bin/crtend.o", "root/Applications/POSIX/lib/crtend.o", false); + CopyFile("bin/crtn.o", "root/Applications/POSIX/lib/crtn.o", false); + CopyFile("bin/crt1.o", "root/Applications/POSIX/lib/crt1.o", false); + CopyFile("bin/crtglue.o", "root/Applications/POSIX/lib/crtglue.o", false); + CopyFile("bin/crt1.o", "cross/lib/gcc/x86_64-essence/" GCC_VERSION "/crt1.o", true); + CopyFile("bin/crtglue.o", "cross/lib/gcc/x86_64-essence/" GCC_VERSION "/crtglue.o", true); + CopyFile("util/linker/userland64.ld", "root/Applications/POSIX/lib/linker/userland64.ld", false); + + char linkerScript[256]; + snprintf(linkerScript, sizeof(linkerScript), "%s/linker/userland64.ld", toolchainLinkerScripts); + Execute(toolchainCC, "util/build_core.c", "-o", "root/Applications/POSIX/bin/build_core", "-g", + "-nostdlib", "bin/crti.o", "bin/crtbegin.o", "bin/crtend.o", "bin/crtn.o", "-T", linkerScript); + } + +#define ADD_DEPENDENCY_FILE(application, _path, _name) \ + { \ + DependencyFile file = {}; \ + strcpy(file.path, _path); \ + file.name = _name; \ + arrput(application.dependencyFiles, file); \ + } + + if (systemBuild) { + Application application = {}; + application.name = "Bootloader"; + application.buildCallback = BuildBootloader; + ADD_DEPENDENCY_FILE(application, "bin/boot1.d", "Boot1"); + ADD_DEPENDENCY_FILE(application, "bin/boot2.d", "Boot2"); + ADD_DEPENDENCY_FILE(application, "bin/boot3.d", "Boot3"); + arrput(applications, application); + } + + if (systemBuild) { + Application application = {}; + application.name = "Desktop"; + application.buildCallback = BuildDesktop; + ADD_DEPENDENCY_FILE(application, "bin/api1.d", "API1"); + ADD_DEPENDENCY_FILE(application, "bin/api2.d", "API2"); + ADD_DEPENDENCY_FILE(application, "bin/api3.d", "API3"); + arrput(applications, application); + } + + for (uintptr_t i = 0; i < arrlenu(applicationManifests); i++) { + ParseApplicationManifest(applicationManifests[i]); + } + + if (systemBuild) { + ParseKernelConfiguration(); + + Application application = {}; + application.name = "Kernel"; + application.buildCallback = BuildKernel; + ADD_DEPENDENCY_FILE(application, "bin/kernel.d", "Kernel1"); + ADD_DEPENDENCY_FILE(application, "bin/kernel2.d", "Kernel2"); + arrput(applications, application); + } + + // Check which applications need to be rebuilt. + + for (uintptr_t i = 0; i < arrlenu(applications); i++) { + bool rebuild = false; + + for (uintptr_t j = 0; j < arrlenu(applications[i].dependencyFiles); j++) { + if (CheckDependencies(applications[i].dependencyFiles[j].name)) { + rebuild = true; + break; + } + } + + if (!rebuild && arrlenu(applications[i].dependencyFiles)) { + applications[i].skipped = true; + } + } + + // Build all these applications. + +#ifdef PARALLEL_BUILD + if (useColoredOutput) StartSpinner(); + pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * threadCount); + + for (uintptr_t i = 0; i < threadCount; i++) { + pthread_create(threads + i, NULL, BuildApplicationThread, NULL); + } + + for (uintptr_t i = 0; i < threadCount; i++) { + pthread_join(threads[i], NULL); + } + + if (useColoredOutput) StopSpinner(); +#else + for (uintptr_t i = 0; i < arrlenu(applications); i++) { + Log("[%d/%d] Compiling %s...\n", i + 1, arrlenu(applications), applications[i].name); + if (applications[i].skipped) continue; + applications[i].buildCallback(&applications[i]); + } +#endif + + // Output information about the built applications, + // and parse the dependency files for successfully built ones. + + bool firstEmptyOutput = true; + + for (uintptr_t i = 0; i < arrlenu(applications); i++) { + if (applications[i].skipped) { + continue; + } + + if (!applications[i].error && !arrlenu(applications[i].output)) { + if (firstEmptyOutput) { + firstEmptyOutput = false; + Log("Compiled "); + } else { + Log(", "); + } + + if (useColoredOutput) { + Log(COLOR_HIGHLIGHT "%s" COLOR_NORMAL, applications[i].name); + } else { + Log("%s", applications[i].name); + } + } + } + + if (!firstEmptyOutput) { + Log(".\n"); + } + + for (uintptr_t i = 0; i < arrlenu(applications); i++) { + if (applications[i].skipped) { + continue; + } + + if (applications[i].error) { + if (useColoredOutput) { + Log(">> Could not build " COLOR_ERROR "%s" COLOR_NORMAL ".\n", applications[i].name); + } else { + Log(">> Could not build %s.\n", applications[i].name); + } + } else if (arrlenu(applications[i].output)) { + if (useColoredOutput) { + Log(">> Built " COLOR_HIGHLIGHT "%s" COLOR_NORMAL ".\n", applications[i].name); + } else { + Log(">> Built %s.\n", applications[i].name); + } + } + + Log("%.*s", (int) arrlen(applications[i].output), applications[i].output); + + if (!applications[i].error) { + for (uintptr_t j = 0; j < arrlenu(applications[i].dependencyFiles); j++) { + ParseDependencies(applications[i].dependencyFiles[j].path, + applications[i].dependencyFiles[j].name, j > 0); + } + } + } + + if (systemBuild) { + LinkKernel(); + OutputSystemConfiguration(); + } + } + + if (driveFile) { + Install(driveFile, partitionSize, partitionLabel); + } + + if (minimalRebuild) { + DependenciesListWrite(); + } + + return encounteredErrors; +} + +#ifdef OS_ESSENCE +void _start() { + int argc; + char **argv; + _init(); + EsPOSIXInitialise(&argc, &argv); + exit(BuildCore(argc, argv)); +} +#endif diff --git a/util/config_editor.c b/util/config_editor.c new file mode 100644 index 0000000..7ec2755 --- /dev/null +++ b/util/config_editor.c @@ -0,0 +1,119 @@ +// TODO Searching for a specific option. +// TODO Option descriptions. + +#include <stdio.h> + +#define UI_LINUX +#define UI_IMPLEMENTATION +#include "luigi.h" + +#include "build_common.h" + +UIWindow *window; +UITable *optionTable; +UILabel *unsavedChangedLabel; + +int OptionTableMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_TABLE_GET_ITEM) { + UITableGetItem *m = (UITableGetItem *) dp; + Option *option = options + m->index; + + if (m->column == 2) { + return snprintf(m->buffer, m->bufferBytes, "%s", option->useDefaultState ? "" : "!"); + } else if (m->column == 1) { + if (option->type == OPTION_TYPE_BOOL) { + return snprintf(m->buffer, m->bufferBytes, "%s", option->state.b ? "Yes" : "No"); + } else if (option->type == OPTION_TYPE_STRING) { + return snprintf(m->buffer, m->bufferBytes, "%s", option->state.s); + } else { + // TODO. + } + } else { + return snprintf(m->buffer, m->bufferBytes, "%s", option->id); + } + } else if (message == UI_MSG_CLICKED) { + int index = UITableHitTest((UITable *) element, element->window->cursorX, element->window->cursorY); + + if (index != -1) { + Option *option = options + index; + + if (option->type == OPTION_TYPE_BOOL) { + option->state.b = !option->state.b; + } else if (option->type == OPTION_TYPE_STRING) { + UIDialogShow(element->window, 0, "New value: \n%t\n%f%b", &option->state.s, "OK"); + } else { + // TODO. + } + + option->useDefaultState = false; + UITableResizeColumns(optionTable); + UIElementRefresh(element); + UILabelSetContent(unsavedChangedLabel, "You have unsaved changes!", -1); + UIElementRefresh(&unsavedChangedLabel->e); + } + } + + return 0; +} + +void ActionDefaults(void *_unused) { + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + options[i].state = options[i].defaultState; + options[i].useDefaultState = true; + } + + UIElementRefresh(&optionTable->e); + UILabelSetContent(unsavedChangedLabel, "You have unsaved changes!", -1); + UIElementRefresh(&unsavedChangedLabel->e); +} + +void ActionSave(void *_unused) { + FILE *f = fopen("bin/config.ini", "wb"); + + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + if (options[i].useDefaultState) { + continue; + } + + if (options[i].type == OPTION_TYPE_BOOL) { + fprintf(f, "%s=%d\n", options[i].id, options[i].state.b); + } else if (options[i].type == OPTION_TYPE_STRING) { + fprintf(f, "%s=%s\n", options[i].id, options[i].state.s ?: ""); + } else { + // TODO. + } + } + + fclose(f); + + UILabelSetContent(unsavedChangedLabel, 0, 0); + UIElementRefresh(&unsavedChangedLabel->e); +} + +int main(int argc, char **argv) { + for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) { + options[i].state = options[i].defaultState; + } + + LoadOptions(); + + UIInitialise(); + window = UIWindowCreate(0, 0, "Config Editor", 0, 0); + UIPanel *panel = UIPanelCreate(&window->e, UI_PANEL_EXPAND); + + UIPanel *toolbar = UIPanelCreate(&panel->e, UI_PANEL_SMALL_SPACING | UI_PANEL_WHITE | UI_PANEL_HORIZONTAL); + UIButtonCreate(&toolbar->e, 0, "Save", -1)->invoke = ActionSave; + UIWindowRegisterShortcut(window, (UIShortcut) { .code = UI_KEYCODE_LETTER('S'), .ctrl = true, .invoke = ActionSave }); + UIButtonCreate(&toolbar->e, 0, "Defaults", -1)->invoke = ActionDefaults; + UISpacerCreate(&toolbar->e, 0, 10, 0); + UILabelCreate(&toolbar->e, 0, "Click an option to modify it. (Changes are local.)", -1); + + optionTable = UITableCreate(&panel->e, UI_ELEMENT_V_FILL, "Option\tValue\tModified"); + optionTable->e.messageUser = OptionTableMessage; + optionTable->itemCount = sizeof(options) / sizeof(options[0]); + UITableResizeColumns(optionTable); + + unsavedChangedLabel = UILabelCreate(&UIPanelCreate(&panel->e, UI_PANEL_WHITE)->e, UI_ELEMENT_H_FILL, 0, 0); + + return UIMessageLoop(); +} diff --git a/util/designer/designer.c b/util/designer/designer.c new file mode 100644 index 0000000..775dff0 --- /dev/null +++ b/util/designer/designer.c @@ -0,0 +1,5541 @@ +// TODO I think this needs to be rewritten... +// TODO Converting linear gradients where all stops are the same color to a solid paint. +// TODO Why does cap mode on dashes not show selected? +// TODO Undoing creating layer, styles, constants. +// TODO Prevent deleting metrics layer. +// TODO Overrides on reused layers (additionally on non-interpolables; but not structural values). +// TODO Global layer list. +// TODO Animations with multiple keyframes. +// TODO More paint types. + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> +#include <assert.h> +#include <string.h> +#include <math.h> +#include <ctype.h> +#include <limits.h> + +#define ES_TEXT_H_LEFT (1 << 0) +#define ES_TEXT_H_CENTER (1 << 1) +#define ES_TEXT_H_RIGHT (1 << 2) +#define ES_TEXT_V_TOP (1 << 3) +#define ES_TEXT_V_CENTER (1 << 4) +#define ES_TEXT_V_BOTTOM (1 << 5) +#define ES_TEXT_ELLIPSIS (1 << 6) +#define ES_TEXT_WRAP (1 << 7) +#define EsCRTsqrtf sqrtf +#define EsAssert assert +#define EsHeapAllocate(x, y) ((y) ? calloc(1, (x)) : malloc((x))) +#define EsHeapFree free +#define EsCRTfabsf fabsf +#define EsCRTfmodf fmodf +#define EsCRTisnanf isnan +#define EsCRTfloorf floorf +#define AbsoluteFloat fabsf +#define EsCRTatan2f atan2f +#define EsCRTsinf sinf +#define EsCRTcosf cosf +#define EsCRTacosf acosf +#define EsCRTceilf ceilf +#define EsMemoryCopy memcpy +#define EsMemoryZero(a, b) memset((a), 0, (b)) +#define ES_INFINITY INFINITY +#define IN_DESIGNER + +typedef struct EsBuffer { + union { const uint8_t *in; uint8_t *out; }; + size_t position, bytes; + bool error; + void *context; +} EsBuffer; + +#include "../luigi.h" +#define NANOSVG_IMPLEMENTATION +#include "../nanosvg.h" +#define STB_TRUETYPE_IMPLEMENTATION +#include "../stb_truetype.h" +#define STB_DS_IMPLEMENTATION +#include "../stb_ds.h" +#include "../../shared/hash.cpp" +#define SHARED_COMMON_WANT_BUFFERS +#include "../../shared/common.cpp" + +#define OP_DO_MOD (1) +#define OP_MAKE_UI (2) +#define OP_EXPORT (3) +#define OP_GET_PALETTE (4) +#define OP_REPLACE_COLOR (5) +#define OP_FIND_COLOR_USERS (6) + +#define PATH_IN_KEYFRAME (0xFFFFFFFE) +#define PATH_ANY (0xFFFFFFFD) + +typedef struct StringOption { + const char *string; +} StringOption; + +typedef struct ModContext { + struct Style *style; + struct Layer *layer; + struct Sequence *sequence; + struct Keyframe *keyframe; +} ModContext; + +const uint32_t saveFormatVersion = 21; + +void SetSelectedItems(ModContext context); +void ColorListRefresh(); + +#define MOD_CONTEXT(style, layer, sequence, keyframe) ((ModContext) { (style), (layer), (sequence), (keyframe) }) + +#define REFLECT_IMPLEMENTATION +#include "reflect.h" +#include "../../bin/designer.h" + +typedef struct PaletteItem { + uint32_t key; + int value; +} PaletteItem; + +typedef struct ColorUsersItem { + uint32_t key; + Style **value; +} ColorUsersItem; + +PaletteItem *palette; +ColorUsersItem *colorUsers; +uint32_t replaceColorFrom, replaceColorTo; +void *currentPaletteOpLayer; + +void PropertyOp(RfState *state, RfItem *item, void *pointer) { + Property *property = (Property *) pointer; + + if (state->op == RF_OP_FREE) { + free(property->path); + RfStructOp(state, item, pointer); + } else if (state->op == RF_OP_SAVE) { + uint8_t count = 0; + + if (property->path) { + for (; property->path[count] != RF_PATH_TERMINATOR; count++); + state->access(state, &count, sizeof(count)); + + for (uintptr_t i = 0; property->path[i] != RF_PATH_TERMINATOR; i++) { + RfIntegerSave(state, property->path + i, sizeof(uint32_t)); + } + } else { + count = 0xFF; + state->access(state, &count, sizeof(count)); + } + + RfStructOp(state, item, pointer); + } else if (state->op == RF_OP_LOAD) { + uint8_t count = 0; + state->access(state, &count, sizeof(count)); + + if (count != 0xFF) { + property->path = malloc(sizeof(uint32_t) * (count + 1)); + property->path[count] = RF_PATH_TERMINATOR; + + for (uintptr_t i = 0; i < count; i++) { + RfIntegerLoad(state, property->path + i, sizeof(uint32_t)); + } + } else { + property->path = NULL; + } + + RfStructOp(state, item, pointer); + } else if (state->op == OP_GET_PALETTE || state->op == OP_REPLACE_COLOR || state->op == OP_FIND_COLOR_USERS) { + void *pointer = currentPaletteOpLayer; + RfItem item = {}; + item.type = &Layer_Type; + item.byteCount = sizeof(Layer); + bool success = RfPathResolve((RfPath *) (property->path + 1), &item, &pointer); + assert(success); + + if (item.type->op == StyleColorOp) { + item.type->op(state, &item, property->data.buffer); + } + } else { + RfStructOp(state, item, pointer); + } +} + +#define MSG_PROPERTY_CHANGED ((UIMessage) (UI_MSG_USER + 1)) + +typedef struct MakeUIState { + RfState s; + uint32_t index; + struct MakeUIState *parent; + uint32_t *basePath; + bool recurse, inKeyframe; +} MakeUIState; + +UIWindow *window; +UITable *tableLayers, *tableSequences, *tableKeyframes; +UIButton *buttonAddLayer, *buttonAddExistingLayer, *buttonPublicStyle; + +typedef struct AnimatingValue { + uint16_t offset; +#define ANIMATING_VALUE_TYPE_I8 (1) +#define ANIMATING_VALUE_TYPE_I16 (2) +#define ANIMATING_VALUE_TYPE_COLOR (3) +#define ANIMATING_VALUE_TYPE_FLOAT (4) +#define ANIMATING_VALUE_TYPE_UNUSED (1 << 7) + uint8_t type; + uint8_t layer; + uint16_t duration, elapsed; // Milliseconds. + union { int8_t i8; int16_t i16; uint32_t u32; float f32; } from, to; +} AnimatingValue; + +typedef struct SequenceStateSelector { + uint32_t primary; + bool focused, checked, indeterminate, _default, itemFocus, listFocus, selected, enter, exit; +} SequenceStateSelector; + +UIElement *elementCanvas; +UISlider *previewWidth, *previewHeight, *previewScale; +UIButton *previewTransition, *previewShowGuides, *previewShowComputed, *previewFixAspectRatio; +uint64_t previewTransitionLastTime; +AnimatingValue *animatingValues; +UIPanel *previewPrimaryStatePanel; +UIButton *previewPrimaryStateIdle; +UIButton *previewPrimaryStateHovered; +UIButton *previewPrimaryStatePressed; +UIButton *previewPrimaryStateDisabled; +UIButton *previewStateFocused; +UIButton *previewStateChecked; +UIButton *previewStateIndeterminate; +UIButton *previewStateDefault; +UIButton *previewStateItemFocus; +UIButton *previewStateListFocus; +UIButton *previewStateSelected; +UIButton *previewStateBeforeEnter; +UIButton *previewStateAfterExit; +UIButton *editPoints; +UIColorPicker *previewBackgroundColor; +uint32_t previewPrimaryState; +SequenceStateSelector currentStateSelector; + +UIPanel *panelInspector; +UIElement **inspectorSubscriptions; + +UIWindow *importDialog; +UITextbox *importPathTextbox; +UILabel *importPathMessage; + +Mod *undoStack, *redoStack; +bool modApplyUndo; + +uint32_t *menuPath; + +StyleSet styleSet; +ModContext selected = MOD_CONTEXT(NULL, NULL, NULL, NULL); + +char temporaryOverride[4096]; + +char *filePath, *exportPath, *embedBitmapPath, *stylesPath; + +void ModApply(ModData *mod); + +char *LoadFile(const char *inputFileName, size_t *byteCount); + +void MakeUI(MakeUIState *state, RfItem *item, void *pointer); +void MakeHeaderAndIndentUI(const char *format, RfState *state, RfItem *item, void *pointer); + +#define MAKE_UI(c, p, k) \ + do { \ + for (uintptr_t i = 0; i < (c ## _Type).fieldCount; i++) { \ + MakeUIState state = { 0 }; \ + state.s.op = OP_MAKE_UI; \ + state.index = i; \ + state.recurse = true; \ + state.inKeyframe = k; \ + RfItem item = (c ## _Type).fields[i].item; \ + void *pointer = (uint8_t *) p + (c ## _Type).fields[i].offset; \ + item.type->op(&state.s, &item, pointer); \ + if (state.recurse) MakeUI(&state, &item, pointer); \ + } \ + } while (0) + +// ------------------- Renderer ------------------- + +int ClampInteger(int from, int to, int value) { + if (value < from) return from; + if (value > to) return to; + return value; +} + +float LinearInterpolate(float from, float to, float progress) { + return from + progress * (to - from); +} + +float GammaInterpolate(float from, float to, float progress) { + from = from * from; + to = to * to; + return sqrtf(from + progress * (to - from)); +} + +int MaximumInteger3(int a, int b, int c) { + if (a >= b && a >= c) { + return a; + } else if (b >= c) { + return b; + } else { + return c; + } +} + +int MinimumInteger3(int a, int b, int c) { + if (a <= b && a <= c) { + return a; + } else if (b <= c) { + return b; + } else { + return c; + } +} + +int MaximumInteger(int a, int b) { + if (a >= b) { + return a; + } else { + return b; + } +} + +int MinimumInteger(int a, int b) { + if (a <= b) { + return a; + } else { + return b; + } +} + +typedef struct Corners32 { int32_t tl, tr, bl, br; } Corners32; +typedef struct Rectangle32 { int32_t l, r, t, b; } Rectangle32; +typedef struct EsRectangle { int32_t l, r, t, b; } EsRectangle; + +bool EsRectangleClip(EsRectangle parent, EsRectangle rectangle, EsRectangle *output) { + EsRectangle current = parent; + EsRectangle intersection = { 0 }; + + if (!((current.l > rectangle.r && current.r > rectangle.l) + || (current.t > rectangle.b && current.b > rectangle.t))) { + intersection.l = current.l > rectangle.l ? current.l : rectangle.l; + intersection.t = current.t > rectangle.t ? current.t : rectangle.t; + intersection.r = current.r < rectangle.r ? current.r : rectangle.r; + intersection.b = current.b < rectangle.b ? current.b : rectangle.b; + } + + if (output) { + *output = intersection; + } + + return intersection.l < intersection.r && intersection.t < intersection.b; +} + +void BlendPixel(uint32_t *destinationPixel, uint32_t modified, bool fullAlpha) { + if ((modified & 0xFF000000) == 0xFF000000) { + *destinationPixel = modified; + } else if ((modified & 0xFF000000) == 0x00000000) { + } else if ((*destinationPixel & 0xFF000000) != 0xFF000000 && fullAlpha) { + uint32_t original = *destinationPixel; + uint32_t alpha1 = (modified & 0xFF000000) >> 24; + uint32_t alpha2 = 255 - alpha1; + uint32_t alphaD = (original & 0xFF000000) >> 24; + uint32_t alphaD2 = alphaD * alpha2; + uint32_t alphaOut = alpha1 + (alphaD2 >> 8); + + if (alphaOut) { + uint32_t m2 = alphaD2 / alphaOut; + uint32_t m1 = (alpha1 << 8) / alphaOut; + if (m2 == 0x100) m2--; + if (m1 == 0x100) m1--; + uint32_t r2 = m2 * ((original & 0x000000FF) >> 0); + uint32_t g2 = m2 * ((original & 0x0000FF00) >> 8); + uint32_t b2 = m2 * ((original & 0x00FF0000) >> 16); + uint32_t r1 = m1 * ((modified & 0x000000FF) >> 0); + uint32_t g1 = m1 * ((modified & 0x0000FF00) >> 8); + uint32_t b1 = m1 * ((modified & 0x00FF0000) >> 16); + uint32_t result = (alphaOut << 24) + | (0x00FF0000 & ((b1 + b2) << 8)) + | (0x0000FF00 & ((g1 + g2) << 0)) + | (0x000000FF & ((r1 + r2) >> 8)); + *destinationPixel = result; + } + } else { + uint32_t original = *destinationPixel; + uint32_t alpha1 = (modified & 0xFF000000) >> 24; + uint32_t alpha2 = 255 - alpha1; + uint32_t r2 = alpha2 * ((original & 0x000000FF) >> 0); + uint32_t g2 = alpha2 * ((original & 0x0000FF00) >> 8); + uint32_t b2 = alpha2 * ((original & 0x00FF0000) >> 16); + uint32_t r1 = alpha1 * ((modified & 0x000000FF) >> 0); + uint32_t g1 = alpha1 * ((modified & 0x0000FF00) >> 8); + uint32_t b1 = alpha1 * ((modified & 0x00FF0000) >> 16); + uint32_t result = 0xFF000000 | (0x00FF0000 & ((b1 + b2) << 8)) + | (0x0000FF00 & ((g1 + g2) << 0)) + | (0x000000FF & ((r1 + r2) >> 8)); + *destinationPixel = result; + } +} + +typedef struct EsPaintTarget { + void *bits; + uint32_t width, height, stride; + bool fullAlpha, readOnly; +} EsPaintTarget; + +typedef struct EsPainter { + EsRectangle clip; + EsPaintTarget *target; +} EsPainter; + +#include "../../desktop/renderer.cpp" +#include "../../desktop/theme.cpp" + +// ------------------- Reflect utilities ------------------- + +int StringCompareRaw(const char *s1, ptrdiff_t length1, const char *s2, ptrdiff_t length2) { + while (length1 || length2) { + if (!length1) return -1; + if (!length2) return 1; + + char c1 = *s1; + char c2 = *s2; + + if (c1 != c2) { + return c1 - c2; + } + + length1--; + length2--; + s1++; + s2++; + } + + return 0; +} + +RfData SaveToGrowableBuffer(RfType *type, size_t byteCount, void *options, void *pointer) { + RfGrowableBuffer state = { 0 }; + state.s.op = RF_OP_SAVE; + state.s.allocate = RfRealloc; + state.s.access = RfWriteGrowableBuffer; + RfItem item = { 0 }; + item.type = type; + item.byteCount = byteCount; + item.options = options; + type->op(&state.s, &item, pointer); + state.data.buffer = realloc(state.data.buffer, state.data.byteCount); + return state.data; +} + +bool ArePathsEqual(uint32_t *path1, uint32_t *path2) { + if (!path1 && !path2) return true; + if (!path1 || !path2) return false; + + while (true) { + if (*path1 != *path2) { + return false; + } + + if (*path1 == RF_PATH_TERMINATOR) { + return true; + } + + path1++; + path2++; + } +} + +uint32_t *DuplicatePath(uint32_t *indices) { + uintptr_t count = 0; + for (; indices[count] != RF_PATH_TERMINATOR; count++); + uint32_t *path = (uint32_t *) malloc((count + 1) * sizeof(uint32_t)); + memcpy(path, indices, (count + 1) * sizeof(uint32_t)); + return path; +} + +void PrintPath(uint32_t *indices) { + printf("{ "); + + for (uintptr_t i = 0; indices[i] != RF_PATH_TERMINATOR; i++) { + printf("%d, ", (int32_t) indices[i]); + } + + printf(" }\n"); +} + +void *ResolveDataObject(RfPath *path, RfItem *item) { + RfItem _item; + if (!item) item = &_item; + + void *pointer; + item->options = NULL; + + bool inKeyframe = false; + + if (path->indices[0] == PATH_IN_KEYFRAME) { + inKeyframe = true; + + // PrintPath(path->indices); + + // Has the property been overridden in the keyframe? + for (uintptr_t i = 0; i < arrlenu(selected.keyframe->properties); i++) { + // PrintPath(selected.keyframe->properties[i].path); + + if (ArePathsEqual(path->indices, selected.keyframe->properties[i].path)) { + // Get the RfItem. + pointer = selected.layer; + item->type = &Layer_Type; + item->byteCount = sizeof(Layer); + bool success = RfPathResolve(path + 1, item, &pointer); + assert(success); + assert(sizeof(temporaryOverride) >= sizeof(item->byteCount)); + + // Load the override. + RfGrowableBuffer state = { 0 }; + state.s.allocate = RfRealloc; + state.s.access = RfReadGrowableBuffer; + state.s.op = RF_OP_LOAD; + state.data = selected.keyframe->properties[i].data; + item->type->op(&state.s, item, temporaryOverride); + + // Return the temporary buffer. + return temporaryOverride; + } + } + + path++; + } + + if (selected.layer && selected.sequence && selected.keyframe && !inKeyframe) { + pointer = selected.keyframe; + item->type = &Keyframe_Type; + item->byteCount = sizeof(Keyframe); + } else if (selected.layer && selected.sequence && !inKeyframe) { + pointer = selected.sequence; + item->type = &Sequence_Type; + item->byteCount = sizeof(Sequence); + } else if (selected.layer) { + pointer = selected.layer; + item->type = &Layer_Type; + item->byteCount = sizeof(Layer); + } else { + pointer = selected.style; + item->type = &Style_Type; + item->byteCount = sizeof(Style); + } + + bool success = RfPathResolve(path, item, &pointer); + assert(success); + return pointer; +} + +// ------------------- Exporting ------------------- + +typedef struct PathToOffset { + uint32_t *path; + uintptr_t offset; +} PathToOffset; + +typedef struct ExportState { + RfGrowableBuffer buffer; + uint32_t *pathStack; + PathToOffset *pathToOffsetList; +} ExportState; + +void ExportAddPathToOffset(ExportState *export, uint32_t last, ptrdiff_t offset) { + uintptr_t stackPosition = arrlenu(export->pathStack); + arrput(export->pathStack, last); + arrput(export->pathStack, RF_PATH_TERMINATOR); + PathToOffset pathToOffset = { 0 }; + pathToOffset.path = DuplicatePath(export->pathStack); + pathToOffset.offset = export->buffer.data.byteCount + offset; + arrsetlen(export->pathStack, stackPosition); + arrput(export->pathToOffsetList, pathToOffset); +} + +void ExportAddPathToOffset2(ExportState *export, uint32_t last1, uint32_t last2, ptrdiff_t offset) { + arrput(export->pathStack, last1); + ExportAddPathToOffset(export, last2, offset); + (void) arrpop(export->pathStack); +} + +void ExportAddPathToOffsetForRectangle(ExportState *export, uint32_t last, ptrdiff_t offset) { + uintptr_t stackPosition = arrlenu(export->pathStack); + arrput(export->pathStack, last); + arrput(export->pathStack, RF_PATH_TERMINATOR); + PathToOffset pathToOffset = { 0 }; + pathToOffset.path = DuplicatePath(export->pathStack); + pathToOffset.offset = export->buffer.data.byteCount + offset; + arrsetlen(export->pathStack, stackPosition); + arrput(export->pathToOffsetList, pathToOffset); +} + +void ExportFreePathToOffsetList(PathToOffset *pathToOffsetList) { + for (uintptr_t i = 0; i < arrlenu(pathToOffsetList); i++) { + free(pathToOffsetList[i].path); + } + + arrfree(pathToOffsetList); +} + +RfData ExportToGrowableBuffer(RfType *type, size_t byteCount, void *options, void *pointer, PathToOffset **pathToOffsetList) { + ExportState state = { 0 }; + state.buffer.s.op = OP_EXPORT; + state.buffer.s.allocate = RfRealloc; + state.buffer.s.access = RfWriteGrowableBuffer; + + RfItem item = { 0 }; + item.type = type; + item.byteCount = byteCount; + item.options = options; + + type->op(&state.buffer.s, &item, pointer); + state.buffer.data.buffer = realloc(state.buffer.data.buffer, state.buffer.data.byteCount); + + arrfree(state.pathStack); + + *pathToOffsetList = state.pathToOffsetList; + return state.buffer.data; +} + +uint32_t ColorLookup(uint32_t id) { + for (uintptr_t i = 0; i < arrlenu(styleSet.colors); i++) { + if (styleSet.colors[i]->id == id) { + return styleSet.colors[i]->value; + } + } + + assert(false); + return 0; +} + +Color *ColorLookupPointer(uint32_t id) { + for (uintptr_t i = 0; i < arrlenu(styleSet.colors); i++) { + if (styleSet.colors[i]->id == id) { + return styleSet.colors[i]; + } + } + + assert(false); + return NULL; +} + +#define EXPORT_FIELD(fromType, fromVariable, toType, toVariable, fromField, toField) \ + ExportAddPathToOffset(export, fromType ## _ ## fromField, offsetof(toType, toField)); \ + toVariable.toField = fromVariable->fromField; +#define EXPORT_FIELD_COLOR(fromType, fromVariable, toType, toVariable, fromField, toField) \ + ExportAddPathToOffset(export, fromType ## _ ## fromField, offsetof(toType, toField)); \ + toVariable.toField = ColorLookup(fromVariable->fromField); +#define EXPORT_FIELD_ALIGN(fromType, fromVariable, toType, toVariable, fromHField, fromVField, toField) \ + toVariable.toField = ((fromVariable->fromHField == ALIGN_START) ? ES_TEXT_H_LEFT : 0) \ + | ((fromVariable->fromHField == ALIGN_CENTER) ? ES_TEXT_H_CENTER : 0) \ + | ((fromVariable->fromHField == ALIGN_END) ? ES_TEXT_H_RIGHT : 0) \ + | ((fromVariable->fromVField == ALIGN_START) ? ES_TEXT_V_TOP : 0) \ + | ((fromVariable->fromVField == ALIGN_CENTER) ? ES_TEXT_V_CENTER : 0) \ + | ((fromVariable->fromVField == ALIGN_END) ? ES_TEXT_V_BOTTOM : 0); +#define EXPORT_RECTANGLE8_FIELD(fromType, fromVariable, toType, toVariable, fromField, toField) \ + ExportAddPathToOffset2(export, fromType ## _ ## fromField, Rectangle8_l, offsetof(toType, toField.l)); \ + ExportAddPathToOffset2(export, fromType ## _ ## fromField, Rectangle8_r, offsetof(toType, toField.r)); \ + ExportAddPathToOffset2(export, fromType ## _ ## fromField, Rectangle8_t, offsetof(toType, toField.t)); \ + ExportAddPathToOffset2(export, fromType ## _ ## fromField, Rectangle8_b, offsetof(toType, toField.b)); \ + toVariable.toField = fromVariable->fromField; +#define EXPORT_RECTANGLE16_FIELD(fromType, fromVariable, toType, toVariable, fromField, toField) \ + ExportAddPathToOffset2(export, fromType ## _ ## fromField, Rectangle16_l, offsetof(toType, toField.l)); \ + ExportAddPathToOffset2(export, fromType ## _ ## fromField, Rectangle16_r, offsetof(toType, toField.r)); \ + ExportAddPathToOffset2(export, fromType ## _ ## fromField, Rectangle16_t, offsetof(toType, toField.t)); \ + ExportAddPathToOffset2(export, fromType ## _ ## fromField, Rectangle16_b, offsetof(toType, toField.b)); \ + toVariable.toField.l = fromVariable->fromField.l; \ + toVariable.toField.r = fromVariable->fromField.r; \ + toVariable.toField.t = fromVariable->fromField.t; \ + toVariable.toField.b = fromVariable->fromField.b; + +void PaintSolidOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + PaintSolid *solid = (PaintSolid *) pointer; + ThemePaintSolid themeSolid = { 0 }; + ExportAddPathToOffset((ExportState *) state, PaintSolid_color, offsetof(ThemePaintSolid, color)); + themeSolid.color = ColorLookup(solid->color); + state->access(state, &themeSolid, sizeof(themeSolid)); + } else { + RfStructOp(state, item, pointer); + } +} + +void PaintOverwriteOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + PaintOverwrite *overwrite = (PaintOverwrite *) pointer; + ThemePaintSolid themeSolid = { 0 }; + ExportAddPathToOffset((ExportState *) state, PaintOverwrite_color, offsetof(ThemePaintSolid, color)); + themeSolid.color = ColorLookup(overwrite->color); + state->access(state, &themeSolid, sizeof(themeSolid)); + } else { + RfStructOp(state, item, pointer); + } +} + +void GradientStopOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + GradientStop *stop = (GradientStop *) pointer; + ThemeGradientStop themeStop = { 0 }; + ExportAddPathToOffset((ExportState *) state, GradientStop_color, offsetof(ThemeGradientStop, color)); + themeStop.color = ColorLookup(stop->color); + ExportAddPathToOffset((ExportState *) state, GradientStop_position, offsetof(ThemeGradientStop, position)); + themeStop.position = stop->position; + state->access(state, &themeStop, sizeof(themeStop)); + } else { + RfStructOp(state, item, pointer); + } +} + +void PaintLinearGradientOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + PaintLinearGradient *gradient = (PaintLinearGradient *) pointer; + ThemePaintLinearGradient themeGradient = { 0 }; + EXPORT_FIELD(PaintLinearGradient, gradient, ThemePaintLinearGradient, themeGradient, transformX, transform[0]); + EXPORT_FIELD(PaintLinearGradient, gradient, ThemePaintLinearGradient, themeGradient, transformY, transform[1]); + EXPORT_FIELD(PaintLinearGradient, gradient, ThemePaintLinearGradient, themeGradient, transformStart, transform[2]); + themeGradient.useGammaInterpolation = gradient->useGammaInterpolation; + themeGradient.useDithering = gradient->useDithering; + themeGradient.useSystemHue = gradient->useSystemHue; + themeGradient.stopCount = arrlenu(gradient->stops); + themeGradient.repeatMode = gradient->repeat == GRADIENT_REPEAT_CLAMP ? RAST_REPEAT_CLAMP + : gradient->repeat == GRADIENT_REPEAT_NORMAL ? RAST_REPEAT_NORMAL + : gradient->repeat == GRADIENT_REPEAT_MIRROR ? RAST_REPEAT_MIRROR : 0; + state->access(state, &themeGradient, sizeof(themeGradient)); + uintptr_t stackPosition = arrlenu(export->pathStack); + + for (uintptr_t i = 0; i < arrlenu(gradient->stops); i++) { + arrput(export->pathStack, PaintLinearGradient_stops); + arrput(export->pathStack, i); + GradientStopOp(state, NULL, gradient->stops + i); + arrsetlen(export->pathStack, stackPosition); + } + } else { + RfStructOp(state, item, pointer); + } +} + +void PaintRadialGradientOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + PaintRadialGradient *gradient = (PaintRadialGradient *) pointer; + ThemePaintRadialGradient themeGradient = { 0 }; + EXPORT_FIELD(PaintRadialGradient, gradient, ThemePaintRadialGradient, themeGradient, transform0, transform[0]); + EXPORT_FIELD(PaintRadialGradient, gradient, ThemePaintRadialGradient, themeGradient, transform1, transform[1]); + EXPORT_FIELD(PaintRadialGradient, gradient, ThemePaintRadialGradient, themeGradient, transform2, transform[2]); + EXPORT_FIELD(PaintRadialGradient, gradient, ThemePaintRadialGradient, themeGradient, transform3, transform[3]); + EXPORT_FIELD(PaintRadialGradient, gradient, ThemePaintRadialGradient, themeGradient, transform4, transform[4]); + EXPORT_FIELD(PaintRadialGradient, gradient, ThemePaintRadialGradient, themeGradient, transform5, transform[5]); + themeGradient.useGammaInterpolation = gradient->useGammaInterpolation; + themeGradient.stopCount = arrlenu(gradient->stops); + themeGradient.repeatMode = gradient->repeat == GRADIENT_REPEAT_CLAMP ? RAST_REPEAT_CLAMP + : gradient->repeat == GRADIENT_REPEAT_NORMAL ? RAST_REPEAT_NORMAL + : gradient->repeat == GRADIENT_REPEAT_MIRROR ? RAST_REPEAT_MIRROR : 0; + state->access(state, &themeGradient, sizeof(themeGradient)); + uintptr_t stackPosition = arrlenu(export->pathStack); + + for (uintptr_t i = 0; i < arrlenu(gradient->stops); i++) { + arrput(export->pathStack, PaintRadialGradient_stops); + arrput(export->pathStack, i); + GradientStopOp(state, NULL, gradient->stops + i); + arrsetlen(export->pathStack, stackPosition); + } + } else { + RfStructOp(state, item, pointer); + } +} + +Layer *LayerLookup(uint64_t id) { + for (uintptr_t i = 0; i < arrlenu(styleSet.layers); i++) { + if (styleSet.layers[i]->id == id) { + return styleSet.layers[i]; + } + } + + return NULL; +} + +void LayerBoxOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + LayerBox *box = (LayerBox *) pointer; + + ThemeLayerBox themeBox = { 0 }; + ExportAddPathToOffset2(export, LayerBox_borders, Rectangle8_l, offsetof(ThemeLayerBox, borders.l)); + ExportAddPathToOffset2(export, LayerBox_borders, Rectangle8_r, offsetof(ThemeLayerBox, borders.r)); + ExportAddPathToOffset2(export, LayerBox_borders, Rectangle8_t, offsetof(ThemeLayerBox, borders.t)); + ExportAddPathToOffset2(export, LayerBox_borders, Rectangle8_b, offsetof(ThemeLayerBox, borders.b)); + themeBox.borders = box->borders; + ExportAddPathToOffset2(export, LayerBox_corners, Corners8_tl, offsetof(ThemeLayerBox, corners.tl)); + ExportAddPathToOffset2(export, LayerBox_corners, Corners8_tr, offsetof(ThemeLayerBox, corners.tr)); + ExportAddPathToOffset2(export, LayerBox_corners, Corners8_bl, offsetof(ThemeLayerBox, corners.bl)); + ExportAddPathToOffset2(export, LayerBox_corners, Corners8_br, offsetof(ThemeLayerBox, corners.br)); + themeBox.corners = box->corners; + if (box->blurred) themeBox.flags |= THEME_LAYER_BOX_IS_BLURRED; + if (box->autoCorners) themeBox.flags |= THEME_LAYER_BOX_AUTO_CORNERS; + if (box->autoBorders) themeBox.flags |= THEME_LAYER_BOX_AUTO_BORDERS; + if (box->shadowHiding) themeBox.flags |= THEME_LAYER_BOX_SHADOW_HIDING; + if (box->shadowCut) themeBox.flags |= THEME_LAYER_BOX_SHADOW_CUT; + themeBox.mainPaintType = box->mainPaint.tag == Paint_solid + 1 ? THEME_PAINT_SOLID + : box->mainPaint.tag == Paint_linearGradient + 1 ? THEME_PAINT_LINEAR_GRADIENT + : box->mainPaint.tag == Paint_overwrite + 1 ? THEME_PAINT_OVERWRITE : 0; + themeBox.borderPaintType = box->borderPaint.tag == Paint_solid + 1 ? THEME_PAINT_SOLID + : box->borderPaint.tag == Paint_linearGradient + 1 ? THEME_PAINT_LINEAR_GRADIENT + : box->borderPaint.tag == Paint_overwrite + 1 ? THEME_PAINT_OVERWRITE : 0; + state->access(state, &themeBox, sizeof(themeBox)); + + uintptr_t stackPosition = arrlenu(export->pathStack); + + if (box->mainPaint.tag) { + RfField *mainPaintField = Paint_Type.fields + box->mainPaint.tag - 1; + arrput(export->pathStack, LayerBox_mainPaint); + arrput(export->pathStack, box->mainPaint.tag - 1); + mainPaintField->item.type->op(state, &mainPaintField->item, (uint8_t *) pointer + + mainPaintField->offset + LayerBox_Type.fields[LayerBox_mainPaint].offset); + arrsetlen(export->pathStack, stackPosition); + } + + if (box->borderPaint.tag) { + RfField *borderPaintField = Paint_Type.fields + box->borderPaint.tag - 1; + arrput(export->pathStack, LayerBox_borderPaint); + arrput(export->pathStack, box->borderPaint.tag - 1); + borderPaintField->item.type->op(state, &borderPaintField->item, (uint8_t *) pointer + + borderPaintField->offset + LayerBox_Type.fields[LayerBox_borderPaint].offset); + arrsetlen(export->pathStack, stackPosition); + } + } else { + RfStructOp(state, item, pointer); + } +} + +void LayerTextOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + LayerText *layer = (LayerText *) pointer; + + ThemeLayerText themeLayer = { 0 }; + + EXPORT_FIELD_COLOR(LayerText, layer, ThemeLayerText, themeLayer, color, color); + EXPORT_FIELD(LayerText, layer, ThemeLayerText, themeLayer, blur, blur); + + state->access(state, &themeLayer, sizeof(themeLayer)); + } else { + RfStructOp(state, item, pointer); + } +} + +void PathFillSolidOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + } else { + RfStructOp(state, item, pointer); + } +} + +void PathFillContourOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + PathFillContour *fill = (PathFillContour *) pointer; + + ThemeLayerPathFillContour themeFill = { 0 }; + + EXPORT_FIELD(PathFillContour, fill, ThemeLayerPathFillContour, themeFill, internalWidth, internalWidth); + EXPORT_FIELD(PathFillContour, fill, ThemeLayerPathFillContour, themeFill, externalWidth, externalWidth); + + if (fill->joinMode != JOIN_MODE_BEVEL) { + EXPORT_FIELD(PathFillContour, fill, ThemeLayerPathFillContour, themeFill, miterLimit, miterLimit); + } + + themeFill.mode = (fill->joinMode == JOIN_MODE_MITER ? RAST_LINE_JOIN_MITER + : fill->joinMode == JOIN_MODE_ROUND ? RAST_LINE_JOIN_ROUND + : fill->joinMode == JOIN_MODE_BEVEL ? RAST_LINE_JOIN_MITER : 0) + | ((fill->capMode == CAP_MODE_FLAT ? RAST_LINE_CAP_FLAT + : fill->capMode == CAP_MODE_ROUND ? RAST_LINE_CAP_ROUND + : fill->capMode == CAP_MODE_SQUARE ? RAST_LINE_CAP_SQUARE : 0) << 2) + | (fill->integerWidthsOnly ? 0x80 : 0); + + state->access(state, &themeFill, sizeof(themeFill)); + } else { + RfStructOp(state, item, pointer); + } +} + +void PathFillDashOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + PathFillDash *fill = (PathFillDash *) pointer; + + ThemeLayerPathFillDash themeFill = { 0 }; + + EXPORT_FIELD(PathFillDash, fill, ThemeLayerPathFillDash, themeFill, gap, gap); + EXPORT_FIELD(PathFillDash, fill, ThemeLayerPathFillDash, themeFill, length, length); + + arrput(export->pathStack, PathFillDash_contour); + + EXPORT_FIELD(PathFillContour, (&fill->contour), ThemeLayerPathFillContour, themeFill.contour, internalWidth, internalWidth); + EXPORT_FIELD(PathFillContour, (&fill->contour), ThemeLayerPathFillContour, themeFill.contour, externalWidth, externalWidth); + + if (fill->contour.joinMode != JOIN_MODE_BEVEL) { + EXPORT_FIELD(PathFillContour, (&fill->contour), ThemeLayerPathFillContour, themeFill.contour, miterLimit, miterLimit); + } + + (void) arrpop(export->pathStack); + + themeFill.contour.mode = (fill->contour.joinMode == JOIN_MODE_MITER ? RAST_LINE_JOIN_MITER + : fill->contour.joinMode == JOIN_MODE_ROUND ? RAST_LINE_JOIN_ROUND + : fill->contour.joinMode == JOIN_MODE_BEVEL ? RAST_LINE_JOIN_MITER : 0) + | ((fill->contour.capMode == CAP_MODE_FLAT ? RAST_LINE_CAP_FLAT + : fill->contour.capMode == CAP_MODE_ROUND ? RAST_LINE_CAP_ROUND + : fill->contour.capMode == CAP_MODE_SQUARE ? RAST_LINE_CAP_SQUARE : 0) << 2) + | (fill->contour.integerWidthsOnly ? 0x80 : 0); + + state->access(state, &themeFill, sizeof(themeFill)); + } else if (state->op == OP_MAKE_UI) { + MakeHeaderAndIndentUI("Dash %d", state, item, pointer); + } else { + RfStructOp(state, item, pointer); + } +} + +void PathFillDashedOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + PathFillDashed *fill = (PathFillDashed *) pointer; + uintptr_t stackPosition = arrlenu(export->pathStack); + + for (uintptr_t i = 0; i < arrlenu(fill->dashes); i++) { + arrput(export->pathStack, PathFillDashed_dashes); + arrput(export->pathStack, i); + PathFillDashOp(state, NULL, fill->dashes + i); + arrsetlen(export->pathStack, stackPosition); + } + } else { + RfStructOp(state, item, pointer); + } +} + +void PathFillOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + PathFill *fill = (PathFill *) pointer; + + ThemeLayerPathFill themeFill = { 0 }; + themeFill.paintAndFillType |= fill->paint.tag == Paint_solid + 1 ? THEME_PAINT_SOLID + : fill->paint.tag == Paint_linearGradient + 1 ? THEME_PAINT_LINEAR_GRADIENT + : fill->paint.tag == Paint_radialGradient + 1 ? THEME_PAINT_RADIAL_GRADIENT + : fill->paint.tag == Paint_overwrite + 1 ? THEME_PAINT_OVERWRITE : 0; + themeFill.paintAndFillType |= fill->mode.tag == PathFillMode_solid + 1 ? THEME_PATH_FILL_SOLID + : fill->mode.tag == PathFillMode_contour + 1 ? THEME_PATH_FILL_CONTOUR + : fill->mode.tag == PathFillMode_dashed + 1 ? THEME_PATH_FILL_DASHED : 0; + themeFill.dashCount = fill->mode.tag == PathFillMode_dashed + 1 ? arrlen(fill->mode.dashed.dashes) : 0; + state->access(state, &themeFill, sizeof(themeFill)); + + uintptr_t stackPosition = arrlenu(export->pathStack); + + if (fill->paint.tag) { + RfField *paintField = Paint_Type.fields + fill->paint.tag - 1; + arrput(export->pathStack, PathFill_paint); + arrput(export->pathStack, fill->paint.tag - 1); + paintField->item.type->op(state, &paintField->item, (uint8_t *) pointer + + paintField->offset + PathFill_Type.fields[PathFill_paint].offset); + arrsetlen(export->pathStack, stackPosition); + } + + if (fill->mode.tag) { + RfField *modeField = PathFillMode_Type.fields + fill->mode.tag - 1; + arrput(export->pathStack, PathFill_mode); + arrput(export->pathStack, fill->mode.tag - 1); + modeField->item.type->op(state, &modeField->item, (uint8_t *) pointer + + modeField->offset + PathFill_Type.fields[PathFill_mode].offset); + arrsetlen(export->pathStack, stackPosition); + } + } else if (state->op == OP_MAKE_UI) { + MakeHeaderAndIndentUI("Fill %d", state, item, pointer); + } else { + RfStructOp(state, item, pointer); + } +} + +void LayerPathOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + LayerPath *layer = (LayerPath *) pointer; + + ThemeLayerPath themeLayer = { 0 }; + if (layer->evenOdd) themeLayer.flags |= THEME_LAYER_PATH_FILL_EVEN_ODD; + if (layer->closed) themeLayer.flags |= THEME_LAYER_PATH_CLOSED; + themeLayer.pointCount = arrlen(layer->points); + themeLayer.fillCount = arrlen(layer->fills); + EXPORT_FIELD(LayerPath, layer, ThemeLayerPath, themeLayer, alpha, alpha); + state->access(state, &themeLayer, sizeof(themeLayer)); + + uintptr_t stackPosition = arrlenu(export->pathStack); + + for (uintptr_t i = 0; i < arrlenu(layer->points); i++) { + arrput(export->pathStack, LayerPath_points); + arrput(export->pathStack, i); + PathPointOp(state, NULL, layer->points + i); + arrsetlen(export->pathStack, stackPosition); + } + + for (uintptr_t i = 0; i < arrlenu(layer->fills); i++) { + arrput(export->pathStack, LayerPath_fills); + arrput(export->pathStack, i); + PathFillOp(state, NULL, layer->fills + i); + arrsetlen(export->pathStack, stackPosition); + } + } else { + RfStructOp(state, item, pointer); + } +} + +Rectangle8 StyleCalculateMaximumGlobalOutsets(uint64_t *styleLayers) { + Rectangle8 globalOutsets = { 0 }; + + for (uintptr_t i = 0; i < arrlenu(styleLayers); i++) { + Layer *layer = LayerLookup(styleLayers[i]); + + if (layer->base.tag != LayerBase_metrics + 1) { + continue; + } + + globalOutsets.l = MaximumInteger(0, -layer->base.metrics.globalOffset.l); + globalOutsets.r = MaximumInteger(0, layer->base.metrics.globalOffset.r); + globalOutsets.t = MaximumInteger(0, -layer->base.metrics.globalOffset.t); + globalOutsets.b = MaximumInteger(0, layer->base.metrics.globalOffset.b); + + for (uintptr_t j = 0; j < arrlenu(layer->sequences); j++) { + for (uintptr_t k = 0; k < arrlenu(layer->sequences[j]->keyframes); k++) { + for (uintptr_t l = 0; l < arrlenu(layer->sequences[j]->keyframes[k]->properties); l++) { + Property property = layer->sequences[j]->keyframes[k]->properties[l]; + + if (property.path[0] != PATH_IN_KEYFRAME || property.path[1] != Layer_base + || property.path[2] != 0 || property.path[3] != LayerMetrics_globalOffset) { + continue; + } + + int8_t value = 0; + RfGrowableBuffer state = { 0 }; + state.s.access = RfReadGrowableBuffer; + state.data = property.data; + state.s.access(&state.s, &value, sizeof(int8_t)); + + if (layer->position.l == 0 && -value > globalOutsets.l && property.path[4] == Rectangle8_l) { + globalOutsets.l = -value; + } + + if (layer->position.r == 100 && value > globalOutsets.r && property.path[4] == Rectangle8_r) { + globalOutsets.r = value; + } + + if (layer->position.t == 0 && -value > globalOutsets.t && property.path[4] == Rectangle8_t) { + globalOutsets.t = -value; + } + + if (layer->position.b == 100 && value > globalOutsets.b && property.path[4] == Rectangle8_b) { + globalOutsets.b = value; + } + } + } + } + + break; + } + + return globalOutsets; +} + +Rectangle8 Rectangle8Add(Rectangle8 a, Rectangle8 b) { + a.l += b.l; + a.t += b.t; + a.r += b.r; + a.b += b.b; + return a; +} + +Rectangle8 StyleCalculatePaintOutsets(uint64_t *styleLayers) { + Rectangle8 paintOutsets = { 0 }; + + for (uintptr_t i = 0; i < arrlenu(styleLayers); i++) { + Layer *layer = LayerLookup(styleLayers[i]); + + if (layer->position.l == 0 && -layer->offset.l > paintOutsets.l) { + paintOutsets.l = -layer->offset.l; + } + + if (layer->position.r == 100 && layer->offset.r > paintOutsets.r) { + paintOutsets.r = layer->offset.r; + } + + if (layer->position.t == 0 && -layer->offset.t > paintOutsets.t) { + paintOutsets.t = -layer->offset.t; + } + + if (layer->position.b == 100 && layer->offset.b > paintOutsets.b) { + paintOutsets.b = layer->offset.b; + } + + for (uintptr_t j = 0; j < arrlenu(layer->sequences); j++) { + for (uintptr_t k = 0; k < arrlenu(layer->sequences[j]->keyframes); k++) { + for (uintptr_t l = 0; l < arrlenu(layer->sequences[j]->keyframes[k]->properties); l++) { + Property property = layer->sequences[j]->keyframes[k]->properties[l]; + + if (property.path[0] != PATH_IN_KEYFRAME || property.path[1] != Layer_offset) { + continue; + } + + int8_t value = 0; + RfGrowableBuffer state = { 0 }; + state.s.access = RfReadGrowableBuffer; + state.data = property.data; + state.s.access(&state.s, &value, sizeof(int8_t)); + + if (layer->position.l == 0 && -value > paintOutsets.l && property.path[2] == Rectangle8_l) { + paintOutsets.l = -value; + } + + if (layer->position.r == 100 && value > paintOutsets.r && property.path[2] == Rectangle8_r) { + paintOutsets.r = value; + } + + if (layer->position.t == 0 && -value > paintOutsets.t && property.path[2] == Rectangle8_t) { + paintOutsets.t = -value; + } + + if (layer->position.b == 100 && value > paintOutsets.b && property.path[2] == Rectangle8_b) { + paintOutsets.b = value; + } + } + } + } + } + + return Rectangle8Add(paintOutsets, StyleCalculateMaximumGlobalOutsets(styleLayers)); +} + +Rectangle8 StyleCalculateOpaqueInsets(uint64_t *styleLayers) { + Rectangle8 opaqueInsets = (Rectangle8) { 0x7F, 0x7F, 0x7F, 0x7F }; + + for (uintptr_t i = 0; i < arrlenu(styleLayers); i++) { + Layer *layer = LayerLookup(styleLayers[i]); + + if (layer->position.l != 0 || layer->position.r != 100 || layer->position.t != 0 || layer->position.b != 100 + || layer->base.tag != LayerBase_box + 1 || layer->base.box.shadowHiding || layer->base.box.blurred) { + continue; + } + + Paint *paint = &layer->base.box.mainPaint; + + bool isOpaque = false; + + if (paint->tag == Paint_solid + 1) { + isOpaque = (paint->solid.color & 0xFF000000) == 0xFF000000; + } else if (paint->tag == Paint_linearGradient + 1) { + isOpaque = true; + + for (uintptr_t j = 0; j < arrlenu(paint->linearGradient.stops); j++) { + if ((paint->linearGradient.stops[j].color & 0xFF000000) != 0xFF000000) { + isOpaque = false; + } + } + } else if (paint->tag == Paint_overwrite + 1) { + isOpaque = true; + } + + Rectangle8 largestBorders = layer->base.box.borders; + Corners8 largestCorners = layer->base.box.corners; + + for (uintptr_t j = 0; j < arrlenu(layer->sequences); j++) { + for (uintptr_t k = 0; k < arrlenu(layer->sequences[j]->keyframes); k++) { + for (uintptr_t l = 0; l < arrlenu(layer->sequences[j]->keyframes[k]->properties); l++) { + Property property = layer->sequences[j]->keyframes[k]->properties[l]; + + if (property.path[0] == PATH_IN_KEYFRAME && property.path[1] == Layer_base + && property.path[2] == LayerBase_box && property.path[3] == LayerBox_borders) { + int8_t value = 0; + RfGrowableBuffer state = { 0 }; + state.s.access = RfReadGrowableBuffer; + state.data = property.data; + state.s.access(&state.s, &value, sizeof(int8_t)); + + if (property.path[4] == Rectangle8_l && largestBorders.l < value) largestBorders.l = value; + if (property.path[4] == Rectangle8_r && largestBorders.r < value) largestBorders.r = value; + if (property.path[4] == Rectangle8_t && largestBorders.t < value) largestBorders.t = value; + if (property.path[4] == Rectangle8_b && largestBorders.b < value) largestBorders.b = value; + } else if (property.path[0] == PATH_IN_KEYFRAME && property.path[1] == Layer_base + && property.path[2] == LayerBase_box && property.path[3] == LayerBox_corners) { + int8_t value = 0; + RfGrowableBuffer state = { 0 }; + state.s.access = RfReadGrowableBuffer; + state.data = property.data; + state.s.access(&state.s, &value, sizeof(int8_t)); + + if (property.path[4] == Corners8_tl && largestCorners.tl < value) largestCorners.tl = value; + if (property.path[4] == Corners8_tr && largestCorners.tr < value) largestCorners.tr = value; + if (property.path[4] == Corners8_bl && largestCorners.bl < value) largestCorners.bl = value; + if (property.path[4] == Corners8_br && largestCorners.br < value) largestCorners.br = value; + } + + if (property.path[0] != PATH_IN_KEYFRAME || property.path[1] != Layer_base + || property.path[2] != LayerBase_box || property.path[3] != LayerBox_mainPaint + || property.path[4] != paint->tag - 1) { + continue; + } + + if (paint->tag == Paint_solid + 1) { + if (property.path[5] != PaintSolid_color) { + continue; + } + } else if (paint->tag == Paint_linearGradient + 1) { + if (property.path[5] != PaintLinearGradient_stops + || property.path[7] != GradientStop_color) { + continue; + } + } + + uint32_t value = 0; + RfGrowableBuffer state = { 0 }; + state.s.access = RfReadGrowableBuffer; + state.data = property.data; + state.s.access(&state.s, &value, sizeof(uint32_t)); + + if ((value & 0xFF000000) != 0xFF000000) { + isOpaque = false; + } + } + } + } + + if (isOpaque) { + opaqueInsets.l = MinimumInteger(opaqueInsets.l, MaximumInteger3(largestCorners.tl, largestCorners.bl, largestBorders.l)); + opaqueInsets.r = MinimumInteger(opaqueInsets.r, MaximumInteger3(largestCorners.tr, largestCorners.br, largestBorders.r)); + opaqueInsets.t = MinimumInteger(opaqueInsets.t, MaximumInteger3(largestCorners.tl, largestCorners.tr, largestBorders.t)); + opaqueInsets.b = MinimumInteger(opaqueInsets.b, MaximumInteger3(largestCorners.bl, largestCorners.br, largestBorders.b)); + } + } + + return Rectangle8Add(opaqueInsets, StyleCalculateMaximumGlobalOutsets(styleLayers)); +} + +Rectangle8 StyleCalculateApproximateBorders(uint64_t *styleLayers) { + for (uintptr_t i = 0; i < arrlenu(styleLayers); i++) { + Layer *layer = LayerLookup(styleLayers[i]); + + if (layer->position.l != 0 || layer->position.r != 100 || layer->position.t != 0 || layer->position.b != 100 + || layer->base.tag != LayerBase_box + 1 || layer->base.box.shadowHiding + || layer->base.box.blurred || !layer->base.box.borderPaint.tag + || layer->mode != LAYER_MODE_BACKGROUND) { + continue; + } + + return layer->base.box.borders; + } + + return (Rectangle8) { 0 }; +} + +void LayerMetricsOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ThemeMetrics metrics = { 0 }; + ExportState *export = (ExportState *) state; + LayerMetrics *layer = (LayerMetrics *) pointer; + LayerMetrics *inherit = NULL; + + if (layer->inheritText.byteCount) { + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + Style *style = styleSet.styles[i]; + + if (layer->inheritText.byteCount == style->name.byteCount + && 0 == memcmp(layer->inheritText.buffer, style->name.buffer, style->name.byteCount)) { + inherit = &LayerLookup(style->layers[0])->base.metrics; + break; + } + } + } + + metrics.insets.l = layer->insets.l; + metrics.insets.r = layer->insets.r; + metrics.insets.t = layer->insets.t; + metrics.insets.b = layer->insets.b; + metrics.clipEnabled = layer->clipEnabled == CLIP_MODE_ENABLED; + metrics.clipInsets.l = layer->clipInsets.l; + metrics.clipInsets.r = layer->clipInsets.r; + metrics.clipInsets.t = layer->clipInsets.t; + metrics.clipInsets.b = layer->clipInsets.b; + metrics.cursor = layer->cursor; + metrics.preferredWidth = layer->preferredSize.width; + metrics.preferredHeight = layer->preferredSize.height; + metrics.minimumWidth = layer->minimumSize.width; + metrics.minimumHeight = layer->minimumSize.height; + metrics.maximumWidth = layer->maximumSize.width; + metrics.maximumHeight = layer->maximumSize.height; + metrics.gapMajor = layer->gaps.major; + metrics.gapMinor = layer->gaps.minor; + metrics.gapWrap = layer->gaps.wrap; + EXPORT_RECTANGLE16_FIELD(LayerMetrics, layer, ThemeMetrics, metrics, globalOffset, globalOffset); + + int fontFamily = inherit ? inherit->fontFamily : layer->fontFamily; + metrics.fontFamily = fontFamily == FONT_FAMILY_SANS ? 0xFFFF : fontFamily == FONT_FAMILY_SERIF ? 0xFFFE : 0xFFFD; + + if (inherit) { + EXPORT_FIELD_COLOR(LayerMetrics, inherit, ThemeMetrics, metrics, textColor, textColor); + EXPORT_FIELD_COLOR(LayerMetrics, inherit, ThemeMetrics, metrics, selectedBackground, selectedBackground); + EXPORT_FIELD_COLOR(LayerMetrics, inherit, ThemeMetrics, metrics, selectedText, selectedText); + EXPORT_FIELD(LayerMetrics, inherit, ThemeMetrics, metrics, textSize, textSize); + EXPORT_FIELD(LayerMetrics, inherit, ThemeMetrics, metrics, fontWeight, fontWeight); + EXPORT_FIELD(LayerMetrics, inherit, ThemeMetrics, metrics, italic, isItalic); + } else { + EXPORT_FIELD_COLOR(LayerMetrics, layer, ThemeMetrics, metrics, textColor, textColor); + EXPORT_FIELD_COLOR(LayerMetrics, layer, ThemeMetrics, metrics, selectedBackground, selectedBackground); + EXPORT_FIELD_COLOR(LayerMetrics, layer, ThemeMetrics, metrics, selectedText, selectedText); + EXPORT_FIELD(LayerMetrics, layer, ThemeMetrics, metrics, textSize, textSize); + EXPORT_FIELD(LayerMetrics, layer, ThemeMetrics, metrics, fontWeight, fontWeight); + EXPORT_FIELD(LayerMetrics, layer, ThemeMetrics, metrics, italic, isItalic); + } + + EXPORT_FIELD(LayerMetrics, layer, ThemeMetrics, metrics, iconSize, iconSize); + EXPORT_FIELD_COLOR(LayerMetrics, layer, ThemeMetrics, metrics, iconColor, iconColor); + EXPORT_FIELD_ALIGN(LayerMetrics, layer, ThemeMetrics, metrics, textHorizontalAlign, textVerticalAlign, textAlign); + if (layer->ellipsis) metrics.textAlign |= ES_TEXT_ELLIPSIS; + if (layer->wrapText) metrics.textAlign |= ES_TEXT_WRAP; + state->access(state, &metrics, sizeof(metrics)); + } else { + RfStructOp(state, item, pointer); + } +} + +void LayerOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + Layer *layer = (Layer *) pointer; + ThemeLayer themeLayer = { 0 }; + ExportAddPathToOffset2(export, Layer_offset, Rectangle8_l, offsetof(ThemeLayer, offset.l)); + ExportAddPathToOffset2(export, Layer_offset, Rectangle8_r, offsetof(ThemeLayer, offset.r)); + ExportAddPathToOffset2(export, Layer_offset, Rectangle8_t, offsetof(ThemeLayer, offset.t)); + ExportAddPathToOffset2(export, Layer_offset, Rectangle8_b, offsetof(ThemeLayer, offset.b)); + themeLayer.offset = layer->offset; + ExportAddPathToOffset2(export, Layer_position, Rectangle8_l, offsetof(ThemeLayer, position.l)); + ExportAddPathToOffset2(export, Layer_position, Rectangle8_r, offsetof(ThemeLayer, position.r)); + ExportAddPathToOffset2(export, Layer_position, Rectangle8_t, offsetof(ThemeLayer, position.t)); + ExportAddPathToOffset2(export, Layer_position, Rectangle8_b, offsetof(ThemeLayer, position.b)); + themeLayer.position = layer->position; + themeLayer.mode = layer->mode; + if (layer->base.tag == LayerBase_box + 1) themeLayer.type = THEME_LAYER_BOX; + if (layer->base.tag == LayerBase_metrics + 1) themeLayer.type = THEME_LAYER_METRICS; + if (layer->base.tag == LayerBase_text + 1) themeLayer.type = THEME_LAYER_TEXT; + if (layer->base.tag == LayerBase_path + 1) themeLayer.type = THEME_LAYER_PATH; + assert(themeLayer.type); + state->access(state, &themeLayer, sizeof(themeLayer)); + uintptr_t stackPosition = arrlenu(export->pathStack); + RfField *baseField = LayerBase_Type.fields + layer->base.tag - 1; + arrput(export->pathStack, Layer_base); + arrput(export->pathStack, 0); + baseField->item.type->op(state, &baseField->item, (uint8_t *) pointer + + baseField->offset + Layer_Type.fields[Layer_base].offset); + arrsetlen(export->pathStack, stackPosition); + } else if (state->op == OP_GET_PALETTE || state->op == OP_REPLACE_COLOR || state->op == OP_FIND_COLOR_USERS) { + currentPaletteOpLayer = pointer; + } else { + RfStructOp(state, item, pointer); + } +} + +void StyleSetOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + ExportState *export = (ExportState *) state; + StyleSet *styleSet = (StyleSet *) pointer; + + // Load the cursors image. + + size_t bitmapBytes = 0; + char *bitmap = NULL; + + if (embedBitmapPath) { + bitmap = LoadFile(embedBitmapPath, &bitmapBytes); + + if (!bitmap) { + printf("Error: Could not load the embedded bitmap!\n"); + return; + } + } + + // Write the header. + + ThemeHeader header = { 0 }; + header.signature = THEME_HEADER_SIGNATURE; + header.styleCount = arrlenu(styleSet->styles); + header.constantCount = arrlenu(styleSet->constants); + header.bitmapBytes = bitmapBytes; + state->access(state, &header, sizeof(header)); + assert((export->buffer.data.byteCount & 3) == 0); + + // Write the list of styles. + + uint32_t styleListOffset = export->buffer.data.byteCount; + + FILE *f = stylesPath ? fopen(stylesPath, "wb") : NULL; + + for (uintptr_t i = 0; i < header.styleCount; i++) { + Style *style = styleSet->styles[i]; + ThemeStyle entry = { 0 }; + entry.id = (style->id << 1) | 1; + entry.layerCount = arrlenu(style->layers); + entry.paintOutsets = StyleCalculatePaintOutsets(style->layers); + entry.opaqueInsets = StyleCalculateOpaqueInsets(style->layers); + entry.approximateBorders = StyleCalculateApproximateBorders(style->layers); + state->access(state, &entry, sizeof(entry)); + assert((export->buffer.data.byteCount & 3) == 0); + + printf("exporting '%.*s' (id: %ld)\n", (int) style->name.byteCount, (char *) style->name.buffer, (style->id << 1) | 1); + + if (style->id && stylesPath) { + fprintf(f, "%s ES_STYLE_", style->publicStyle ? "define" : "define_private"); + + bool dot = false; + + for (uintptr_t j = 0; j < style->name.byteCount; j++) { + char c = ((const char *) style->name.buffer)[j]; + + if (c == '.') { + fprintf(f, "_"); + dot = true; + } else if (c >= 'A' && c <= 'Z' && j && !dot) { + fprintf(f, "_%c", c); + } else { + fprintf(f, "%c", toupper(c)); + dot = false; + } + } + + fprintf(f, " (ES_STYLE_CAST(%ld))\n", (style->id << 1) | 1); + } + } + + if (stylesPath) fclose(f); + + // Write the list of constants. + + uint32_t constantListOffset = export->buffer.data.byteCount; + + for (uintptr_t i = 0; i < header.constantCount; i++) { + Constant *constant = styleSet->constants[i]; + ThemeConstant entry = { 0 }; + entry.hash = CalculateCRC64(constant->key.buffer, constant->key.byteCount, 0); + state->access(state, &entry, sizeof(entry)); + assert((export->buffer.data.byteCount & 3) == 0); + } + + for (uintptr_t i = 0; i < header.constantCount; i++) { + Constant *constant = styleSet->constants[i]; + ThemeConstant *entry = (ThemeConstant *) ((uint8_t *) export->buffer.data.buffer + constantListOffset) + i; + entry->valueOffset = export->buffer.data.byteCount; + entry->valueByteCount = constant->value.byteCount + 1; + entry->scale = constant->scale; + state->access(state, constant->value.buffer, constant->value.byteCount); + uint8_t terminate = 0; + state->access(state, &terminate, 1); + uint32_t pad = 0; + state->access(state, &pad, 4 - ((constant->value.byteCount + 1) & 3)); + assert((export->buffer.data.byteCount & 3) == 0); + } + + // Write out all layers. + + for (uintptr_t i = 0; i < arrlenu(styleSet->layers); i++) { + Layer *layer = styleSet->layers[i]; + layer->exportOffset = export->buffer.data.byteCount; + assert((layer->exportOffset & 3) == 0); + RfItem item = { 0 }; + item.type = &Layer_Type; + item.byteCount = sizeof(Layer); + LayerOp(state, &item, layer); + ThemeLayer *entry = (ThemeLayer *) ((uint8_t *) export->buffer.data.buffer + layer->exportOffset); + entry->dataByteCount = export->buffer.data.byteCount - layer->exportOffset; + entry->sequenceDataOffset = arrlenu(layer->sequences) ? export->buffer.data.byteCount : 0; + + Layer *previousLayer = selected.layer; + selected.layer = layer; // HACK! + + // Write out the sequences. + + for (uintptr_t j = 0; j < arrlenu(layer->sequences); j++) { + Sequence *sequence = layer->sequences[j]; + uint32_t headerOffset = export->buffer.data.byteCount; + + { + ThemeSequenceHeader header = { 0 }; + header.state = sequence->primaryState + | (sequence->flagFocused ? THEME_STATE_FOCUSED : 0) + | (sequence->flagChecked ? THEME_STATE_CHECKED : 0) + | (sequence->flagIndeterminate ? THEME_STATE_INDETERMINATE : 0) + | (sequence->flagDefault ? THEME_STATE_DEFAULT_BUTTON : 0) + | (sequence->flagItemFocus ? THEME_STATE_FOCUSED_ITEM : 0) + | (sequence->flagListFocus ? THEME_STATE_LIST_FOCUSED : 0) + | (sequence->flagBeforeEnter ? THEME_STATE_BEFORE_ENTER : 0) + | (sequence->flagAfterExit ? THEME_STATE_AFTER_EXIT : 0) + | (sequence->flagSelected ? THEME_STATE_SELECTED : 0); + header.duration = sequence->duration; + header.isLastSequence = j == arrlenu(layer->sequences) - 1; + state->access(state, &header, sizeof(header)); + } + + uint32_t overrideCount = 0; + + for (uintptr_t k = 0; k < arrlenu(sequence->keyframes); k++) { + for (uintptr_t l = 0; l < arrlenu(sequence->keyframes[k]->properties); l++) { + Property *property = sequence->keyframes[k]->properties + l; + + for (uintptr_t m = 0; m < arrlenu(export->pathToOffsetList); m++) { + const PathToOffset *pathToOffset = export->pathToOffsetList + m; + + if (!ArePathsEqual(pathToOffset->path, property->path + 1)) { + continue; + } + + RfItem item; + Keyframe *previousKeyframe = selected.keyframe; + selected.keyframe = (Keyframe *) sequence->keyframes[k]; // HACK! + void *source = ResolveDataObject((RfPath *) property->path, &item); + selected.keyframe = previousKeyframe; + + ThemeOverride override = { 0 }; + override.offset = pathToOffset->offset - layer->exportOffset; + + if (item.type == &StyleI8_Type) { + override.type = THEME_OVERRIDE_I8; + override.data.i8 = *(int8_t *) source; + } else if (item.type == &StyleI16_Type) { + override.type = THEME_OVERRIDE_I16; + override.data.i16 = *(int16_t *) source; + } else if (item.type == &StyleFloat_Type) { + override.type = THEME_OVERRIDE_F32; + override.data.f32 = *(float *) source; + } else if (item.type == &StyleColor_Type) { + override.type = THEME_OVERRIDE_COLOR; + override.data.u32 = ColorLookup(*(uint32_t *) source); + } else { + assert(false); + } + + overrideCount++; + state->access(state, &override, sizeof(override)); + + break; + } + } + } + + ThemeSequenceHeader *header = (ThemeSequenceHeader *) ((uint8_t *) export->buffer.data.buffer + headerOffset); + header->overrideCount = overrideCount; + } + + selected.layer = previousLayer; + + ExportFreePathToOffsetList(export->pathToOffsetList); + export->pathToOffsetList = NULL; + } + + // Write out layer lists for styles, and update the style list to point to them. + + for (uintptr_t i = 0; i < header.styleCount; i++) { + Style *style = styleSet->styles[i]; + uint32_t layerListOffset = export->buffer.data.byteCount; + assert((export->buffer.data.byteCount & 3) == 0); + + for (uintptr_t j = 0; j < arrlenu(style->layers); j++) { + uint32_t layerOffset = LayerLookup(style->layers[j])->exportOffset; + state->access(state, &layerOffset, sizeof(layerOffset)); + } + + ThemeStyle *entry = (ThemeStyle *) ((uint8_t *) export->buffer.data.buffer + styleListOffset) + i; + entry->layerListOffset = layerListOffset; + } + + // Write out the bitmap. + state->access(state, bitmap, bitmapBytes); + + free(bitmap); + } else { + RfStructOp(state, item, pointer); + } +} + +void ActionExport(void *_unused) { + PathToOffset *pathToOffsetList; + RfData data = ExportToGrowableBuffer(&StyleSet_Type, sizeof(StyleSet), NULL, &styleSet, &pathToOffsetList); + ExportFreePathToOffsetList(pathToOffsetList); + FILE *f = fopen(exportPath, "wb"); + fwrite(data.buffer, 1, data.byteCount, f); + fclose(f); + free(data.buffer); + + { + RfState state = { 0 }; + state.op = OP_FIND_COLOR_USERS; + RfItem item = { 0 }; + item.type = &StyleSet_Type; + item.byteCount = sizeof(StyleSet); + item.options = NULL; + RfBroadcast(&state, &item, &styleSet, true); + + for (uintptr_t i = 0; i < hmlenu(colorUsers); i++) { + Color *color = ColorLookupPointer(colorUsers[i].key); + + printf("%.*s - ", (int) color->key.byteCount, (char *) color->key.buffer); + + for (uintptr_t j = 0; j < arrlenu(colorUsers[i].value); j++) { + Style *style = colorUsers[i].value[j]; + printf("%.*s, ", (int) style->name.byteCount, (char *) style->name.buffer); + } + + printf("\n"); + arrfree(colorUsers[i].value); + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.colors); i++) { + printf("%.*s\t%.8X\n", (int) styleSet.colors[i]->key.byteCount, (char *) styleSet.colors[i]->key.buffer, styleSet.colors[i]->value); + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.colors); i++) { + for (uintptr_t j = 0; j < hmlenu(colorUsers); j++) { + if (styleSet.colors[i]->id == colorUsers[j].key) { + goto used; + } + } + + printf("Color '%.*s' is unused.\n", (int) styleSet.colors[i]->key.byteCount, (char *) styleSet.colors[i]->key.buffer); + used:; + } + + hmfree(colorUsers); + } +} + +// ------------------- Preview canvas ------------------- + +float Smooth(float x) { + return x * x * (3 - 2 * x); +} + +void ApplyKeyframeOverrides(const Keyframe *keyframe, const PathToOffset *pathToOffsetList, const RfData data) { + for (uintptr_t j = 0; j < arrlenu(keyframe->properties); j++) { + const Property *property = keyframe->properties + j; + bool found = false; + + for (uintptr_t k = 0; k < arrlenu(pathToOffsetList); k++) { + const PathToOffset *pathToOffset = pathToOffsetList + k; + + if (!ArePathsEqual(pathToOffset->path, property->path + 1)) { + continue; + } + + found = true; + + RfItem item; + Keyframe *previousKeyframe = selected.keyframe; + selected.keyframe = (Keyframe *) keyframe; // HACK! + void *source = ResolveDataObject((RfPath *) property->path, &item); + selected.keyframe = previousKeyframe; + void *destination = (uint8_t *) data.buffer + pathToOffset->offset; + + if (pathToOffset->offset + item.byteCount > data.byteCount) { + break; + } + + if (item.type->op == StyleColorOp) { + *(uint32_t *) destination = ColorLookup(*(uint32_t *) source); + } else { + memcpy(destination, source, item.byteCount); + } + + break; + } + + // If it wasn't found, that's fine. + // e.g. deleting gradient stop, but a keyframe still has an override. + (void) found; + } +} + +void AnimatingValueCalculate(AnimatingValue *value) { + float progress = value->duration ? Smooth((float) value->elapsed / value->duration) : 1; + + if (value->type == ANIMATING_VALUE_TYPE_COLOR) { + uint32_t from = value->from.u32; + float fr = UI_COLOR_RED_F(from); + float fg = UI_COLOR_GREEN_F(from); + float fb = UI_COLOR_BLUE_F(from); + float fa = UI_COLOR_ALPHA_F(from); + uint32_t to = value->to.u32; + float tr = UI_COLOR_RED_F(to); + float tg = UI_COLOR_GREEN_F(to); + float tb = UI_COLOR_BLUE_F(to); + float ta = UI_COLOR_ALPHA_F(to); + if (!fa) fr = tr, fg = tg, fb = tb; + if (!ta) tr = fr, tg = fg, tb = fb; + float dr = (tr - fr) * progress + fr; + float dg = (tg - fg) * progress + fg; + float db = (tb - fb) * progress + fb; + float da = (ta - fa) * progress + fa; + value->from.u32 = UI_COLOR_FROM_RGBA_F(dr, dg, db, da); + } else if (value->type == ANIMATING_VALUE_TYPE_I8) { + value->from.i8 = (value->to.i8 - value->from.i8) * progress + value->from.i8; + } else if (value->type == ANIMATING_VALUE_TYPE_I16) { + value->from.i16 = (value->to.i16 - value->from.i16) * progress + value->from.i16; + } else if (value->type == ANIMATING_VALUE_TYPE_FLOAT) { + value->from.f32 = (value->to.f32 - value->from.f32) * progress + value->from.f32; + } else { + assert(false); + } +} + +SequenceStateSelector GetCurrentSequenceStateSelector() { + SequenceStateSelector s = { 0 }; + s.primary = previewPrimaryState; + s.focused = previewStateFocused->e.flags & UI_BUTTON_CHECKED; + s.checked = previewStateChecked->e.flags & UI_BUTTON_CHECKED; + s.indeterminate = previewStateIndeterminate->e.flags & UI_BUTTON_CHECKED; + s._default = previewStateDefault->e.flags & UI_BUTTON_CHECKED; + s.itemFocus = previewStateItemFocus->e.flags & UI_BUTTON_CHECKED; + s.listFocus = previewStateListFocus->e.flags & UI_BUTTON_CHECKED; + s.selected = previewStateSelected->e.flags & UI_BUTTON_CHECKED; + s.enter = previewStateBeforeEnter->e.flags & UI_BUTTON_CHECKED; + s.exit = previewStateAfterExit->e.flags & UI_BUTTON_CHECKED; + return s; +} + +bool SequenceMatchesPreviewState(Sequence *sequence, SequenceStateSelector selector) { + return (sequence->primaryState == selector.primary || sequence->primaryState == PRIMARY_STATE_ANY) + && (!sequence->flagFocused || selector.focused) + && (!sequence->flagChecked || selector.checked) + && (!sequence->flagIndeterminate || selector.indeterminate) + && (!sequence->flagDefault || selector._default) + && (!sequence->flagItemFocus || selector.itemFocus) + && (!sequence->flagListFocus || selector.listFocus) + && (!sequence->flagBeforeEnter || selector.enter) + && (!sequence->flagAfterExit || selector.exit) + && (!sequence->flagSelected || selector.selected); +} + +void ApplySequenceOverrides(Layer *layer, PathToOffset *pathToOffsetList, RfData data, SequenceStateSelector selector) { + for (uintptr_t j = 0; j < arrlenu(layer->sequences); j++) { + if (SequenceMatchesPreviewState(layer->sequences[j], selector)) { + for (uintptr_t k = 0; k < arrlenu(layer->sequences[j]->keyframes); k++) { + Layer *previousLayer = selected.layer; + selected.layer = layer; // HACK! + ApplyKeyframeOverrides(layer->sequences[j]->keyframes[k], pathToOffsetList, data); + selected.layer = previousLayer; + } + } + } +} + +void *PrepareThemeDataForLayer(EsBuffer *themeData, EsPainter *themePainter, Layer *layer, bool applyOverrides, uintptr_t index, UIPainter *painter) { + PathToOffset *pathToOffsetList = NULL; + RfData data = ExportToGrowableBuffer(&Layer_Type, sizeof(Layer), NULL, layer, &pathToOffsetList); + + if (applyOverrides) { + Keyframe *keyframe = NULL; + + if (layer == selected.layer && selected.keyframe) { + keyframe = selected.keyframe; + } + + if (keyframe) { + ApplyKeyframeOverrides(keyframe, pathToOffsetList, data); + } else { + ApplySequenceOverrides(layer, pathToOffsetList, data, currentStateSelector); + + for (uintptr_t j = 0; j < arrlenu(animatingValues); j++) { + if (animatingValues[j].layer != index) { + continue; + } + + AnimatingValue value = animatingValues[j]; + uint8_t *destination = (uint8_t *) data.buffer + value.offset; + AnimatingValueCalculate(&value); + + if (value.type == ANIMATING_VALUE_TYPE_COLOR) { + *(uint32_t *) destination = value.from.u32; + } else if (value.type == ANIMATING_VALUE_TYPE_I8) { + *(int8_t *) destination = value.from.i8; + } else if (value.type == ANIMATING_VALUE_TYPE_I16) { + *(int16_t *) destination = value.from.i16; + } else if (value.type == ANIMATING_VALUE_TYPE_FLOAT) { + *(float *) destination = value.from.f32; + } else { + assert(false); + } + } + } + } + + ExportFreePathToOffsetList(pathToOffsetList); + + themeData->in = data.buffer; + themeData->bytes = data.byteCount; + themePainter->clip.l = painter->clip.l; + themePainter->clip.r = painter->clip.r; + themePainter->clip.t = painter->clip.t; + themePainter->clip.b = painter->clip.b; + themePainter->target->bits = painter->bits; + themePainter->target->width = painter->width; + themePainter->target->height = painter->height; + themePainter->target->stride = painter->width * 4; + return data.buffer; +} + +void DrawStyle(UIPainter *painter, UIRectangle generalBounds, UIRectangle *globalOffset, float scale, UIRectangle *opaqueRegion, bool applyOverrides, Style *style) { + for (uintptr_t i = 0; i < arrlenu(style->layers); i++) { + Layer *layer = LayerLookup(style->layers[i]); + EsPaintTarget paintTarget = { 0 }; + EsPainter themePainter = { 0 }; + themePainter.target = &paintTarget; + EsBuffer themeData = { 0 }; + void *dataBuffer = PrepareThemeDataForLayer(&themeData, &themePainter, layer, applyOverrides, i, painter); + + if (i) { + UIRectangle bounds = UIRectangleAdd(generalBounds, *globalOffset); + EsRectangle bounds2 = { bounds.l, bounds.r, bounds.t, bounds.b }; + ThemeDrawLayer(&themePainter, bounds2, &themeData, scale, *(EsRectangle *) opaqueRegion); + } else { + EsBufferRead(&themeData, sizeof(ThemeLayer)); + const ThemeMetrics *metrics = (const ThemeMetrics *) EsBufferRead(&themeData, sizeof(ThemeMetrics)); + globalOffset->l = metrics->globalOffset.l * scale; + globalOffset->r = metrics->globalOffset.r * scale; + globalOffset->t = metrics->globalOffset.t * scale; + globalOffset->b = metrics->globalOffset.b * scale; + } + + free(dataBuffer); + } + + if (editPoints->e.flags & UI_BUTTON_CHECKED) { + for (uintptr_t i = 0; i < arrlenu(style->layers); i++) { + Layer *_layer = LayerLookup(style->layers[i]); + + if (_layer->base.tag != LayerBase_path + 1 || _layer != selected.layer) { + continue; + } + + EsPaintTarget paintTarget = { 0 }; + EsPainter themePainter = { 0 }; + themePainter.target = &paintTarget; + EsBuffer themeData = { 0 }; + void *dataBuffer = PrepareThemeDataForLayer(&themeData, &themePainter, _layer, applyOverrides, i, painter); + + const ThemeLayer *layer = (const ThemeLayer *) EsBufferRead(&themeData, sizeof(ThemeLayer)); + UIRectangle _bounds = UIRectangleAdd(generalBounds, *globalOffset), bounds; + bounds.l = _bounds.l + (int) (scale * layer->offset.l) + THEME_RECT_WIDTH(_bounds) * layer->position.l / 100; + bounds.r = _bounds.l + (int) (scale * layer->offset.r) + THEME_RECT_WIDTH(_bounds) * layer->position.r / 100; + bounds.t = _bounds.t + (int) (scale * layer->offset.t) + THEME_RECT_HEIGHT(_bounds) * layer->position.t / 100; + bounds.b = _bounds.t + (int) (scale * layer->offset.b) + THEME_RECT_HEIGHT(_bounds) * layer->position.b / 100; + + const ThemeLayerPath *path = (const ThemeLayerPath *) EsBufferRead(&themeData, sizeof(ThemeLayerPath)); + const float *points = (const float *) EsBufferRead(&themeData, sizeof(float) * 6 * path->pointCount); + +#if 0 + for (uintptr_t i = 0; i < path->pointCount * 6; i += 2) { + intptr_t k = (i / 2) % 3; + if (k == 0) continue; + float x = points[i + 0], y = points[i + 1]; + intptr_t m = k == 2 ? (i + 2) : (i - 2); + if (m < 0) m += path->pointCount * 6; + if (m == path->pointCount * 6) m = 0; + float mx = points[m + 0], my = points[m + 1]; + + x = UI_RECT_WIDTH(bounds) * x / 100.0f + bounds.l; + y = UI_RECT_HEIGHT(bounds) * y / 100.0f + bounds.t; + mx = UI_RECT_WIDTH(bounds) * mx / 100.0f + bounds.l; + my = UI_RECT_HEIGHT(bounds) * my / 100.0f + bounds.t; + + UIDrawLine(painter, x, y, mx, my, 0xFF000000); + } + + for (uintptr_t i = 0; i < path->pointCount * 6; i += 2) { + intptr_t k = (i / 2) % 3; + if (k == 0) continue; + float x = points[i + 0], y = points[i + 1]; + + x = UI_RECT_WIDTH(bounds) * x / 100.0f + bounds.l; + y = UI_RECT_HEIGHT(bounds) * y / 100.0f + bounds.t; + + UIDrawRectangle(painter, UI_RECT_4(x - 6, x + 6, y - 6, y + 6), + 0xFFE0E0E0, 0xFFA8A8A8, UI_RECT_1(1)); + } +#endif + + for (uintptr_t i = 0; i < path->pointCount * 6; i += 2) { + intptr_t k = (i / 2) % 3; + if (k != 0) continue; + float x = points[i + 0], y = points[i + 1]; + + x = UI_RECT_WIDTH(bounds) * x / 100.0f + bounds.l; + y = UI_RECT_HEIGHT(bounds) * y / 100.0f + bounds.t; + + UIDrawRectangle(painter, UI_RECT_4(x - 6, x + 6, y - 6, y + 6), + 0xFFFFFFFF, 0xFFA8A8A8, UI_RECT_1(1)); + } + + free(dataBuffer); + } + } +} + +int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) { +#define CANVAS_DRAW_BOUNDS() \ + float scale = previewScale->position * 4 + 1; \ + int drawX = 100 + elementCanvas->bounds.l; \ + int drawY = 100 + elementCanvas->bounds.t; \ + int drawWidth = 1000 * previewWidth->position * scale; \ + int drawHeight = 1000 * previewHeight->position * scale + + if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + uint32_t background; + UIColorToRGB(previewBackgroundColor->hue, previewBackgroundColor->saturation, previewBackgroundColor->value, &background); + UIDrawBlock(painter, element->bounds, background | 0xFF000000); + + CANVAS_DRAW_BOUNDS(); + + UIRectangle generalBounds = UI_RECT_4(drawX, drawX + drawWidth, drawY, drawY + drawHeight); + + if (!selected.style) { + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + UIRectangle iBounds = UIRectangleAdd(generalBounds, UI_RECT_1I(-10)); + + if (UIRectangleContains(iBounds, element->window->cursorX, element->window->cursorY)) { + UIDrawString(painter, UI_RECT_4(element->bounds.l, element->bounds.r, element->bounds.t, element->bounds.t + 25), + styleSet.styles[i]->name.buffer, styleSet.styles[i]->name.byteCount, 0x000000, UI_ALIGN_LEFT, NULL); + UIDrawBlock(painter, iBounds, 0xFFA2A0A4); + } + + UIRectangle opaqueRegion = { 0 }; + UIRectangle globalOffset = { 0 }; + DrawStyle(painter, generalBounds, &globalOffset, scale, &opaqueRegion, false, styleSet.styles[i]); + + if (generalBounds.r + drawWidth > elementCanvas->bounds.r - 100) { + generalBounds.l = 100 + elementCanvas->bounds.l; + generalBounds.r = generalBounds.l + drawWidth; + generalBounds.t += drawHeight + 20; + generalBounds.b += drawHeight + 20; + } else { + generalBounds.l += drawWidth + 20; + generalBounds.r += drawWidth + 20; + } + } + + // UIDrawString(painter, element->bounds, "(select a style to preview it)", -1, 0x000000, UI_ALIGN_CENTER, NULL); + return 0; + } + + if (!arrlenu(selected.style->layers)) { + UIDrawString(painter, element->bounds, "(selected style has no layers)", -1, 0x000000, UI_ALIGN_CENTER, NULL); + return 0; + } + + if (previewShowGuides->e.flags & UI_BUTTON_CHECKED) { + UIDrawBlock(painter, UIRectangleAdd(generalBounds, UI_RECT_1I(-5)), 0xFFA2A0A4); + UIDrawBlock(painter, UIRectangleAdd(generalBounds, UI_RECT_1I(-3)), 0xFFC2C0C4); + } + + Rectangle8 opaqueInsets = StyleCalculateOpaqueInsets(selected.style->layers); + UIRectangle opaqueRegion = { 0 }; + + if (opaqueInsets.l != 0x7F && opaqueInsets.r != 0x7F + && opaqueInsets.t != 0x7F && opaqueInsets.b != 0x7F) { + opaqueRegion = UIRectangleAdd(generalBounds, UI_RECT_4(opaqueInsets.l * scale, -opaqueInsets.r * scale, + opaqueInsets.t * scale, -opaqueInsets.b * scale)); + } + + UIRectangle globalOffset = { 0 }; + + DrawStyle(painter, generalBounds, &globalOffset, scale, &opaqueRegion, true, selected.style); + + if (previewShowComputed->e.flags & UI_BUTTON_CHECKED) { + Rectangle8 paintOutsets8 = StyleCalculatePaintOutsets(selected.style->layers); + UIRectangle paintOutsets = UI_RECT_4(-paintOutsets8.l * scale, paintOutsets8.r * scale, -paintOutsets8.t * scale, paintOutsets8.b * scale); + UIDrawBlock(painter, UIRectangleAdd(generalBounds, paintOutsets), 0xFF0000); + + Rectangle8 opaqueInsets8 = StyleCalculateOpaqueInsets(selected.style->layers); + + if (opaqueInsets8.l != 0x7F && opaqueInsets8.r != 0x7F && opaqueInsets8.t != 0x7F && opaqueInsets8.b != 0x7F) { + UIRectangle opaqueInsets = UI_RECT_4(opaqueInsets8.l * scale, -opaqueInsets8.r * scale, opaqueInsets8.t * scale, -opaqueInsets8.b * scale); + UIDrawBlock(painter, UIRectangleAdd(generalBounds, opaqueInsets), 0x00FF00); + } + } + + { + char buffer[128]; + snprintf(buffer, 128, "%dx%dpx at %d%% scale", (int) (1000 * previewWidth->position), (int) (1000 * previewHeight->position), (int) (100 * scale)); + UIRectangle bounds = element->bounds; + bounds.b = bounds.t + 16; + UIDrawString(painter, bounds, buffer, -1, 0x000000, UI_ALIGN_LEFT, NULL); + } + } else if (message == UI_MSG_ANIMATE) { + uint64_t current = UIAnimateClock(); + uint64_t delta = current - previewTransitionLastTime; + + for (uintptr_t i = 0; i < arrlenu(animatingValues); i++) { + animatingValues[i].elapsed += delta; + + if (animatingValues[i].elapsed >= animatingValues[i].duration) { + animatingValues[i].elapsed = animatingValues[i].duration; + } + } + + previewTransitionLastTime = current; + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_MOUSE_MOVE) { + if (!selected.style) { + UIElementRepaint(element, NULL); + } + } + + return 0; +} + +void PreviewTransitionInvoke(void *_unused) { + previewTransition->e.flags ^= UI_BUTTON_CHECKED; + + if (previewTransition->e.flags & UI_BUTTON_CHECKED) { + UIElementAnimate(elementCanvas, false); + previewTransitionLastTime = UIAnimateClock(); + } else { + UIElementAnimate(elementCanvas, true); + arrfree(animatingValues); + } + + UIElementRepaint(&previewTransition->e, NULL); + UIElementRepaint(elementCanvas, NULL); +} + +void PreviewPreferredSizeInvoke(void *_unused) { + previewWidth->position = selected.style ? LayerLookup(selected.style->layers[0])->base.metrics.preferredSize.width / 1000.0f : 0.1f; + previewHeight->position = selected.style ? LayerLookup(selected.style->layers[0])->base.metrics.preferredSize.height / 1000.0f : 0.1f; + + UIElementRefresh(&previewWidth->e); + UIElementRefresh(&previewHeight->e); + UIElementRepaint(elementCanvas, NULL); +} + +void PreviewFixAspectRatioInvoke(void *_unused) { + previewHeight->position = previewWidth->position; + previewFixAspectRatio->e.flags ^= UI_BUTTON_CHECKED; + previewHeight->e.flags ^= UI_ELEMENT_HIDE; + UIElementRefresh(&previewFixAspectRatio->e); + UIElementRefresh(&previewHeight->e); + UIElementRepaint(elementCanvas, NULL); +} + +void PreviewShowGuidesInvoke(void *_unused) { + previewShowGuides->e.flags ^= UI_BUTTON_CHECKED; + UIElementRefresh(&previewShowGuides->e); + UIElementRepaint(elementCanvas, NULL); +} + +void PreviewShowComputedInvoke(void *_unused) { + previewShowComputed->e.flags ^= UI_BUTTON_CHECKED; + UIElementRefresh(&previewShowComputed->e); + UIElementRepaint(elementCanvas, NULL); +} + +void EditPointsInvoke(void *_unused) { + editPoints->e.flags ^= UI_BUTTON_CHECKED; + UIElementRefresh(&editPoints->e); + UIElementRepaint(elementCanvas, NULL); +} + +int PreviewSliderMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_VALUE_CHANGED) { + if (previewFixAspectRatio->e.flags & UI_BUTTON_CHECKED) { + previewHeight->position = previewWidth->position; + } + UIElementRepaint(elementCanvas, NULL); + } + + return 0; +} + +void UpdateAnimationListWithSequence(Sequence *sequence, int layer, PathToOffset *pathToOffsetList, uint8_t *data) { + for (uintptr_t i = 0; i < arrlenu(sequence->keyframes); i++) { + Keyframe *keyframe = sequence->keyframes[i]; + + for (uintptr_t j = 0; j < arrlenu(keyframe->properties); j++) { + Property *property = keyframe->properties + j; + + uint16_t offset = 0xFFFF; + + for (uintptr_t k = 0; k < arrlenu(pathToOffsetList); k++) { + const PathToOffset *pathToOffset = pathToOffsetList + k; + + if (!ArePathsEqual(pathToOffset->path, property->path + 1)) { + continue; + } + + offset = pathToOffset->offset; + assert(pathToOffset->offset < 0xFFFF); + break; + } + + if (offset == 0xFFFF) { + continue; + } + + // TODO Binary search. + + uintptr_t point = 0; + bool found = false; + + for (uintptr_t k = 0; k < arrlenu(animatingValues); k++) { + if (animatingValues[k].layer < layer || animatingValues[k].offset < offset) { + point = k + 1; + } else if (animatingValues[k].layer == layer && animatingValues[k].offset == offset) { + found = true; + point = k; + break; + } + } + + AnimatingValue *value; + + if (found) { + value = animatingValues + point; + value->elapsed = 0; + value->duration = sequence->duration; + } else { + AnimatingValue _value = { 0 }; + _value.offset = offset; + _value.layer = layer; + _value.duration = sequence->duration; + arrins(animatingValues, point, _value); + value = animatingValues + point; + } + + RfItem item; + void *source; + + { + Keyframe *previousKeyframe = selected.keyframe; + selected.keyframe = keyframe; // HACK! + source = ResolveDataObject((RfPath *) property->path, &item); + selected.keyframe = previousKeyframe; + } + + if (item.type == &StyleI8_Type) { + value->type = ANIMATING_VALUE_TYPE_I8; + if (!found) value->from.i8 = *(int8_t *) (data + offset); + value->to.i8 = *(int8_t *) source; + } else if (item.type == &StyleI16_Type) { + value->type = ANIMATING_VALUE_TYPE_I16; + if (!found) value->from.i16 = *(int16_t *) (data + offset); + value->to.i16 = *(int16_t *) source; + } else if (item.type == &StyleColor_Type) { + value->type = ANIMATING_VALUE_TYPE_COLOR; + if (!found) value->from.u32 = *(uint32_t *) (data + offset); + value->to.u32 = ColorLookup(*(uint32_t *) source); + } else if (item.type == &StyleFloat_Type) { + value->type = ANIMATING_VALUE_TYPE_FLOAT; + if (!found) value->from.f32 = *(float *) (data + offset); + value->to.f32 = *(float *) source; + } else { + assert(false); + } + } + } +} + +void UpdateAnimationList() { + if (!selected.style) return; + + SequenceStateSelector oldStateSelector = currentStateSelector; + currentStateSelector = GetCurrentSequenceStateSelector(); + + for (uintptr_t i = 0; i < arrlenu(animatingValues); i++) { + AnimatingValueCalculate(animatingValues + i); + animatingValues[i].type |= ANIMATING_VALUE_TYPE_UNUSED; + } + + for (uintptr_t i = 0; i < arrlenu(selected.style->layers); i++) { + Layer *layer = LayerLookup(selected.style->layers[i]); + + PathToOffset *pathToOffsetList = NULL; + RfData data = ExportToGrowableBuffer(&Layer_Type, sizeof(Layer), NULL, layer, &pathToOffsetList); + ApplySequenceOverrides(layer, pathToOffsetList, data, oldStateSelector); + + PathToOffset *pathToOffsetList2 = NULL; + RfData data2 = ExportToGrowableBuffer(&Layer_Type, sizeof(Layer), NULL, layer, &pathToOffsetList2); + ApplySequenceOverrides(layer, pathToOffsetList2, data2, currentStateSelector); + + for (uintptr_t j = 0; j < arrlenu(layer->sequences); j++) { + Sequence *sequence = layer->sequences[j]; + + if (SequenceMatchesPreviewState(sequence, currentStateSelector)) { + Layer *previousLayer = selected.layer; + selected.layer = layer; // HACK! + UpdateAnimationListWithSequence(sequence, i, pathToOffsetList, (uint8_t *) data.buffer); + selected.layer = previousLayer; + } + } + + for (uintptr_t j = 0; j < arrlenu(animatingValues); j++) { + AnimatingValue *value = animatingValues + j; + + if ((value->type & ANIMATING_VALUE_TYPE_UNUSED) && value->layer == i) { + // Return values to base. + + value->type &= ~ANIMATING_VALUE_TYPE_UNUSED; + value->elapsed = 0; + uint8_t *source = ((uint8_t *) data2.buffer + value->offset); + + if (value->type == ANIMATING_VALUE_TYPE_I8) { + value->to.i8 = *(int8_t *) source; + } else if (value->type == ANIMATING_VALUE_TYPE_I16) { + value->to.i16 = *(int16_t *) source; + } else if (value->type == ANIMATING_VALUE_TYPE_COLOR) { + value->to.u32 = *(uint32_t *) source; + } else if (value->type == ANIMATING_VALUE_TYPE_FLOAT) { + value->to.f32 = *(float *) source; + } else { + assert(false); + } + } + } + + ExportFreePathToOffsetList(pathToOffsetList); + ExportFreePathToOffsetList(pathToOffsetList2); + free(data.buffer); + free(data2.buffer); + } +} + +void PreviewSetPrimaryState(void *cp) { + previewPrimaryState = (uintptr_t) cp; + + UIElement *child = previewPrimaryStatePanel->e.children; + + while (child) { + if (child->cp == cp) child->flags |= UI_BUTTON_CHECKED; + else child->flags &= ~UI_BUTTON_CHECKED; + child = child->next; + } + + UIElementRefresh(&previewPrimaryStatePanel->e); + UpdateAnimationList(); +} + +int PreviewToggleState(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_CLICKED) { + element->flags ^= UI_BUTTON_CHECKED; + UIElementRefresh(element); + UpdateAnimationList(); + } + + return 0; +} + +int PreviewChangeBackgroundColor(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_VALUE_CHANGED) { + UIElementRefresh(elementCanvas); + } + + return 0; +} + +// ------------------- Paths ------------------- + +void MakeUI(MakeUIState *state, RfItem *item, void *pointer) { + RfIterator iterator = { 0 }; + iterator.includeRemovedFields = true; + iterator.s.op = RF_OP_COUNT; + item->type->op(&iterator.s, item, pointer); + iterator.s.op = RF_OP_ITERATE; + uint32_t count = iterator.index; + + for (uint32_t i = 0; i < count; i++) { + iterator.index = i; + item->type->op(&iterator.s, item, pointer); + if (iterator.s.error) return; + MakeUIState s = { 0 }; + s.s = state->s; + s.index = i; + s.parent = state; + s.inKeyframe = state->inKeyframe; + s.recurse = true; + if (iterator.isRemoved) continue; + iterator.item.type->op(&s.s, &iterator.item, iterator.pointer); + if (s.recurse) MakeUI(&s, &iterator.item, iterator.pointer); + } +} + +void MakeHeaderAndIndentUI(const char *format, RfState *state, RfItem *item, void *pointer) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), format, ((MakeUIState *) state)->index + 1); + +#if 0 + UILabelCreate(0, 0, buffer, -1); + UIPanel *subPanel = UIPanelCreate(0, UI_PANEL_EXPAND | UI_ELEMENT_PARENT_PUSH); + subPanel->gap = 5; + subPanel->border.l = 20; + subPanel->border.b = 20; +#endif + + UIExpandPane *pane = UIExpandPaneCreate(0, UI_ELEMENT_PARENT_PUSH, buffer, -1, UI_PANEL_EXPAND); + pane->panel->gap = 5; + pane->panel->border.l = 20; + pane->panel->border.t = 5; + pane->panel->border.r = 5; + pane->panel->border.b = 20; + + MakeUI((MakeUIState *) state, item, pointer); + UIParentPop(); + + ((MakeUIState *) state)->recurse = false; +} + +void InspectorUnsubscribe(UIElement *element) { + for (uintptr_t i = 0; i < arrlenu(inspectorSubscriptions); i++) { + if (inspectorSubscriptions[i] == element) { + arrdel(inspectorSubscriptions, i); + free(element->cp); + return; + } + } + + assert(false); +} + +void BuildPathForUI(MakeUIState *state, uint32_t last, UIElement *element) { + int count = 1; + + if (state->inKeyframe) { + count++; + } + + MakeUIState *s = state; + + while (s) { + count++; + + if (!s->parent && s->basePath) { + for (uintptr_t i = 0; s->basePath[i] != RF_PATH_TERMINATOR; i++) { + count++; + } + } + + s = s->parent; + } + + RfPath *path = (RfPath *) malloc((count + 1) * sizeof(uint32_t)); + + path->indices[count - 1] = last; + path->indices[count] = RF_PATH_TERMINATOR; + + s = state; + count--; + + while (s) { + path->indices[--count] = s->index; + + if (!s->parent && s->basePath) { + for (uintptr_t i = 0; s->basePath[i] != RF_PATH_TERMINATOR; i++) { + path->indices[state->inKeyframe ? (i + 1) : i] = s->basePath[i]; + count--; + } + } + + s = s->parent; + } + + if (state->inKeyframe) { + path->indices[--count] = PATH_IN_KEYFRAME; + } + + assert(!count); + element->cp = path; + arrput(inspectorSubscriptions, element); + UIElementMessage(element, MSG_PROPERTY_CHANGED, 0, ResolveDataObject(path, NULL)); +} + +// ------------------- Inspector ------------------- + +int StyleI8Message(UIElement *element, UIMessage message, int di, void *dp) { + UITextbox *textbox = (UITextbox *) element; + + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == UI_MSG_VALUE_CHANGED) { + textbox->string = realloc(textbox->string, textbox->bytes + 1); + textbox->string[textbox->bytes] = 0; + int8_t newValue = atoi(textbox->string); + + ModData mod = { 0 }; + mod.tag = ModData_changeProperty + 1; + mod.changeProperty.property.path = DuplicatePath((uint32_t *) element->cp); + mod.changeProperty.property.data = SaveToGrowableBuffer(&StyleI8_Type, sizeof(newValue), NULL, &newValue); + mod.changeProperty.source = element; + ModApply(&mod); + } else if (message == MSG_PROPERTY_CHANGED) { + char buffer[16]; + textbox->carets[0] = 0; + textbox->carets[1] = textbox->bytes; + UITextboxReplace(textbox, buffer, snprintf(buffer, 16, "%d", *(int8_t *) dp), false); + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_UPDATE && di == UI_UPDATE_FOCUSED) { + if (element->window->focused == element) { + textbox->carets[0] = 0; + textbox->carets[1] = textbox->bytes; + } else { + StyleI8Message(element, MSG_PROPERTY_CHANGED, 0, ResolveDataObject((RfPath *) element->cp, NULL)); + } + } + + return 0; +} + +int StyleI16Message(UIElement *element, UIMessage message, int di, void *dp) { + UITextbox *textbox = (UITextbox *) element; + + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == UI_MSG_VALUE_CHANGED) { + textbox->string = realloc(textbox->string, textbox->bytes + 1); + textbox->string[textbox->bytes] = 0; + int16_t newValue = atoi(textbox->string); + + ModData mod = { 0 }; + mod.tag = ModData_changeProperty + 1; + mod.changeProperty.property.path = DuplicatePath((uint32_t *) element->cp); + mod.changeProperty.property.data = SaveToGrowableBuffer(&StyleI16_Type, sizeof(newValue), NULL, &newValue); + mod.changeProperty.source = element; + ModApply(&mod); + } else if (message == MSG_PROPERTY_CHANGED) { + char buffer[16]; + textbox->carets[0] = 0; + textbox->carets[1] = textbox->bytes; + UITextboxReplace(textbox, buffer, snprintf(buffer, 16, "%d", *(int16_t *) dp), false); + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_UPDATE && di == UI_UPDATE_FOCUSED) { + if (element->window->focused == element) { + textbox->carets[0] = 0; + textbox->carets[1] = textbox->bytes; + } else { + StyleI16Message(element, MSG_PROPERTY_CHANGED, 0, ResolveDataObject((RfPath *) element->cp, NULL)); + } + } + + return 0; +} + +int StyleFloatMessage(UIElement *element, UIMessage message, int di, void *dp) { + UITextbox *textbox = (UITextbox *) element; + + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == UI_MSG_VALUE_CHANGED) { + textbox->string = realloc(textbox->string, textbox->bytes + 1); + textbox->string[textbox->bytes] = 0; + float newValue = strtof(textbox->string, NULL); + + ModData mod = { 0 }; + mod.tag = ModData_changeProperty + 1; + mod.changeProperty.property.path = DuplicatePath((uint32_t *) element->cp); + mod.changeProperty.property.data = SaveToGrowableBuffer(&StyleFloat_Type, sizeof(newValue), NULL, &newValue); + mod.changeProperty.source = element; + ModApply(&mod); + } else if (message == MSG_PROPERTY_CHANGED) { + char buffer[16]; + textbox->carets[0] = 0; + textbox->carets[1] = textbox->bytes; + UITextboxReplace(textbox, buffer, snprintf(buffer, 16, "%.2f", *(float *) dp), false); + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_UPDATE && di == UI_UPDATE_FOCUSED) { + if (element->window->focused == element) { + textbox->carets[0] = 0; + textbox->carets[1] = textbox->bytes; + } else { + StyleFloatMessage(element, MSG_PROPERTY_CHANGED, 0, ResolveDataObject((RfPath *) element->cp, NULL)); + } + } + + return 0; +} + +int StyleStringMessage(UIElement *element, UIMessage message, int di, void *dp) { + UITextbox *textbox = (UITextbox *) element; + + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == UI_MSG_VALUE_CHANGED) { + RfData data = { 0 }; + data.buffer = textbox->string; + data.byteCount = textbox->bytes; + + ModData mod = { 0 }; + mod.tag = ModData_changeProperty + 1; + mod.changeProperty.property.path = DuplicatePath((uint32_t *) element->cp); + mod.changeProperty.property.data = SaveToGrowableBuffer(&StyleString_Type, sizeof(data), NULL, &data); + mod.changeProperty.source = element; + ModApply(&mod); + } else if (message == MSG_PROPERTY_CHANGED) { + RfData *data = (RfData *) dp; + textbox->carets[0] = 0; + textbox->carets[1] = textbox->bytes; + UITextboxReplace(textbox, data->buffer, data->byteCount, false); + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_UPDATE && di == UI_UPDATE_FOCUSED && element->window->focused == element) { + textbox->carets[0] = 0; + textbox->carets[1] = textbox->bytes; + } + + return 0; +} + +int StyleBoolMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == UI_MSG_CLICKED) { + element->flags ^= UI_BUTTON_CHECKED; + bool newValue = element->flags & UI_BUTTON_CHECKED; + + ModData mod = { 0 }; + mod.tag = ModData_changeProperty + 1; + mod.changeProperty.property.path = DuplicatePath((uint32_t *) element->cp); + mod.changeProperty.property.data = SaveToGrowableBuffer(&StyleBool_Type, sizeof(newValue), NULL, &newValue); + mod.changeProperty.source = element; + ModApply(&mod); + } else if (message == MSG_PROPERTY_CHANGED) { + if (*(bool *) dp) element->flags |= UI_BUTTON_CHECKED; + else element->flags &= ~UI_BUTTON_CHECKED; + UIElementRepaint(element, NULL); + } + + return 0; +} + +int StyleUnionButtonMessage(UIElement *element, UIMessage message, int di, void *dp) { + // Also used for enums. + + if (message == UI_MSG_CLICKED && (~element->flags & UI_BUTTON_CHECKED)) { + uint32_t newValue = (uint32_t) (uintptr_t) element->cp; + + ModData mod = { 0 }; + mod.tag = ModData_changeProperty + 1; + mod.changeProperty.property.path = DuplicatePath((uint32_t *) element->parent->cp); + mod.changeProperty.property.data = SaveToGrowableBuffer(&rfU32, sizeof(newValue), NULL, &newValue); + ModApply(&mod); + } + + return 0; +} + +void StyleEnumMenuItemInvoke(void *cp) { + uint32_t newValue = (uint32_t) (uintptr_t) cp; + + ModData mod = { 0 }; + mod.tag = ModData_changeProperty + 1; + mod.changeProperty.property.path = DuplicatePath(menuPath); + mod.changeProperty.property.data = SaveToGrowableBuffer(&rfU32, sizeof(newValue), NULL, &newValue); + ModApply(&mod); +} + +int StyleUnionButtonPanelMessage(UIElement *element, UIMessage message, int di, void *dp) { + // Also used for enums. + + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == MSG_PROPERTY_CHANGED) { + UIElement *child = element->children; + + while (child) { + if ((uint32_t) (uintptr_t) child->cp == *(uint32_t *) dp) { + child->flags |= UI_BUTTON_CHECKED; + } else { + child->flags &= ~UI_BUTTON_CHECKED; + } + + UIElementRepaint(child, NULL); + child = child->next; + } + } + + return 0; +} + +void RefreshAncestorsUntilInspector(UIElement *element) { + while (element != &panelInspector->e) { + element->clip = UI_RECT_1(0); + element = element->parent; + } + + UIElementRefresh(&panelInspector->e); +} + +int StyleChoiceButtonMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == UI_MSG_GET_WIDTH) { + return 240 * element->window->scale; + } else if (message == MSG_PROPERTY_CHANGED) { + RfItem item; + void *_dp = ResolveDataObject((RfPath *) element->cp, &item); + assert(dp == _dp); + UIButton *button = (UIButton *) element; + free(button->label); + button->label = UIStringCopy(((StringOption *) item.type->fields[*(uint32_t *) dp].item.options)->string, -1); + UIElementRefresh(element); + } else if (message == UI_MSG_CLICKED) { + RfItem item; + ResolveDataObject((RfPath *) element->cp, &item); + UIMenu *menu = UIMenuCreate(element, 0); + menuPath = (uint32_t *) element->cp; + + for (uintptr_t i = 0; i < item.type->fieldCount; i++) { + UIMenuAddItem(menu, 0, ((StringOption *) item.type->fields[i].item.options)->string, -1, StyleEnumMenuItemInvoke, (void *) i); + } + + UIMenuShow(menu); + } + + return 0; +} + +int StyleUnionPanelMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == MSG_PROPERTY_CHANGED) { + UIElementDestroyDescendents(element); + + uint32_t *path = (uint32_t *) element->cp; + uintptr_t last = 0; + for (; path[last] != RF_PATH_TERMINATOR; last++); + assert(last && path[last - 1] == 0); + path[last - 1] = RF_PATH_TERMINATOR; + RfItem item; + void *_dp = ResolveDataObject((RfPath *) path, &item); + assert(dp == _dp); + + MakeUIState state = { 0 }; + state.s.op = OP_MAKE_UI; + state.index = *(uint32_t *) dp; + state.basePath = element->cp; + state.inKeyframe = state.basePath[0] == PATH_IN_KEYFRAME; + if (state.inKeyframe) state.basePath++; + if (state.index) state.index--; + RfField *field = item.type->fields + state.index; + RfItem fieldItem = field->item; + uint8_t *pointer = (uint8_t *) dp + field->offset; + UIParentPush(element); + fieldItem.type->op(&state.s, &fieldItem, pointer); + MakeUI(&state, &fieldItem, pointer); + UIParentPop(); + + path[last - 1] = 0; // Restore previous path. + RefreshAncestorsUntilInspector(element); + } + + return 0; +} + +int StyleArrayPanelMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == MSG_PROPERTY_CHANGED) { + UIElementDestroyDescendents(element); + + uint32_t *path = (uint32_t *) element->cp; + RfItem item; + void *_dp = ResolveDataObject((RfPath *) path, &item); + assert(dp == _dp); + + RfArrayHeader *header = *(RfArrayHeader **) dp; + UIParentPush(element); + + for (uintptr_t i = 0; header && i < header[-1].length; i++) { + MakeUIState state = { 0 }; + state.s.op = OP_MAKE_UI; + state.index = i; + state.basePath = element->cp; + state.inKeyframe = state.basePath[0] == PATH_IN_KEYFRAME; + if (state.inKeyframe) state.basePath++; + RfItem *fieldItem = (RfItem *) item.options; + uint8_t *pointer = (*(uint8_t **) dp) + i * fieldItem->byteCount; + state.recurse = true; + fieldItem->type->op(&state.s, fieldItem, pointer); + if (state.recurse) MakeUI(&state, fieldItem, pointer); + } + + UIParentPop(); + RefreshAncestorsUntilInspector(element); + } + + return 0; +} + +int StyleArrayAddMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_CLICKED) { + ModData mod = { 0 }; + mod.tag = ModData_array + 1; + mod.array.property.path = DuplicatePath((uint32_t *) ((UIElement *) element->cp)->cp); + RfItem item; + ResolveDataObject((RfPath *) mod.array.property.path, &item); + RfItem *elementItem = (RfItem *) item.options; + void *temporary = malloc(elementItem->byteCount); + memset(temporary, 0, elementItem->byteCount); + mod.changeProperty.property.data = SaveToGrowableBuffer(elementItem->type, elementItem->byteCount, elementItem->options, temporary); + free(temporary); + ModApply(&mod); + } + + return 0; +} + +int StyleArrayDeleteMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_CLICKED) { + uint32_t *path = (uint32_t *) ((UIElement *) element->cp)->cp; + RfItem item; + RfArrayHeader *pointer = *(RfArrayHeader **) ResolveDataObject((RfPath *) path, &item); + + if (pointer && pointer[-1].length) { + ModData mod = { 0 }; + mod.tag = ModData_array + 1; + mod.array.property.path = DuplicatePath(path); + mod.array.isDelete = true; + ModApply(&mod); + } + } + + return 0; +} + +int RemoveOverrideButtonMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_CLICKED) { + ModData mod = { 0 }; + mod.tag = ModData_deleteOverride + 1; + mod.deleteOverride.property.path = DuplicatePath(element->cp); + ModApply(&mod); + } else if (message == MSG_PROPERTY_CHANGED) { + if (dp == temporaryOverride) { + element->flags &= ~UI_ELEMENT_DISABLED; + } else { + element->flags |= UI_ELEMENT_DISABLED; + } + + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } + + return 0; +} + +void MakeOverrideButton(UIElement *parent, RfState *state, uint32_t last) { + if (!((MakeUIState *) state)->inKeyframe) return; + UIButton *removeOverride = UIButtonCreate(parent, UI_BUTTON_SMALL, "X", -1); + removeOverride->e.messageUser = RemoveOverrideButtonMessage; + BuildPathForUI((MakeUIState *) state, last, &removeOverride->e); +} + +void StyleColorMenuItemInvoke(void *cp) { + uint32_t newValue = (uint32_t) (uintptr_t) cp; + + ModData mod = { 0 }; + mod.tag = ModData_changeProperty + 1; + mod.changeProperty.property.path = DuplicatePath((uint32_t *) menuPath); + mod.changeProperty.property.data = SaveToGrowableBuffer(&StyleColor_Type, sizeof(newValue), NULL, &newValue); + ModApply(&mod); +} + +int StyleColorButtonMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_DESTROY) { + InspectorUnsubscribe(element); + } else if (message == UI_MSG_GET_WIDTH) { + return 240 * element->window->scale; + } else if (message == MSG_PROPERTY_CHANGED) { + RfItem item; + void *_dp = ResolveDataObject((RfPath *) element->cp, &item); + assert(dp == _dp); + UIButton *button = (UIButton *) element; + free(button->label); + + RfData key = ColorLookupPointer(*(uint32_t *) dp)->key; + button->label = UIStringCopy(key.buffer, key.byteCount); + + UIElementRefresh(element); + } else if (message == UI_MSG_CLICKED) { + RfItem item; + ResolveDataObject((RfPath *) element->cp, &item); + UIMenu *menu = UIMenuCreate(element, 0); + menuPath = (uint32_t *) element->cp; + + for (uintptr_t i = 0; i < arrlenu(styleSet.colors); i++) { + UIMenuAddItem(menu, 0, styleSet.colors[i]->key.buffer, styleSet.colors[i]->key.byteCount, + StyleColorMenuItemInvoke, (void *) (uintptr_t) styleSet.colors[i]->id); + } + + UIMenuShow(menu); + } + + return 0; +} + +void StyleColorRenameButtonCommand(void *cp) { + UIButton *button = (UIButton *) cp; + RfItem item; + void *dp = ResolveDataObject((RfPath *) button->e.cp, &item); + uint32_t id = *(uint32_t *) dp; + Color *color = ColorLookupPointer(id); + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%.*s", (int) color->key.byteCount, (char *) color->key.buffer); + char *key = strdup(buffer); + UIDialogShow(window, 0, "Rename color \n%t\n%f%b", &key, "Rename"); + free(color->key.buffer); + color->key.buffer = key; + color->key.byteCount = strlen(key); + free(button->label); + button->label = UIStringCopy(key, -1); + UIElementRefresh(&button->e); + ColorListRefresh(); +} + +void StyleColorOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UIPanel *labelPanel = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + UILabelCreate(&labelPanel->e, UI_ELEMENT_H_FILL, ((StringOption *) item->options)->string, -1); + MakeOverrideButton(&labelPanel->e, state, RF_PATH_TERMINATOR); + UIPanel *row = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + UIButton *button = UIButtonCreate(&row->e, UI_BUTTON_DROP_DOWN, "", -1); + button->e.messageUser = StyleColorButtonMessage; + UIButton *rename = UIButtonCreate(&row->e, 0, "Rename", -1); + rename->e.cp = button; + rename->invoke = StyleColorRenameButtonCommand; + BuildPathForUI((MakeUIState *) state, RF_PATH_TERMINATOR, &button->e); + } else if (state->op == OP_GET_PALETTE) { + uint32_t color = *(uint32_t *) pointer; + int count = hmget(palette, color); + count++; + hmput(palette, color, count); + } else if (state->op == OP_REPLACE_COLOR) { + assert(*(uint32_t *) pointer != replaceColorTo); + + if (*(uint32_t *) pointer == replaceColorFrom) { + *(uint32_t *) pointer = replaceColorTo; + } + } else if (state->op == OP_FIND_COLOR_USERS) { + uint32_t id = *(uint32_t *) pointer; + Style **list = hmget(colorUsers, id); + Layer *layer = (Layer *) currentPaletteOpLayer; + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + for (uintptr_t j = 0; j < arrlenu(styleSet.styles[i]->layers); j++) { + if (styleSet.styles[i]->layers[j] == layer->id) { + for (uintptr_t k = 0; k < arrlenu(list); k++) { + if (list[k] == styleSet.styles[i]) { + goto found; + } + } + + arrput(list, styleSet.styles[i]); + goto found; + } + } + } + + found:; + hmput(colorUsers, id, list); + } else { + RfEndianOp(state, item, pointer); + } +} + +void StyleBoolOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + if (((MakeUIState *) state)->inKeyframe) return; + UIButton *button = UIButtonCreate(&UIPanelCreate(0, UI_PANEL_HORIZONTAL)->e, + 0, ((StringOption *) item->options)->string, -1); + button->e.messageUser = StyleBoolMessage; + BuildPathForUI((MakeUIState *) state, RF_PATH_TERMINATOR, &button->e); + } else { + RfEndianOp(state, item, pointer); + } +} + +void StyleStringOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + if (((MakeUIState *) state)->inKeyframe) return; + UILabelCreate(0, 0, ((StringOption *) item->options)->string, -1); + UITextbox *textbox = UITextboxCreate(0, UI_ELEMENT_H_FILL); + textbox->e.messageUser = StyleStringMessage; + BuildPathForUI((MakeUIState *) state, RF_PATH_TERMINATOR, &textbox->e); + } else { + RfDataOp(state, item, pointer); + } +} + +void Rectangle8Op(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UILabelCreate(0, 0, ((StringOption *) item->options)->string, -1); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + + MakeOverrideButton(0, state, Rectangle8_l); + UITextbox *l = UITextboxCreate(0, UI_ELEMENT_H_FILL); + l->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Rectangle8_l, &l->e); + MakeOverrideButton(0, state, Rectangle8_r); + UITextbox *r = UITextboxCreate(0, UI_ELEMENT_H_FILL); + r->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Rectangle8_r, &r->e); + MakeOverrideButton(0, state, Rectangle8_t); + UITextbox *t = UITextboxCreate(0, UI_ELEMENT_H_FILL); + t->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Rectangle8_t, &t->e); + MakeOverrideButton(0, state, Rectangle8_b); + UITextbox *b = UITextboxCreate(0, UI_ELEMENT_H_FILL); + b->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Rectangle8_b, &b->e); + + UIParentPop(); + ((MakeUIState *) state)->recurse = false; + } else { + RfStructOp(state, item, pointer); + } +} + +void Rectangle16Op(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UILabelCreate(0, 0, ((StringOption *) item->options)->string, -1); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + + MakeOverrideButton(0, state, Rectangle16_l); + UITextbox *l = UITextboxCreate(0, UI_ELEMENT_H_FILL); + l->e.messageUser = StyleI16Message; + BuildPathForUI((MakeUIState *) state, Rectangle16_l, &l->e); + MakeOverrideButton(0, state, Rectangle16_r); + UITextbox *r = UITextboxCreate(0, UI_ELEMENT_H_FILL); + r->e.messageUser = StyleI16Message; + BuildPathForUI((MakeUIState *) state, Rectangle16_r, &r->e); + MakeOverrideButton(0, state, Rectangle16_t); + UITextbox *t = UITextboxCreate(0, UI_ELEMENT_H_FILL); + t->e.messageUser = StyleI16Message; + BuildPathForUI((MakeUIState *) state, Rectangle16_t, &t->e); + MakeOverrideButton(0, state, Rectangle16_b); + UITextbox *b = UITextboxCreate(0, UI_ELEMENT_H_FILL); + b->e.messageUser = StyleI16Message; + BuildPathForUI((MakeUIState *) state, Rectangle16_b, &b->e); + + UIParentPop(); + ((MakeUIState *) state)->recurse = false; + } else { + RfStructOp(state, item, pointer); + } +} + +void PathPointOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_EXPORT) { + PathPoint *point = (PathPoint *) pointer; + float themePoint[6]; + themePoint[0] = point->x0; ExportAddPathToOffset((ExportState *) state, PathPoint_x0, 0 * sizeof(float)); + themePoint[1] = point->y0; ExportAddPathToOffset((ExportState *) state, PathPoint_y0, 1 * sizeof(float)); + themePoint[2] = point->x1; ExportAddPathToOffset((ExportState *) state, PathPoint_x1, 2 * sizeof(float)); + themePoint[3] = point->y1; ExportAddPathToOffset((ExportState *) state, PathPoint_y1, 3 * sizeof(float)); + themePoint[4] = point->x2; ExportAddPathToOffset((ExportState *) state, PathPoint_x2, 4 * sizeof(float)); + themePoint[5] = point->y2; ExportAddPathToOffset((ExportState *) state, PathPoint_y2, 5 * sizeof(float)); + state->access(state, themePoint, sizeof(themePoint)); + } else if (state->op == OP_MAKE_UI) { + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + + for (int i = 0; i < 6; i++) { + MakeOverrideButton(0, state, PathPoint_x0 + i); + UITextbox *textbox = UITextboxCreate(0, UI_ELEMENT_H_FILL); + textbox->e.messageUser = StyleFloatMessage; + BuildPathForUI((MakeUIState *) state, PathPoint_x0 + i, &textbox->e); + if (i == 1 || i == 3) UISpacerCreate(0, 0, 5, 0); + } + + UIParentPop(); + ((MakeUIState *) state)->recurse = false; + } else { + RfStructOp(state, item, pointer); + } +} + +void Gaps8Op(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UILabelCreate(0, 0, ((StringOption *) item->options)->string, -1); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + + MakeOverrideButton(0, state, Gaps8_major); + UITextbox *major = UITextboxCreate(0, UI_ELEMENT_H_FILL); + major->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Gaps8_major, &major->e); + MakeOverrideButton(0, state, Gaps8_minor); + UITextbox *minor = UITextboxCreate(0, UI_ELEMENT_H_FILL); + minor->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Gaps8_minor, &minor->e); + MakeOverrideButton(0, state, Gaps8_wrap); + UITextbox *wrap = UITextboxCreate(0, UI_ELEMENT_H_FILL); + wrap->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Gaps8_wrap, &wrap->e); + + UIParentPop(); + ((MakeUIState *) state)->recurse = false; + } else { + RfStructOp(state, item, pointer); + } +} + +void Size16Op(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UILabelCreate(0, 0, ((StringOption *) item->options)->string, -1); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + + MakeOverrideButton(0, state, Size16_width); + UITextbox *width = UITextboxCreate(0, UI_ELEMENT_H_FILL); + width->e.messageUser = StyleI16Message; + BuildPathForUI((MakeUIState *) state, Size16_width, &width->e); + MakeOverrideButton(0, state, Size16_height); + UITextbox *height = UITextboxCreate(0, UI_ELEMENT_H_FILL); + height->e.messageUser = StyleI16Message; + BuildPathForUI((MakeUIState *) state, Size16_height, &height->e); + + UIParentPop(); + ((MakeUIState *) state)->recurse = false; + } else { + RfStructOp(state, item, pointer); + } +} + +void Corners8Op(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UILabelCreate(0, 0, ((StringOption *) item->options)->string, -1); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + MakeOverrideButton(0, state, Corners8_tl); + UITextbox *l = UITextboxCreate(0, UI_ELEMENT_H_FILL); + l->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Corners8_tl, &l->e); + MakeOverrideButton(0, state, Corners8_tr); + UITextbox *r = UITextboxCreate(0, UI_ELEMENT_H_FILL); + r->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Corners8_tr, &r->e); + MakeOverrideButton(0, state, Corners8_bl); + UITextbox *t = UITextboxCreate(0, UI_ELEMENT_H_FILL); + t->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Corners8_bl, &t->e); + MakeOverrideButton(0, state, Corners8_br); + UITextbox *b = UITextboxCreate(0, UI_ELEMENT_H_FILL); + b->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, Corners8_br, &b->e); + UIParentPop(); + ((MakeUIState *) state)->recurse = false; + } else { + RfStructOp(state, item, pointer); + } +} + +void StyleI8Op(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UIPanel *labelPanel = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + UILabelCreate(&labelPanel->e, UI_ELEMENT_H_FILL, ((StringOption *) item->options)->string, -1); + MakeOverrideButton(&labelPanel->e, state, RF_PATH_TERMINATOR); + UITextbox *textbox = UITextboxCreate(0, 0); + textbox->e.messageUser = StyleI8Message; + BuildPathForUI((MakeUIState *) state, RF_PATH_TERMINATOR, &textbox->e); + } else { + rfI8.op(state, item, pointer); + } +} + +void StyleI16Op(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UIPanel *labelPanel = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + UILabelCreate(&labelPanel->e, UI_ELEMENT_H_FILL, ((StringOption *) item->options)->string, -1); + MakeOverrideButton(&labelPanel->e, state, RF_PATH_TERMINATOR); + UITextbox *textbox = UITextboxCreate(0, 0); + textbox->e.messageUser = StyleI16Message; + BuildPathForUI((MakeUIState *) state, RF_PATH_TERMINATOR, &textbox->e); + } else { + rfI16.op(state, item, pointer); + } +} + +void StyleFloatOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + UIPanel *labelPanel = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + UILabelCreate(&labelPanel->e, UI_ELEMENT_H_FILL, ((StringOption *) item->options)->string, -1); + MakeOverrideButton(&labelPanel->e, state, RF_PATH_TERMINATOR); + UITextbox *textbox = UITextboxCreate(0, 0); + textbox->e.messageUser = StyleFloatMessage; + BuildPathForUI((MakeUIState *) state, RF_PATH_TERMINATOR, &textbox->e); + } else { + rfF32.op(state, item, pointer); + } +} + +void StyleUnionOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + MakeUIState *makeUI = (MakeUIState *) state; + + UILabelCreate(0, 0, ((StringOption *) item->options)->string, -1); + + if (!makeUI->inKeyframe) { + UIPanel *buttonPanel = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + buttonPanel->e.messageUser = StyleUnionButtonPanelMessage; + + for (uintptr_t i = 0; i < item->type->fieldCount; i++) { + uint32_t tag = i ? i + 1 : 0; + const char *name = i ? ((StringOption *) item->type->fields[i].item.options)->string : "(none)"; + UIButton *button = UIButtonCreate(&buttonPanel->e, UI_BUTTON_SMALL, name, -1); + button->e.cp = (void *) (uintptr_t) tag; + button->e.messageUser = StyleUnionButtonMessage; + } + + BuildPathForUI(makeUI, 0, &buttonPanel->e); + } + + UIPanel *subPanel = UIPanelCreate(0, UI_PANEL_WHITE | UI_PANEL_EXPAND); + subPanel->gap = 5; + subPanel->e.messageUser = StyleUnionPanelMessage; + BuildPathForUI(makeUI, 0, &subPanel->e); + makeUI->recurse = false; + } else { + RfStructOp(state, item, pointer); + } +} + +void StyleEnumOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + MakeUIState *makeUI = (MakeUIState *) state; + + if (makeUI->inKeyframe) { + return; + } + + if (item->type->fieldCount > 5) { + UIPanel *panel = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + UILabelCreate(&panel->e, UI_ELEMENT_H_FILL, ((StringOption *) item->options)->string, -1); + UIButton *button = UIButtonCreate(&panel->e, UI_BUTTON_DROP_DOWN, "", -1); + button->e.messageUser = StyleChoiceButtonMessage; + BuildPathForUI(makeUI, RF_PATH_TERMINATOR, &button->e); + } else { + UIPanel *buttonPanel = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + UILabelCreate(&buttonPanel->e, 0, ((StringOption *) item->options)->string, -1); + buttonPanel->e.messageUser = StyleUnionButtonPanelMessage; + + for (uintptr_t i = 0; i < item->type->fieldCount; i++) { + uint32_t tag = i; + const char *name = ((StringOption *) item->type->fields[i].item.options)->string; + UIButton *button = UIButtonCreate(&buttonPanel->e, UI_BUTTON_SMALL, name, -1); + button->e.cp = (void *) (uintptr_t) tag; + button->e.messageUser = StyleUnionButtonMessage; + } + + BuildPathForUI(makeUI, RF_PATH_TERMINATOR, &buttonPanel->e); + } + } else { + RfEnumOp(state, item, pointer); + } +} + +void StyleArrayOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + MakeUIState *makeUI = (MakeUIState *) state; + + UIPanel *buttonPanel = UIPanelCreate(0, UI_PANEL_HORIZONTAL); + UILabelCreate(&buttonPanel->e, 0, ((StringOption *) ((RfItem *) item->options)->options)->string, -1); + + UIPanel *subPanel = UIPanelCreate(0, UI_PANEL_WHITE | UI_PANEL_EXPAND); + subPanel->gap = 5; + subPanel->e.messageUser = StyleArrayPanelMessage; + BuildPathForUI(makeUI, RF_PATH_TERMINATOR, &subPanel->e); + makeUI->recurse = false; + + if (!makeUI->inKeyframe) { + UIButton *addButton = UIButtonCreate(&buttonPanel->e, UI_BUTTON_SMALL, "Add", -1); + addButton->e.cp = subPanel; + addButton->e.messageUser = StyleArrayAddMessage; + UIButton *deleteButton = UIButtonCreate(&buttonPanel->e, UI_BUTTON_SMALL, "Delete", -1); + deleteButton->e.cp = subPanel; + deleteButton->e.messageUser = StyleArrayDeleteMessage; + } + } else { + RfArrayOp(state, item, pointer); + } +} + +void ButtonMoveLayerUp(void *_unused) { + uintptr_t index = 0; + + for (uintptr_t i = 0; i < arrlenu(selected.style->layers); i++) { + if (selected.style->layers[i] == selected.layer->id) { + index = i; + break; + } + } + + if (index <= 1) { + return; + } + + ModData mod = { 0 }; + mod.tag = ModData_swapLayers + 1; + mod.swapLayers.index = index - 1; + ModApply(&mod); +} + +void ButtonMoveLayerDown(void *_unused) { + uintptr_t index = 0; + + for (uintptr_t i = 0; i < arrlenu(selected.style->layers); i++) { + if (selected.style->layers[i] == selected.layer->id) { + index = i; + break; + } + } + + if (index == arrlenu(selected.style->layers) - 1) { + return; + } + + ModData mod = { 0 }; + mod.tag = ModData_swapLayers + 1; + mod.swapLayers.index = index; + ModApply(&mod); +} + +void ForkLayer(void *_unused) { + // TODO Undo. + // TODO Memory leak of state.data? + + if (!selected.layer) return; + + RfGrowableBuffer state = { 0 }; + state.data = SaveToGrowableBuffer(&Layer_Type, sizeof(Layer), NULL, selected.layer); + + ModData mod = { 0 }; + mod.tag = ModData_deleteLayer + 1; + bool found = false; + + for (uintptr_t i = 0; i < arrlenu(selected.style->layers); i++) { + if (selected.style->layers[i] == selected.layer->id) { + mod.deleteLayer.index = i; + found = true; + break; + } + } + + assert(found); + ModApply(&mod); + + state.s.version = saveFormatVersion; + state.data.byteCount -= sizeof(uint32_t); + state.s.allocate = RfRealloc; + state.s.access = RfReadGrowableBuffer; + + RfItem item = { 0 }; + item.type = &Layer_Type; + item.byteCount = sizeof(Layer); + state.s.op = RF_OP_LOAD; + + Layer *layer = calloc(1, sizeof(Layer)); + item.type->op(&state.s, &item, layer); + layer->id = ++styleSet.lastID; + + mod.tag = ModData_addLayer + 1; + mod.addLayer.index = mod.deleteLayer.index; + mod.addLayer.layer = layer; + ModApply(&mod); +} + +void RebuildInspector() { + UIElementDestroyDescendents(&panelInspector->e); + UIParentPush(&panelInspector->e); + + if (selected.keyframe) { + MAKE_UI(Keyframe, selected.keyframe, false); + MAKE_UI(Layer, selected.layer, true); + } else if (selected.sequence) { + MAKE_UI(Sequence, selected.sequence, false); + } else if (selected.layer) { + char buffer[256]; + snprintf(buffer, 256, "Layer ID: %ld", selected.layer->id); + UILabelCreate(0, 0, buffer, -1); + + uintptr_t layerUsageCount = 0; + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + Style *style = styleSet.styles[i]; + + for (uintptr_t j = 0; j < arrlenu(style->layers); j++) { + if (style->layers[j] == selected.layer->id) { + layerUsageCount++; + } + } + } + + if (layerUsageCount > 1) { + snprintf(buffer, 256, "This layer is used %ld times.", layerUsageCount); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH)->gap = 10; + UILabelCreate(0, 0, buffer, -1); + UIButtonCreate(0, 0, "Fork", -1)->invoke = ForkLayer; + UIParentPop(); + } + + if (selected.layer->isMetricsLayer) { + assert(selected.layer->base.tag == LayerBase_metrics + 1); + MakeUIState state = { 0 }; + state.s.op = OP_MAKE_UI; + state.index = Layer_base; + state.recurse = true; + RfItem item = Layer_Type.fields[Layer_base].item; + void *pointer = (uint8_t *) selected.layer + Layer_Type.fields[Layer_base].offset; + MakeUI(&state, &item, pointer); + } else { + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + UIButtonCreate(0, UI_BUTTON_SMALL, "Move up", -1)->invoke = ButtonMoveLayerUp; + UIButtonCreate(0, UI_BUTTON_SMALL, "Move down", -1)->invoke = ButtonMoveLayerDown; + UIParentPop(); + + MAKE_UI(Layer, selected.layer, false); + } + } + + UIParentPop(); + UIElementRefresh(&panelInspector->e); + UIElementRepaint(elementCanvas, NULL); +} + +void StyleListRefresh(); + +void SetSelectedItems(ModContext context) { + if (0 == memcmp(&selected, &context, sizeof(context))) { + return; + } + + arrfree(animatingValues); + + selected = context; + + tableLayers->itemCount = selected.style ? arrlen(selected.style->layers) : 0; + UITableResizeColumns(tableLayers); + UIElementRefresh(&tableLayers->e); + + tableSequences->itemCount = selected.layer ? arrlen(selected.layer->sequences) : 0; + UITableResizeColumns(tableSequences); + UIElementRefresh(&tableSequences->e); + + tableKeyframes->itemCount = selected.sequence ? arrlen(selected.sequence->keyframes) : 0; + UITableResizeColumns(tableKeyframes); + UIElementRefresh(&tableKeyframes->e); + + static uint32_t layerNamePath[] = { Layer_name, RF_PATH_TERMINATOR }; + if (selected.layer && !selected.sequence) tableLayers->e.cp = layerNamePath; + else tableLayers->e.cp = NULL; + + static uint32_t sequencePath[] = { PATH_ANY, RF_PATH_TERMINATOR }; + if (selected.sequence && !selected.keyframe) tableSequences->e.cp = sequencePath; + else tableSequences->e.cp = NULL; + + static uint32_t keyframeProgressPath[] = { Keyframe_progress, RF_PATH_TERMINATOR }; + if (selected.keyframe) tableSequences->e.cp = keyframeProgressPath; + else tableKeyframes->e.cp = NULL; + + StyleListRefresh(); + RebuildInspector(); +} + +// ------------------- Modifications ------------------- + +void ModPushUndo(ModData *data) { + Mod mod = { 0 }; + mod.context = selected; + mod.data = *data; + + if (modApplyUndo) { + arrput(redoStack, mod); + } else { + arrput(undoStack, mod); + } +} + +void _ModApply(Mod *mod) { + if (memcmp(&mod->context, &selected, sizeof(ModContext))) { + SetSelectedItems(mod->context); + } + + RfIterator iterator = { 0 }; + iterator.s.op = RF_OP_ITERATE; + RfItem item = { 0 }; + item.type = &ModData_Type; + item.byteCount = sizeof(Mod); + item.type->op(&iterator.s, &item, &mod->data); + + RfState state = { 0 }; + state.op = OP_DO_MOD; + iterator.item.type->op(&state, &iterator.item, iterator.pointer); + + UIElementRepaint(elementCanvas, NULL); +} + +void ClearUndoRedo() { + RfState state = { 0 }; + state.op = RF_OP_FREE; + state.allocate = RfRealloc; + RfItem item = { 0 }; + item.type = &Mod_Type; + item.byteCount = sizeof(Mod); + + for (uintptr_t i = 0; i < arrlenu(redoStack); i++) { + item.type->op(&state, &item, redoStack + i); + } + + for (uintptr_t i = 0; i < arrlenu(undoStack); i++) { + item.type->op(&state, &item, undoStack + i); + } + + arrfree(redoStack); + arrfree(undoStack); +} + +void ModApply(ModData *data) { + arrfree(animatingValues); + + Mod mod = { 0 }; + mod.context = selected; + mod.data = *data; + + modApplyUndo = false; + _ModApply(&mod); + + RfState state = { 0 }; + state.op = RF_OP_FREE; + state.allocate = RfRealloc; + RfItem item = { 0 }; + item.type = &Mod_Type; + item.byteCount = sizeof(Mod); + + for (uintptr_t i = 0; i < arrlenu(redoStack); i++) { + item.type->op(&state, &item, redoStack + i); + } + + arrfree(redoStack); + + if (arrlenu(undoStack) >= 2 && data->tag != ModData_deleteOverride + 1) { + Mod *undo1 = undoStack + arrlen(undoStack) - 1; + Mod *undo2 = undoStack + arrlen(undoStack) - 2; + + if (0 == memcmp(&undo1->context, &undo2->context, sizeof(ModContext))) { + if ((undo1->data.tag == ModData_changeProperty + 1 && undo2->data.tag == ModData_changeProperty + 1 + && ArePathsEqual(undo1->data.changeProperty.property.path, undo2->data.changeProperty.property.path)) + || (undo1->data.tag == ModData_changeProperty + 1 && undo2->data.tag == ModData_deleteOverride + 1 + && ArePathsEqual(undo1->data.changeProperty.property.path, undo2->data.deleteOverride.property.path))) { + item.type->op(&state, &item, undo1); + (void) arrpop(undoStack); + } + } + } +} + +void NotifySubscriptions(UIElement *source, uint32_t *path, void *pointer) { + for (uintptr_t i = 0; i < arrlenu(inspectorSubscriptions); i++) { + if (inspectorSubscriptions[i] == source) { + continue; + } + + uint32_t *subscription = (uint32_t *) inspectorSubscriptions[i]->cp; + + if (!subscription) { + continue; + } + + if (subscription[0] == PATH_ANY || ArePathsEqual(subscription, path)) { + UIElementMessage(inspectorSubscriptions[i], MSG_PROPERTY_CHANGED, 0, pointer); + } + } +} + +void ModChangePropertyOp(RfState *state, RfItem *item, void *pointer) { + ModChangeProperty *mod = (ModChangeProperty *) pointer; + + if (state->op == OP_DO_MOD) { + // Do we need to use an override? + bool isOverride = mod->property.path[0] == PATH_IN_KEYFRAME; + void *pointer = NULL; + + if (isOverride) { + bool foundOverride = false; + + // Does an override exist? + for (uintptr_t i = 0; i < arrlenu(selected.keyframe->properties); i++) { + if (ArePathsEqual(mod->property.path, selected.keyframe->properties[i].path)) { + // Save the old value for undo. + ModData undo = { 0 }; + undo.tag = ModData_changeProperty + 1; + undo.changeProperty.property.path = mod->property.path; + undo.changeProperty.property.data = selected.keyframe->properties[i].data; + ModPushUndo(&undo); + + // Load the new value. + selected.keyframe->properties[i].data = mod->property.data; + foundOverride = true; + break; + } + } + + if (!foundOverride) { + // Create the undo mod. + ModData undo = { 0 }; + undo.tag = ModData_deleteOverride + 1; + undo.deleteOverride.property.path = mod->property.path; + ModPushUndo(&undo); + + // Add the override. + Property property = mod->property; + property.path = DuplicatePath(property.path); + arrput(selected.keyframe->properties, property); + } + + // Load the object so we can notify subscribers. + RfItem item; + pointer = ResolveDataObject((RfPath *) mod->property.path, &item); + } else { + // Resolve the pointer. + RfItem item; + pointer = ResolveDataObject((RfPath *) mod->property.path, &item); + + // Save the old value for undo. + ModData undo = { 0 }; + undo.tag = ModData_changeProperty + 1; + undo.changeProperty.property.path = mod->property.path; + undo.changeProperty.property.data = SaveToGrowableBuffer(item.type, item.byteCount, item.options, pointer); + ModPushUndo(&undo); + + // Free the old value. + RfGrowableBuffer state = { 0 }; + state.s.allocate = RfRealloc; + state.s.op = RF_OP_FREE; + item.type->op(&state.s, &item, pointer); + + // Load the new value. + state.s.op = RF_OP_LOAD; + state.s.access = RfReadGrowableBuffer; + state.data = mod->property.data; + state.position = 0; + item.type->op(&state.s, &item, pointer); + free(state.data.buffer); + } + + // Notify subscribed elements in the inspector. + NotifySubscriptions(mod->source, mod->property.path, pointer); + } else { + RfStructOp(state, item, pointer); + } +} + +void ModDeleteOverrideOp(RfState *state, RfItem *item, void *pointer) { + ModDeleteOverride *mod = (ModDeleteOverride *) pointer; + + if (state->op == OP_DO_MOD) { + // Find the override. + for (uintptr_t i = 0; i < arrlenu(selected.keyframe->properties); i++) { + if (ArePathsEqual(mod->property.path, selected.keyframe->properties[i].path)) { + // Save the old value for undo. + ModData undo = { 0 }; + undo.tag = ModData_changeProperty + 1; + undo.changeProperty.property.path = mod->property.path; + undo.changeProperty.property.data = selected.keyframe->properties[i].data; + ModPushUndo(&undo); + + // Delete the override. + free(selected.keyframe->properties[i].path); + arrdel(selected.keyframe->properties, i); + + // Notify subscribed elements in the inspector. + RfItem item; + NotifySubscriptions(NULL, mod->property.path, + ResolveDataObject((RfPath *) mod->property.path, &item)); + + return; + } + } + + assert(false); + } else { + RfStructOp(state, item, pointer); + } +} + +void ModArrayOp(RfState *state, RfItem *item, void *pointer) { + ModArray *mod = (ModArray *) pointer; + + if (state->op == OP_DO_MOD) { + // Resolve the pointer. + RfItem item; + void **pointer = (void **) ResolveDataObject((RfPath *) mod->property.path, &item); + RfItem *elementItem = (RfItem *) item.options; + + if (mod->isDelete) { + size_t length = --((RfArrayHeader *) *pointer)[-1].length; + + ModData undo = { 0 }; + undo.tag = ModData_array + 1; + undo.array.property.path = mod->property.path; + undo.array.property.data = SaveToGrowableBuffer(elementItem->type, elementItem->byteCount, elementItem->options, + (uint8_t *) *pointer + elementItem->byteCount * length); + ModPushUndo(&undo); + } else { + *pointer = stbds_arrgrowf(*pointer, elementItem->byteCount, 1, 0); + + size_t length = ++((RfArrayHeader *) *pointer)[-1].length; + RfGrowableBuffer state = { 0 }; + state.s.allocate = RfRealloc; + state.s.op = RF_OP_LOAD; + state.s.access = RfReadGrowableBuffer; + state.data = mod->property.data; + state.position = 0; + uint8_t *p = (uint8_t *) *pointer + elementItem->byteCount * (length - 1); + memset(p, 0, elementItem->byteCount); + elementItem->type->op(&state.s, elementItem, p); + free(state.data.buffer); + + ModData undo = { 0 }; + undo.tag = ModData_array + 1; + undo.array.property.path = mod->property.path; + undo.array.isDelete = true; + ModPushUndo(&undo); + } + + // Notify subscribed elements in the inspector. + NotifySubscriptions(NULL, mod->property.path, pointer); + } else { + RfStructOp(state, item, pointer); + } +} + +// ------------------- Styles ------------------- + +UITextbox *stylesTextbox; +UITable *stylesTable; +UIButton *stylesShowWithSelectedLayer; +Style **stylesInList; + +int StylesTableMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_TABLE_GET_ITEM) { + UITableGetItem *m = (UITableGetItem *) dp; + Style *style = stylesInList[m->index]; + m->isSelected = style == selected.style; + + if (!style) { + return snprintf(m->buffer, m->bufferBytes, "View all"); + } else if (style->name.byteCount) { + return snprintf(m->buffer, m->bufferBytes, "%.*s", (int) style->name.byteCount, (char *) style->name.buffer); + } else { + return snprintf(m->buffer, m->bufferBytes, "(default)"); + } + } else if (message == UI_MSG_CLICKED || message == UI_MSG_MOUSE_DRAG) { + int index = UITableHitTest(stylesTable, element->window->cursorX, element->window->cursorY); + assert(index <= arrlen(stylesInList)); + + if (index >= 0) { + bool keepExistingLayer = false; + + if (selected.layer && stylesInList[index]) { + for (uintptr_t i = 0; i < arrlenu(stylesInList[index]->layers); i++) { + if (stylesInList[index]->layers[i] == selected.layer->id) { + keepExistingLayer = true; + break; + } + } + } + + SetSelectedItems(MOD_CONTEXT(stylesInList[index], keepExistingLayer ? selected.layer : NULL, NULL, NULL)); + UIElementRefresh(&stylesTable->e); + } + } + + return 0; +} + +int StyleCompare(const void *_left, const void *_right) { + Style *left = *(Style **) _left; + Style *right = *(Style **) _right; + return StringCompareRaw(left->name.buffer, left->name.byteCount, right->name.buffer, right->name.byteCount); +} + +void StyleListRefresh() { + qsort(styleSet.styles, arrlenu(styleSet.styles), sizeof(Style *), StyleCompare); + + arrfree(stylesInList); + + bool showWithSelectedLayer = stylesShowWithSelectedLayer->e.flags & UI_BUTTON_CHECKED; + + if (!showWithSelectedLayer) { + arrput(stylesInList, NULL); + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + bool include = false; + + if (showWithSelectedLayer && selected.layer) { + for (uintptr_t j = 0; j < arrlenu(styleSet.styles[i]->layers); j++) { + if (styleSet.styles[i]->layers[j] == selected.layer->id) { + include = true; + break; + } + } + } else { + include = true; + } + + if (include) { + arrput(stylesInList, styleSet.styles[i]); + } + } + + stylesTable->itemCount = arrlenu(stylesInList); + UITableResizeColumns(stylesTable); + UIElementRefresh(&stylesTable->e); + + UITextboxClear(stylesTextbox, false); + UIElementRefresh(&stylesTextbox->e); + + if (selected.style && selected.style->publicStyle) buttonPublicStyle->e.flags |= UI_BUTTON_CHECKED; + else buttonPublicStyle->e.flags &= ~UI_BUTTON_CHECKED; +} + +void ButtonCreateStyle(void *_unused) { + if (!stylesTextbox->bytes) { + return; + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + if (styleSet.styles[i]->name.byteCount == (size_t) stylesTextbox->bytes + && 0 == memcmp(styleSet.styles[i]->name.buffer, stylesTextbox->string, stylesTextbox->bytes)) { + return; + } + } + + Style *style = calloc(1, sizeof(Style)); + style->name.buffer = malloc((style->name.byteCount = stylesTextbox->bytes)); + style->id = ++styleSet.lastID; + memcpy(style->name.buffer, stylesTextbox->string, style->name.byteCount); + Layer *metrics = calloc(1, sizeof(Layer)); + metrics->id = ++styleSet.lastID; + metrics->name.buffer = malloc(16); + metrics->name.byteCount = snprintf(metrics->name.buffer, 16, "Metrics"); + metrics->base.tag = LayerBase_metrics + 1; + metrics->isMetricsLayer = true; + arrput(style->layers, metrics->id); + arrput(styleSet.layers, metrics); + arrput(styleSet.styles, style); + SetSelectedItems(MOD_CONTEXT(style, NULL, NULL, NULL)); + + ClearUndoRedo(); + StyleListRefresh(); +} + +void ButtonDeleteStyle(void *_unused) { + if (!selected.style) return; + Style *style = selected.style; + SetSelectedItems(MOD_CONTEXT(NULL, NULL, NULL, NULL)); + + bool found = false; + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + if (styleSet.styles[i] == style) { + RfState state = { 0 }; + state.op = RF_OP_FREE; + state.allocate = RfRealloc; + RfItem item = { 0 }; + item.type = &Style_Type; + item.byteCount = sizeof(Style); + item.type->op(&state, &item, style); + arrdel(styleSet.styles, i); + found = true; + break; + } + } + + assert(found); + + ClearUndoRedo(); + StyleListRefresh(); +} + +void ButtonTogglePublicStyle(void *_unused) { + if (!selected.style) { + return; + } + + selected.style->publicStyle = !selected.style->publicStyle; + + if (selected.style->publicStyle) buttonPublicStyle->e.flags |= UI_BUTTON_CHECKED; + else buttonPublicStyle->e.flags &= ~UI_BUTTON_CHECKED; +} + +void ButtonRenameStyle(void *_unused) { + if (!stylesTextbox->bytes || !selected.style) { + return; + } + + selected.style->name.buffer = realloc(selected.style->name.buffer, (selected.style->name.byteCount = stylesTextbox->bytes)); + memcpy(selected.style->name.buffer, stylesTextbox->string, selected.style->name.byteCount); + + ClearUndoRedo(); + StyleListRefresh(); +} + +void ButtonShowStylesWithSelectedLayer(void *_unused) { + stylesShowWithSelectedLayer->e.flags ^= UI_BUTTON_CHECKED; + StyleListRefresh(); +} + +// ------------------- Constants ------------------- + +UITextbox *constantsTextbox; +UITextbox *constantsValue; +UIButton *constantsScale; +UITable *constantsTable; +Constant *selectedConstant; + +void ConstantsDialogSetSelected(Constant *constant) { + selectedConstant = constant; + UIElementRefresh(&constantsTable->e); + + UITextboxClear(constantsValue, false); + + if (constant) { + UITextboxReplace(constantsValue, constant->value.buffer, constant->value.byteCount, false); + constantsValue->e.flags &= ~UI_ELEMENT_DISABLED; + UIElementRefresh(&constantsValue->e); + + if (constant->scale) constantsScale->e.flags |= UI_BUTTON_CHECKED; + else constantsScale->e.flags &= ~UI_BUTTON_CHECKED; + UIElementRefresh(&constantsScale->e); + } else { + constantsValue->e.flags |= UI_ELEMENT_DISABLED; + UIElementRefresh(&constantsValue->e); + + constantsScale->e.flags &= ~UI_BUTTON_CHECKED; + UIElementRefresh(&constantsScale->e); + } +} + +int ConstantsTableMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_TABLE_GET_ITEM) { + UITableGetItem *m = (UITableGetItem *) dp; + Constant *constant = styleSet.constants[m->index]; + m->isSelected = constant == selectedConstant; + return snprintf(m->buffer, m->bufferBytes, "%.*s", (int) constant->key.byteCount, (char *) constant->key.buffer); + } else if (message == UI_MSG_CLICKED || message == UI_MSG_MOUSE_DRAG) { + int index = UITableHitTest(constantsTable, element->window->cursorX, element->window->cursorY); + + if (index != -1) { + ConstantsDialogSetSelected(styleSet.constants[index]); + } + } + + return 0; +} + +int ConstantsValueMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_VALUE_CHANGED) { + if (selectedConstant) { + free(selectedConstant->value.buffer); + selectedConstant->value.buffer = malloc(constantsValue->bytes); + selectedConstant->value.byteCount = constantsValue->bytes; + memcpy(selectedConstant->value.buffer, constantsValue->string, constantsValue->bytes); + } + } + + return 0; +} + +int ConstantsScaleMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_CLICKED) { + if (selectedConstant) { + element->flags ^= UI_BUTTON_CHECKED; + selectedConstant->scale = element->flags & UI_BUTTON_CHECKED; + } + } + + return 0; +} + +int ConstantCompare(const void *_left, const void *_right) { + Constant *left = *(Constant **) _left; + Constant *right = *(Constant **) _right; + return StringCompareRaw(left->key.buffer, left->key.byteCount, right->key.buffer, right->key.byteCount); +} + +void ConstantListRefresh() { + constantsTable->itemCount = arrlenu(styleSet.constants); + qsort(styleSet.constants, constantsTable->itemCount, sizeof(Constant *), ConstantCompare); + UITableResizeColumns(constantsTable); + UIElementRefresh(&constantsTable->e); + + UITextboxClear(constantsTextbox, false); + UIElementRefresh(&constantsTextbox->e); +} + +void ButtonAddConstant(void *_unused) { + if (!constantsTextbox->bytes) { + return; + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.constants); i++) { + if (styleSet.constants[i]->key.byteCount == (size_t) constantsTextbox->bytes + && 0 == memcmp(styleSet.constants[i]->key.buffer, constantsTextbox->string, constantsTextbox->bytes)) { + return; + } + } + + Constant *constant = calloc(1, sizeof(Constant)); + constant->key.buffer = malloc((constant->key.byteCount = constantsTextbox->bytes)); + memcpy(constant->key.buffer, constantsTextbox->string, constant->key.byteCount); + arrput(styleSet.constants, constant); + + ConstantsDialogSetSelected(constant); + ConstantListRefresh(); +} + +void ButtonDeleteConstant(void *_unused) { + if (!selectedConstant) { + return; + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.constants); i++) { + if (styleSet.constants[i] == selectedConstant) { + arrdel(styleSet.constants, i); + ConstantsDialogSetSelected(NULL); + ConstantListRefresh(); + } + } +} + +// ------------------- Colors ------------------- + +UITextbox *colorsTextbox; +UITextbox *colorsValue; +UIColorPicker *colorsValue2; +UITable *colorsTable; +UIElement *colorsPreview; +Color *selectedColor; + +int ColorsPreviewMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_PAINT) { + UIDrawRectangle((UIPainter *) dp, element->bounds, selectedColor ? selectedColor->value : 0, 0xFF000000, UI_RECT_1(1)); + } else if (message == UI_MSG_GET_WIDTH || message == UI_MSG_GET_HEIGHT) { + return 20; + } + + return 0; +} + +void ColorsDialogSetSelected(Color *color) { + selectedColor = color; + UIElementRefresh(&colorsTable->e); + + UITextboxClear(colorsValue, false); + + if (color) { + char buffer[16]; + sprintf(buffer, "%.8X", color->value); + UITextboxReplace(colorsValue, buffer, -1, false); + colorsValue->e.flags &= ~UI_ELEMENT_DISABLED; + UIColorToHSV(color->value, &colorsValue2->hue, &colorsValue2->saturation, &colorsValue2->value); + colorsValue2->opacity = (selectedColor->value >> 24) / 255.0f; + UIElementRefresh(&colorsValue->e); + UIElementRefresh(&colorsValue2->e); + UIElementRefresh(colorsPreview); + } else { + colorsValue->e.flags |= UI_ELEMENT_DISABLED; + UIElementRefresh(&colorsValue->e); + } +} + +int ColorsTableMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_TABLE_GET_ITEM) { + UITableGetItem *m = (UITableGetItem *) dp; + Color *color = styleSet.colors[m->index]; + m->isSelected = color == selectedColor; + + if (m->column == 1) { + return snprintf(m->buffer, m->bufferBytes, "%.8X", color->value); + } else { + return snprintf(m->buffer, m->bufferBytes, "%.*s", (int) color->key.byteCount, (char *) color->key.buffer); + } + } else if (message == UI_MSG_CLICKED || message == UI_MSG_MOUSE_DRAG) { + int index = UITableHitTest(colorsTable, element->window->cursorX, element->window->cursorY); + + if (index != -1) { + ColorsDialogSetSelected(styleSet.colors[index]); + } + } + + return 0; +} + +int ColorsValue2Message(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_VALUE_CHANGED) { + if (selectedColor) { + uint32_t newValue; + UIColorToRGB(colorsValue2->hue, colorsValue2->saturation, colorsValue2->value, &newValue); + newValue |= (uint32_t) (colorsValue2->opacity * 255.0f) << 24; + selectedColor->value = newValue; + char buffer[16]; + sprintf(buffer, "%.8X", selectedColor->value); + UITextboxClear(colorsValue, false); + UITextboxReplace(colorsValue, buffer, -1, false); + UIElementRefresh(&colorsValue->e); + UIElementRefresh(colorsPreview); + UIElementRepaint(elementCanvas, NULL); + } + } + + return 0; +} + +int ColorsValueMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_VALUE_CHANGED) { + if (selectedColor) { + char buffer[16]; + int length = 15 > colorsValue->bytes ? colorsValue->bytes : 15; + memcpy(buffer, colorsValue->string, length); + buffer[length] = 0; + selectedColor->value = strtol(buffer, NULL, 16); + UITableResizeColumns(colorsTable); + UIElementRefresh(&colorsTable->e); + UIColorToHSV(selectedColor->value, &colorsValue2->hue, &colorsValue2->saturation, &colorsValue2->value); + colorsValue2->opacity = (selectedColor->value >> 24) / 255.0f; + UIElementRefresh(&colorsValue2->e); + UIElementRefresh(colorsPreview); + UIElementRepaint(elementCanvas, NULL); + } + } + + return 0; +} + +int ColorCompare(const void *_left, const void *_right) { + Color *left = *(Color **) _left; + Color *right = *(Color **) _right; + return StringCompareRaw(left->key.buffer, left->key.byteCount, right->key.buffer, right->key.byteCount); +} + +void ColorListRefresh() { + colorsTable->itemCount = arrlenu(styleSet.colors); + qsort(styleSet.colors, colorsTable->itemCount, sizeof(Color *), ColorCompare); + UITableResizeColumns(colorsTable); + UIElementRefresh(&colorsTable->e); + + UITextboxClear(colorsTextbox, false); + UIElementRefresh(&colorsTextbox->e); +} + +void ButtonAddColor(void *_unused) { + if (!colorsTextbox->bytes) { + return; + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.colors); i++) { + if (styleSet.colors[i]->key.byteCount == (size_t) colorsTextbox->bytes + && 0 == memcmp(styleSet.colors[i]->key.buffer, colorsTextbox->string, colorsTextbox->bytes)) { + return; + } + } + + Color *color = calloc(1, sizeof(Color)); + color->id = ++styleSet.lastID; + color->key.buffer = malloc((color->key.byteCount = colorsTextbox->bytes)); + memcpy(color->key.buffer, colorsTextbox->string, color->key.byteCount); + arrput(styleSet.colors, color); + + ColorsDialogSetSelected(color); + ColorListRefresh(); +} + +void ButtonDeleteColor(void *_unused) { + if (!selectedColor) { + return; + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.colors); i++) { + if (styleSet.colors[i] == selectedColor) { + arrdel(styleSet.colors, i); + ColorsDialogSetSelected(NULL); + ColorListRefresh(); + } + } +} + +// ------------------- Item lists ------------------- + +void DoAddItemMod(void ***array, void *item, int index, int undoField) { + ModData undo = { 0 }; + undo.tag = undoField + 1; + undo.deleteLayer.index = index; + ModPushUndo(&undo); + arrins(*array, index, item); +} + +void DoDeleteItemMod(void ***array, int index, int undoField) { + ModData undo = { 0 }; + undo.tag = undoField + 1; + undo.addLayer.layer = (Layer *) (*array)[index]; + undo.addLayer.index = index; + ModPushUndo(&undo); + arrdel(*array, index); +} + +void ButtonDeleteItem(void *selected, void **array, int field) { + if (!selected) return; + + ModData mod = { 0 }; + mod.tag = field + 1; + bool found = false; + + for (uintptr_t i = 0; i < arrlenu(array); i++) { + if (array[i] == selected) { + mod.deleteLayer.index = i; + found = true; + break; + } + } + + assert(found); + ModApply(&mod); +} + +void DesignerArrayOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == OP_MAKE_UI) { + ((MakeUIState *) state)->recurse = false; + } else { + RfArrayOp(state, item, pointer); + } +} + +// ------------------- Fonts ------------------- + +BasicFontKerningEntry *kerningEntries; + +bool ImportFont(char *fileData) { + arrfree(kerningEntries); + stbtt_fontinfo font = {}; + + if (!stbtt_InitFont(&font, (uint8_t *) fileData, 0)) { + return false; + } + + float scale = stbtt_ScaleForPixelHeight(&font, 100); + + const char *charactersToImport = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + + for (uintptr_t character = 0; charactersToImport[character]; character++) { + int glyphIndex = stbtt_FindGlyphIndex(&font, charactersToImport[character]); + stbtt_vertex *vertices; + int vertexCount = stbtt_GetGlyphShape(&font, glyphIndex, &vertices); + // printf("importing glyph for character '%c'\n", charactersToImport[character]); + + int x0, y0, x1, y1, advanceWidth, leftSideBearing; + stbtt_GetGlyphHMetrics(&font, glyphIndex, &advanceWidth, &leftSideBearing); + stbtt_GetGlyphBox(&font, glyphIndex, &x0, &y0, &x1, &y1); + // printf("\t%d, %d, %d, %d, %d, %d\n", x0, x1, y0, y1, advanceWidth, leftSideBearing); + + Style *style = calloc(1, sizeof(Style)); + style->name.buffer = malloc(32); + style->name.byteCount = snprintf(style->name.buffer, 32, "Glyph %c", charactersToImport[character]); + style->id = ++styleSet.lastID; + Layer *metrics = calloc(1, sizeof(Layer)); + metrics->id = ++styleSet.lastID; + metrics->name.buffer = malloc(16); + metrics->name.byteCount = snprintf(metrics->name.buffer, 16, "Metrics"); + metrics->base.tag = LayerBase_metrics + 1; + metrics->base.metrics.minimumSize.width = x0; // Put these somewhere with 16 bits of space... + metrics->base.metrics.maximumSize.width = x1; + metrics->base.metrics.minimumSize.height = y0; + metrics->base.metrics.maximumSize.height = y1; + metrics->base.metrics.preferredSize.width = advanceWidth; + metrics->isMetricsLayer = true; + arrput(style->layers, metrics->id); + arrput(styleSet.layers, metrics); + arrput(styleSet.styles, style); + + Layer *layer = calloc(1, sizeof(Layer)); + layer->id = ++styleSet.lastID; + layer->name.buffer = malloc(16); + layer->name.byteCount = snprintf(layer->name.buffer, 16, "Path"); + layer->base.tag = LayerBase_path + 1; + layer->mode = LAYER_MODE_BACKGROUND; + layer->position.r = 100; + layer->position.b = 100; + arrput(style->layers, layer->id); + arrput(styleSet.layers, layer); + + LayerPath *layerPath = &layer->base.path; + layerPath->closed = true; + layerPath->alpha = 255; + + PathFill fill = {}; + fill.mode.tag = PathFillMode_solid + 1; + fill.paint.tag = Paint_solid + 1; + fill.paint.solid.color = 0xFF000000; + arrput(layerPath->fills, fill); + + int i = 0; + + while (i < vertexCount) { + if (vertices[i].type == STBTT_vmove) { + // printf("move to %d, %d\n", vertices[i].x, vertices[i].y); + + if (arrlen(layerPath->points)) { + PathPoint *p = &arrlast(layerPath->points); + p->x1 = -1e6; + } + + PathPoint point = {}; + point.x0 = vertices[i].x; + point.y0 = vertices[i].y; + arrput(layerPath->points, point); + } else if (vertices[i].type == STBTT_vline) { + // printf("line to %d, %d\n", vertices[i].x, vertices[i].y); + + if (!arrlen(layerPath->points)) return false; + PathPoint *p = &arrlast(layerPath->points); + p->x1 = p->x0; + p->y1 = p->y0; + p->x2 = vertices[i].x; + p->y2 = vertices[i].y; + PathPoint point = {}; + point.x0 = vertices[i].x; + point.y0 = vertices[i].y; + arrput(layerPath->points, point); + } else if (vertices[i].type == STBTT_vcurve) { + // printf("curve to %d, %d via %d, %d\n", vertices[i].x, vertices[i].y, vertices[i].cx, vertices[i].cy); + + if (!arrlen(layerPath->points)) return false; + PathPoint *p = &arrlast(layerPath->points); + p->x1 = (p->x0 + 0.6667f * (vertices[i].cx - p->x0)); + p->y1 = (p->y0 + 0.6667f * (vertices[i].cy - p->y0)); + p->x2 = (vertices[i].x + 0.6667f * (vertices[i].cx - vertices[i].x)); + p->y2 = (vertices[i].y + 0.6667f * (vertices[i].cy - vertices[i].y)); + PathPoint point = {}; + point.x0 = vertices[i].x; + point.y0 = vertices[i].y; + arrput(layerPath->points, point); + } else if (vertices[i].type == STBTT_vcubic) { + // printf("cubic to %d, %d\n", vertices[i].x, vertices[i].y); + + if (!arrlen(layerPath->points)) return false; + PathPoint *p = &arrlast(layerPath->points); + p->x1 = vertices[i].cx; + p->y1 = vertices[i].cy; + p->x2 = vertices[i].cx1; + p->y2 = vertices[i].cy1; + PathPoint point = {}; + point.x0 = vertices[i].x; + point.y0 = vertices[i].y; + arrput(layerPath->points, point); + } else { + return false; + } + + i++; + } + + for (uintptr_t i = 0; i < arrlenu(layerPath->points); i++) { + layerPath->points[i].x0 *= scale; + if (layerPath->points[i].x1 != -1e6) layerPath->points[i].x1 *= scale; + layerPath->points[i].x2 *= scale; + layerPath->points[i].y0 *= scale; + layerPath->points[i].y1 *= scale; + layerPath->points[i].y2 *= scale; + } + + stbtt_FreeShape(&font, vertices); + } + + int ascent, descent, lineGap; + stbtt_GetFontVMetrics(&font, &ascent, &descent, &lineGap); + + { + Constant *constant = calloc(1, sizeof(Constant)); + constant->key.buffer = malloc(16); + constant->key.byteCount = strlen(strcpy((char *) constant->key.buffer, "ascent")); + constant->value.buffer = malloc(16); + constant->value.byteCount = snprintf((char *) constant->value.buffer, 16, "%d", ascent); + arrput(styleSet.constants, constant); + } + + { + Constant *constant = calloc(1, sizeof(Constant)); + constant->key.buffer = malloc(16); + constant->key.byteCount = strlen(strcpy((char *) constant->key.buffer, "descent")); + constant->value.buffer = malloc(16); + constant->value.byteCount = snprintf((char *) constant->value.buffer, 16, "%d", descent); + arrput(styleSet.constants, constant); + } + + { + Constant *constant = calloc(1, sizeof(Constant)); + constant->key.buffer = malloc(16); + constant->key.byteCount = strlen(strcpy((char *) constant->key.buffer, "lineGap")); + constant->value.buffer = malloc(16); + constant->value.byteCount = snprintf((char *) constant->value.buffer, 16, "%d", lineGap); + arrput(styleSet.constants, constant); + } + + for (uintptr_t c1 = 0; charactersToImport[c1]; c1++) { + for (uintptr_t c2 = 0; charactersToImport[c2]; c2++) { + int xAdvance = stbtt_GetGlyphKernAdvance(&font, + stbtt_FindGlyphIndex(&font, charactersToImport[c1]), + stbtt_FindGlyphIndex(&font, charactersToImport[c2])); + if (!xAdvance) continue; + + BasicFontKerningEntry entry = { 0 }; + entry.leftGlyphIndex = charactersToImport[c1]; + entry.rightGlyphIndex = charactersToImport[c2]; + entry.xAdvance = xAdvance; + arrput(kerningEntries, entry); + } + } + + return true; +} + +void ExportFont(const char *path) { + FILE *f = fopen(path, "wb"); + + BasicFontHeader header = { BASIC_FONT_SIGNATURE }; + + for (uintptr_t i = 0; i < arrlenu(styleSet.constants); i++) { + if (styleSet.constants[i]->key.byteCount == 6 && 0 == memcmp(styleSet.constants[i]->key.buffer, "ascent", 6)) { + header.ascender = atoi((char *) styleSet.constants[i]->value.buffer); + } else if (styleSet.constants[i]->key.byteCount == 7 && 0 == memcmp(styleSet.constants[i]->key.buffer, "descent", 7)) { + header.descender = atoi((char *) styleSet.constants[i]->value.buffer); + } + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + Style *style = styleSet.styles[i]; + + if (style->name.byteCount > 6 && 0 == memcmp(style->name.buffer, "Glyph ", 6)) { + header.glyphCount++; + } + } + + header.kerningEntries = arrlenu(kerningEntries); + + fwrite(&header, 1, sizeof(BasicFontHeader), f); + + uint32_t offsetToPoints = sizeof(BasicFontHeader) + + sizeof(BasicFontGlyph) * header.glyphCount + + sizeof(BasicFontKerningEntry) * header.kerningEntries; + + uint32_t *characters = NULL; + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + Style *style = styleSet.styles[i]; + + if (style->name.byteCount > 6 && 0 == memcmp(style->name.buffer, "Glyph ", 6)) { + BasicFontGlyph glyph = { 0 }; + assert(arrlenu(style->layers) == 2); + glyph.codepoint = ((char *) style->name.buffer)[6]; + LayerMetrics *metrics = &LayerLookup(style->layers[0])->base.metrics; + LayerPath *path = &LayerLookup(style->layers[1])->base.path; + glyph.xAdvance = metrics->preferredSize.width; + glyph.xOffset = metrics->minimumSize.width; + glyph.yOffset = metrics->minimumSize.height; + glyph.width = metrics->maximumSize.width - metrics->minimumSize.width; + glyph.height = metrics->maximumSize.height - metrics->minimumSize.height; + glyph.pointCount = arrlenu(path->points); + glyph.offsetToPoints = offsetToPoints; + offsetToPoints += glyph.pointCount * 6 * sizeof(float); + fwrite(&glyph, 1, sizeof(BasicFontGlyph), f); + arrput(characters, glyph.codepoint); + } + } + + arrfree(characters); + + for (uintptr_t i = 0; i < arrlenu(kerningEntries); i++) { + BasicFontKerningEntry *entry = kerningEntries + i; + BasicFontKerningEntry copy = *entry; + + for (uintptr_t i = 0; i < arrlenu(characters); i++) { + if (entry->leftGlyphIndex == characters[i]) { + copy.leftGlyphIndex = i; + } + + if (entry->rightGlyphIndex == characters[i]) { + copy.rightGlyphIndex = i; + } + } + + fwrite(©, 1, sizeof(BasicFontKerningEntry), f); + } + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + Style *style = styleSet.styles[i]; + + if (style->name.byteCount > 6 && 0 == memcmp(style->name.buffer, "Glyph ", 6)) { + LayerPath *path = &LayerLookup(style->layers[1])->base.path; + // printf("%ld at %ld, %ld\n", i, ftell(f), arrlenu(path->points)); + fwrite(path->points, 1, arrlenu(path->points) * 6 * sizeof(float), f); + } + } + + fclose(f); +} + +void ButtonImportFontConfirm(void *_unused) { + if (!importDialog) { + return; + } + + char path[4096]; + + if (importPathTextbox->bytes > (ptrdiff_t) sizeof(path) - 1) { + UILabelSetContent(importPathMessage, "Path too long", -1); + UIElementRefresh(&importPathMessage->e); + return; + } + + memcpy(path, importPathTextbox->string, importPathTextbox->bytes); + path[importPathTextbox->bytes] = 0; + + char *fileData = LoadFile(path, NULL); + + if (fileData && ImportFont(fileData)) { + ConstantListRefresh(); + ClearUndoRedo(); + StyleListRefresh(); + UIElementDestroy(&importDialog->e); + importDialog = NULL; + } else { + UILabelSetContent(importPathMessage, "Invalid or unsupported font file.", -1); + UIElementRefresh(&importPathMessage->e); + } + + free(fileData); +} + +void ActionImportFont(void *_unused) { + if (importDialog) { + return; + } + + importDialog = UIWindowCreate(window, UI_WINDOW_CENTER_IN_OWNER, "Import Font", 400, 100); + + UIPanelCreate(&importDialog->e, UI_PANEL_GRAY | UI_ELEMENT_PARENT_PUSH | UI_PANEL_EXPAND | UI_PANEL_MEDIUM_SPACING); + UILabelCreate(0, 0, "Enter path to font file:", -1); + importPathTextbox = UITextboxCreate(0, 0); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + importPathMessage = UILabelCreate(0, UI_ELEMENT_H_FILL, "", -1); + UIButtonCreate(0, 0, "Import", -1)->invoke = ButtonImportFontConfirm; + UIParentPop(); + UIParentPop(); + + UIElementFocus(&importPathTextbox->e); +} + +// ------------------- Importing SVG ------------------- + +void ImportSVGPath(NSVGimage *image, NSVGshape *shape) { + // TODO If shape has multiple paths, and has a contour fills, + // then the contours need to use each path separately. + + if ((~shape->flags & NSVG_FLAGS_VISIBLE) || shape->opacity == 0) { + return; + } + + ModData mod = { 0 }; + mod.tag = ModData_addLayer + 1; + mod.addLayer.index = arrlen(selected.style->layers); + + Layer *layer = calloc(1, sizeof(Layer)); + layer->id = ++styleSet.lastID; + layer->name.buffer = malloc(16); + layer->name.byteCount = snprintf(layer->name.buffer, 16, "path %d", mod.addLayer.index); + layer->base.tag = LayerBase_path + 1; + layer->mode = LAYER_MODE_BACKGROUND; + layer->position.r = 100; + layer->position.b = 100; + + LayerPath *layerPath = &layer->base.path; + layerPath->evenOdd = shape->fillRule == NSVG_FILLRULE_EVENODD; + layerPath->closed = shape->paths->closed; // TODO See comment about multiple paths above. + layerPath->alpha = shape->opacity * 255; + + float scale = 100.0f / image->width; + + NSVGpath *path = shape->paths; + + while (path) { + for (int i = 0; i < path->npts; i += 3) { + PathPoint point = {}; + + point.x0 = path->pts[i * 2 + 0] * scale; + point.y0 = path->pts[i * 2 + 1] * scale; + + if (i + 1 < path->npts) { + point.x1 = path->pts[i * 2 + 2] * scale; + point.y1 = path->pts[i * 2 + 3] * scale; + } else { + point.x1 = path->pts[i * 2 + 0] * scale; + point.y1 = path->pts[i * 2 + 1] * scale; + } + + if (i + 2 < path->npts) { + point.x2 = path->pts[i * 2 + 4] * scale; + point.y2 = path->pts[i * 2 + 5] * scale; + } else { + point.x2 = path->pts[i * 2 + 0] * scale; + point.y2 = path->pts[i * 2 + 1] * scale; + } + + arrput(layerPath->points, point); + } + + if (arrlenu(layerPath->points) && (path->closed || path->next)) { + PathPoint point = layerPath->points[0]; + point.x1 = -1e6; + point.x2 = point.y1 = point.y2 = 0; + arrput(layerPath->points, point); + } + + path = path->next; + } + + for (uintptr_t i = 0; i < 2; i++) { + NSVGpaint *paint = i ? &shape->stroke : &shape->fill; + + PathFill fill = {}; + + if (i) { + // TODO Dashes. + + fill.mode.tag = PathFillMode_contour + 1; + fill.mode.contour.internalWidth = shape->strokeWidth * 0.5f + 0.5f; // TODO Floating-point contour widths? + fill.mode.contour.externalWidth = shape->strokeWidth * 0.5f; + fill.mode.contour.joinMode = shape->strokeLineJoin == NSVG_JOIN_ROUND ? JOIN_MODE_ROUND + : shape->strokeLineJoin == NSVG_JOIN_BEVEL ? JOIN_MODE_BEVEL : JOIN_MODE_MITER; + fill.mode.contour.capMode = shape->strokeLineCap == NSVG_CAP_BUTT ? CAP_MODE_FLAT + : shape->strokeLineCap == NSVG_CAP_ROUND ? CAP_MODE_ROUND : CAP_MODE_SQUARE; + fill.mode.contour.miterLimit = shape->strokeWidth * shape->miterLimit; + } else { + fill.mode.tag = PathFillMode_solid + 1; + } + + if (paint->type == NSVG_PAINT_COLOR) { + fill.paint.tag = Paint_solid + 1; + fill.paint.solid.color = (paint->color & 0xFF00FF00) | ((paint->color & 0xFF) << 16) | ((paint->color & 0xFF0000) >> 16); + } else if (paint->type == NSVG_PAINT_LINEAR_GRADIENT) { + NSVGgradient *gradient = paint->gradient; + fill.paint.tag = Paint_linearGradient + 1; + + fill.paint.linearGradient.transformX = gradient->xform[1] * image->width; + fill.paint.linearGradient.transformY = gradient->xform[3] * image->height; + fill.paint.linearGradient.transformStart = gradient->xform[5]; + + size_t stopCount = gradient->nstops; + if (stopCount > 16) stopCount = 16; + + for (int i = 0; i < gradient->nstops; i++) { + GradientStop stop = {}; + uint32_t color = gradient->stops[i].color; + stop.color = (color & 0xFF00FF00) | ((color & 0xFF) << 16) | ((color & 0xFF0000) >> 16); + stop.position = gradient->stops[i].offset * 100; + arrput(fill.paint.linearGradient.stops, stop); + } + + if (gradient->spread == NSVG_SPREAD_PAD) { + fill.paint.linearGradient.repeat = GRADIENT_REPEAT_CLAMP; + } else if (gradient->spread == NSVG_SPREAD_REFLECT) { + fill.paint.linearGradient.repeat = GRADIENT_REPEAT_MIRROR; + } else if (gradient->spread == NSVG_SPREAD_REPEAT) { + fill.paint.linearGradient.repeat = GRADIENT_REPEAT_NORMAL; + } + } else if (paint->type == NSVG_PAINT_RADIAL_GRADIENT) { + NSVGgradient *gradient = paint->gradient; + fill.paint.tag = Paint_radialGradient + 1; + + fill.paint.radialGradient.transform0 = gradient->xform[0] * image->width; + fill.paint.radialGradient.transform1 = gradient->xform[2] * image->width; + fill.paint.radialGradient.transform2 = gradient->xform[4]; + fill.paint.radialGradient.transform3 = gradient->xform[1] * image->height; + fill.paint.radialGradient.transform4 = gradient->xform[3] * image->height; + fill.paint.radialGradient.transform5 = gradient->xform[5]; + + size_t stopCount = gradient->nstops; + if (stopCount > 16) stopCount = 16; + + for (int i = 0; i < gradient->nstops; i++) { + GradientStop stop = {}; + uint32_t color = gradient->stops[i].color; + stop.color = (color & 0xFF00FF00) | ((color & 0xFF) << 16) | ((color & 0xFF0000) >> 16); + stop.position = gradient->stops[i].offset * 100; + arrput(fill.paint.radialGradient.stops, stop); + } + + if (gradient->spread == NSVG_SPREAD_PAD) { + fill.paint.radialGradient.repeat = GRADIENT_REPEAT_CLAMP; + } else if (gradient->spread == NSVG_SPREAD_REFLECT) { + fill.paint.radialGradient.repeat = GRADIENT_REPEAT_MIRROR; + } else if (gradient->spread == NSVG_SPREAD_REPEAT) { + fill.paint.radialGradient.repeat = GRADIENT_REPEAT_NORMAL; + } + } + + arrput(layerPath->fills, fill); + } + + mod.addLayer.layer = layer; + ModApply(&mod); +} + +void ImportSVGImage(NSVGimage *image) { + previewWidth->position = image->width / 1000.0f; + previewHeight->position = image->height / 1000.0f; + + NSVGshape *shape = image->shapes; + + while (shape) { + if (shape->paths) { + ImportSVGPath(image, shape); + } + + shape = shape->next; + } +} + +void ButtonImportSVGConfirm(void *_unused) { + if (!importDialog) { + return; + } + + char path[4096]; + + if (importPathTextbox->bytes > (ptrdiff_t) sizeof(path) - 1) { + UILabelSetContent(importPathMessage, "Path too long", -1); + UIElementRefresh(&importPathMessage->e); + return; + } + + memcpy(path, importPathTextbox->string, importPathTextbox->bytes); + path[importPathTextbox->bytes] = 0; + + NSVGimage *image = nsvgParseFromFile(path, "px", 96.0f); + + if (image) { + UIElementDestroy(&importDialog->e); + importDialog = NULL; + ImportSVGImage(image); + nsvgDelete(image); + } else { + UILabelSetContent(importPathMessage, "Invalid or unsupported SVG file.", -1); + UIElementRefresh(&importPathMessage->e); + } +} + +void ButtonImportSVG(void *_unused) { + if (importDialog || !selected.style) { + return; + } + + importDialog = UIWindowCreate(window, UI_WINDOW_CENTER_IN_OWNER, "Import SVG", 400, 100); + + UIPanelCreate(&importDialog->e, UI_PANEL_GRAY | UI_ELEMENT_PARENT_PUSH | UI_PANEL_EXPAND | UI_PANEL_MEDIUM_SPACING); + UILabelCreate(0, 0, "Enter path to SVG file:", -1); + importPathTextbox = UITextboxCreate(0, 0); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + importPathMessage = UILabelCreate(0, UI_ELEMENT_H_FILL, "", -1); + UIButtonCreate(0, 0, "Import", -1)->invoke = ButtonImportSVGConfirm; + UIParentPop(); + UIParentPop(); + + UIElementFocus(&importPathTextbox->e); +} + +// ------------------- Layers ------------------- + +void CleanupUnusedLayers(void *_unused) { + ClearUndoRedo(); + + struct { + uint64_t key; + bool value; + } *usedLayers = NULL; + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + for (uintptr_t j = 0; j < arrlenu(styleSet.styles[i]->layers); j++) { + hmput(usedLayers, styleSet.styles[i]->layers[j], true); + } + } + + for (uintptr_t j = 0; j < arrlenu(styleSet.layers); j++) { + if (hmget(usedLayers, styleSet.layers[j]->id)) { + continue; + } + + printf("remove %ld\n", styleSet.layers[j]->id); + + RfState state = { 0 }; + state.op = RF_OP_FREE; + state.allocate = RfRealloc; + RfItem item = { 0 }; + item.type = &Layer_Type; + item.byteCount = sizeof(Layer); + item.type->op(&state, &item, styleSet.layers[j]); + + arrdel(styleSet.layers, j); + j--; + } +} + +int TableLayersMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_TABLE_GET_ITEM) { + UITableGetItem *m = (UITableGetItem *) dp; + Layer *l = LayerLookup(selected.style->layers[m->index]); + m->isSelected = selected.layer == l; + return snprintf(m->buffer, m->bufferBytes, "%.*s", (int) l->name.byteCount, (char *) l->name.buffer); + } else if (message == UI_MSG_CLICKED || message == UI_MSG_MOUSE_DRAG) { + int index = UITableHitTest(tableLayers, element->window->cursorX, element->window->cursorY); + + if (index != -1) { + SetSelectedItems(MOD_CONTEXT(selected.style, LayerLookup(selected.style->layers[index]), NULL, NULL)); + } + } else if (message == MSG_PROPERTY_CHANGED) { + UITableResizeColumns(tableLayers); + UIElementRefresh(&tableLayers->e); + } + + return 0; +} + +void ModAddLayerOp(RfState *state, RfItem *item, void *pointer) { + ModAddLayer *mod = (ModAddLayer *) pointer; + + if (state->op == OP_DO_MOD) { + ModData undo = { 0 }; + undo.tag = ModData_deleteLayer + 1; + undo.deleteLayer.index = mod->index; + ModPushUndo(&undo); + + arrins(selected.style->layers, mod->index, mod->layer->id); + arrput(styleSet.layers, mod->layer); + + SetSelectedItems(MOD_CONTEXT(selected.style, mod->layer, NULL, NULL)); + } else { + RfStructOp(state, item, pointer); + } +} + +void ButtonAddBoxLayer(void *_unused) { + if (!selected.style) return; + + ModData mod = { 0 }; + mod.tag = ModData_addLayer + 1; + mod.addLayer.index = arrlen(selected.style->layers); + + Layer *layer = calloc(1, sizeof(Layer)); + layer->id = ++styleSet.lastID; + layer->name.buffer = malloc(16); + layer->name.byteCount = snprintf(layer->name.buffer, 16, "box %d", mod.addLayer.index); + layer->base.tag = LayerBase_box + 1; + layer->position.r = 100; + layer->position.b = 100; + + mod.addLayer.layer = layer; + + ModApply(&mod); +} + +void ButtonAddTextLayer(void *_unused) { + if (!selected.style) return; + + ModData mod = { 0 }; + mod.tag = ModData_addLayer + 1; + mod.addLayer.index = arrlen(selected.style->layers); + + Layer *layer = calloc(1, sizeof(Layer)); + layer->id = ++styleSet.lastID; + layer->name.buffer = malloc(16); + layer->name.byteCount = snprintf(layer->name.buffer, 16, "text %d", mod.addLayer.index); + layer->base.tag = LayerBase_text + 1; + layer->mode = LAYER_MODE_CONTENT; + + mod.addLayer.layer = layer; + + ModApply(&mod); +} + +void ButtonAddPathLayer(void *_unused) { + if (!selected.style) return; + + ModData mod = { 0 }; + mod.tag = ModData_addLayer + 1; + mod.addLayer.index = arrlen(selected.style->layers); + + Layer *layer = calloc(1, sizeof(Layer)); + layer->id = ++styleSet.lastID; + layer->name.buffer = malloc(16); + layer->name.byteCount = snprintf(layer->name.buffer, 16, "path %d", mod.addLayer.index); + layer->base.tag = LayerBase_path + 1; + layer->mode = LAYER_MODE_BACKGROUND; + + mod.addLayer.layer = layer; + + ModApply(&mod); +} + +void ButtonAddLayer(void *_unused) { + UIMenu *menu = UIMenuCreate(&buttonAddLayer->e, 0); + UIMenuAddItem(menu, 0, "Add box...", -1, ButtonAddBoxLayer, NULL); + UIMenuAddItem(menu, 0, "Add text...", -1, ButtonAddTextLayer, NULL); + UIMenuAddItem(menu, 0, "Add path...", -1, ButtonAddPathLayer, NULL); + UIMenuShow(menu); +} + +void ButtonDuplicateLayer(void *_unused) { + if (!selected.layer) return; + RfGrowableBuffer state = { 0 }; + state.data = SaveToGrowableBuffer(&Layer_Type, sizeof(Layer), NULL, selected.layer); + ModData mod = { 0 }; + mod.tag = ModData_addLayer + 1; + mod.addLayer.index = arrlen(selected.style->layers); + Layer *layer = calloc(1, sizeof(Layer)); + state.s.version = saveFormatVersion; + state.data.byteCount -= sizeof(uint32_t); + state.s.allocate = RfRealloc; + state.s.access = RfReadGrowableBuffer; + RfItem item = { 0 }; + item.type = &Layer_Type; + item.byteCount = sizeof(Layer); + state.s.op = RF_OP_LOAD; + item.type->op(&state.s, &item, layer); + layer->id = ++styleSet.lastID; + mod.addLayer.layer = layer; + ModApply(&mod); +} + +void ButtonAddExistingLayer2(void *_layer) { + if (!selected.style) return; + + ModData mod = { 0 }; + mod.tag = ModData_addLayer + 1; + mod.addLayer.index = arrlen(selected.style->layers); + mod.addLayer.layer = (Layer *) _layer; + + ModApply(&mod); +} + +void ButtonAddExistingLayer(void *_unused) { + UIMenu *menu = UIMenuCreate(&buttonAddExistingLayer->e, 0); + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + Style *style = styleSet.styles[i]; + + for (uintptr_t j = 0; j < arrlenu(style->layers); j++) { + Layer *layer = LayerLookup(style->layers[j]); + if (!layer) continue; + char name[64]; + snprintf(name, sizeof(name), "%.*s:%.*s", (int) style->name.byteCount, (char *) style->name.buffer, + (int) layer->name.byteCount, (char *) layer->name.buffer); + UIMenuAddItem(menu, 0, name, -1, ButtonAddExistingLayer2, layer); + } + } + + UIMenuShow(menu); +} + +void ModDeleteLayerOp(RfState *state, RfItem *item, void *pointer) { + ModDeleteLayer *mod = (ModDeleteLayer *) pointer; + + if (state->op == OP_DO_MOD) { + ModData undo = { 0 }; + undo.tag = ModData_addLayer + 1; + undo.addLayer.layer = LayerLookup(selected.style->layers[mod->index]); + undo.addLayer.index = mod->index; + ModPushUndo(&undo); + arrdel(selected.style->layers, mod->index); + + if ((uintptr_t) mod->index < arrlenu(selected.style->layers)) { + SetSelectedItems(MOD_CONTEXT(selected.style, LayerLookup(selected.style->layers[mod->index]), NULL, NULL)); + } else if (arrlenu(selected.style->layers)) { + SetSelectedItems(MOD_CONTEXT(selected.style, LayerLookup(arrlast(selected.style->layers)), NULL, NULL)); + } else { + SetSelectedItems(MOD_CONTEXT(selected.style, NULL, NULL, NULL)); + } + } else { + RfStructOp(state, item, pointer); + } +} + +void ButtonDeleteLayer(void *_unused) { + if (!selected.layer) return; + + ModData mod = { 0 }; + mod.tag = ModData_deleteLayer + 1; + bool found = false; + + for (uintptr_t i = 0; i < arrlenu(selected.style->layers); i++) { + if (selected.style->layers[i] == selected.layer->id) { + mod.deleteLayer.index = i; + found = true; + break; + } + } + + assert(found); + ModApply(&mod); +} + +void ButtonDeleteLayerInAllStyles(void *_unused) { + if (!selected.layer) { + return; + } + + ClearUndoRedo(); + + for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { + for (uintptr_t j = 0; j < arrlenu(styleSet.styles[i]->layers); j++) { + if (styleSet.styles[i]->layers[j] == selected.layer->id) { + arrdel(styleSet.styles[i]->layers, j); + j--; + } + } + } + + bool found = false; + + for (uintptr_t i = 0; i < arrlenu(styleSet.layers); i++) { + if (styleSet.layers[i] == selected.layer) { + arrdel(styleSet.layers, i); + found = true; + break; + } + } + + assert(found); + + RfState state = { 0 }; + state.op = RF_OP_FREE; + state.allocate = RfRealloc; + RfItem item = { 0 }; + item.type = &Layer_Type; + item.byteCount = sizeof(Layer); + item.type->op(&state, &item, selected.layer); + + StyleListRefresh(); + SetSelectedItems(MOD_CONTEXT(selected.style, NULL, NULL, NULL)); +} + +void ModSwapLayersOp(RfState *state, RfItem *item, void *pointer) { + ModSwapLayers *mod = (ModSwapLayers *) pointer; + + if (state->op == OP_DO_MOD) { + assert(mod->index >= 0 && mod->index < arrlen(selected.style->layers) - 1); + + ModData undo = { 0 }; + undo.tag = ModData_swapLayers + 1; + undo.swapLayers.index = mod->index; + ModPushUndo(&undo); + + uint64_t temporary = selected.style->layers[mod->index]; + selected.style->layers[mod->index] = selected.style->layers[mod->index + 1]; + selected.style->layers[mod->index + 1] = temporary; + + UIElementRefresh(&tableLayers->e); + } else { + RfStructOp(state, item, pointer); + } +} + +// ------------------- Sequences ------------------- + +int TableSequencesMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_TABLE_GET_ITEM) { + UITableGetItem *m = (UITableGetItem *) dp; + Sequence *s = selected.layer->sequences[m->index]; + m->isSelected = selected.sequence == s; + return snprintf(m->buffer, m->bufferBytes, "%s%s%s%s%s%s%s%s%s%s", + ((StringOption *) PrimaryState_Type.fields[s->primaryState].item.options)->string, + s->flagFocused ? " (focused)" : "", + s->flagChecked ? " (checked)" : "", + s->flagIndeterminate ? " (indeterminate)" : "", + s->flagDefault ? " (default)" : "", + s->flagItemFocus ? " (list item focus)" : "", + s->flagListFocus ? " (list focus)" : "", + s->flagBeforeEnter ? " (before enter)" : "", + s->flagAfterExit ? " (after exit)" : "", + s->flagSelected ? " (selected)" : ""); + } else if (message == UI_MSG_CLICKED || message == UI_MSG_MOUSE_DRAG) { + int index = UITableHitTest(tableSequences, element->window->cursorX, element->window->cursorY); + + if (index != -1) { + SetSelectedItems(MOD_CONTEXT(selected.style, selected.layer, selected.layer->sequences[index], NULL)); + } + } else if (message == MSG_PROPERTY_CHANGED) { + UITableResizeColumns(tableSequences); + UIElementRefresh(&tableSequences->e); + } + + return 0; +} + +void ModAddSequenceOp(RfState *state, RfItem *item, void *pointer) { + ModAddSequence *mod = (ModAddSequence *) pointer; + + if (state->op == OP_DO_MOD) { + DoAddItemMod((void ***) &selected.layer->sequences, mod->sequence, mod->index, ModData_deleteSequence); + SetSelectedItems(MOD_CONTEXT(selected.style, selected.layer, mod->sequence, NULL)); + } else { + RfStructOp(state, item, pointer); + } +} + +void ButtonAddSequence(void *_unused) { + if (!selected.layer) return; + ModData mod = { 0 }; + mod.tag = ModData_addSequence + 1; + mod.addSequence.sequence = calloc(1, sizeof(Sequence)); + mod.addSequence.index = arrlen(selected.layer->sequences); + ModApply(&mod); +} + +void ModDeleteSequenceOp(RfState *state, RfItem *item, void *pointer) { + ModDeleteSequence *mod = (ModDeleteSequence *) pointer; + + if (state->op == OP_DO_MOD) { + DoDeleteItemMod((void ***) &selected.layer->sequences, mod->index, ModData_addSequence); + SetSelectedItems(MOD_CONTEXT(selected.style, selected.layer, NULL, NULL)); + } else { + RfStructOp(state, item, pointer); + } +} + +void ButtonDeleteSequence(void *_unused) { + if (!selected.sequence) return; + ButtonDeleteItem(selected.sequence, (void **) selected.layer->sequences, ModData_deleteSequence); +} + +void ButtonMoveSequenceUp(void *_unused) { + if (!selected.sequence) { + return; + } + + uintptr_t index = 0; + + for (uintptr_t i = 0; i < arrlenu(selected.layer->sequences); i++) { + if (selected.layer->sequences[i] == selected.sequence) { + index = i; + break; + } + } + + if (index <= 1) { + return; + } + + ModData mod = { 0 }; + mod.tag = ModData_swapSequences + 1; + mod.swapSequences.index = index - 1; + ModApply(&mod); +} + +void ButtonMoveSequenceDown(void *_unused) { + if (!selected.sequence) { + return; + } + + uintptr_t index = 0; + + for (uintptr_t i = 0; i < arrlenu(selected.layer->sequences); i++) { + if (selected.layer->sequences[i] == selected.sequence) { + index = i; + break; + } + } + + if (index == arrlenu(selected.layer->sequences) - 1) { + return; + } + + ModData mod = { 0 }; + mod.tag = ModData_swapSequences + 1; + mod.swapSequences.index = index; + ModApply(&mod); +} + +void ModSwapSequencesOp(RfState *state, RfItem *item, void *pointer) { + ModSwapSequences *mod = (ModSwapSequences *) pointer; + + if (state->op == OP_DO_MOD) { + assert(mod->index >= 0 && mod->index < arrlen(selected.layer->sequences) - 1); + + ModData undo = { 0 }; + undo.tag = ModData_swapSequences + 1; + undo.swapSequences.index = mod->index; + ModPushUndo(&undo); + + Sequence *temporary = selected.layer->sequences[mod->index]; + selected.layer->sequences[mod->index] = selected.layer->sequences[mod->index + 1]; + selected.layer->sequences[mod->index + 1] = temporary; + + UIElementRefresh(&tableSequences->e); + } else { + RfStructOp(state, item, pointer); + } +} + +// ------------------- Keyframes ------------------- + +int TableKeyframesMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_TABLE_GET_ITEM) { + UITableGetItem *m = (UITableGetItem *) dp; + Keyframe *k = selected.sequence->keyframes[m->index]; + m->isSelected = selected.keyframe == k; + return snprintf(m->buffer, m->bufferBytes, "%d%%", k->progress); + } else if (message == UI_MSG_CLICKED || message == UI_MSG_MOUSE_DRAG) { + int index = UITableHitTest(tableKeyframes, element->window->cursorX, element->window->cursorY); + + if (index != -1) { + SetSelectedItems(MOD_CONTEXT(selected.style, selected.layer, selected.sequence, selected.sequence->keyframes[index])); + } + } else if (message == MSG_PROPERTY_CHANGED) { + UITableResizeColumns(tableKeyframes); + UIElementRefresh(&tableKeyframes->e); + } + + return 0; +} + +void ModAddKeyframeOp(RfState *state, RfItem *item, void *pointer) { + ModAddKeyframe *mod = (ModAddKeyframe *) pointer; + + if (state->op == OP_DO_MOD) { + DoAddItemMod((void ***) &selected.sequence->keyframes, mod->keyframe, mod->index, ModData_deleteKeyframe); + SetSelectedItems(MOD_CONTEXT(selected.style, selected.layer, selected.sequence, mod->keyframe)); + } else { + RfStructOp(state, item, pointer); + } +} + +void ButtonAddKeyframe(void *_unused) { + if (!selected.sequence) return; + ModData mod = { 0 }; + mod.tag = ModData_addKeyframe + 1; + mod.addKeyframe.keyframe = calloc(1, sizeof(Keyframe)); + mod.addKeyframe.index = arrlen(selected.sequence->keyframes); + mod.addKeyframe.keyframe->progress = 100; + ModApply(&mod); +} + +void ModDeleteKeyframeOp(RfState *state, RfItem *item, void *pointer) { + ModDeleteKeyframe *mod = (ModDeleteKeyframe *) pointer; + + if (state->op == OP_DO_MOD) { + DoDeleteItemMod((void ***) &selected.sequence->keyframes, mod->index, ModData_addKeyframe); + SetSelectedItems(MOD_CONTEXT(selected.style, selected.layer, selected.sequence, NULL)); + } else { + RfStructOp(state, item, pointer); + } +} + +void ButtonDeleteKeyframe(void *_unused) { + if (!selected.keyframe) return; + ButtonDeleteItem(selected.keyframe, (void **) selected.sequence->keyframes, ModData_deleteKeyframe); +} + +// ------------------- Actions ------------------- + +void ActionSave(void *_unused) { + RfData data = SaveToGrowableBuffer(&StyleSet_Type, sizeof(styleSet), NULL, &styleSet); + FILE *f = fopen(filePath, "wb"); + fwrite(&saveFormatVersion, 1, sizeof(uint32_t), f); + fwrite(data.buffer, 1, data.byteCount, f); + fclose(f); + free(data.buffer); +} + +char *LoadFile(const char *inputFileName, size_t *byteCount) { + FILE *inputFile = fopen(inputFileName, "rb"); + + if (!inputFile) { + return NULL; + } + + fseek(inputFile, 0, SEEK_END); + size_t inputFileBytes = ftell(inputFile); + fseek(inputFile, 0, SEEK_SET); + + char *inputBuffer = (char *) malloc(inputFileBytes + 1); + size_t inputBytesRead = fread(inputBuffer, 1, inputFileBytes, inputFile); + inputBuffer[inputBytesRead] = 0; + fclose(inputFile); + + if (byteCount) *byteCount = inputBytesRead; + return inputBuffer; +} + +void ActionLoad(void *_unused) { + selectedConstant = NULL; + + RfGrowableBuffer state = { 0 }; + uint32_t *buffer = (uint32_t *) LoadFile(filePath, &state.data.byteCount); + + if (state.data.byteCount > sizeof(uint32_t)) { + state.s.version = *buffer; + state.data.buffer = buffer + 1; + state.data.byteCount -= sizeof(uint32_t); + state.s.allocate = RfRealloc; + state.s.access = RfReadGrowableBuffer; + + RfItem item = { 0 }; + item.type = &StyleSet_Type; + item.byteCount = sizeof(styleSet); + state.s.op = RF_OP_FREE; + item.type->op(&state.s, &item, &styleSet); + state.s.op = RF_OP_LOAD; + item.type->op(&state.s, &item, &styleSet); + + if (state.s.error) { + state.s.op = RF_OP_FREE; + state.s.error = false; + item.type->op(&state.s, &item, &styleSet); + } else { + if (state.s.version <= 17) { + RfState state = { 0 }; + state.op = OP_GET_PALETTE; + RfItem item = { 0 }; + item.type = &StyleSet_Type; + item.byteCount = sizeof(StyleSet); + item.options = NULL; + RfBroadcast(&state, &item, &styleSet, true); + + for (uintptr_t i = 0; i < hmlenu(palette); i++) { + fprintf(stderr, "%.8X (%d)\n", palette[i].key, palette[i].value); + + char name[16]; + snprintf(name, sizeof(name), "Color %d", (int) i + 1); + Color *color = calloc(1, sizeof(Color)); + color->key.buffer = strdup(name); + color->key.byteCount = strlen(name); + color->value = palette[i].key; + color->id = i + 1; + arrput(styleSet.colors, color); + + state.op = OP_REPLACE_COLOR; + replaceColorFrom = color->value; + replaceColorTo = color->id; + RfBroadcast(&state, &item, &styleSet, true); + } + + hmfree(palette); + } + + if (state.s.version <= 18) { + char name[16]; + snprintf(name, sizeof(name), "Uninitialised"); + Color *color = calloc(1, sizeof(Color)); + color->key.buffer = strdup(name); + color->key.byteCount = strlen(name); + color->value = 0; + color->id = 0; + arrput(styleSet.colors, color); + } + } + } + + free(buffer); + SetSelectedItems(MOD_CONTEXT(NULL, NULL, NULL, NULL)); + StyleListRefresh(); + ConstantListRefresh(); + ColorListRefresh(); + UIElementRepaint(elementCanvas, NULL); +} + +void ActionUndo(void *_unused) { + if (!arrlen(undoStack)) return; + modApplyUndo = true; + Mod mod = arrpop(undoStack); + _ModApply(&mod); +} + +void ActionRedo(void *_unused) { + if (!arrlen(redoStack)) return; + modApplyUndo = false; + Mod mod = arrpop(redoStack); + _ModApply(&mod); +} + +// ------------------- Initialisation ------------------- + +#ifdef _WIN32 +int WinMain(void *, void *, char *, int) +#else +int main(int argc, char **argv) +#endif +{ + if (argc == 4 && 0 == strcmp(argv[1], "--make-font")) { + bool success = ImportFont(LoadFile(argv[2], NULL)); + if (success) ExportFont(argv[3]); + return success ? 0 : 1; + } + + if (argc < 3 || argc > 5) { + fprintf(stderr, "Usage: %s <source path> <export path> <optional: embed bitmap path> <optional: styles header path>\n", argv[0]); + exit(1); + } + + filePath = argv[1]; + exportPath = argv[2]; + embedBitmapPath = argc >= 4 ? argv[3] : NULL; + stylesPath = argc >= 5 ? argv[4] : NULL; + + UIInitialise(); + + window = UIWindowCreate(0, 0, "Designer", 1600, 900); + + UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_LETTER('S'), true, false, false, ActionSave, NULL)); + UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_LETTER('E'), true, false, false, ActionExport, NULL)); + UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_LETTER('Z'), true, false, false, ActionUndo, NULL)); + UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_LETTER('Y'), true, false, false, ActionRedo, NULL)); + + UISplitPane *splitPane1 = UISplitPaneCreate(&window->e, UI_ELEMENT_V_FILL, 0.25f); + + UIPanel *panel1 = UIPanelCreate(&splitPane1->e, UI_PANEL_EXPAND); + + UIPanelCreate(&panel1->e, UI_PANEL_GRAY | UI_PANEL_HORIZONTAL | UI_PANEL_MEDIUM_SPACING | UI_ELEMENT_PARENT_PUSH); + UIButtonCreate(0, 0, "Save", -1)->invoke = ActionSave; + UIButtonCreate(0, 0, "Load", -1)->invoke = ActionLoad; + UIButtonCreate(0, 0, "Export", -1)->invoke = ActionExport; + UIButtonCreate(0, 0, "Import font", -1)->invoke = ActionImportFont; + UIParentPop(); + + UITabPaneCreate(&panel1->e, UI_ELEMENT_PARENT_PUSH | UI_ELEMENT_V_FILL, "Layers\tAnimation\tConstants\tColors"); + UISplitPaneCreate(0, UI_SPLIT_PANE_VERTICAL | UI_ELEMENT_PARENT_PUSH, 0.5f); + UIPanelCreate(0, UI_PANEL_GRAY | UI_PANEL_EXPAND | UI_PANEL_MEDIUM_SPACING | UI_ELEMENT_PARENT_PUSH); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + stylesTextbox = UITextboxCreate(0, UI_ELEMENT_H_FILL); + UIButtonCreate(0, UI_BUTTON_SMALL, "Create", -1)->invoke = ButtonCreateStyle; + UIButtonCreate(0, UI_BUTTON_SMALL, "Rename", -1)->invoke = ButtonRenameStyle; + UIButtonCreate(0, UI_BUTTON_SMALL, "Delete", -1)->invoke = ButtonDeleteStyle; + buttonPublicStyle = UIButtonCreate(0, UI_BUTTON_SMALL, "Public", -1); + buttonPublicStyle->invoke = ButtonTogglePublicStyle; + UIParentPop(); + + stylesShowWithSelectedLayer = UIButtonCreate(0, 0, "Show styles with selected layer", -1); + stylesShowWithSelectedLayer->invoke = ButtonShowStylesWithSelectedLayer; + + UIButtonCreate(0, 0, "Cleanup unused layers", -1)->invoke = CleanupUnusedLayers; + + stylesTable = UITableCreate(0, UI_ELEMENT_V_FILL, "Name"); + stylesTable->e.messageUser = StylesTableMessage; + UITableResizeColumns(stylesTable); + UIParentPop(); + + UIPanelCreate(0, UI_PANEL_GRAY | UI_PANEL_EXPAND | UI_ELEMENT_PARENT_PUSH); + tableLayers = UITableCreate(0, UI_ELEMENT_V_FILL, "Layers"); + tableLayers->e.messageUser = TableLayersMessage; + UITableResizeColumns(tableLayers); + arrput(inspectorSubscriptions, &tableLayers->e); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_PANEL_SMALL_SPACING | UI_ELEMENT_PARENT_PUSH); + buttonAddLayer = UIButtonCreate(0, UI_BUTTON_SMALL, "Add...", -1); + buttonAddLayer->invoke = ButtonAddLayer; + UIButtonCreate(0, UI_BUTTON_SMALL, "Delete", -1)->invoke = ButtonDeleteLayer; + buttonAddExistingLayer = UIButtonCreate(0, UI_BUTTON_SMALL, "Use existing", -1); + buttonAddExistingLayer->invoke = ButtonAddExistingLayer; + UIButtonCreate(0, UI_BUTTON_SMALL, "Duplicate", -1)->invoke = ButtonDuplicateLayer; + UIButtonCreate(0, UI_BUTTON_SMALL, "Import SVG", -1)->invoke = ButtonImportSVG; + UIParentPop(); + + UIButtonCreate(0, UI_BUTTON_SMALL, "Delete layer in all styles", -1)->invoke = ButtonDeleteLayerInAllStyles; + UIParentPop(); + UIParentPop(); + + UISplitPaneCreate(0, UI_SPLIT_PANE_VERTICAL | UI_ELEMENT_PARENT_PUSH, 0.5f); + UIPanelCreate(0, UI_PANEL_GRAY | UI_PANEL_EXPAND | UI_ELEMENT_PARENT_PUSH); + tableSequences = UITableCreate(0, UI_ELEMENT_V_FILL, "Sequences"); + tableSequences->e.messageUser = TableSequencesMessage; + UITableResizeColumns(tableSequences); + arrput(inspectorSubscriptions, &tableSequences->e); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_PANEL_SMALL_SPACING | UI_ELEMENT_PARENT_PUSH); + UIButtonCreate(0, UI_BUTTON_SMALL, "Add", -1)->invoke = ButtonAddSequence; + UIButtonCreate(0, UI_BUTTON_SMALL, "Delete", -1)->invoke = ButtonDeleteSequence; + UISpacerCreate(0, 0, 10, 0); + UIButtonCreate(0, UI_BUTTON_SMALL, "Move up", -1)->invoke = ButtonMoveSequenceUp; + UIButtonCreate(0, UI_BUTTON_SMALL, "Move down", -1)->invoke = ButtonMoveSequenceDown; + UIParentPop(); + UIParentPop(); + + UIPanelCreate(0, UI_PANEL_GRAY | UI_PANEL_EXPAND | UI_ELEMENT_PARENT_PUSH); + tableKeyframes = UITableCreate(0, UI_ELEMENT_V_FILL, "Keyframes"); + tableKeyframes->e.messageUser = TableKeyframesMessage; + UITableResizeColumns(tableKeyframes); + arrput(inspectorSubscriptions, &tableKeyframes->e); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_PANEL_SMALL_SPACING | UI_ELEMENT_PARENT_PUSH); + UIButtonCreate(0, UI_BUTTON_SMALL, "Add", -1)->invoke = ButtonAddKeyframe; + UIButtonCreate(0, UI_BUTTON_SMALL, "Delete", -1)->invoke = ButtonDeleteKeyframe; + UIParentPop(); + UIParentPop(); + UIParentPop(); + + UIPanelCreate(0, UI_PANEL_GRAY | UI_PANEL_MEDIUM_SPACING | UI_ELEMENT_PARENT_PUSH | UI_PANEL_EXPAND); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + constantsTextbox = UITextboxCreate(0, UI_ELEMENT_H_FILL); + UIButtonCreate(0, 0, "Add", -1)->invoke = ButtonAddConstant; + UIButtonCreate(0, 0, "Delete", -1)->invoke = ButtonDeleteConstant; + UIParentPop(); + + constantsTable = UITableCreate(0, UI_ELEMENT_V_FILL, "Name"); + constantsTable->e.messageUser = ConstantsTableMessage; + constantsTable->itemCount = arrlenu(styleSet.constants); + UITableResizeColumns(constantsTable); + + UIPanelCreate(0, UI_PANEL_WHITE | UI_PANEL_EXPAND | UI_PANEL_MEDIUM_SPACING | UI_ELEMENT_PARENT_PUSH); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + UILabelCreate(0, UI_ELEMENT_H_FILL, "Value", -1); + constantsScale = UIButtonCreate(0, 0, "Scale", -1); + constantsScale->e.messageUser = ConstantsScaleMessage; + UIParentPop(); + + constantsValue = UITextboxCreate(0, UI_ELEMENT_DISABLED); + constantsValue->e.messageUser = ConstantsValueMessage; + UIParentPop(); + UIParentPop(); + + UIPanelCreate(0, UI_PANEL_GRAY | UI_PANEL_MEDIUM_SPACING | UI_ELEMENT_PARENT_PUSH | UI_PANEL_EXPAND); + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + colorsTextbox = UITextboxCreate(0, UI_ELEMENT_H_FILL); + UIButtonCreate(0, 0, "Add", -1)->invoke = ButtonAddColor; + UIButtonCreate(0, 0, "Delete", -1)->invoke = ButtonDeleteColor; + UIParentPop(); + + colorsTable = UITableCreate(0, UI_ELEMENT_V_FILL, "Name\tValue"); + colorsTable->e.messageUser = ColorsTableMessage; + colorsTable->itemCount = arrlenu(styleSet.colors); + UITableResizeColumns(colorsTable); + + UIPanelCreate(0, UI_PANEL_WHITE | UI_PANEL_EXPAND | UI_PANEL_MEDIUM_SPACING | UI_ELEMENT_PARENT_PUSH); + colorsValue2 = UIColorPickerCreate(&UIPanelCreate(0, 0)->e, UI_COLOR_PICKER_HAS_OPACITY); + colorsValue2->e.messageUser = ColorsValue2Message; + colorsValue = UITextboxCreate(0, UI_ELEMENT_DISABLED); + colorsValue->e.messageUser = ColorsValueMessage; + colorsPreview = UIElementCreate(sizeof(UIElement), 0, 0, ColorsPreviewMessage, "color preview"); + UIParentPop(); + UIParentPop(); + UIParentPop(); + + UISplitPane *splitPane2 = UISplitPaneCreate(&splitPane1->e, 0, 0.7f); + UIPanel *panel6 = UIPanelCreate(&splitPane2->e, UI_PANEL_EXPAND); + elementCanvas = UIElementCreate(sizeof(UIElement), &panel6->e, UI_ELEMENT_V_FILL, CanvasMessage, "Canvas"); + + UIPanelCreate(&panel6->e, UI_PANEL_GRAY | UI_PANEL_EXPAND | UI_ELEMENT_PARENT_PUSH | UI_PANEL_HORIZONTAL | UI_ELEMENT_H_FILL); + UIPanelCreate(0, UI_PANEL_EXPAND | UI_PANEL_MEDIUM_SPACING | UI_ELEMENT_PARENT_PUSH | UI_ELEMENT_H_FILL); + UILabelCreate(0, 0, "Preview options", -1); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + UISpacerCreate(0, 0, 20, 0); + UILabelCreate(0, 0, "Width: ", -1); + UISpacerCreate(0, 0, 5, 0); + previewWidth = UISliderCreate(0, 0); + previewWidth->position = 0.1f; + previewWidth->e.messageUser = PreviewSliderMessage; + UISpacerCreate(0, 0, 20, 0); + previewFixAspectRatio = UIButtonCreate(0, UI_BUTTON_SMALL, "=", -1); + previewFixAspectRatio->invoke = PreviewFixAspectRatioInvoke; + UISpacerCreate(0, 0, 20, 0); + UILabelCreate(0, 0, "Height:", -1); + UISpacerCreate(0, 0, 5, 0); + previewHeight = UISliderCreate(0, 0); + previewHeight->position = 0.1f; + previewHeight->e.messageUser = PreviewSliderMessage; + UIParentPop(); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + UISpacerCreate(0, 0, 20, 0); + UILabelCreate(0, 0, "Scale: ", -1); + UISpacerCreate(0, 0, 5, 0); + previewScale = UISliderCreate(0, 0); + previewScale->steps = 17; + previewScale->e.messageUser = PreviewSliderMessage; + UIParentPop(); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + previewTransition = UIButtonCreate(0, 0, "Preview transition", -1); + previewTransition->invoke = PreviewTransitionInvoke; + UIButtonCreate(0, 0, "Preferred size", -1)->invoke = PreviewPreferredSizeInvoke; + previewShowGuides = UIButtonCreate(0, 0, "Show guides", -1); + previewShowGuides->invoke = PreviewShowGuidesInvoke; + previewShowComputed = UIButtonCreate(0, 0, "Show computed rectangles", -1); + previewShowComputed->invoke = PreviewShowComputedInvoke; + editPoints = UIButtonCreate(0, 0, "View points", -1); + editPoints->invoke = EditPointsInvoke; + UIParentPop(); + + previewPrimaryStatePanel = UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + previewPrimaryStateIdle = UIButtonCreate(0, UI_BUTTON_SMALL | UI_BUTTON_CHECKED, "Idle", -1); + previewPrimaryStateIdle->invoke = PreviewSetPrimaryState; + previewPrimaryStateIdle->e.cp = (void *) PRIMARY_STATE_IDLE; + previewPrimaryStateHovered = UIButtonCreate(0, UI_BUTTON_SMALL, "Hovered", -1); + previewPrimaryStateHovered->invoke = PreviewSetPrimaryState; + previewPrimaryStateHovered->e.cp = (void *) PRIMARY_STATE_HOVERED; + previewPrimaryStatePressed = UIButtonCreate(0, UI_BUTTON_SMALL, "Pressed", -1); + previewPrimaryStatePressed->invoke = PreviewSetPrimaryState; + previewPrimaryStatePressed->e.cp = (void *) PRIMARY_STATE_PRESSED; + previewPrimaryStateDisabled = UIButtonCreate(0, UI_BUTTON_SMALL, "Disabled", -1); + previewPrimaryStateDisabled->invoke = PreviewSetPrimaryState; + previewPrimaryStateDisabled->e.cp = (void *) PRIMARY_STATE_DISABLED; + UIParentPop(); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + previewStateFocused = UIButtonCreate(0, UI_BUTTON_SMALL, "Focused", -1); + previewStateFocused->e.messageUser = PreviewToggleState; + previewStateChecked = UIButtonCreate(0, UI_BUTTON_SMALL, "Checked", -1); + previewStateChecked->e.messageUser = PreviewToggleState; + previewStateIndeterminate = UIButtonCreate(0, UI_BUTTON_SMALL, "Indeterminate", -1); + previewStateIndeterminate->e.messageUser = PreviewToggleState; + previewStateDefault = UIButtonCreate(0, UI_BUTTON_SMALL, "Default", -1); + previewStateDefault->e.messageUser = PreviewToggleState; + previewStateItemFocus = UIButtonCreate(0, UI_BUTTON_SMALL, "Item focus", -1); + previewStateItemFocus->e.messageUser = PreviewToggleState; + previewStateListFocus = UIButtonCreate(0, UI_BUTTON_SMALL, "List focus", -1); + previewStateListFocus->e.messageUser = PreviewToggleState; + previewStateSelected = UIButtonCreate(0, UI_BUTTON_SMALL, "Selected", -1); + previewStateSelected->e.messageUser = PreviewToggleState; + previewStateBeforeEnter = UIButtonCreate(0, UI_BUTTON_SMALL, "Before enter", -1); + previewStateBeforeEnter->e.messageUser = PreviewToggleState; + previewStateAfterExit = UIButtonCreate(0, UI_BUTTON_SMALL, "After exit", -1); + previewStateAfterExit->e.messageUser = PreviewToggleState; + UIParentPop(); + UIParentPop(); + + UIPanelCreate(0, UI_PANEL_HORIZONTAL | UI_ELEMENT_PARENT_PUSH); + previewBackgroundColor = UIColorPickerCreate(0, 0); + previewBackgroundColor->e.messageUser = PreviewChangeBackgroundColor; + UIColorToHSV(0xC0C0C0, &previewBackgroundColor->hue, &previewBackgroundColor->saturation, &previewBackgroundColor->value); + UIParentPop(); + UIParentPop(); + + panelInspector = UIPanelCreate(&splitPane2->e, UI_PANEL_GRAY | UI_PANEL_EXPAND | UI_PANEL_SCROLL); + panelInspector->border = UI_RECT_1(10); + panelInspector->gap = 5; + + ActionLoad(NULL); + + return UIMessageLoop(); +} diff --git a/util/designer/designer.rf b/util/designer/designer.rf new file mode 100644 index 0000000..6fa7436 --- /dev/null +++ b/util/designer/designer.rf @@ -0,0 +1,430 @@ +type StyleColor_Type StyleColorOp; +type StyleString_Type StyleStringOp; +type StyleBool_Type StyleBoolOp; +type StyleArray_Type StyleArrayOp; +type StyleFloat_Type StyleFloatOp; +type StyleI8_Type StyleI8Op; +type StyleI16_Type StyleI16Op; + +struct Property Property_Type PropertyOp { + rfNone "uint32_t *" path; + rfData RfData data; +}; + +struct Rectangle8 Rectangle8_Type Rectangle8Op { + StyleI8_Type int8_t l; + StyleI8_Type int8_t r; + StyleI8_Type int8_t t; + StyleI8_Type int8_t b; +}; + +struct Rectangle16 Rectangle16_Type Rectangle16Op { + StyleI16_Type int16_t l; + StyleI16_Type int16_t r; + StyleI16_Type int16_t t; + StyleI16_Type int16_t b; +}; + +struct Corners8 Corners8_Type Corners8Op { + StyleI8_Type int8_t tl; + StyleI8_Type int8_t tr; + StyleI8_Type int8_t bl; + StyleI8_Type int8_t br; +}; + +struct Gaps8 Gaps8_Type Gaps8Op { + StyleI8_Type int8_t major; + StyleI8_Type int8_t minor; + StyleI8_Type int8_t wrap; +}; + +struct Size16 Size16_Type Size16Op { + StyleI16_Type int16_t width; + StyleI16_Type int16_t height; +}; + +struct PaintSolid PaintSolid_Type PaintSolidOp { + StyleColor_Type uint32_t color #StringOption { "Color" }; +}; + +struct PaintOverwrite PaintOverwrite_Type PaintOverwriteOp { + StyleColor_Type uint32_t color #StringOption { "Color" }; +}; + +struct GradientStop GradientStop_Type GradientStopOp { + StyleColor_Type uint32_t color #StringOption { "Color" }; + StyleI8_Type int8_t position #StringOption { "Position" }; +}; + +enum GradientRepeat_Type StyleEnumOp { + GRADIENT_REPEAT_CLAMP #StringOption { "Clamp" }; + GRADIENT_REPEAT_NORMAL #StringOption { "Normal" }; + GRADIENT_REPEAT_MIRROR #StringOption { "Mirror" }; +}; + +struct PaintLinearGradient PaintLinearGradient_Type PaintLinearGradientOp { + Rectangle16_Type Rectangle16 range #StringOption { "Range" } to 6; + StyleBool_Type bool useGammaInterpolation #StringOption { "Use gamma-accurate color interpolation" }; + StyleArray_Type "GradientStop *" stops #RfItem { &GradientStop_Type, sizeof(GradientStop), &(StringOption) { "Stops: " } }; + StyleBool_Type bool useDithering #StringOption { "Use dithering" } from 4; + GradientRepeat_Type uint8_t repeat #StringOption { "Repeat mode" } from 5; + StyleFloat_Type float transformX #StringOption { "Transform X" } from 6; + StyleFloat_Type float transformY #StringOption { "Transform Y" } from 6; + StyleFloat_Type float transformStart #StringOption { "Transform start" } from 6; + StyleBool_Type bool useSystemHue #StringOption { "Use system hue" } from 20; + StyleBool_Type bool _unused #StringOption { "_unused" } from 21; +}; + +struct PaintRadialGradient PaintRadialGradient_Type PaintRadialGradientOp { + StyleBool_Type bool useGammaInterpolation #StringOption { "Use gamma-accurate color interpolation" }; + StyleArray_Type "GradientStop *" stops #RfItem { &GradientStop_Type, sizeof(GradientStop), &(StringOption) { "Stops: " } }; + GradientRepeat_Type uint8_t repeat #StringOption { "Repeat mode" }; + StyleFloat_Type float transform0 #StringOption { "Transform X scale" }; + StyleFloat_Type float transform2 #StringOption { "Transform X offset" }; + StyleFloat_Type float transform4 #StringOption { "Transform Y scale" }; + StyleFloat_Type float transform5 #StringOption { "Transform Y offset" }; + StyleFloat_Type float transform1 #StringOption { "Transform X skew" } from 8; + StyleFloat_Type float transform3 #StringOption { "Transform Y skew" } from 8; +}; + +struct Paint Paint_Type StyleUnionOp { + rfU32 uint32_t tag; + PaintSolid_Type PaintSolid solid #StringOption { "Solid" }; + PaintLinearGradient_Type PaintLinearGradient linearGradient #StringOption { "Linear gradient" }; + PaintOverwrite_Type PaintOverwrite overwrite #StringOption { "Overwrite" } from 2; + PaintRadialGradient_Type PaintRadialGradient radialGradient #StringOption { "Radial gradient" } from 7; +}; + +struct LayerBox LayerBox_Type LayerBoxOp { + Rectangle8_Type Rectangle8 borders #StringOption { "Borders" }; + Corners8_Type Corners8 corners #StringOption { "Corners" }; + Paint_Type Paint mainPaint #StringOption { "Main paint" }; + Paint_Type Paint borderPaint #StringOption { "Border paint" }; + StyleBool_Type bool blurred #StringOption { "Blurred" }; + StyleBool_Type bool autoCorners #StringOption { "Auto corners" }; + StyleBool_Type bool autoBorders #StringOption { "Auto borders" }; + StyleBool_Type bool shadowHiding #StringOption { "Shadow hiding" }; + StyleBool_Type bool shadowCut #StringOption { "Shadow cut" } from 13; +}; + +enum ClipMode_Type StyleEnumOp { + CLIP_MODE_ENABLED #StringOption { "Enabled" }; + CLIP_MODE_DISABLED #StringOption { "Disabled" }; +}; + +enum Cursor_Type StyleEnumOp { + CURSOR_NORMAL #StringOption { "Normal" }; + CURSOR_TEXT #StringOption { "Text" }; + CURSOR_RESIZE_VERTICAL #StringOption { "Resize vertical" }; + CURSOR_RESIZE_HORIZONTAL #StringOption { "Resize horizontal" }; + CURSOR_RESIZE_DIAGONAL_1 #StringOption { "Diagonal 1" }; + CURSOR_RESIZE_DIAGONAL_2 #StringOption { "Diagonal 2" }; + CURSOR_SPLIT_VERTICAL #StringOption { "Split vertical" }; + CURSOR_SPLIT_HORIZONTAL #StringOption { "Split horizontal" }; + CURSOR_HAND_HOVER #StringOption { "Hand hover" }; + CURSOR_HAND_DRAG #StringOption { "Hand drag" }; + CURSOR_HAND_POINT #StringOption { "Hand point" }; + CURSOR_SCROLL_UP_LEFT #StringOption { "Scroll up-left" }; + CURSOR_SCROLL_UP #StringOption { "Scroll up" }; + CURSOR_SCROLL_UP_RIGHT #StringOption { "Scroll up-right" }; + CURSOR_SCROLL_LEFT #StringOption { "Scroll left" }; + CURSOR_SCROLL_CENTER #StringOption { "Scroll center" }; + CURSOR_SCROLL_RIGHT #StringOption { "Scroll right" }; + CURSOR_SCROLL_DOWN_LEFT #StringOption { "Scroll down-left" }; + CURSOR_SCROLL_DOWN #StringOption { "Scroll down" }; + CURSOR_SCROLL_DOWN_RIGHT #StringOption { "Scroll down-right" }; + CURSOR_SELECT_LINES #StringOption { "Select lines" }; + CURSOR_DROP_TEXT #StringOption { "Drop text" }; + CURSOR_CROSS_HAIR_PICK #StringOption { "Cross hair pick" }; + CURSOR_CROSS_HAIR_RESIZE #StringOption { "Cross hair resize" }; + CURSOR_MOVE_HOVER #StringOption { "Move hover" }; + CURSOR_MOVE_DRAG #StringOption { "Move drag" }; + CURSOR_ROTATE_HOVER #StringOption { "Rotate hover" }; + CURSOR_ROTATE_DRAG #StringOption { "Rotate drag" }; + CURSOR_BLANK #StringOption { "Blank" }; +}; + +enum Transition_Type StyleEnumOp { + TRANSITION_NONE #StringOption { "None" }; + TRANSITION_SLIDE_UP #StringOption { "Slide up" }; + TRANSITION_SLIDE_DOWN #StringOption { "Slide down" }; + TRANSITION_COVER_UP #StringOption { "Cover up" }; + TRANSITION_COVER_DOWN #StringOption { "Cover down" }; + TRANSITION_SQUISH_UP #StringOption { "Squish up" }; + TRANSITION_SQUISH_DOWN #StringOption { "Squish down" }; + TRANSITION_REVEAL_UP #StringOption { "Reveal up" }; + TRANSITION_REVEAL_DOWN #StringOption { "Reveal down" }; + TRANSITION_ZOOM_OUT #StringOption { "Zoom out" }; + TRANSITION_ZOOM_IN #StringOption { "Zoom in" }; + TRANSITION_ZOOM_OUT_LIGHT #StringOption { "Zoom out (light)" }; + TRANSITION_ZOOM_IN_LIGHT #StringOption { "Zoom in (light)" }; + TRANSITION_FADE_OUT #StringOption { "Fade out" }; + TRANSITION_FADE_IN #StringOption { "Fade in" }; +}; + +enum Align_Type StyleEnumOp { + ALIGN_START #StringOption { "Start" }; + ALIGN_CENTER #StringOption { "Center" }; + ALIGN_END #StringOption { "End" }; +}; + +enum FontFamily_Type StyleEnumOp { + FONT_FAMILY_SANS #StringOption { "Sans" }; + FONT_FAMILY_SERIF #StringOption { "Serif" }; + FONT_FAMILY_MONO #StringOption { "Mono" }; +}; + +struct LayerMetrics LayerMetrics_Type LayerMetricsOp { + Rectangle8_Type Rectangle8 insets #StringOption { "Insets" }; + ClipMode_Type uint32_t clipEnabled #StringOption { "Clipping: " }; + Rectangle8_Type Rectangle8 clipInsets #StringOption { "Clip insets" }; + Size16_Type Size16 preferredSize #StringOption { "Preferred size" }; + Size16_Type Size16 minimumSize #StringOption { "Minimum size" }; + Size16_Type Size16 maximumSize #StringOption { "Maximum size" }; + Gaps8_Type Gaps8 gaps #StringOption { "Gaps" }; + Cursor_Type uint32_t cursor #StringOption { "Cursor" }; + Transition_Type uint32_t entranceTransition #StringOption { "Entrance transition" }; + StyleI16_Type int16_t entranceDuration #StringOption { "Entrance duration (ms)" }; + Transition_Type uint32_t exitTransition #StringOption { "Exit transition" }; + StyleI16_Type int16_t exitDuration #StringOption { "Exit duration (ms)" }; + Rectangle8_Type Rectangle8 globalOffset #StringOption { "Global offset" }; + Align_Type uint32_t textVerticalAlign #StringOption { "Text vertical align: " }; + Align_Type uint32_t textHorizontalAlign #StringOption { "Text horizontal align: " }; + StyleI8_Type int8_t textSize #StringOption { "Font size" }; + FontFamily_Type uint32_t fontFamily #StringOption { "Font family: " }; + StyleI8_Type int8_t fontWeight #StringOption { "Font weight" }; + StyleBool_Type bool italic #StringOption { "Italic" }; + StyleBool_Type bool wrapText #StringOption { "Wrap text" }; + StyleBool_Type bool ellipsis #StringOption { "Ellipsis" }; + StyleColor_Type uint32_t textColor #StringOption { "Text color" }; + StyleColor_Type uint32_t selectedBackground #StringOption { "Selected background" }; + StyleColor_Type uint32_t selectedText #StringOption { "Selected text" }; + StyleI8_Type int8_t iconSize #StringOption { "Icon size" }; + StyleColor_Type uint32_t iconColor #StringOption { "Icon color" }; + StyleString_Type RfData inheritText #StringOption { "Inherit text properties from:" } from 11; +}; + +struct LayerText LayerText_Type LayerTextOp { + StyleColor_Type uint32_t color #StringOption { "Color" }; + StyleI8_Type int8_t blur #StringOption { "Blur radius" }; +}; + +struct PathPoint PathPoint_Type PathPointOp { + StyleFloat_Type float x0 #StringOption { "x0" }; + StyleFloat_Type float y0 #StringOption { "y0" }; + StyleFloat_Type float x1 #StringOption { "x1" }; + StyleFloat_Type float y1 #StringOption { "y1" }; + StyleFloat_Type float x2 #StringOption { "x2" }; + StyleFloat_Type float y2 #StringOption { "y2" }; +}; + +struct PathFillSolid PathFillSolid_Type PathFillSolidOp { +}; + +enum JoinMode StyleEnumOp { + JOIN_MODE_MITER #StringOption { "Miter" }; + JOIN_MODE_ROUND #StringOption { "Round" }; + JOIN_MODE_BEVEL #StringOption { "Bevel" }; +}; + +enum CapMode StyleEnumOp { + CAP_MODE_FLAT #StringOption { "Flat" }; + CAP_MODE_ROUND #StringOption { "Round" }; + CAP_MODE_SQUARE #StringOption { "Square" }; +}; + +struct PathFillContour PathFillContour_Type PathFillContourOp { + StyleI8_Type int8_t internalWidth #StringOption { "Internal width" }; + StyleI8_Type int8_t externalWidth #StringOption { "External width" }; + StyleFloat_Type float miterLimit #StringOption { "Miter limit" }; + JoinMode uint8_t joinMode #StringOption { "Join mode: " }; + CapMode uint8_t capMode #StringOption { "Cap mode: " }; + StyleBool_Type bool integerWidthsOnly #StringOption { "Integer widths only when scaling" } from 14; +}; + +struct PathFillDash PathFillDash_Type PathFillDashOp { + PathFillContour_Type PathFillContour contour; + StyleI8_Type int8_t length #StringOption { "Length" }; + StyleI8_Type int8_t gap #StringOption { "Gap" }; +}; + +struct PathFillDashed PathFillDashed_Type PathFillDashedOp { + StyleArray_Type "PathFillDash *" dashes #RfItem { &PathFillDash_Type, sizeof(PathFillDash), &(StringOption) { "Dashes: " } }; +}; + +struct PathFillMode PathFillMode_Type StyleUnionOp { + rfU32 uint32_t tag; + PathFillSolid_Type PathFillSolid solid #StringOption { "Solid" }; + PathFillContour_Type PathFillContour contour #StringOption { "Contour" }; + PathFillDashed_Type PathFillDashed dashed #StringOption { "Dashed" }; +}; + +struct PathFill PathFill_Type PathFillOp { + PathFillMode_Type PathFillMode mode #StringOption { "Mode" }; + Paint_Type Paint paint #StringOption { "Paint" }; +}; + +struct LayerPath LayerPath_Type LayerPathOp { + StyleBool_Type bool evenOdd #StringOption { "Even-odd fill rule" }; + StyleBool_Type bool closed #StringOption { "Closed path" }; + StyleI16_Type int16_t alpha #StringOption { "Alpha" }; + StyleArray_Type "PathPoint *" points #RfItem { &PathPoint_Type, sizeof(PathPoint), &(StringOption) { "Points: " } }; + StyleArray_Type "PathFill *" fills #RfItem { &PathFill_Type, sizeof(PathFill), &(StringOption) { "Fills: " } }; +}; + +union LayerBase LayerBase_Type RfUnionOp { + LayerBox_Type LayerBox box; + LayerMetrics_Type LayerMetrics metrics; + rfNone bool _removed0; + rfNone bool _removed1; + LayerText_Type LayerText text; + LayerPath_Type LayerPath path; +}; + +type DesignerArray_Type DesignerArrayOp; + +struct Keyframe Keyframe_Type RfStructOp { + StyleI8_Type int8_t progress #StringOption { "Progress (%)" }; + DesignerArray_Type "Property *" properties #RfItem { &Property_Type, sizeof(Property), NULL }; +}; + +enum PrimaryState_Type StyleEnumOp { + PRIMARY_STATE_ANY #StringOption { "Any" }; + PRIMARY_STATE_IDLE #StringOption { "Idle" }; + PRIMARY_STATE_HOVERED #StringOption { "Hovered" }; + PRIMARY_STATE_PRESSED #StringOption { "Pressed" }; + PRIMARY_STATE_DISABLED #StringOption { "Disabled" }; +}; + +struct Sequence Sequence_Type RfStructOp { + DesignerArray_Type "Keyframe **" keyframes #RfItem { &rfObject, sizeof(Keyframe *), &(RfItem) { &Keyframe_Type, sizeof(Keyframe), NULL } }; + StyleI16_Type int16_t duration #StringOption { "Duration (ms)" }; + PrimaryState_Type uint32_t primaryState #StringOption { "Primary state" }; + StyleBool_Type bool flagFocused #StringOption { "Focused?" }; + StyleBool_Type bool flagChecked #StringOption { "Checked?" }; + StyleBool_Type bool flagIndeterminate #StringOption { "Indeterminate?" }; + StyleBool_Type bool flagDefault #StringOption { "Default?" }; + StyleBool_Type bool flagItemFocus #StringOption { "List item focus?" }; + StyleBool_Type bool flagListFocus #StringOption { "List focus?" }; + StyleBool_Type bool flagSelected #StringOption { "Selected?" }; + StyleBool_Type bool flagBeforeEnter #StringOption { "Before enter?" }; + StyleBool_Type bool flagAfterExit #StringOption { "After exit?" }; +}; + +enum LayerMode_Type StyleEnumOp { + LAYER_MODE_BACKGROUND #StringOption { "Background" }; + LAYER_MODE_SHADOW #StringOption { "Shadow" }; + LAYER_MODE_CONTENT #StringOption { "Content" }; + LAYER_MODE_OVERLAY #StringOption { "Overlay" }; +}; + +struct Layer Layer_Type LayerOp { + rfU64 uint64_t id; + rfNone uint32_t exportOffset; + + DesignerArray_Type "Sequence **" sequences #RfItem { &rfObject, sizeof(Sequence *), &(RfItem) { &Sequence_Type, sizeof(Sequence), NULL } }; + StyleString_Type RfData name #StringOption { "Layer name" }; + rfBool bool isMetricsLayer; + + Rectangle8_Type Rectangle8 offset #StringOption { "Offset (dpx)" }; + Rectangle8_Type Rectangle8 position #StringOption { "Position (%)" }; + LayerMode_Type uint8_t mode #StringOption { "Mode: " }; + LayerBase_Type LayerBase base; +}; + +struct Style Style_Type RfStructOp { + DesignerArray_Type "uint64_t *" layers #RfItem { &rfU64, sizeof(uint64_t), NULL }; + rfData RfData name; + rfU64 uint64_t id from 15; + rfBool bool publicStyle from 16; +}; + +struct Constant Constant_Type RfStructOp { + rfData RfData key; + StyleString_Type RfData value; + StyleBool_Type bool scale from 9; +}; + +struct Color Color_Type RfStructOp { + rfData RfData key; + rfU32 uint32_t value; + rfU32 uint32_t id; +}; + +struct StyleSet StyleSet_Type StyleSetOp { + rfU64 uint64_t lastID; + DesignerArray_Type "Style **" styles #RfItem { &rfObject, sizeof(Style *), &(RfItem) { &Style_Type, sizeof(Style), NULL } }; + DesignerArray_Type "Layer **" layers #RfItem { &rfObject, sizeof(Layer *), &(RfItem) { &Layer_Type, sizeof(Layer), NULL } }; + DesignerArray_Type "Constant **" constants #RfItem { &rfObject, sizeof(Constant *), &(RfItem) { &Constant_Type, sizeof(Constant), NULL } }; + DesignerArray_Type "Color **" colors #RfItem { &rfObject, sizeof(Color *), &(RfItem) { &Color_Type, sizeof(Color), NULL } } from 17; +}; + +///////////////////////////////////////////////////// + +struct ModAddLayer ModAddLayer_Type ModAddLayerOp { + rfObject "Layer *" layer #RfItem { &Layer_Type, sizeof(Layer), NULL }; + rfI32 int index; +}; + +struct ModDeleteLayer ModDeleteLayer_Type ModDeleteLayerOp { + rfI32 int index; +}; + +struct ModSwapLayers ModSwapLayers_Type ModSwapLayersOp { + rfI32 int index; +}; + +struct ModSwapSequences ModSwapSequences_Type ModSwapSequencesOp { + rfI32 int index; +}; + +struct ModAddSequence ModAddSequence_Type ModAddSequenceOp { + rfObject "Sequence *" sequence #RfItem { &Sequence_Type, sizeof(Sequence), NULL }; + rfI32 int index; +}; + +struct ModDeleteSequence ModDeleteSequence_Type ModDeleteSequenceOp { + rfI32 int index; +}; + +struct ModAddKeyframe ModAddKeyframe_Type ModAddKeyframeOp { + rfObject "Keyframe *" keyframe #RfItem { &Keyframe_Type, sizeof(Keyframe), NULL }; + rfI32 int index; +}; + +struct ModDeleteKeyframe ModDeleteKeyframe_Type ModDeleteKeyframeOp { + rfI32 int index; +}; + +struct ModChangeProperty ModChangeProperty_Type ModChangePropertyOp { + Property_Type Property property; + rfNone "struct UIElement *" source; +}; + +struct ModArray ModArray_Type ModArrayOp { + Property_Type Property property; + rfBool bool isDelete; +}; + +struct ModDeleteOverride ModDeleteOverride_Type ModDeleteOverrideOp { + Property_Type Property property; +}; + +union ModData ModData_Type RfUnionOp { + ModAddLayer_Type ModAddLayer addLayer; + ModDeleteLayer_Type ModDeleteLayer deleteLayer; + ModSwapLayers_Type ModSwapLayers swapLayers; + ModSwapSequences_Type ModSwapSequences swapSequences; + ModAddSequence_Type ModAddSequence addSequence; + ModDeleteSequence_Type ModDeleteSequence deleteSequence; + ModAddKeyframe_Type ModAddKeyframe addKeyframe; + ModDeleteKeyframe_Type ModDeleteKeyframe deleteKeyframe; + ModChangeProperty_Type ModChangeProperty changeProperty; + ModArray_Type ModArray array; + ModDeleteOverride_Type ModDeleteOverride deleteOverride; +}; + +struct Mod Mod_Type RfStructOp { + rfNone ModContext context; + ModData_Type ModData data; +}; diff --git a/util/designer/designer_luigi.c b/util/designer/designer_luigi.c new file mode 100644 index 0000000..1bbe37d --- /dev/null +++ b/util/designer/designer_luigi.c @@ -0,0 +1,8 @@ +#ifdef _WIN32 +#define UI_WINDOWS +#else +#define UI_LINUX +#endif + +#define UI_IMPLEMENTATION +#include "../luigi.h" diff --git a/util/designer/reflect.h b/util/designer/reflect.h new file mode 100644 index 0000000..a591eda --- /dev/null +++ b/util/designer/reflect.h @@ -0,0 +1,652 @@ +// TODO Bitsets. +// TODO Versioning support for unions and enums. + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#ifndef RF_ASSERT +#include <assert.h> +#define RF_ASSERT assert +#endif + +#ifndef RF_MEMZERO +#include <string.h> +#define RF_MEMZERO(pointer, byteCount) memset((pointer), 0, (byteCount)) +#endif + +#ifndef RF_MEMCPY +#include <string.h> +#define RF_MEMCPY(destination, source, byteCount) memcpy((destination), (source), (byteCount)) +#endif + +#ifndef RF_REALLOC +#include <stdlib.h> +#define RF_REALLOC(previous, byteCount) realloc((previous), (byteCount)) +#endif + +#define RF_SIZE_OF(containerType, field) sizeof(((containerType *) NULL)->field) +#define RF_FIELD(containerType, field, fieldRfType, ...) \ + { \ + .item.type = &fieldRfType, \ + .item.byteCount = RF_SIZE_OF(containerType, field), \ + .cName = #field, \ + .offset = offsetof(containerType, field), \ + __VA_ARGS__ \ + } + +#define RF_OP_SAVE (-1) // Set access in RfState. +#define RF_OP_LOAD (-2) // Set access and allocate in RfState. +#define RF_OP_FREE (-3) // Set allocate in RfState. +#define RF_OP_ITERATE (-4) // Pass RfIterator; set index. +#define RF_OP_COUNT (-5) // Pass RfIterator; result saved in index. +// User-defined operations use positive integers. + +typedef struct RfState { + bool error; + int16_t op; + uint32_t version, flags; + void *(*allocate)(struct RfState *state, void *previous, size_t byteCount); + void (*access)(struct RfState *state, void *buffer, size_t byteCount); +} RfState; + +typedef struct RfItem { + struct RfType *type; + size_t byteCount; + void *options; +} RfItem; + +typedef struct RfField { + RfItem item; + const char *cName; + ptrdiff_t offset; + uint32_t firstVersion, lastVersion; + uint32_t flagsInclude, flagsExclude; +} RfField; + +typedef struct RfType { + void (*op)(RfState *state, RfItem *field, void *pointer); + const char *cName; + size_t fieldCount; + RfField *fields; +} RfType; + +typedef struct RfIterator { + RfState s; + void *pointer; + RfItem item; + uint32_t index; + bool includeRemovedFields; + bool isRemoved; +} RfIterator; + +typedef struct RfPath { +#define RF_PATH_TERMINATOR (0xFFFFFFFF) + uint32_t indices[1]; +} RfPath; + +typedef struct RfUnionHeader { + uint32_t tag; +} RfUnionHeader; + +typedef struct RfArrayHeader { + size_t length, capacity; + + // For compatability with stb_ds.h. + void *hashTable; + ptrdiff_t temporary; +} RfArrayHeader; + +typedef struct RfData { + void *buffer; + size_t byteCount; +} RfData; + +typedef struct RfGrowableBuffer { + RfState s; + RfData data; + + // When writing - allocated space in data. + // When reading - position in data. + size_t position; +} RfGrowableBuffer; + +extern RfType rfI8, rfI16, rfI32, rfI64, + rfU8, rfU16, rfU32, rfU64, + rfF32, rfF64, + rfChar, rfBool, + rfData, rfNone, + rfObject /* options - RfItem */, + rfArray /* options - RfItem */; + +bool RfPathResolve(RfPath *path, RfItem *item, void **pointer); // Returns true if successful. +void RfBroadcast(RfState *state, RfItem *item, void *pointer, bool recurse); +void RfUnionSelect(RfState *state, RfItem *item, RfUnionHeader *header, uint32_t tag); + +void RfReadGrowableBuffer(RfState /* RfGrowableBuffer */ *state, void *buffer, size_t byteCount); +void RfWriteGrowableBuffer(RfState /* RfGrowableBuffer */ *state, void *buffer, size_t byteCount); +void *RfRealloc(RfState *state, void *previous, size_t byteCount); + +void RfStructOp(RfState *state, RfItem *item, void *pointer); +void RfUnionOp(RfState *state, RfItem *item, void *pointer); +void RfEnumOp(RfState *state, RfItem *item, void *pointer); +void RfBitSetOp(RfState *state, RfItem *item, void *pointer); +void RfEndianOp(RfState *state, RfItem *item, void *pointer); +void RfIntegerOp(RfState *state, RfItem *item, void *pointer); +void RfNoneOp(RfState *state, RfItem *item, void *pointer); + +#ifdef REFLECT_IMPLEMENTATION + +void RfIntegerSave(RfState *state, void *pointer, size_t inByteCount) { + uint8_t in[16]; + RF_ASSERT(inByteCount < 16); + RF_MEMCPY(in, pointer, inByteCount); + + bool negative = in[inByteCount - 1] & 0x80; + size_t inBitCount = 1; + + for (int i = inByteCount - 1; i >= 0; i--) { + for (int j = 7; j >= 0; j--) { + if (((in[i] >> j) & 1) != negative) { + inBitCount = i * 8 + j + 2; + goto gotBitCount; + } + } + } + + gotBitCount:; + + size_t outByteCount = (inBitCount + 6) / 7; + uint8_t out[16]; + RF_ASSERT(outByteCount < 16); + + for (uintptr_t i = 0; i < outByteCount; i++) { + uint8_t b = 0; + + for (uintptr_t j = 0; j < 7; j++) { + uintptr_t bitIndex = i * 7 + j; + bool inBit = negative; + if (bitIndex < 8 * inByteCount) inBit = in[bitIndex >> 3] & (1 << (bitIndex & 7)); + if (inBit) b |= 1 << j; + } + + out[i] = b; + } + + out[outByteCount - 1] |= 0x80; + state->access(state, out, outByteCount); +} + +void RfIntegerLoad(RfState *state, void *pointer, size_t byteCount) { + uint8_t out[16]; + uintptr_t outIndex = 0; + RF_ASSERT(byteCount < 16); + RF_MEMZERO(out, byteCount); + + while (!state->error) { + uint8_t b; + state->access(state, &b, 1); + + for (uintptr_t i = 0; i < 7; i++) { + if (outIndex == byteCount * 8) break; + if (b & (1 << i)) out[outIndex >> 3] |= 1 << (outIndex & 7); + outIndex++; + } + + if (b & 0x80) { + if (b & 0x40) { + for (uintptr_t i = outIndex; i < byteCount * 8; i++) { + out[i >> 3] |= 1 << (i & 7); + } + } + + break; + } + } + + if (!state->error && pointer) { + RF_MEMCPY(pointer, out, byteCount); + } +} + +void RfStructOp(RfState *state, RfItem *item, void *pointer) { + RfType *type = item->type; + + if (state->op == RF_OP_SAVE || state->op == RF_OP_LOAD || state->op == RF_OP_FREE) { + for (uintptr_t i = 0; i < type->fieldCount && !state->error; i++) { + RfField *field = type->fields + i; + + if (state->flags & field->flagsExclude) continue; + if ((state->flags & field->flagsInclude) != field->flagsInclude) continue; + + void *fieldPointer = pointer ? ((uint8_t *) pointer + field->offset) : NULL; + + if (state->op == RF_OP_LOAD) { + if (state->version < field->firstVersion) { + // The field exists, but we're loading from a version where it did not exist. + // Ignore it. + continue; + } else if (field->lastVersion && state->version > field->lastVersion) { + // The field no longer exists, and we're from loading a version where it did not exist. + // Ignore it. + continue; + } else if (field->lastVersion) { + // The field no longer exists, but we're loading a version where it did. + // Skip over it. + fieldPointer = NULL; + } else { + // The field exists, and we're loading from a version where it exists. + } + } else { + if (field->lastVersion) { + continue; + } + } + + field->item.type->op(state, &field->item, fieldPointer); + + if (state->op == RF_OP_FREE) { + RF_MEMZERO(fieldPointer, field->item.byteCount); + } + } + } else if (state->op == RF_OP_COUNT) { + RfIterator *iterator = (RfIterator *) state; + uint32_t count = 0; + + for (uintptr_t i = 0; i < type->fieldCount; i++) { + if (!type->fields[i].lastVersion) { + count++; + } + } + + iterator->index = count; + } else if (state->op == RF_OP_ITERATE) { + RfIterator *iterator = (RfIterator *) state; + uint32_t count = 0; + + for (uintptr_t i = 0; i < type->fieldCount; i++) { + iterator->isRemoved = type->fields[i].lastVersion; + + if (!iterator->isRemoved || iterator->includeRemovedFields) { + if (iterator->index == count) { + iterator->pointer = (uint8_t *) pointer + type->fields[i].offset; + iterator->item = type->fields[i].item; + return; + } + + count++; + } + } + + state->error = true; + } +} + +void RfUnionOp(RfState *state, RfItem *item, void *pointer) { + RfType *type = item->type; + RfUnionHeader *header = (RfUnionHeader *) pointer; + + if (state->op == RF_OP_SAVE) { + state->access(state, &header->tag, sizeof(uint32_t)); + + if (header->tag) { + RfField *field = type->fields + header->tag - 1; + field->item.type->op(state, &field->item, (uint8_t *) pointer + field->offset); + } + } else if (state->op == RF_OP_LOAD) { + uint32_t tag = 0; + state->access(state, &tag, sizeof(uint32_t)); + + if (tag > type->fieldCount) { + tag = 0; + state->error = true; + } else if (tag) { + RfField *field = type->fields + tag - 1; + if (field->lastVersion) tag = 0; + field->item.type->op(state, &field->item, pointer && !field->lastVersion ? ((uint8_t *) pointer + field->offset) : NULL); + } + + if (header) { + header->tag = tag; + } + } else if (state->op == RF_OP_FREE) { + if (header->tag) { + RfField *field = type->fields + header->tag - 1; + field->item.type->op(state, &field->item, (uint8_t *) pointer + field->offset); + } + + header->tag = 0; + } else if (state->op == RF_OP_COUNT) { + RfIterator *iterator = (RfIterator *) state; + iterator->index = header->tag ? 1 : 0; + } else if (state->op == RF_OP_ITERATE) { + RfIterator *iterator = (RfIterator *) state; + + if (!header->tag || iterator->index > 1) { + state->error = true; + } else { + RfField *field = type->fields + header->tag - 1; + iterator->pointer = (uint8_t *) pointer + field->offset; + iterator->item = field->item; + } + } +} + +void RfUnionSelect(RfState *state, RfItem *item, RfUnionHeader *header, uint32_t tag) { + RF_ASSERT(header->tag < item->type->fieldCount && !item->type->fields[header->tag].lastVersion); + RF_ASSERT(tag < item->type->fieldCount && !item->type->fields[tag].lastVersion); + + if (header->tag) { + RfField *field = item->type->fields + header->tag - 1; + field->item.type->op(state, &field->item, (uint8_t *) header + field->offset); + } + + header->tag = tag + 1; +} + +void RfEnumOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == RF_OP_SAVE) { + RfIntegerSave(state, pointer, item->byteCount); + } else if (state->op == RF_OP_LOAD) { + RfIntegerLoad(state, pointer, item->byteCount); + + uint32_t value = 0; + + if (item->byteCount == 1) { + value = *(uint8_t *) pointer; + } else if (item->byteCount == 2) { + value = *(uint16_t *) pointer; + } else if (item->byteCount == 4) { + value = *(uint32_t *) pointer; + } else { + RF_ASSERT(false); + } + + if (value >= item->type->fieldCount) { + state->error = true; + } + } +} + +void RfEndianOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == RF_OP_SAVE || state->op == RF_OP_LOAD) { + state->access(state, pointer, item->byteCount); + } +} + +void RfBoolOp(RfState *state, RfItem *item, void *pointer) { + RfEndianOp(state, item, pointer); + + if (state->op == RF_OP_LOAD) { + if (pointer && *(uint8_t *) pointer > 1) { + state->error = true; + } + } +} + +void RfIntegerOp(RfState *state, RfItem *item, void *pointer) { + if (state->op == RF_OP_SAVE) { + RfIntegerSave(state, pointer, item->byteCount); + } else if (state->op == RF_OP_LOAD) { + RfIntegerLoad(state, pointer, item->byteCount); + } +} + +void RfDataOp(RfState *state, RfItem *item, void *pointer) { + (void) item; + RfData *data = (RfData *) pointer; + + if (state->op == RF_OP_SAVE) { + uint32_t byteCount = data->byteCount; + RfIntegerSave(state, &byteCount, sizeof(uint32_t)); + state->access(state, data->buffer, data->byteCount); + } else if (state->op == RF_OP_LOAD) { + uint32_t byteCount = 0; + RfIntegerLoad(state, &byteCount, sizeof(uint32_t)); + + if (data) { + RF_ASSERT(!data->buffer); + data->buffer = state->allocate(state, NULL, byteCount); + if (!data->buffer) { state->error = true; return; } + data->byteCount = byteCount; + } + + state->access(state, data ? data->buffer : NULL, data->byteCount); + } else if (state->op == RF_OP_FREE) { + state->allocate(state, data->buffer, 0); + data->buffer = NULL; + } +} + +void RfObjectOp(RfState *state, RfItem *item, void *pointer) { + RfItem *objectItem = (RfItem *) item->options; + void **object = (void **) pointer; + + if (state->op == RF_OP_SAVE) { + uint8_t present = *object != NULL; + state->access(state, &present, sizeof(uint8_t)); + if (present) objectItem->type->op(state, objectItem, *object); + } else if (state->op == RF_OP_LOAD) { + uint8_t present = 0; + state->access(state, &present, sizeof(uint8_t)); + + if (object) { + RF_ASSERT(!(*object)); + + if (present) { + *object = state->allocate(state, NULL, objectItem->byteCount); + if (!(*object)) { state->error = true; return; } + RF_MEMZERO(*object, objectItem->byteCount); + objectItem->type->op(state, objectItem, *object); + } + } else if (present) { + objectItem->type->op(state, objectItem, NULL); + } + } else if (state->op == RF_OP_FREE) { + if (*object) { + objectItem->type->op(state, objectItem, *object); + state->allocate(state, *object, 0); + *object = NULL; + } + } else if (state->op == RF_OP_COUNT) { + RfIterator *iterator = (RfIterator *) state; + iterator->index = *object ? 1 : 0; + } else if (state->op == RF_OP_ITERATE) { + RfIterator *iterator = (RfIterator *) state; + + if (!(*object) || iterator->index > 1) { + state->error = true; + } else { + iterator->pointer = *object; + iterator->item = *objectItem; + } + } +} + +void RfNoneOp(RfState *state, RfItem *item, void *pointer) { + (void) state; + (void) item; + (void) pointer; +} + +void RfArrayOp(RfState *state, RfItem *item, void *_pointer) { + RfArrayHeader **pointer = (RfArrayHeader **) _pointer; + RfItem *objectItem = (RfItem *) item->options; + + if (state->op == RF_OP_SAVE) { + uint32_t length = 0; + + if (*pointer) { + length = (*pointer)[-1].length; + } + + RfIntegerSave(state, &length, sizeof(uint32_t)); + + for (uint32_t i = 0; i < length; i++) { + objectItem->type->op(state, objectItem, (uint8_t *) (*pointer) + i * objectItem->byteCount); + } + } else if (state->op == RF_OP_LOAD) { + RF_ASSERT(!pointer || !(*pointer)); + + uint32_t length = 0; + RfIntegerLoad(state, &length, sizeof(uint32_t)); + + if (length >= 0xFFFFFFFF / objectItem->byteCount) { + state->error = true; + return; + } + + if (!length) { + return; + } + + if (pointer) { + void *allocation = state->allocate(state, NULL, length * objectItem->byteCount + sizeof(RfArrayHeader)); + + if (!allocation) { + state->error = true; + return; + } + + *pointer = (RfArrayHeader *) allocation + 1; + + (*pointer)[-1].length = 0; + (*pointer)[-1].capacity = length; + (*pointer)[-1].hashTable = NULL; + (*pointer)[-1].temporary = 0; + } + + for (uint32_t i = 0; i < length && !state->error; i++) { + if (pointer) { + uint32_t index = (*pointer)[-1].length; + (*pointer)[-1].length++; + uint8_t *p = (uint8_t *) (*pointer) + index * objectItem->byteCount; + RF_MEMZERO(p, objectItem->byteCount); + objectItem->type->op(state, objectItem, p); + } else { + objectItem->type->op(state, objectItem, NULL); + } + } + } else if (state->op == RF_OP_FREE) { + if (*pointer) { + state->allocate(state, (*pointer) - 1, 0); + (*pointer) = NULL; + } + } else if (state->op == RF_OP_COUNT) { + RfIterator *iterator = (RfIterator *) state; + iterator->index = *pointer ? (*pointer)[-1].length : 0; + } else if (state->op == RF_OP_ITERATE) { + RfIterator *iterator = (RfIterator *) state; + + if (!(*pointer) || iterator->index > (*pointer)[-1].length) { + state->error = true; + } else { + iterator->pointer = (uint8_t *) (*pointer) + iterator->index * objectItem->byteCount; + iterator->item = *objectItem; + } + } +} + +bool RfPathResolve(RfPath *path, RfItem *item, void **pointer) { + RfIterator iterator = { 0 }; + iterator.s.op = RF_OP_ITERATE; + iterator.item = *item; + iterator.pointer = *pointer; + iterator.includeRemovedFields = true; + + for (int i = 0; path->indices[i] != RF_PATH_TERMINATOR && !iterator.s.error; i++) { + iterator.index = path->indices[i]; + RfItem _item = iterator.item; + _item.type->op(&iterator.s, &_item, iterator.pointer); + } + + *item = iterator.item; + *pointer = iterator.pointer; + return !iterator.s.error; +} + +void RfBroadcast(RfState *state, RfItem *item, void *pointer, bool recurse) { + RfIterator iterator = { 0 }; + iterator.s.op = RF_OP_COUNT; + item->type->op(&iterator.s, item, pointer); + iterator.s.op = RF_OP_ITERATE; + uint32_t count = iterator.index; + + for (uint32_t i = 0; i < count; i++) { + iterator.index = i; + item->type->op(&iterator.s, item, pointer); + if (iterator.s.error) return; + + iterator.item.type->op(state, &iterator.item, iterator.pointer); + + if (recurse) { + RfBroadcast(state, &iterator.item, iterator.pointer, true); + } + } +} + +void RfWriteGrowableBuffer(RfState *state, void *source, size_t byteCount) { + if (state->error) return; + + RfGrowableBuffer *destination = (RfGrowableBuffer *) state; + + if (destination->data.byteCount + byteCount > destination->position) { + destination->position = destination->position * 2; + + if (destination->data.byteCount + byteCount > destination->position) { + destination->position = destination->data.byteCount + byteCount + 64; + } + + void *old = destination->data.buffer; + destination->data.buffer = state->allocate(state, destination->data.buffer, destination->position); + + if (!destination->data.buffer) { + state->allocate(state, old, 0); + state->error = true; + return; + } + } + + RF_MEMCPY((uint8_t *) destination->data.buffer + destination->data.byteCount, source, byteCount); + destination->data.byteCount += byteCount; +} + +void RfReadGrowableBuffer(RfState *state, void *destination, size_t byteCount) { + if (state->error) return; + + RfGrowableBuffer *source = (RfGrowableBuffer *) state; + + if (source->position + byteCount > source->data.byteCount) { + state->error = true; + } else { + if (destination) { + RF_MEMCPY(destination, (uint8_t *) source->data.buffer + source->position, byteCount); + } + + source->position += byteCount; + } +} + +void *RfRealloc(RfState *state, void *previous, size_t byteCount) { + (void) state; + return RF_REALLOC(previous, byteCount); +} + +RfType rfI8 = { .op = RfEndianOp, .cName = "I8" }; +RfType rfI16 = { .op = RfIntegerOp, .cName = "I16" }; +RfType rfI32 = { .op = RfIntegerOp, .cName = "I32" }; +RfType rfI64 = { .op = RfIntegerOp, .cName = "I64" }; +RfType rfU8 = { .op = RfEndianOp, .cName = "U8" }; +RfType rfU16 = { .op = RfIntegerOp, .cName = "U16" }; +RfType rfU32 = { .op = RfIntegerOp, .cName = "U32" }; +RfType rfU64 = { .op = RfIntegerOp, .cName = "U64" }; +RfType rfChar = { .op = RfEndianOp, .cName = "Char" }; +RfType rfBool = { .op = RfBoolOp, .cName = "Bool" }; +RfType rfF32 = { .op = RfEndianOp, .cName = "F32" }; +RfType rfF64 = { .op = RfEndianOp, .cName = "F64" }; +RfType rfData = { .op = RfDataOp, .cName = "Data" }; +RfType rfObject = { .op = RfObjectOp, .cName = "Object" }; +RfType rfArray = { .op = RfArrayOp, .cName = "Array" }; +RfType rfNone = { .op = RfNoneOp, .cName = "None" }; + +#endif diff --git a/util/designer/reflect_gen.c b/util/designer/reflect_gen.c new file mode 100644 index 0000000..22d67ab --- /dev/null +++ b/util/designer/reflect_gen.c @@ -0,0 +1,531 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#define STB_DS_IMPLEMENTATION +#include "../stb_ds.h" + +#define TOKEN_BLOCK (0) +#define TOKEN_LEFT_BRACE (1) +#define TOKEN_RIGHT_BRACE (2) +#define TOKEN_LEFT_PAREN (3) +#define TOKEN_RIGHT_PAREN (4) +#define TOKEN_SEMICOLON (5) +#define TOKEN_IDENTIFIER (6) +#define TOKEN_STRING (7) +#define TOKEN_EOF (8) +#define TOKEN_COMMA (9) +#define TOKEN_NUMBER (10) +#define TOKEN_HASH (11) +#define TOKEN_QUESTION (12) +#define TOKEN_EQUALS (13) +#define TOKEN_LEFT_BRACKET (14) +#define TOKEN_RIGHT_BRACKET (15) +#define TOKEN_COLON (16) +#define TOKEN_EXCLAMATION (17) + +typedef struct Parse { + const char *position; + int line; + bool success; +} Parse; + +typedef struct Token { + int type; + double number; + char *string; +} Token; + +typedef struct ParsedField { + char *rfType, *cTypeBefore, *fieldName, *cTypeAfter; + int firstVersion, lastVersion; + char **flagsInclude, **flagsExclude; + char *optionsType, *optionsBlock; +} ParsedField; + +typedef struct ParsedType { + bool isStruct, isUnion, isCustom, isEnum; + char *cName, *rfName, *opFunction; + ParsedField *fields; +} ParsedType; + +ParsedType *parsedTypes; + +bool IsDigit(char c) { return (c >= '0' && c <= '9'); } +bool IsAlpha(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } +bool IsAlnum(char c) { return (IsDigit(c) || IsAlpha(c)); } + +bool _NextToken(Parse *parse, Token *token) { + if (!parse->success) return false; + + while (true) { + char c = *parse->position; + parse->position++; + + if (c == ' ' || c == '\t' || c == '\r') { + continue; + } else if (c == '\n') { + parse->line++; + continue; + } else if (c == '/' && *parse->position == '/') { + while (*parse->position != '\n') parse->position++; + continue; + } else if (c == '/' && *parse->position == '*') { + while (parse->position[0] != '*' || parse->position[1] != '/') parse->position++; + parse->position += 2; + continue; +#define PARSE_CHARACTER(a, b) \ + } else if (c == a) { \ + Token t = {}; \ + t.type = b; \ + *token = t; \ + return true + PARSE_CHARACTER('{', TOKEN_LEFT_BRACE ); + PARSE_CHARACTER('}', TOKEN_RIGHT_BRACE ); + PARSE_CHARACTER('(', TOKEN_LEFT_PAREN ); + PARSE_CHARACTER(')', TOKEN_RIGHT_PAREN ); + PARSE_CHARACTER('[', TOKEN_LEFT_BRACKET ); + PARSE_CHARACTER(']', TOKEN_RIGHT_BRACKET ); + PARSE_CHARACTER(';', TOKEN_SEMICOLON ); + PARSE_CHARACTER(':', TOKEN_COLON ); + PARSE_CHARACTER(',', TOKEN_COMMA ); + PARSE_CHARACTER('#', TOKEN_HASH ); + PARSE_CHARACTER('?', TOKEN_QUESTION ); + PARSE_CHARACTER('=', TOKEN_EQUALS ); + PARSE_CHARACTER('!', TOKEN_EXCLAMATION ); + } else if (IsAlpha(c) || c == '_') { + const char *start = parse->position - 1; + + while (true) { + char c2 = *parse->position; + if (c2 == 0) break; + if (!IsAlnum(c2) && c2 != '_') break; + parse->position++; + } + + Token _token = { 0 }; + _token.type = TOKEN_IDENTIFIER; + _token.string = malloc(parse->position - start + 1); + if (!_token.string) { parse->success = false; return false; } + memcpy(_token.string, start, parse->position - start); + _token.string[parse->position - start] = 0; + *token = _token; + return true; + } else if (IsDigit(c) || c == '-') { + const char *start = parse->position - 1; + + while (true) { + char c2 = *parse->position; + if (c2 == 0) break; + if (!IsAlnum(c2) && c2 != '.') break; + parse->position++; + } + + Token _token = { 0 }; + _token.type = TOKEN_NUMBER; + _token.string = malloc(parse->position - start + 1); + if (!_token.string) { parse->success = false; return false; } + memcpy(_token.string, start, parse->position - start); + _token.string[parse->position - start] = 0; + + bool negate = _token.string[0] == '-'; + bool afterDot = false; + bool hexadecimal = false; + double fraction = 0.1; + + for (uintptr_t i = negate ? 1 : 0; _token.string[i]; i++) { + char c = _token.string[i]; + + if (c == '.') { + if (hexadecimal) { + parse->success = false; + return false; + } + + afterDot = true; + } else if (c == 'x') { + if (i != 1 || _token.string[0] != '0' || afterDot) { + parse->success = false; + return false; + } + + hexadecimal = true; + } else if (afterDot) { + if (!IsDigit(c)) { + parse->success = false; + return false; + } + + _token.number += (c - '0') * fraction; + fraction *= 0.1; + } else { + if (hexadecimal) { + _token.number *= 16; + + if (c >= '0' && c <= '9') { + _token.number += c - '0'; + } else if (c >= 'a' && c <= 'f') { + _token.number += c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + _token.number += c - 'A' + 10; + } else { + parse->success = false; + return false; + } + } else { + if (!IsDigit(c)) { + parse->success = false; + return false; + } + + _token.number *= 10; + _token.number += c - '0'; + } + } + + } + + if (negate) _token.number = -_token.number; + *token = _token; + return true; + } else if (c == '"') { + const char *start = parse->position; + + while (true) { + char c2 = *parse->position; + if (c2 == 0) break; + parse->position++; + if (c2 == '"') break; + } + + Token _token = { 0 }; + _token.type = TOKEN_STRING; + _token.string = (char *) malloc(parse->position - start); + if (!_token.string) { parse->success = false; return false; } + memcpy(_token.string, start, parse->position - start - 1); + _token.string[parse->position - start - 1] = 0; + *token = _token; + return true; + } else if (c == 0) { + Token t = {}; + t.type = TOKEN_EOF; + *token = t; + return true; + } else { + parse->success = false; + return false; + } + } +} + +Token NextToken(Parse *parse) { + Token token = { 0 }; + bool success = _NextToken(parse, &token); + + if (!success) { + fprintf(stderr, "error: invalid token on line %d\n", parse->line); + exit(1); + } + + return token; +} + +char *NextString(Parse *parse) { + Token token = NextToken(parse); + + if (token.type == TOKEN_IDENTIFIER || token.type == TOKEN_STRING) { + return token.string; + } else { + fprintf(stderr, "error: expected string or identifier on line %d\n", parse->line); + exit(1); + return NULL; + } +} + +Token ExpectToken(Parse *parse, int type) { + Token token = NextToken(parse); + + if (token.type == type) { + return token; + } else { + fprintf(stderr, "error: expected token of type %d of line %d\n", type, parse->line); + exit(1); + return (Token) { 0 }; + } +} + +char *NextBlock(Parse *parse) { + ExpectToken(parse, TOKEN_LEFT_BRACE); + + int depth = 1; + const char *start = parse->position; + + while (depth) { + if (*parse->position == '{') { + depth++; + parse->position++; + } else if (*parse->position == '}') { + depth--; + parse->position++; + } else if (*parse->position == '"') { + ExpectToken(parse, TOKEN_STRING); + } else if (*parse->position == 0) { + fprintf(stderr, "error: unexpected end of file during block\n"); + exit(1); + } else { + parse->position++; + } + } + + char *result = malloc(parse->position - start); + memcpy(result, start, parse->position - start - 1); + result[parse->position - start - 1] = 0; + return result; +} + +Token PeekToken(Parse *parse) { + Parse old = *parse; + Token token = NextToken(parse); + *parse = old; + return token; +} + +char *LoadFile(const char *inputFileName, size_t *byteCount) { + FILE *inputFile = fopen(inputFileName, "rb"); + + if (!inputFile) { + return NULL; + } + + fseek(inputFile, 0, SEEK_END); + size_t inputFileBytes = ftell(inputFile); + fseek(inputFile, 0, SEEK_SET); + + char *inputBuffer = (char *) malloc(inputFileBytes + 1); + size_t inputBytesRead = fread(inputBuffer, 1, inputFileBytes, inputFile); + inputBuffer[inputBytesRead] = 0; + fclose(inputFile); + + if (byteCount) *byteCount = inputBytesRead; + return inputBuffer; +} + +void ParseAdditionalFieldInformation(Parse *parse, ParsedField *field) { + while (PeekToken(parse).type != TOKEN_SEMICOLON) { + Token token = NextToken(parse); + + if (token.type == TOKEN_IDENTIFIER && 0 == strcmp(token.string, "from") && !field->firstVersion) { + field->firstVersion = ExpectToken(parse, TOKEN_NUMBER).number; + } else if (token.type == TOKEN_IDENTIFIER && 0 == strcmp(token.string, "to") && !field->lastVersion) { + field->lastVersion = ExpectToken(parse, TOKEN_NUMBER).number; + } else if (token.type == TOKEN_IDENTIFIER && 0 == strcmp(token.string, "if") && !field->flagsInclude && !field->flagsExclude) { + ExpectToken(parse, TOKEN_LEFT_PAREN); + + while (PeekToken(parse).type != TOKEN_RIGHT_PAREN) { + if (PeekToken(parse).type == TOKEN_EXCLAMATION) { + ExpectToken(parse, TOKEN_EXCLAMATION); + arrput(field->flagsExclude, NextString(parse)); + } else { + arrput(field->flagsInclude, NextString(parse)); + } + } + + ExpectToken(parse, TOKEN_RIGHT_PAREN); + } else if (token.type == TOKEN_HASH) { + field->optionsType = NextString(parse); + field->optionsBlock = NextBlock(parse); + } else { + fprintf(stderr, "error: unexpected token in field on line %d\n", parse->line); + exit(1); + } + } +} + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr, "usage: reflect_gen <input file>\n"); + return 1; + } + + char *input = LoadFile(argv[1], NULL); + + if (!input) { + fprintf(stderr, "error: could not open input file '%s'\n", argv[1]); + return 1; + } + + Parse parse = { 0 }; + parse.position = input; + parse.line = 1; + parse.success = true; + + while (true) { + Token token = NextToken(&parse); + + if (token.type == TOKEN_EOF) { + break; + } + + if (token.type == TOKEN_IDENTIFIER && (0 == strcmp(token.string, "struct") || 0 == strcmp(token.string, "union"))) { + ParsedType type = { 0 }; + type.isStruct = 0 == strcmp(token.string, "struct"); + type.isUnion = 0 == strcmp(token.string, "union"); + type.cName = NextString(&parse); + type.rfName = NextString(&parse); + type.opFunction = NextString(&parse); + ExpectToken(&parse, TOKEN_LEFT_BRACE); + + while (PeekToken(&parse).type != TOKEN_RIGHT_BRACE) { + ParsedField field = { 0 }; + field.rfType = NextString(&parse); + field.cTypeBefore = NextString(&parse); + field.fieldName = NextString(&parse); + + if (PeekToken(&parse).type == TOKEN_STRING) { + field.cTypeAfter = NextString(&parse); + } + + ParseAdditionalFieldInformation(&parse, &field); + ExpectToken(&parse, TOKEN_SEMICOLON); + arrput(type.fields, field); + } + + ExpectToken(&parse, TOKEN_RIGHT_BRACE); + ExpectToken(&parse, TOKEN_SEMICOLON); + arrput(parsedTypes, type); + } else if (token.type == TOKEN_IDENTIFIER && 0 == strcmp(token.string, "type")) { + ParsedType type = { 0 }; + type.isCustom = true; + type.rfName = NextString(&parse); + type.opFunction = NextString(&parse); + ExpectToken(&parse, TOKEN_SEMICOLON); + arrput(parsedTypes, type); + } else if (token.type == TOKEN_IDENTIFIER && 0 == strcmp(token.string, "enum")) { + ParsedType type = { 0 }; + type.isEnum = true; + type.rfName = NextString(&parse); + type.opFunction = NextString(&parse); + ExpectToken(&parse, TOKEN_LEFT_BRACE); + + while (PeekToken(&parse).type != TOKEN_RIGHT_BRACE) { + ParsedField field = { 0 }; + field.fieldName = NextString(&parse); + ParseAdditionalFieldInformation(&parse, &field); + ExpectToken(&parse, TOKEN_SEMICOLON); + arrput(type.fields, field); + } + + ExpectToken(&parse, TOKEN_RIGHT_BRACE); + ExpectToken(&parse, TOKEN_SEMICOLON); + arrput(parsedTypes, type); + } else { + fprintf(stderr, "error: unexpected token at root on line %d\n", parse.line); + exit(1); + } + } + + // Output C type declarations. + + for (uintptr_t i = 0; i < arrlenu(parsedTypes); i++) { + ParsedType *type = parsedTypes + i; + + if (type->isCustom) { + continue; + } else if (type->isEnum) { + for (uintptr_t j = 0; j < arrlenu(type->fields); j++) { + ParsedField *field = type->fields + j; + printf("#define %s (%d)\n", field->fieldName, (int) j); + } + + printf("\n"); + continue; + } + + printf("typedef struct %s {\n", type->cName); + const char *indent = "\t"; + + if (type->isUnion) { + printf("\tuint32_t tag;\n\n\tunion {\n"); + indent = "\t\t"; + } + + for (uintptr_t j = 0; j < arrlenu(type->fields); j++) { + ParsedField *field = type->fields + j; + printf("%s%s %s %s;\n", indent, field->cTypeBefore, field->fieldName, field->cTypeAfter ? field->cTypeAfter : ""); + } + + if (type->isUnion) { + printf("\t};\n"); + } + + printf("} %s;\n\n", type->cName); + } + + // Forward-declare op functions. + + for (uintptr_t i = 0; i < arrlenu(parsedTypes); i++) { + ParsedType *type = parsedTypes + i; + printf("void %s(RfState *state, RfItem *item, void *pointer);\n", type->opFunction); + } + + // Output reflect type information. + + for (uintptr_t i = 0; i < arrlenu(parsedTypes); i++) { + ParsedType *type = parsedTypes + i; + + printf("#ifdef REFLECT_IMPLEMENTATION\n"); + printf("RfType %s = {\n", type->rfName); + printf("\t.op = %s,\n\t.cName = \"%s\",\n\t.fieldCount = %d,\n", type->opFunction, type->cName, (int) arrlen(type->fields)); + + if (arrlenu(type->fields)) { + printf("\n\t.fields = (RfField []) {\n"); + + for (uintptr_t j = 0; j < arrlenu(type->fields); j++) { + ParsedField *field = type->fields + j; + + if (type->isEnum) { + printf("\t\t{ .cName = \"%s\", ", field->fieldName); + } else { + printf("\t\t{ .item.type = &%s, .item.byteCount = RF_SIZE_OF(%s, %s), .cName = \"%s\", .offset = offsetof(%s, %s), ", + field->rfType, type->cName, field->fieldName, field->fieldName, type->cName, field->fieldName); + } + + printf(".firstVersion = %d, .lastVersion = %d, .flagsInclude = 0", field->firstVersion, field->lastVersion); + + for (uintptr_t k = 0; k < arrlenu(field->flagsInclude); k++) { + printf(" | %s", field->flagsInclude[k]); + } + + printf(", .flagsExclude = 0"); + + for (uintptr_t k = 0; k < arrlenu(field->flagsExclude); k++) { + printf(" | %s", field->flagsExclude[k]); + } + + if (field->optionsType) { + printf(", .item.options = &(%s) { %s }", field->optionsType, field->optionsBlock); + } + + printf(" },\n"); + } + + printf("\t},\n"); + } + + printf("};\n\n"); + printf("#else\nextern RfType %s;\n#endif\n", type->rfName); + + if (!type->isEnum) { + for (uintptr_t j = 0; j < arrlenu(type->fields); j++) { + ParsedField *field = type->fields + j; + + printf("#define %s_%s (%d)\n", type->cName, field->fieldName, (int) j); + } + } + } + + return 0; +} diff --git a/util/esfs2.h b/util/esfs2.h new file mode 100644 index 0000000..4e9d9f0 --- /dev/null +++ b/util/esfs2.h @@ -0,0 +1,1178 @@ +// TODO Kernel driver: +// Extent allocation algorithm. +// TODO Design: +// Meta/flex block groups. +// Journal. +// Inline b-tree. +// Further data indirection. +// Hash collisions. (Probably just remove index and enumerate directory contents instead?) + +#ifndef KERNEL + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif + +#ifndef OS_ESSENCE +typedef struct EsUniqueIdentifier { + uint8_t d[16]; +} EsUniqueIdentifier; +#endif + +#endif + +#define ESFS_BOOT_SUPER_BLOCK_SIZE (8192) // The bootloader and superblock take up 16KB. +#define ESFS_DRIVE_MINIMUM_SIZE (1048576) // The minimum drive size that can be formatted. +#define ESFS_DRIVER_VERSION (10) // The current driver version. +#define ESFS_MAXIMUM_VOLUME_NAME_LENGTH (32) // The volume name limit. + +#define ESFS_CORE_NODE_KERNEL (0) // The kernel core node. +#define ESFS_CORE_NODE_ROOT (1) // The root directory core node. +#define ESFS_CORE_NODE_COUNT (2) // The number of core nodes. + +#define ESFS_SIGNATURE_STRING ("!EssenceFS2-----") // The signature in the superblock. +#define ESFS_DIRECTORY_ENTRY_SIGNATURE ("DirEntry") // The signature in directory entries. +#define ESFS_GROUP_DESCRIPTOR_SIGNATURE ("GDTE") // The signature in a group descriptor. +#define ESFS_INDEX_VERTEX_SIGNATURE ("INXE") // The signature in a index vertex. + +#define ESFS_NODE_TYPE_FILE (1) // DirectoryEntry.nodeType: a file. +#define ESFS_NODE_TYPE_DIRECTORY (2) // DirectoryEntry.nodeType: a directory. + +#define ESFS_ATTRIBUTE_DATA (1) // Contains the data of the file, or a list of DirectoryEntries. +#define ESFS_ATTRIBUTE_FILENAME (2) // The UTF-8 filename. +#define ESFS_ATTRIBUTE_DIRECTORY (3) // Additional information about the directory. + +#define ESFS_INDIRECTION_DIRECT (1) // The data is stored in the attribute. +#define ESFS_INDIRECTION_L1 (2) // The attribute contains a extent list that points to the data. + +#define ESFS_INDEX_MAX_DEPTH (16) // The maximum depth of the index tree. I'd be surprised if this gets past 8. +#define ESFS_VERTEX_KEY(vertex, key) ((IndexKey *) ((uint8_t *) vertex + vertex->offset) + key) + +typedef struct Attribute { + /* 0 */ uint16_t type; // Attribute type. + /* 2 */ uint16_t size; // The size in bytes. Must be 8 byte aligned. +} Attribute; + +typedef struct AttributeFilename { + /* 0 */ uint16_t type; // ESFS_ATTRIBUTE_FILENAME. + /* 2 */ uint16_t size; // The size in bytes. Must be 8 byte aligned. + /* 4 */ uint16_t length; // The length of the filename in bytes. + /* 6 */ uint16_t _unused; // Unused. + +#define ESFS_FILENAME_HEADER_SIZE (8) // The size of the header of a AttributeFilename. + /* 8 */ uint8_t filename[1]; // The UTF-8 filename. +} AttributeFilename; + +typedef struct AttributeDirectory { + /* 0 */ uint16_t type; // ESFS_ATTRIBUTE_DIRECTORY. + /* 2 */ uint16_t size; // The size in bytes. Must be 8 byte aligned. + /* 8 */ uint64_t childNodes; // The number of child nodes in the directory. + /* 16 */ uint64_t indexRootBlock; // The block containing the root IndexVertex for the directory. + /* 24 */ uint64_t totalSize; // The sum of sizes of all the directory's children in bytes. +} AttributeDirectory; + +typedef struct AttributeData { + /* 0 */ uint16_t type; // ESFS_ATTRIBUTE_DATA. + /* 2 */ uint16_t size; // The size in bytes. Must be 8 byte aligned. + /* 4 */ uint8_t indirection; // The indirection used to access the data. + /* 5 */ uint8_t dataOffset; // The offset into the attribute where the data or extent list can be found. + /* 6 */ uint16_t count; // The number of data bytes in the attribute, or extents in the list. + /* 8 */ uint64_t _unused[3]; // Unused. +#define ESFS_DATA_OFFSET (32) + /* 32 */ uint8_t data[1]; // The data or extent list. + + // Format of each extent in the extent list: + // uint8_t offsetSize : 3, countSize : 3, unused : 2; // The size of the offset and count fields in bytes - 1. + // uint8_t offset[offsetSize + 1]; // The first block in the extent, expressed as a signed offset from the start + // of the previous extent in the list, or from 0 for the first extent. Big endian. + // uint8_t count[countSize + 1]; // The number of blocks encompassed by the extent. Big endian. +} AttributeData; + +typedef struct DirectoryEntry { + /* 0 */ char signature[8]; // Must be ESFS_DIRECTORY_ENTRY_SIGNATURE. + /* 8 */ EsUniqueIdentifier identifier; // Identifier of the node. + /* 24 */ uint32_t checksum; // CRC-32 checksum of DirectoryEntry. + /* 28 */ uint16_t attributeOffset; // Offset to the first attribute. + /* 30 */ uint8_t nodeType; // Node type. + /* 31 */ uint8_t attributeCount; // The number of attributes in the list. + /* 32 */ uint64_t creationTime, accessTime, modificationTime; // Timekeeping. In microseconds since 1st January 1970. + /* 56 */ uint64_t fileSize; // The amount of data referenced by the data attribute in bytes. + /* 64 */ EsUniqueIdentifier parent; // Identifier of the parent directory. + +#define ESFS_ATTRIBUTE_OFFSET (80) + /* 80 */ uint8_t attributes[1024 - ESFS_ATTRIBUTE_OFFSET]; // Attribute list. +} DirectoryEntry; + +typedef struct GroupDescriptor { + /* 0 */ char signature[4]; // Must be ESFS_GROUP_DESCRIPTOR_SIGNATURE. + /* 4 */ uint32_t blocksUsed; // The number of used blocks in the group. + /* 8 */ uint64_t blockBitmap; // The bitmap indicating which blocks in the group are used. + /* 16 */ uint32_t bitmapChecksum; // CRC-32 checksum of the bitmap. + /* 20 */ uint32_t checksum; // CRC-32 checksum of this descriptor. + /* 24 */ uint32_t largestExtent; // The largest number of contiguous blocks. + /* 28 */ uint32_t _unused[7]; // Unused. +} GroupDescriptor; + +typedef struct DirectoryEntryReference { + /* 0 */ uint64_t block; // The block containing the directory entry. + /* 8 */ uint32_t offsetIntoBlock; // Offset into the block to find the directory entry. + /* 12 */ uint32_t _unused; // Unused. +} DirectoryEntryReference; + +typedef struct IndexKey { + /* 0 */ uint64_t value; // The CRC-64 hashed node path. Ignored for the +1 vertex (assumed to be maximum possible). + /* 8 */ uint64_t child; // The block containing the child IndexVertex. Set to 0 for a leaf. + // All keys in the child should be less than this key. + // This is the only valid field in the +1 key. + /* 16 */ DirectoryEntryReference data; // The directory entry this key refers to. +} IndexKey; + +typedef struct IndexVertex { + /* 0 */ char signature[4]; // Must be ESFS_INDEX_VERTEX_SIGNATURE. + /* 4 */ uint32_t checksum; // CRC-32 checksum of IndexVertex. + /* 8 */ uint16_t offset; // Offset to the first IndexKey. + /* 10 */ uint16_t count; // The number of IndexKeys, (superblock.blockSize - this.offset) / sizeof(IndexKey). + /* 12 */ uint16_t maxCount; // The maximum number of IndexKeys that can fit in the vertex. + /* 14 */ uint16_t _unused0; // Unused. + /* 16 */ uint64_t _unused1[2]; // Unused. + +#define ESFS_INDEX_KEY_OFFSET (32) + /* 32 */ IndexKey keys[1]; // There are this.count keys. +} IndexVertex; + +typedef struct Superblock { + /* 0 */ char signature[16]; // The filesystem signature; should be ESFS_SIGNATURE_STRING. + /* 16 */ char volumeName[ESFS_MAXIMUM_VOLUME_NAME_LENGTH]; // The name of the volume. + + /* 48 */ uint16_t requiredReadVersion; // If this is greater than the driver's version, then the filesystem cannot be read. + /* 50 */ uint16_t requiredWriteVersion; // If this is greater than the driver's version, then the filesystem cannot be written. + + /* 52 */ uint32_t checksum; // CRC-32 checksum of Superblock. + /* 56 */ uint8_t mounted; // Non-zero to indicate that the volume is mounted, or was not properly unmounted. + + /* 64 */ uint64_t blockSize; // The size of a block on the volume. + /* 72 */ uint64_t blockCount; // The number of blocks on the volume. + /* 80 */ uint64_t blocksUsed; // The number of blocks that are in use. + + /* 88 */ uint32_t blocksPerGroup; // The number of blocks in a group. + /* 96 */ uint64_t groupCount; // The number of groups on the volume. + /* 104 */ uint64_t blocksPerGroupBlockBitmap; // The number of blocks used to a store a group's block bitmap. + /* 112 */ uint64_t gdtFirstBlock; // The first block in the group descriptor table. + /* 120 */ uint64_t directoryEntriesPerBlock; // The number of directory entries in a block. + /* 128 */ uint64_t _unused0; // Unused. + + /* 136 */ EsUniqueIdentifier identifier; // The unique identifier for the volume. + /* 152 */ EsUniqueIdentifier osInstallation; // The unique identifier of the Essence installation this volume was made for. All zero for a non-installation volume. + /* 168 */ EsUniqueIdentifier nextIdentifier; // The identifier to give to the next created file. + + /* 184 */ DirectoryEntryReference kernel; // The kernel. For convenient access by the bootloader. + /* 200 */ DirectoryEntryReference root; // The root directory. + + /* 216 */ uint8_t _unused1[8192 - 216]; // Unused. +} Superblock; + +uint64_t EncodeExtent(uint64_t extentStart, uint64_t previousExtentStart, uint64_t extentCount, uint8_t *encode) { + int64_t relativeStart = (int64_t) (extentStart - previousExtentStart); + uint64_t absoluteRelativeStart = (uint64_t) (relativeStart < 0 ? -relativeStart : relativeStart); + + uint8_t startBytes = + absoluteRelativeStart < 0x80 ? 1 + : absoluteRelativeStart < 0x8000 ? 2 + : absoluteRelativeStart < 0x800000 ? 3 + : absoluteRelativeStart < 0x80000000 ? 4 + : absoluteRelativeStart < 0x8000000000 ? 5 + : absoluteRelativeStart < 0x800000000000 ? 6 + : absoluteRelativeStart < 0x80000000000000 ? 7 + : 8; + uint8_t countBytes = + extentCount < 0x80 ? 1 + : extentCount < 0x8000 ? 2 + : extentCount < 0x800000 ? 3 + : extentCount < 0x80000000 ? 4 + : extentCount < 0x8000000000 ? 5 + : extentCount < 0x800000000000 ? 6 + : extentCount < 0x80000000000000 ? 7 + : 8; + + uint64_t position = 0; + encode[position++] = (startBytes - 1) + ((countBytes - 1) << 3); + + for (int i = 0; i < startBytes; i++, position++) encode[position] = (uint8_t) (relativeStart >> ((startBytes - 1 - i) * 8)); + for (int i = 0; i < countBytes; i++, position++) encode[position] = (uint8_t) (extentCount >> ((countBytes - 1 - i) * 8)); + +#if 0 + Log("encode: %d/%d --> ", startBytes, countBytes); + + for (unsigned i = 0; i < position; i++) { + Log("%.2X ", (uint32_t) encode[i]); + } + + Log("\n"); +#endif + + return position; +} + +bool DecodeExtent(uint64_t *previousExtentStart, uint64_t *extentCount, uint8_t *extents, uint64_t *position, uint64_t end) { + uint64_t extentStart = 0; + *extentCount = 0; + + if (*position == end) return false; + uint8_t header = extents[*position]; + *position = *position + 1; + + uint8_t startBytes = ((header >> 0) & 7) + 1; + uint8_t countBytes = ((header >> 3) & 7) + 1; + + bool negative = false; + + for (uint8_t i = 0; i < startBytes; i++) { + if (*position == end) return false; + uint8_t byte = extents[*position]; + if (!i) negative = byte & 0x80; + extentStart <<= 8; + extentStart += byte; + *position = *position + 1; + } + + for (uint8_t i = 0; i < countBytes; i++) { + if (*position == end) return false; + *extentCount = *extentCount << 8; + *extentCount = *extentCount + extents[*position]; + *position = *position + 1; + } + + if (negative) { + for (uint64_t i = startBytes; i < sizeof(uint64_t) / sizeof(uint8_t); i++) { + extentStart |= (uint64_t) 0xFF << (i * 8); + } + } + + *previousExtentStart = *previousExtentStart + extentStart; + return true; +} + +#ifndef KERNEL + +typedef struct ImportNode { + const char *name, *path; + struct ImportNode *children; + bool isFile; +} ImportNode; + +ImportNode *ImportNodeFindChild(ImportNode *thisNode, const char *name) { + for (uintptr_t i = 0; i < arrlenu(thisNode->children); i++) { + if (0 == strcmp(thisNode->children[i].name, name)) { + return thisNode->children + i; + } + } + + return NULL; +} + +void ImportNodeAddFile(ImportNode *thisNode, const char *name, const char *path) { + assert(!ImportNodeFindChild(thisNode, name)); + ImportNode node = {}; + node.name = name; + node.path = path; + node.isFile = true; + arrput(thisNode->children, node); +} + +ImportNode *ImportNodeMakeDirectory(ImportNode *thisNode, const char *name) { + assert(!ImportNodeFindChild(thisNode, name)); + ImportNode node = {}; + node.name = name; + arrput(thisNode->children, node); + return &arrlast(thisNode->children); +} + +void ImportNodeRemoveChild(ImportNode *thisNode, const char *name) { + for (uintptr_t i = 0; i < arrlenu(thisNode->children); i++) { + if (0 == strcmp(thisNode->children[i].name, name)) { + arrdel(thisNode->children, i); + return; + } + } + + assert(false); +} + +uint64_t blockSize; +Superblock superblock; +GroupDescriptor *groupDescriptorTable; +uint64_t copiedCount; + +void ReadBlock(uint64_t block, uint64_t count, void *buffer); +void WriteBlock(uint64_t block, uint64_t count, void *buffer); +void WriteBytes(uint64_t offset, uint64_t count, void *buffer); + +void ReadDirectoryEntryReference(DirectoryEntryReference reference, DirectoryEntry *entry) { + uint8_t buffer[superblock.blockSize]; + ReadBlock(reference.block, 1, buffer); + memcpy(entry, buffer + reference.offsetIntoBlock, sizeof(DirectoryEntry)); +} + +void WriteDirectoryEntryReference(DirectoryEntryReference reference, DirectoryEntry *entry) { + entry->checksum = 0; + entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0); + uint8_t buffer[superblock.blockSize]; + ReadBlock(reference.block, 1, buffer); + memcpy(buffer + reference.offsetIntoBlock, entry, sizeof(DirectoryEntry)); + WriteBlock(reference.block, 1, buffer); +} + +Attribute *FindAttribute(DirectoryEntry *entry, uint16_t type) { + Attribute *attribute = (Attribute *) ((uint8_t *) entry + entry->attributeOffset); + int count = 0; + + while (attribute->type != type) { + attribute = (Attribute *) ((uint8_t *) attribute + attribute->size); + + if (count++ == entry->attributeCount) { + Log("Could not find attribute %d.\n", type); + exit(1); + } + } + + return attribute; +} + +void GenerateUniqueIdentifier(EsUniqueIdentifier *u, bool random) { + if (random) { + for (int i = 0; i < 16; i++) { + u->d[i] = rand(); + } + } else { + *u = superblock.nextIdentifier; + + for (int i = 0; i < 16; i++) { + superblock.nextIdentifier.d[i]++; + if (superblock.nextIdentifier.d[i]) break; + } + } +} + +IndexKey *InsertKeyIntoVertex(uint64_t newKey, IndexVertex *vertex) { + // Find where in this vertex we should insert the key. + + int position; + + for (position = 0; position < vertex->count; position++) { + if (newKey < ESFS_VERTEX_KEY(vertex, position)->value) { + break; + } + } + + // Insert the key. + + // Log("%d//%d\n", vertex->count, vertex->maxCount); + assert(vertex->count != vertex->maxCount); + IndexKey *insertionPosition = ESFS_VERTEX_KEY(vertex, position); + memmove(insertionPosition + 1, insertionPosition, + (vertex->count + 1 - position) * sizeof(IndexKey)); + vertex->count++; + insertionPosition->value = newKey; + + // Update the checksum. + + vertex->checksum = 0; + vertex->checksum = CalculateCRC32(vertex, superblock.blockSize, 0); + + return insertionPosition; +} + +void AllocateExtent(uint64_t increaseBlocks, uint64_t *extentStart, uint64_t *extentCount) { + // Log("used %ld/%ld, need %ld more\n", superblock.blocksUsed, superblock.blockCount, increaseBlocks); + + // Find a group to allocate the next extent from. + + GroupDescriptor *target = NULL; + + { + for (uint64_t i = 0; !target && i < superblock.groupCount; i++) { + GroupDescriptor *group = groupDescriptorTable + i; + if (!group->blocksUsed) group->largestExtent = superblock.blocksPerGroup - superblock.blocksPerGroupBlockBitmap; + if (group->largestExtent >= increaseBlocks) target = group; + } + + for (uint64_t i = 0; !target && i < superblock.groupCount; i++) { + GroupDescriptor *group = groupDescriptorTable + i; + if (superblock.blocksPerGroup - group->blocksUsed >= increaseBlocks) target = group; + } + + for (uint64_t i = 0; !target && i < superblock.groupCount; i++) { + GroupDescriptor *group = groupDescriptorTable + i; + if (superblock.blocksPerGroup != group->blocksUsed) target = group; + } + } + + if (!target) { + Log("Out of space.\n"); + exit(1); + } + + // Load the bitmap, find the largest extent, and mark it as in use. + + uint8_t bitmap[superblock.blocksPerGroupBlockBitmap * superblock.blockSize]; + + { + if (target->blockBitmap) { + ReadBlock(target->blockBitmap, superblock.blocksPerGroupBlockBitmap, bitmap); + } else { + memset(bitmap, 0, superblock.blocksPerGroupBlockBitmap * superblock.blockSize); + for (uint64_t i = 0; i < superblock.blocksPerGroupBlockBitmap; i++) bitmap[i / 8] |= 1 << (i % 8); + target->blockBitmap = superblock.blocksPerGroup * (target - groupDescriptorTable); + target->blocksUsed = superblock.blocksPerGroupBlockBitmap; + } + + uint64_t largestExtentStart = 0, largestExtentCount = 0, i = 0; + + while (i < superblock.blocksPerGroup) { + if (bitmap[i / 8] & (1 << (i % 8))) { + i++; + } else { + uint64_t start = i, count = 0; + + while (i < superblock.blocksPerGroup) { + if (bitmap[i / 8] & (1 << (i % 8))) break; + else count++, i++; + } + + if (largestExtentCount < count) { + largestExtentStart = start; + largestExtentCount = count; + } + } + } + + assert(largestExtentCount == target->largestExtent); + + *extentStart = largestExtentStart; + *extentCount = largestExtentCount; + + if (*extentCount > increaseBlocks) { + *extentCount = increaseBlocks; + } + + for (uint64_t i = *extentStart; i < *extentStart + *extentCount; i++) { + bitmap[i / 8] |= 1 << (i % 8); + } + + { + uint64_t largestExtentCount = 0, i = 0; + + while (i < superblock.blocksPerGroup) { + if (bitmap[i / 8] & (1 << (i % 8))) { + i++; + } else { + uint64_t count = 0; + + while (i < superblock.blocksPerGroup) { + if (bitmap[i / 8] & (1 << (i % 8))) break; + else count++, i++; + } + + if (largestExtentCount < count) { + largestExtentCount = count; + } + } + } + + target->blocksUsed += *extentCount; + target->largestExtent = largestExtentCount; + + assert(superblock.blocksPerGroup == target->blocksUsed || target->largestExtent); + } + + target->bitmapChecksum = CalculateCRC32(bitmap, sizeof(bitmap), 0); + target->checksum = 0; + target->checksum = CalculateCRC32(target, sizeof(GroupDescriptor), 0); + + WriteBlock(target->blockBitmap, superblock.blocksPerGroupBlockBitmap, bitmap); + } + + *extentStart = *extentStart + (target - groupDescriptorTable) * superblock.blocksPerGroup; + superblock.blocksUsed += *extentCount; + // Log("allocate extent: %ld -> %ld (for %ld)\n", extentStart, extentStart + extentCount, increaseBlocks); +} + +void AccessNode(DirectoryEntry *node, void *buffer, uint64_t offsetIntoFile, uint64_t totalCount, DirectoryEntryReference *reference, bool read) { + if (!totalCount) return; + AttributeData *dataAttribute = (AttributeData *) FindAttribute(node, ESFS_ATTRIBUTE_DATA); + + if (dataAttribute->indirection == ESFS_INDIRECTION_DIRECT && read) { + memcpy(buffer, dataAttribute->data + offsetIntoFile, totalCount); + return; + } else if (dataAttribute->indirection == ESFS_INDIRECTION_DIRECT && !read) { + assert(!reference); + memcpy(dataAttribute->data + offsetIntoFile, buffer, totalCount); + return; + } + + assert(dataAttribute->indirection == ESFS_INDIRECTION_L1); + + int decoded = -1; + + // Log("\twrite %ld bytes at %ld\n", totalCount, offsetIntoFile); + + next:; + uint64_t block = offsetIntoFile / superblock.blockSize; + uint64_t offset = offsetIntoFile % superblock.blockSize; + uint64_t count = superblock.blockSize - offset; + if (totalCount < count) count = totalCount; + + // Log("block: %ld, offset: %ld, count: %ld\n", block, offset, count); + + // Find the extent. + + uint8_t *extents = ((uint8_t *) dataAttribute + dataAttribute->dataOffset); + + { + uint64_t position = 0, blockInFile = 0, extentStart = 0; + assert(dataAttribute->count || !node->fileSize); + + bool found = false; + + for (uint64_t i = 0; i < dataAttribute->count; i++) { + uint64_t extentCount = 0; + DecodeExtent(&extentStart, &extentCount, extents, &position, dataAttribute->size - dataAttribute->dataOffset); + if (decoded < (int) i) { + decoded = i; + } + + if (blockInFile + extentCount > block) { + uint64_t offsetIntoExtent = block - blockInFile; + block = extentStart + offsetIntoExtent; + found = true; + break; + } + + blockInFile += extentCount; + } + + assert(found); + } + + uint8_t blockBuffer[superblock.blockSize]; + ReadBlock(block, 1, blockBuffer); + + if (read) { + memcpy(buffer, blockBuffer + offset, count); + } else { + memcpy(blockBuffer + offset, buffer, count); + WriteBlock(block, 1, blockBuffer); + } + + if (reference) { + reference->block = block; + reference->offsetIntoBlock = offset; + } + + totalCount -= count; + + if (totalCount) { + offsetIntoFile += count; + buffer = (uint8_t *) buffer + count; + goto next; + } +} + +void ResizeNode(DirectoryEntry *entry, uint64_t newSize) { + assert(newSize >= entry->fileSize); + + AttributeData *dataAttribute = (AttributeData *) FindAttribute(entry, ESFS_ATTRIBUTE_DATA); + + if (newSize < (uint64_t) (dataAttribute->size - dataAttribute->dataOffset) && entry->nodeType == ESFS_NODE_TYPE_FILE) { + dataAttribute->indirection = ESFS_INDIRECTION_DIRECT; + dataAttribute->count = entry->fileSize = newSize; + return; + } + + // Log("\tresize to %lu\n", newSize); + + dataAttribute->indirection = ESFS_INDIRECTION_L1; + + uint64_t oldSize = entry->fileSize; + uint64_t oldBlocks = (oldSize + superblock.blockSize - 1) / superblock.blockSize; + uint64_t newBlocks = (newSize + superblock.blockSize - 1) / superblock.blockSize; + + entry->fileSize = newSize; + + if (oldBlocks == newBlocks) { + // Do nothing. + } else if (oldBlocks < newBlocks) { + uint64_t increaseBlocks = newBlocks - oldBlocks; + uint64_t previousExtentStart = 0, previousExtentCount = 0, previousExtentStart2 = 0; + + uint8_t *extents = ((uint8_t *) dataAttribute + dataAttribute->dataOffset); + uint64_t offsetIntoExtentList = 0; + uint64_t previousOffsetIntoExtentList = 0; + + for (uint64_t i = 0; i < dataAttribute->count; i++) { + previousOffsetIntoExtentList = offsetIntoExtentList; + previousExtentStart2 = previousExtentStart; + DecodeExtent(&previousExtentStart, &previousExtentCount, extents, &offsetIntoExtentList, dataAttribute->size - dataAttribute->dataOffset); + // Log("%ld/%ld/%ld\n", previousExtentStart, extentCount, offsetIntoExtentList); + assert(previousExtentStart < superblock.blockCount); + } + + while (increaseBlocks) { + uint64_t extentStart, extentCount, encodedLength; + uint8_t encode[32]; + + AllocateExtent(increaseBlocks, &extentStart, &extentCount); + + if (extentStart == previousExtentStart + previousExtentCount) { + dataAttribute->count--; + offsetIntoExtentList = previousOffsetIntoExtentList; + encodedLength = EncodeExtent(previousExtentStart, previousExtentStart2, extentCount + previousExtentCount, encode); + } else { + encodedLength = EncodeExtent(extentStart, previousExtentStart, extentCount, encode); + } + + // Log("\t@%ld alloc %ld, %ld\n", offsetIntoExtentList, extentStart, extentCount); + + // Log("%ld vs %ld\n", offsetIntoExtentList + encodedLength, (uint64_t) (dataAttribute->size - dataAttribute->dataOffset)); + + if (offsetIntoExtentList + encodedLength > (uint64_t) (dataAttribute->size - dataAttribute->dataOffset)) { + Log("Unimplemented - indirection past L1.\n"); + exit(1); + } + + memcpy(extents + offsetIntoExtentList, encode, encodedLength); + offsetIntoExtentList += encodedLength; + increaseBlocks -= extentCount; + dataAttribute->count++; + previousExtentStart = extentStart; + } + } else { + Log("Unimplemented - node truncation.\n"); + exit(1); + } +} + +#if 0 +void PrintTree(uint64_t block, int indent = 2, uint64_t lowerThan = -1) { + if (!block) return; + + uint8_t buffer[superblock.blockSize]; + ReadBlock(block, 1, buffer); + IndexVertex *node = (IndexVertex *) buffer; + const char *spaces = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | "; + +#ifndef VALIDATE_TREE_ONLY + Log("%.*snode with %d+1 keys [%p]\n", indent, spaces, node->count, node); +#endif + + for (uint64_t i = 0; i <= node->count; i++) { + if (i && i != node->count && node->keys[i].value <= node->keys[i - 1].value) { + Log("%.*s %lu VIOLATION [1]\n", indent, spaces, i); + assert(false); + } + + uint64_t next = lowerThan; + + if (i == node->count) { +#ifndef VALIDATE_TREE_ONLY + Log("%.*s %lu last key\n", indent, spaces, i); +#endif + } else { + if (node->keys[i].value >= lowerThan) { + Log("%.*s %lu VIOLATION [2]\n", indent, spaces, i); + assert(false); + } + +#ifndef VALIDATE_TREE_ONLY + Log("%.*s %lu key = %lu\n", indent, spaces, i, node->keys[i].value); +#endif + next = node->keys[i].value; + } + + PrintTree(node->keys[i].child, indent + 4, next); + } +} +#endif + +void NewDirectoryEntry(DirectoryEntry *entry, uint8_t nodeType, EsUniqueIdentifier parentUID, const char *name) { + memcpy(entry->signature, ESFS_DIRECTORY_ENTRY_SIGNATURE, 8); + GenerateUniqueIdentifier(&entry->identifier, false); + entry->attributeOffset = ESFS_ATTRIBUTE_OFFSET; + entry->nodeType = nodeType; + entry->parent = parentUID; + + uint8_t *position = (uint8_t *) entry + entry->attributeOffset; + size_t newFilenameSize = ((strlen(name) + ESFS_FILENAME_HEADER_SIZE - 1) & ~7) + 8; // Size of name + size of header, rounded up to the nearest 8 bytes. + + if (nodeType == ESFS_NODE_TYPE_DIRECTORY) { + AttributeDirectory *directory = (AttributeDirectory *) position; + directory->type = ESFS_ATTRIBUTE_DIRECTORY; + directory->size = sizeof(AttributeDirectory); + directory->indexRootBlock = 0; + directory->totalSize = 0; + entry->attributeCount++; + position += directory->size; + } + + AttributeData *data = (AttributeData *) position; + data->type = ESFS_ATTRIBUTE_DATA; + data->size = sizeof(DirectoryEntry) - newFilenameSize - (position - (uint8_t *) entry); + data->indirection = nodeType == ESFS_NODE_TYPE_DIRECTORY ? ESFS_INDIRECTION_L1 : ESFS_INDIRECTION_DIRECT; + data->dataOffset = ESFS_DATA_OFFSET; + entry->attributeCount++; + position += data->size; + + AttributeFilename *filename = (AttributeFilename *) position; + filename->type = ESFS_ATTRIBUTE_FILENAME; + filename->size = newFilenameSize; + filename->length = strlen(name); + memcpy(filename->filename, name, filename->length); + entry->attributeCount++; + position += filename->size; + + assert(position == (uint8_t *) (entry + 1)); + entry->checksum = 0; + entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0); +} + +void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, DirectoryEntryReference *outputReference, + DirectoryEntryReference directoryReference) { + // Log("add %s to %s\n", name, path); + + // Step 1: Resize the directory so that it can fit another directory entry. + + DirectoryEntry directory; + + ReadDirectoryEntryReference(directoryReference, &directory); + AttributeData *dataAttribute = (AttributeData *) FindAttribute(&directory, ESFS_ATTRIBUTE_DATA); + AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY); + + { + + assert(dataAttribute->indirection == ESFS_INDIRECTION_L1); + + if (!(directoryAttribute->childNodes % superblock.directoryEntriesPerBlock)) { + // Log("increasing directory to fit %ld entries\n========={\n", (directory.fileSize + superblock.blockSize) / sizeof(DirectoryEntry)); + ResizeNode(&directory, directory.fileSize + superblock.blockSize); + // Log("========}\n"); + } + + directoryAttribute->childNodes++; + WriteDirectoryEntryReference(directoryReference, &directory); + } + + // Step 2: Create the directory entry, and write it to the directory. + + DirectoryEntryReference reference = {}; + DirectoryEntry entry = {}; + + { + NewDirectoryEntry(&entry, nodeType, directory.identifier, name); + // Log("\tchild nodes: %ld\n", directoryAttribute->childNodes); + AccessNode(&directory, &entry, (directoryAttribute->childNodes - 1) * sizeof(DirectoryEntry), sizeof(DirectoryEntry), &reference, false); + } + + // Step 3: Add the node into the index. + + uint64_t newKey = CalculateCRC64(name, strlen(name), 0); + // Log("adding file '%s' to index...\n", name); + + { + // Find the leaf to insert the key into. + + uint8_t buffer[superblock.blockSize]; + memset(buffer, 0, superblock.blockSize); + IndexVertex *vertex = (IndexVertex *) buffer; + uint64_t depth = 0, blocks[ESFS_INDEX_MAX_DEPTH] = { directoryAttribute->indexRootBlock }; + + if (blocks[0] == 0) { + // Directory is empty - create the root vertex. + + uint64_t _unused; + AllocateExtent(1, &directoryAttribute->indexRootBlock, &_unused); + blocks[0] = directoryAttribute->indexRootBlock; + vertex->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; + vertex->offset = ESFS_INDEX_KEY_OFFSET; + memcpy(vertex->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4); + // Log("rootBlock = %ld for %s\n", directoryAttribute->indexRootBlock, path); + } else { + ReadBlock(blocks[0], 1, vertex); + // Log("start = %ld for %s\n", blocks[0], path); + } + + while (true) { + for (int i = 0; i < vertex->count; i++) { + if (ESFS_VERTEX_KEY(vertex, i)->value == newKey) { + // The key is already in the tree. + Log("The file already exists."); + exit(1); + } + } + + for (int i = 0; i <= vertex->count; i++) { + IndexKey *key = ESFS_VERTEX_KEY(vertex, i); + + if ((i == vertex->count || newKey < key->value) && key->child) { + blocks[++depth] = key->child; + ReadBlock(key->child, 1, vertex); + goto next; + } + } + + break; + next:; + } + + // Insert the key into the vertex. + + InsertKeyIntoVertex(newKey, vertex)->data = reference; + + // While the vertex is full... + + assert(vertex->count <= vertex->maxCount); + + while (vertex->count == vertex->maxCount) { + // Log("\tsplit!\n"); + + char _buffer0[superblock.blockSize]; + char _buffer1[superblock.blockSize]; + memset(_buffer0, 0, superblock.blockSize); + memset(_buffer1, 0, superblock.blockSize); + + // Create a new sibling. + + uint64_t siblingBlock = 0, _unused; + AllocateExtent(1, &siblingBlock, &_unused); + IndexVertex *sibling = (IndexVertex *) _buffer0; + sibling->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; + sibling->offset = ESFS_INDEX_KEY_OFFSET; + memcpy(sibling->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4); + + // Load the parent vertex. + + bool newRoot = !depth; + IndexVertex *parent = (IndexVertex *) _buffer1; + + if (newRoot) { + // Create a new root block. + + // Log("\t(new root)\n"); + + blocks[1] = blocks[0]; + depth++; + + uint64_t _unused; + AllocateExtent(1, &blocks[0], &_unused); + + parent->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; + parent->offset = ESFS_INDEX_KEY_OFFSET; + memcpy(parent->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4); + + // The superblock points to the new root, and the +1 key of the new root points to the old root. + // It has no other keys yet. + + parent->keys[0].child = blocks[1]; + directoryAttribute->indexRootBlock = blocks[0]; + } else { + ReadBlock(blocks[depth - 1], 1, parent); + } + + IndexKey *parentKeys = (IndexKey *) ((uint8_t *) parent + parent->offset); + IndexKey *vertexKeys = (IndexKey *) ((uint8_t *) vertex + vertex->offset); + IndexKey *siblingKeys = (IndexKey *) ((uint8_t *) sibling + sibling->offset); + + // Change the link to this vertex to point to the sibling. + + int found = 0; + + for (uint64_t i = 0; i <= parent->count; i++) { + if (parentKeys[i].child == blocks[depth]) { + parentKeys[i].child = siblingBlock; + found++; + } + } + + assert(found == 1); + + // Move the median key to the parent. + // If this makes the parent full we'll fix it next iteration. + + uint64_t median = (vertex->maxCount - 1) / 2; + uint64_t newKey = vertexKeys[median].value; + + for (uint64_t i = 0; i <= parent->count; i++) { + if (i == parent->count || newKey < parentKeys[i].value) { + memmove(parentKeys + i + 1, parentKeys + i, (++parent->count - i) * sizeof(IndexKey)); + parentKeys[i].value = newKey; + parentKeys[i].data = vertexKeys[median].data; + parentKeys[i].child = blocks[depth]; + break; + } + } + + // Move all keys above the median key to the new sibling. + sibling->count = vertex->count - median /*Kept in the node*/ - 1 /*Added to the parent*/; + vertex->count = median; // The data on the median key becomes the +1 key's data. + memcpy(siblingKeys, vertexKeys + median + 1, (sibling->count + 1) * sizeof(IndexKey)); + + // Write the blocks. + + sibling->checksum = 0; sibling->checksum = CalculateCRC32(sibling, superblock.blockSize, 0); + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock.blockSize, 0); + WriteBlock(siblingBlock, 1, sibling); + WriteBlock(blocks[depth], 1, vertex); + + // Check if the parent vertex is full. + + memcpy(vertex, parent, superblock.blockSize); + depth--; + } + + // Write the block. + + vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock.blockSize, 0); + WriteBlock(blocks[depth], 1, vertex); + } + + if (outputEntry) *outputEntry = entry; + if (outputReference) *outputReference = reference; + + // PrintTree(directoryAttribute->indexRootBlock); + WriteDirectoryEntryReference(directoryReference, &directory); +} + +void MountVolume() { + // Read the superblock. + blockSize = ESFS_BOOT_SUPER_BLOCK_SIZE; + ReadBlock(1, 1, &superblock); + + if (superblock.mounted) { + Log("EsFS: Volume not unmounted, exiting...\n"); + exit(1); + } + + superblock.mounted = 1; + WriteBlock(1, 1, &superblock); + blockSize = superblock.blockSize; + + // Read the group descriptor table. + groupDescriptorTable = (GroupDescriptor *) malloc(superblock.groupCount * sizeof(GroupDescriptor) + superblock.blockSize - 1); + ReadBlock(superblock.gdtFirstBlock, (superblock.groupCount * sizeof(GroupDescriptor) + superblock.blockSize - 1) / superblock.blockSize, groupDescriptorTable); +} + +void UnmountVolume() { + WriteBlock(superblock.gdtFirstBlock, (superblock.groupCount * sizeof(GroupDescriptor) + superblock.blockSize - 1) / superblock.blockSize, groupDescriptorTable); + blockSize = ESFS_BOOT_SUPER_BLOCK_SIZE; + superblock.mounted = 0; + superblock.checksum = 0; + superblock.checksum = CalculateCRC32(&superblock, sizeof(Superblock), 0); + WriteBlock(1, 1, &superblock); + free(groupDescriptorTable); +} + +bool FindNode(const char *cName, DirectoryEntry *node, DirectoryEntryReference directoryReference) { + DirectoryEntry directory; + ReadDirectoryEntryReference(directoryReference, &directory); + AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY); + + for (uintptr_t i = 0; i < directoryAttribute->childNodes; i++) { + AccessNode(&directory, node, sizeof(DirectoryEntry) * i, sizeof(DirectoryEntry), NULL, true); + AttributeFilename *filename = (AttributeFilename *) FindAttribute(node, ESFS_ATTRIBUTE_FILENAME); + + if (filename->length == strlen(cName) && 0 == memcmp(filename->filename, cName, filename->length)) { + return true; + } + } + + Log("Could not find '%s'.\n", cName); + return false; +} + +#if 0 +void Read(char *target, DirectoryEntryReference parentDirectory) { + DirectoryEntryReference outputReference; + DirectoryEntry entry; + if (!FindNode(target, &entry, parentDirectory)) return; + char *data = (char *) malloc(entry.fileSize); + AccessNode(&entry, data, 0, entry.fileSize, &outputReference, true); + fwrite(data, 1, entry.fileSize, stdout); +} +#endif + +uint64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) { + uint64_t totalSize = 0; + + for (uintptr_t i = 0; i < arrlenu(node.children); i++) { + if (node.children[i].isFile) { + size_t fileLength; + void *data = LoadFile(node.children[i].path, &fileLength); + + if (!data) { + Log("Warning: Could not read file '%s'!\n", node.children[i].path); + } else { + copiedCount += fileLength; + + DirectoryEntryReference reference; + DirectoryEntry entry; + + AddNode(node.children[i].name, ESFS_NODE_TYPE_FILE, &entry, &reference, parentDirectory); + ResizeNode(&entry, fileLength); + totalSize += fileLength; + + AccessNode(&entry, data, 0, fileLength, NULL, false); + WriteDirectoryEntryReference(reference, &entry); + + free(data); + } + } else { + DirectoryEntryReference reference; + AddNode(node.children[i].name, ESFS_NODE_TYPE_DIRECTORY, NULL, &reference, parentDirectory); + uint64_t size = Import(node.children[i], reference); + DirectoryEntry directory; + ReadDirectoryEntryReference(reference, &directory); + AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY); + directoryAttribute->totalSize = size; + WriteDirectoryEntryReference(reference, &directory); + totalSize += size; + } + } + + return totalSize; +} + +void Format(uint64_t driveSize, const char *volumeName, EsUniqueIdentifier osInstallation, + void *kernel, size_t kernelBytes) { + assert(sizeof(Superblock) == 8192); + + if (driveSize < ESFS_DRIVE_MINIMUM_SIZE) { + Log("Error: Cannot create a drive of %d bytes (too small).\n", (int) driveSize); + exit(1); + } + + if (strlen(volumeName) > ESFS_MAXIMUM_VOLUME_NAME_LENGTH) { + Log("Error: Volume name '%s' is too long; must be <= %d bytes.\n", volumeName, (int) ESFS_MAXIMUM_VOLUME_NAME_LENGTH); + exit(1); + } + + // Format the volume. + + { + memcpy(superblock.signature, ESFS_SIGNATURE_STRING, 16); + memcpy(superblock.volumeName, volumeName, strlen(volumeName)); + + superblock.requiredReadVersion = ESFS_DRIVER_VERSION; + superblock.requiredWriteVersion = ESFS_DRIVER_VERSION; + + if (driveSize < 2048l * 1024 * 1024) { // < 2GB + superblock.blockSize = 2048; // Must be >= sizeof(DirectoryEntry). + } else if (driveSize < 2l * 1024 * 1024 * 1024 * 1024) { // < 2TB + superblock.blockSize = 4096; + } else if (driveSize < 256l * 1024 * 1024 * 1024 * 1024) { // < 256TB + superblock.blockSize = 8192; + } else { + superblock.blockSize = 16384; + } + + superblock.blockCount = driveSize / superblock.blockSize; + superblock.blocksPerGroup = 32768; + if (superblock.blockCount < superblock.blocksPerGroup) superblock.blocksPerGroup = superblock.blockCount / 2; + superblock.groupCount = (superblock.blockCount + superblock.blocksPerGroup - 1) / superblock.blocksPerGroup; + superblock.blocksPerGroupBlockBitmap = ((superblock.blocksPerGroup + 7) / 8 + superblock.blockSize - 1) / superblock.blockSize; + superblock.directoryEntriesPerBlock = superblock.blockSize / sizeof(DirectoryEntry); + + uint64_t blockGDT = ESFS_BOOT_SUPER_BLOCK_SIZE * 2 / superblock.blockSize + 1; + uint64_t blockGroup0Bitmap = blockGDT + (superblock.groupCount * sizeof(GroupDescriptor) + superblock.blockSize - 1) / superblock.blockSize; + uint64_t blockCoreNodes = blockGroup0Bitmap + superblock.blocksPerGroupBlockBitmap; + uint64_t end = blockCoreNodes + ((ESFS_CORE_NODE_COUNT + superblock.directoryEntriesPerBlock - 1) / superblock.directoryEntriesPerBlock); + + superblock.blocksUsed = end; + superblock.gdtFirstBlock = blockGDT; + + GenerateUniqueIdentifier(&superblock.identifier, true); + superblock.osInstallation = osInstallation; + + DirectoryEntry coreNodes[ESFS_CORE_NODE_COUNT] = {}; + + superblock.root.block = (blockCoreNodes * superblock.blockSize + sizeof(DirectoryEntry) * ESFS_CORE_NODE_ROOT) / superblock.blockSize; + superblock.root.offsetIntoBlock = (blockCoreNodes * superblock.blockSize + sizeof(DirectoryEntry) * ESFS_CORE_NODE_ROOT) % superblock.blockSize; + superblock.kernel.block = (blockCoreNodes * superblock.blockSize + sizeof(DirectoryEntry) * ESFS_CORE_NODE_KERNEL) / superblock.blockSize; + superblock.kernel.offsetIntoBlock = (blockCoreNodes * superblock.blockSize + sizeof(DirectoryEntry) * ESFS_CORE_NODE_KERNEL) % superblock.blockSize; + + { + // Root directory. + DirectoryEntry *entry = coreNodes + ESFS_CORE_NODE_ROOT; + memcpy(entry->signature, ESFS_DIRECTORY_ENTRY_SIGNATURE, 8); + GenerateUniqueIdentifier(&entry->identifier, false); + entry->attributeOffset = ESFS_ATTRIBUTE_OFFSET; + entry->nodeType = ESFS_NODE_TYPE_DIRECTORY; + entry->attributeCount = 2; + AttributeDirectory *directory = (AttributeDirectory *) entry->attributes; + directory->type = ESFS_ATTRIBUTE_DIRECTORY; + directory->size = sizeof(AttributeDirectory); + AttributeData *data = (AttributeData *) ((uint8_t *) directory + directory->size); + data->type = ESFS_ATTRIBUTE_DATA; + data->size = sizeof(DirectoryEntry) - ESFS_ATTRIBUTE_OFFSET - directory->size; + data->indirection = ESFS_INDIRECTION_L1; + data->dataOffset = ESFS_ATTRIBUTE_OFFSET; + entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0); + } + + WriteBytes(blockCoreNodes * superblock.blockSize, sizeof(coreNodes), &coreNodes); + superblock.checksum = CalculateCRC32(&superblock, sizeof(Superblock), 0); + WriteBytes(ESFS_BOOT_SUPER_BLOCK_SIZE, ESFS_BOOT_SUPER_BLOCK_SIZE, &superblock); + + { + GroupDescriptor *buffer = (GroupDescriptor *) malloc(superblock.groupCount * sizeof(GroupDescriptor)); + memset(buffer, 0, superblock.groupCount * sizeof(GroupDescriptor)); + + for (uintptr_t i = 0; i < superblock.groupCount; i++) { + memcpy(buffer[i].signature, ESFS_GROUP_DESCRIPTOR_SIGNATURE, 4); + buffer[i].largestExtent = superblock.blocksPerGroup - superblock.blocksPerGroupBlockBitmap; + + if (i == 0) { + uint8_t firstGroupBitmap[superblock.blocksPerGroupBlockBitmap * superblock.blockSize]; + memset(firstGroupBitmap, 0, superblock.blocksPerGroupBlockBitmap * superblock.blockSize); + for (uint64_t i = 0; i < superblock.blocksUsed; i++) firstGroupBitmap[i / 8] |= 1 << (i % 8); + buffer[i].blocksUsed = superblock.blocksUsed; + buffer[i].blockBitmap = blockGroup0Bitmap; + buffer[i].bitmapChecksum = CalculateCRC32(firstGroupBitmap, sizeof(firstGroupBitmap), 0); + buffer[i].largestExtent = superblock.blocksPerGroup - superblock.blocksUsed; + WriteBytes(blockGroup0Bitmap * superblock.blockSize, sizeof(firstGroupBitmap), &firstGroupBitmap); + } + + buffer[i].checksum = CalculateCRC32(buffer + i, sizeof(GroupDescriptor), 0); + } + + WriteBytes(superblock.gdtFirstBlock * superblock.blockSize, superblock.groupCount * sizeof(GroupDescriptor), buffer); + free(buffer); + } + } + + // Add the kernel. + + { + MountVolume(); + + DirectoryEntryReference reference = superblock.kernel; + DirectoryEntry entry; + EsUniqueIdentifier unused = {}; + + NewDirectoryEntry(&entry, ESFS_NODE_TYPE_FILE, unused, "Kernel"); + WriteDirectoryEntryReference(reference, &entry); + ResizeNode(&entry, kernelBytes); + AccessNode(&entry, kernel, 0, kernelBytes, NULL, false); + WriteDirectoryEntryReference(reference, &entry); + + UnmountVolume(); + } +} + +#endif diff --git a/util/header_generator.c b/util/header_generator.c new file mode 100644 index 0000000..4d6e363 --- /dev/null +++ b/util/header_generator.c @@ -0,0 +1,1270 @@ +const char **apiTableEntries; + +File output, outputAPIArray, outputSyscallArray, outputDependencies, outputEnumStringsArray; +char *buffer; +int position; + +#define DEST_OS "root/Applications/POSIX/include/essence.h" +#define DEST_API_ARRAY "bin/api_array.h" +#define DEST_SYSCALL_ARRAY "bin/syscall_array.h" +#define DEST_ENUM_STRINGS_ARRAY "bin/enum_strings_array.h" +#define DEST_DEPENDENCIES "bin/api_header.d" + +typedef struct Token { +#define TOKEN_IDENTIFIER (1) +#define TOKEN_LEFT_BRACE (2) +#define TOKEN_RIGHT_BRACE (3) +#define TOKEN_EQUALS (4) +#define TOKEN_ENUM (5) +#define TOKEN_STRUCT (6) +#define TOKEN_NUMBER (8) +#define TOKEN_ASTERISK (9) +#define TOKEN_COMMA (10) +#define TOKEN_SEMICOLON (11) +#define TOKEN_DEFINE (12) +#define TOKEN_FUNCTION (13) +#define TOKEN_FUNCTION_NOT_IN_KERNEL (15) +#define TOKEN_EOF (16) +#define TOKEN_ELLIPSIS (17) +#define TOKEN_UNION (18) +#define TOKEN_VOLATILE (19) +#define TOKEN_CONST (20) +#define TOKEN_LEFT_BRACKET (21) +#define TOKEN_RIGHT_BRACKET (22) +#define TOKEN_LEFT_PAREN (23) +#define TOKEN_RIGHT_PAREN (24) +#define TOKEN_INCLUDE (26) +#define TOKEN_API_TYPE (29) +#define TOKEN_FUNCTION_POINTER (30) +#define TOKEN_TYPE_NAME (31) +#define TOKEN_DEFINE_PRIVATE (32) + int type, value; + char *text; +} Token; + +#define ENTRY_ROOT (0) +#define ENTRY_DEFINE (1) +#define ENTRY_DEFINE_PRIVATE (2) +#define ENTRY_ENUM (3) +#define ENTRY_STRUCT (4) +#define ENTRY_UNION (5) +#define ENTRY_FUNCTION (6) +#define ENTRY_VARIABLE (7) +#define ENTRY_API_TYPE (8) +#define ENTRY_TYPE_NAME (9) + +typedef struct Entry { + int type; + + char *name; + struct Entry *children; + + union { + struct { + char *type, *arraySize, *initialValue; + int pointer; + bool isArray, isVolatile, isConst, isForwardDeclared; + } variable; + + struct { + char *value; + } define; + + struct { + bool inKernel, functionPointer; + int apiArrayIndex; + } function; + + struct { + char *parent; + } apiType; + + char *oldTypeName; + }; +} Entry; + +char *TokenToString(Token token) { + if (!token.value) return NULL; + char *string = (char *) malloc(token.value + 1); + memcpy(string, token.text, token.value); + string[token.value] = 0; + return string; +} + +int currentLine = 1; + +Token NextToken() { + tryAgain:; + + char c = buffer[position++]; + + if (c == '\t') goto tryAgain; + if (c == '\n') { currentLine++; goto tryAgain; } + if (c == ' ') goto tryAgain; + + if (c == '/' && buffer[position] == '/') { while (buffer[position++] != '\n'); goto tryAgain; } + + Token token = {}; + + if (c == 0) token.type = TOKEN_EOF; + + else if (c == '{') token.type = TOKEN_LEFT_BRACE; + else if (c == '}') token.type = TOKEN_RIGHT_BRACE; + else if (c == '[') token.type = TOKEN_LEFT_BRACKET; + else if (c == ']') token.type = TOKEN_RIGHT_BRACKET; + else if (c == '(') token.type = TOKEN_LEFT_PAREN; + else if (c == ')') token.type = TOKEN_RIGHT_PAREN; + else if (c == '=') token.type = TOKEN_EQUALS; + else if (c == '*') token.type = TOKEN_ASTERISK; + else if (c == ',') token.type = TOKEN_COMMA; + else if (c == ';') token.type = TOKEN_SEMICOLON; + + else if (c == '.' && buffer[position] == '.' && buffer[position + 1] == '.') position += 2, token.type = TOKEN_ELLIPSIS; + + else if ((c >= '0' && c <= '9') || c == '-') { + token.type = TOKEN_NUMBER; + token.text = buffer + position - 1; + + do { + token.value++; + c = buffer[position++]; + } while ((c >= '0' && c <= '9')); + + position--; + } + + else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') { + token.type = TOKEN_IDENTIFIER; + token.text = buffer + position - 1; + + do { + token.value++; + c = buffer[position++]; + } while ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9')); + + position--; + +#define COMPARE_KEYWORD(x, y) if (strlen(x) == token.value && 0 == memcmp(x, token.text, token.value)) token.type = y + COMPARE_KEYWORD("define", TOKEN_DEFINE); + COMPARE_KEYWORD("define_private", TOKEN_DEFINE_PRIVATE); + COMPARE_KEYWORD("enum", TOKEN_ENUM); + COMPARE_KEYWORD("struct", TOKEN_STRUCT); + COMPARE_KEYWORD("function", TOKEN_FUNCTION); + COMPARE_KEYWORD("function_not_in_kernel", TOKEN_FUNCTION_NOT_IN_KERNEL); + COMPARE_KEYWORD("union", TOKEN_UNION); + COMPARE_KEYWORD("volatile", TOKEN_VOLATILE); + COMPARE_KEYWORD("const", TOKEN_CONST); + COMPARE_KEYWORD("include", TOKEN_INCLUDE); + COMPARE_KEYWORD("opaque_type", TOKEN_API_TYPE); + COMPARE_KEYWORD("function_pointer", TOKEN_FUNCTION_POINTER); + COMPARE_KEYWORD("type_name", TOKEN_TYPE_NAME); + } + + else { + Log("unrecognised token '%c', at '%.*s'\n", c, 10, buffer + position - 5); + exit(1); + } + + return token; +} + +bool FoundEndOfLine(int length) { + if (buffer[position + length] == '\n') return true; + if (buffer[position + length] == '/' && buffer[position + length + 1] == '/') return true; + return false; +} + +Token ParseVariable(Token token, bool forFunction, Entry *_variable, Entry *parent) { + int pointer = 0; + bool array = false, isVolatile = false, isConst = false, isForwardDeclared = false; + Token arraySize = {}; + + Token type = token; + + if (type.type == TOKEN_VOLATILE) { isVolatile = true; type = NextToken(); } + if (type.type == TOKEN_CONST) { isConst = true; type = NextToken(); } + if (type.type == TOKEN_STRUCT) { isForwardDeclared = true; type = NextToken(); } + + commaRepeat:; + pointer = 0; + + Token name = {}; + + if (type.type != TOKEN_ELLIPSIS) { + name = NextToken(); + + while (name.type == TOKEN_ASTERISK) { + name = NextToken(); + pointer++; + } + + if (name.type == TOKEN_FUNCTION) name.type = TOKEN_IDENTIFIER; + } + + Token semicolon = NextToken(); + + if (semicolon.type == TOKEN_LEFT_BRACKET) { + arraySize = NextToken(); + assert(arraySize.type == TOKEN_IDENTIFIER || arraySize.type == TOKEN_NUMBER || arraySize.type == TOKEN_RIGHT_BRACKET); + array = true; + + if (arraySize.type != TOKEN_RIGHT_BRACKET) { + assert(NextToken().type == TOKEN_RIGHT_BRACKET); + } + + semicolon = NextToken(); + } + + if (type.type != TOKEN_ELLIPSIS) { + assert(type.type == TOKEN_IDENTIFIER); + assert(name.type == TOKEN_IDENTIFIER); + } + + Entry entry = { .type = ENTRY_VARIABLE, .name = TokenToString(name), .variable = { + .type = TokenToString(type), .arraySize = TokenToString(arraySize), .pointer = pointer, .isArray = array, + .isVolatile = isVolatile, .isConst = isConst, .isForwardDeclared = isForwardDeclared + } }; + + if (forFunction && semicolon.type == TOKEN_EQUALS) { + entry.variable.initialValue = TokenToString(NextToken()); + semicolon = NextToken(); + } + + if (_variable) { + *_variable = entry; + } + + arrput(parent->children, entry); + + if (forFunction) { + return semicolon; + } + + if (semicolon.type == TOKEN_SEMICOLON) { + } else if (semicolon.type == TOKEN_COMMA) { + goto commaRepeat; + } else { + assert(false); + } + + return semicolon; +} + +Entry ParseRecord(bool isUnion) { + Entry entry = { .type = isUnion ? ENTRY_UNION : ENTRY_STRUCT }; + Token token = NextToken(); + + while (true) { + if (token.type == TOKEN_RIGHT_BRACE) { + break; + } else if (token.type == TOKEN_UNION) { + assert(NextToken().type == TOKEN_LEFT_BRACE); + arrput(entry.children, ParseRecord(true)); + assert(NextToken().type == TOKEN_SEMICOLON); + } else if (token.type == TOKEN_STRUCT) { + assert(NextToken().type == TOKEN_LEFT_BRACE); + Entry child = ParseRecord(false); + Token name = NextToken(); + + if (name.type == TOKEN_IDENTIFIER) { + assert(NextToken().type == TOKEN_SEMICOLON); + child.name = TokenToString(name); + } else { + assert(name.type == TOKEN_SEMICOLON); + } + + arrput(entry.children, child); + } else { + ParseVariable(token, false, NULL, &entry); + } + + token = NextToken(); + } + + return entry; +} + +void ParseFile(Entry *root, const char *name) { + if (outputDependencies.ready) { + FilePrintFormat(outputDependencies, "%s\n", name); + } + + char *oldBuffer = buffer; + int oldPosition = position; + buffer = (char *) LoadFile(name, NULL); + assert(buffer); + position = 0; + + Token token; + bool nextToken = true; + + while (true) { + if (nextToken) token = NextToken(); + nextToken = true; + + if (token.type == TOKEN_DEFINE) { + Token identifier = NextToken(); + size_t length = 0; + while (!FoundEndOfLine(length)) length++; + Entry entry = { .type = ENTRY_DEFINE, .name = TokenToString(identifier) }; + entry.define.value = TokenToString((Token) { .value = (int) length, .text = buffer + position }); + arrput(root->children, entry); + position += length; + } else if (token.type == TOKEN_DEFINE_PRIVATE) { + Token identifier = NextToken(); + size_t length = 0; + while (!FoundEndOfLine(length)) length++; + Entry entry = { .type = ENTRY_DEFINE_PRIVATE, .name = TokenToString(identifier) }; + entry.define.value = TokenToString((Token) { .value = (int) length, .text = buffer + position }); + arrput(root->children, entry); + position += length; + } else if (token.type == TOKEN_INCLUDE) { + size_t length = 0; + while (!FoundEndOfLine(length)) length++; + char a = buffer[position + length]; + int oldCurrentLine = currentLine; + currentLine = 1; + buffer[position + length] = 0; + ParseFile(root, buffer + position + 1); + currentLine = oldCurrentLine; + buffer[position + length] = a; + position += length; + } else if (token.type == TOKEN_ENUM) { + Token name = NextToken(); + assert(name.type == TOKEN_IDENTIFIER); + assert(NextToken().type == TOKEN_LEFT_BRACE); + + Entry entry = { .type = ENTRY_ENUM, .name = TokenToString(name) }; + Token token = NextToken(); + + while (true) { + if (token.type == TOKEN_RIGHT_BRACE) { + break; + } + + Token entryName = token; + token = NextToken(); + assert(entryName.type == TOKEN_IDENTIFIER); + Entry define = { .type = ENTRY_DEFINE, .name = TokenToString(entryName) }; + + if (token.type == TOKEN_EQUALS) { + size_t length = 0; + while (!FoundEndOfLine(length)) length++; + define.define.value = TokenToString((Token) { .value = (int) length, .text = buffer + position }); + position += length; + token = NextToken(); + } + + arrput(entry.children, define); + } + + arrput(root->children, entry); + } else if (token.type == TOKEN_STRUCT) { + Token structName = NextToken(); + assert(structName.type == TOKEN_IDENTIFIER); + assert(NextToken().type == TOKEN_LEFT_BRACE); + Entry entry = ParseRecord(false); + entry.name = TokenToString(structName); + arrput(root->children, entry); + } else if (token.type == TOKEN_FUNCTION || token.type == TOKEN_FUNCTION_NOT_IN_KERNEL + || token.type == TOKEN_FUNCTION_POINTER) { + bool inKernel = token.type != TOKEN_FUNCTION_NOT_IN_KERNEL; + Entry objectFunctionType; + bool firstVariable = true; + Entry entry = { .type = ENTRY_FUNCTION, .function = { .inKernel = inKernel, .apiArrayIndex = 0 } }; + + if (token.type == TOKEN_FUNCTION_POINTER) { + entry.function.functionPointer = true; + } + + Token leftParen = ParseVariable(NextToken(), true, NULL, &entry); + assert(leftParen.type == TOKEN_LEFT_PAREN); + Token token = NextToken(); + + while (true) { + if (token.type == TOKEN_RIGHT_PAREN) break; + if (token.type == TOKEN_COMMA) token = NextToken(); + token = ParseVariable(token, true, firstVariable ? &objectFunctionType : NULL, &entry); + firstVariable = false; + } + + arrput(root->children, entry); + } else if (token.type == TOKEN_API_TYPE) { + Token name = NextToken(), parent = NextToken(); + Entry entry = { .type = ENTRY_API_TYPE, .name = TokenToString(name), .apiType = { .parent = TokenToString(parent) } }; + arrput(root->children, entry); + } else if (token.type == TOKEN_TYPE_NAME) { + Token oldName = NextToken(), newName = NextToken(); + Entry entry = { .type = ENTRY_TYPE_NAME, .name = TokenToString(newName), .oldTypeName = TokenToString(oldName) }; + arrput(root->children, entry); + } else if (token.type == TOKEN_SEMICOLON) { + } else if (token.type == TOKEN_EOF) { + break; + } else { + Log("unexpected token '%.*s' at top level\n", token.value, token.text); + exit(1); + } + } + + free(buffer); + buffer = oldBuffer; + position = oldPosition; +} + +bool OutputCVariable(Entry *variable, bool noInitialValue, const char *nameOverride, + bool forFunction, bool forFunctionPointer) { + FilePrintFormat(output, "%s%s%s", variable->variable.isVolatile ? "volatile " : "", + variable->variable.isConst ? "const " : "", + variable->variable.isForwardDeclared ? "struct " : ""); + + if (variable->variable.type) { + if (0 == strcmp(variable->variable.type, "STRING")) { + FilePrintFormat(output, "const char *%s", nameOverride ?: variable->name); + assert(!variable->variable.pointer && !variable->variable.isArray); + char *initialValue = variable->variable.initialValue; + bool isBlankString = initialValue && 0 == strcmp(initialValue, "BLANK_STRING"); + if (!isBlankString) assert(!initialValue || !initialValue[0]); + if (!noInitialValue && isBlankString) FilePrintFormat(output, " = nullptr"); + + if (!forFunction) { + FilePrintFormat(output, "; ptrdiff_t %sBytes; ", nameOverride ?: variable->name); + } else { + FilePrintFormat(output, ", ptrdiff_t %sBytes", nameOverride ?: variable->name); + } + + if (!noInitialValue && isBlankString) { FilePrintFormat(output, " = -1"); return true; } + } else { + FilePrintFormat(output, "%s %.*s%s%s%s", variable->variable.type, variable->variable.pointer, "********", forFunctionPointer ? "(*" : "", + nameOverride ?: variable->name, forFunctionPointer ? ")" : ""); + + if (variable->variable.isArray) { + FilePrintFormat(output, "[%s]", variable->variable.arraySize ?: ""); + } + + char *initialValue = variable->variable.initialValue; + + if (initialValue && !noInitialValue) { + FilePrintFormat(output, " = %s", initialValue); + return true; + } + } + } else { + FilePrintFormat(output, "..."); + } + + return false; +} + +void OutputCRecord(Entry *record, int indent) { + for (int i = 0; i < arrlen(record->children); i++) { + Entry *entry = record->children + i; + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, "\t"); + + if (entry->type == ENTRY_VARIABLE) { + OutputCVariable(entry, true, NULL, false, false); + FilePrintFormat(output, ";\n"); + } else if (entry->type == ENTRY_UNION) { + FilePrintFormat(output, "union {\n"); + OutputCRecord(entry, indent + 1); + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, "\t"); + FilePrintFormat(output, "};\n\n"); + } else if (entry->type == ENTRY_STRUCT) { + FilePrintFormat(output, "struct {\n"); + OutputCRecord(entry, indent + 1); + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, "\t"); + FilePrintFormat(output, "} %s;\n\n", entry->name ?: ""); + } + } +} + +void OutputCFunction(Entry *entry) { + if (entry->function.functionPointer) { + FilePrintFormat(output, "typedef "); + + for (int i = 0; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + OutputCVariable(variable, true, NULL, true, i == 0); + if (i == 0) FilePrintFormat(output, "("); + } + + FilePrintFormat(output, ");\n"); + + return; + } + + bool inKernel = entry->function.inKernel; + if (!inKernel) FilePrintFormat(output, "#ifndef KERNEL\n"); + FilePrintFormat(output, "#ifdef ES_FORWARD\n#ifndef __cplusplus\nES_EXTERN_FORWARD "); + + // C code in API. + + for (int i = 0; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + OutputCVariable(variable, true, NULL, true, false); + if (i == 0) FilePrintFormat(output, "("); + } + + FilePrintFormat(output, ");\n#else\nES_EXTERN_FORWARD "); + + // C++ code in API. + + bool anyDefaultArguments = false; + + for (int i = 0; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + if (OutputCVariable(variable, false, NULL, true, false)) anyDefaultArguments = true; + if (i == 0) FilePrintFormat(output, "("); + } + + FilePrintFormat(output, ");\n#endif\n#endif\n#ifndef ES_DIRECT_API\ntypedef "); + + // Code in application. + + Entry *functionVariable = entry->children + 0; + char *functionName = functionVariable->name; + + for (int i = 0; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + + if (i == 0) { + char name[256]; + sprintf(name, "(*__typeof_%s)", functionName); + OutputCVariable(variable, true, name, true, false); + FilePrintFormat(output, "("); + } else { + OutputCVariable(variable, true, NULL, true, false); + } + } + + FilePrintFormat(output, ");\n#ifndef __cplusplus\n#define %s ((__typeof_%s) ES_API_BASE[%d])\n#else\n", + functionName, functionName, entry->function.apiArrayIndex); + + if (anyDefaultArguments) { + FilePrintFormat(output, "__attribute__((always_inline)) inline \n"); + + // C++ code in application with default arguments. + + for (int i = 0; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + OutputCVariable(variable, false, NULL, true, false); + if (i == 0) FilePrintFormat(output, "("); + } + + FilePrintFormat(output, ") { \n\t%s((__typeof_%s) ES_API_BASE[%d])(", + (functionVariable->variable.pointer == 0 && 0 == strcmp(functionVariable->variable.type, "void")) ? "" : "return ", + functionName, entry->function.apiArrayIndex); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i > 1) FilePrintFormat(output, ", "); + FilePrintFormat(output, "%s", variable->name); + + if (0 == strcmp(variable->variable.type, "STRING")) { + FilePrintFormat(output, ", %sBytes", variable->name); + } + } + + FilePrintFormat(output, "); }"); + } else { + // C/C++ code in application without default arguments. + + FilePrintFormat(output, "#define %s ((__typeof_%s) ES_API_BASE[%d])", + functionName, functionName, entry->function.apiArrayIndex); + } + + FilePrintFormat(output, "\n#endif\n#endif\n"); + if (!inKernel) FilePrintFormat(output, "#endif\n"); +} + +void OutputC(Entry *root) { + { + size_t bytes; + char *buffer = LoadFile("desktop/prefix.h", &bytes); + if (outputDependencies.ready) FilePrintFormat(outputDependencies, "%s\n", "desktop/prefix.h"); + FilePrintFormat(output, "%.*s\n", (int) bytes, buffer); + free(buffer); + } + + for (int i = 0; i < arrlen(root->children); i++) { + Entry *entry = root->children + i; + + if (entry->type == ENTRY_DEFINE) { + FilePrintFormat(output, "#define %s (%s)\n", entry->name, entry->define.value); + } else if (entry->type == ENTRY_DEFINE_PRIVATE) { + FilePrintFormat(output, "#ifdef ES_API\n#define %s (%s)\n#endif\n", entry->name, entry->define.value); + } else if (entry->type == ENTRY_STRUCT) { + FilePrintFormat(output, "typedef struct %s {\n", entry->name); + OutputCRecord(entry, 0); + FilePrintFormat(output, "#ifdef %s_MEMBER_FUNCTIONS\n\t%s_MEMBER_FUNCTIONS\n#endif\n", entry->name, entry->name); + FilePrintFormat(output, "} %s;\n\n", entry->name); + } else if (entry->type == ENTRY_ENUM) { + bool isSyscallType = 0 == strcmp(entry->name, "EsSyscallType"); + FilePrintFormat(output, "typedef enum %s {\n", entry->name); + + if (outputEnumStringsArray.ready) { + FilePrintFormat(outputEnumStringsArray, "static const EnumString enumStrings_%s[] = {\n", entry->name); + } + + for (int i = 0; i < arrlen(entry->children); i++) { + if (entry->children[i].define.value) { + FilePrintFormat(output, "\t%s = %s,\n", entry->children[i].name, entry->children[i].define.value); + } else { + FilePrintFormat(output, "\t%s,\n", entry->children[i].name); + } + + if (isSyscallType && outputSyscallArray.ready) { + FilePrintFormat(outputSyscallArray, "Do%s,\n", entry->children[i].name); + } + + if (outputEnumStringsArray.ready) { + FilePrintFormat(outputEnumStringsArray, "\t{ \"%s\", %s },\n", entry->children[i].name, + entry->children[i].define.value ?: "-1"); + } + } + + if (outputEnumStringsArray.ready) { + FilePrintFormat(outputEnumStringsArray, "\t{ nullptr, -1 },\n};\n\n"); + } + + FilePrintFormat(output, "} %s;\n\n", entry->name); + } else if (entry->type == ENTRY_API_TYPE) { + FilePrintFormat(output, "#ifdef __cplusplus\nstruct %s;\n#else\n#define %s %s\n#endif\n", + entry->name, entry->name, 0 == strcmp(entry->apiType.parent, "none") ? "void" : entry->apiType.parent); + } else if (entry->type == ENTRY_FUNCTION) { + OutputCFunction(entry); + } else if (entry->type == ENTRY_TYPE_NAME) { + FilePrintFormat(output, "typedef %s %s;\n", entry->oldTypeName, entry->name); + } + } + + for (int i = 0; i < arrlen(root->children); i++) { + Entry *entry = root->children + i; + + if (entry->type == ENTRY_API_TYPE) { + bool hasParent = 0 != strcmp(entry->apiType.parent, "none"); + + if (!hasParent) { + FilePrintFormat(output, "#ifdef __cplusplus\n#ifndef ES_API\n#ifndef KERNEL\nstruct %s {\n\tvoid *_private;\n", entry->name); + } else { + FilePrintFormat(output, "#ifdef __cplusplus\n#ifndef ES_API\n#ifndef KERNEL\nstruct %s : %s {\n", entry->name, entry->apiType.parent); + } + + FilePrintFormat(output, "};\n#endif\n#endif\n#endif\n"); + } + } + + FilePrintFormat(output, "#endif\n"); +} + +char *TrimPrefix(char *in) { + if (in[0] == 'E' && in[1] == 's' && isupper(in[2])) { + return in + 2; + } else if (in[0] == 'E' && in[1] == 'S' && in[2] == '_') { + return in + 3; + } else { + return in; + } +} + +#define REPLACE(x, y) (0 == strcmp(copy, x) || (!exact && strstr(copy, x))) memcpy(strstr(copy, x), y " ", strlen(x)) + +char *OdinReplaceTypes(const char *string, bool exact) { + char *copy = (char *) malloc(strlen(string) + 1); + strcpy(copy, string); + + if REPLACE("uint64_t", "u64"); + else if REPLACE("int64_t", "i64"); + else if REPLACE("uint32_t", "u32"); + else if REPLACE("int32_t", "i32"); + else if REPLACE("uint16_t", "u16"); + else if REPLACE("int16_t", "i16"); + else if REPLACE("uint8_t", "u8"); + else if REPLACE("int8_t", "i8"); + else if REPLACE("char", "i8"); + else if REPLACE("intptr_t", "int"); + else if REPLACE("size_t", "int"); + else if REPLACE("ptrdiff_t", "int"); + else if REPLACE("uintptr_t", "uint"); + else if REPLACE("(_EsLongConstant)", ""); + else if REPLACE("unsigned", "u32"); + else if REPLACE("int", "i32"); + else if REPLACE("long", "i64"); + else if REPLACE("double", "f64"); + else if REPLACE("float", "f32"); + else if REPLACE("EsCString", "cstring"); + + while REPLACE("Es", ""); + while REPLACE("ES_", ""); + + return TrimPrefix(copy); +} + +void OutputOdinType(Entry *entry) { + if (0 == strcmp(entry->variable.type, "void")) { + assert(entry->variable.pointer); + entry->variable.type = (char *) "rawptr"; + entry->variable.pointer--; + } + + FilePrintFormat(output, "%c%s%c%.*s%s", entry->variable.isArray ? '[' : ' ', entry->variable.arraySize ? OdinReplaceTypes(entry->variable.arraySize, true) : "", + entry->variable.isArray ? ']' : ' ', entry->variable.pointer, "^^^^^^^^^^^^^^^^^", OdinReplaceTypes(entry->variable.type, true)); +} + +void OutputOdinVariable(Entry *entry, bool expandStrings, const char *nameSuffix) { + if (!entry->variable.type) { + FilePrintFormat(output, "_varargs%s : ..any", nameSuffix); + return; + } + + if (0 == strcmp(entry->name, "context")) { + entry->name = (char *) "_context"; + } + + if (0 == strcmp(entry->variable.type, "STRING")) { + if (expandStrings) { + FilePrintFormat(output, "%s%s : ^u8, %sBytes%s : int", entry->name, nameSuffix, entry->name, nameSuffix); + } else { + FilePrintFormat(output, "%s%s : string", entry->name, nameSuffix); + } + } else { + FilePrintFormat(output, "%s%s : ", entry->name, nameSuffix); + OutputOdinType(entry); + } +} + +void OutputOdinRecord(Entry *record, int indent) { + for (int i = 0; i < arrlen(record->children); i++) { + Entry *entry = record->children + i; + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, "\t"); + + if (entry->type == ENTRY_VARIABLE) { + OutputOdinVariable(entry, false, ""); + FilePrintFormat(output, ",\n"); + } else if (entry->type == ENTRY_UNION) { + FilePrintFormat(output, "using _ : struct #raw_union {\n"); + OutputOdinRecord(entry, indent + 1); + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, "\t"); + FilePrintFormat(output, "},\n"); + } else if (entry->type == ENTRY_STRUCT) { + FilePrintFormat(output, "%s : struct {\n", entry->name ?: "using _ "); + OutputOdinRecord(entry, indent + 1); + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, "\t"); + FilePrintFormat(output, "},\n"); + } + } +} + +void OutputOdinFunction(Entry *entry) { + bool hasReturnValue = strcmp(entry->children[0].variable.type, "void") || entry->children[0].variable.pointer; + + for (int i = 0; i < arrlen(entry->children); i++) { + if (entry->children[i].variable.type && strstr(entry->children[i].variable.type, "va_list")) { + return; + } + } + + if (entry->function.functionPointer) { + FilePrintFormat(output, "%s :: distinct #type proc \"c\" (", TrimPrefix(entry->children[0].name)); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + OutputOdinType(variable); + } + + FilePrintFormat(output, ")"); + + if (hasReturnValue) { + FilePrintFormat(output, " -> "); + OutputOdinType(entry->children + 0); + } + + FilePrintFormat(output, ";\n"); + + return; + } + + FilePrintFormat(output, "%s :: #force_inline proc \"c\" (", TrimPrefix(entry->children[0].name)); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + OutputOdinVariable(variable, false, "_"); + + if (variable->variable.initialValue) { + // FilePrintFormat(stderr, "initial value: %s\n", variable->variable.initialValue); + + const char *initialValue = TrimPrefix(variable->variable.initialValue); + + if (0 == strcmp(initialValue, "NULL")) { + initialValue = "nil"; + } else if (0 == strcmp(initialValue, "DEFAULT_PROPERTIES")) { + initialValue = "{}"; + } else if (0 == strcmp(initialValue, "BLANK_STRING")) { + initialValue = "\"\""; + } + + FilePrintFormat(output, " = %s", initialValue); + } + } + + FilePrintFormat(output, ")"); + + if (hasReturnValue) { + FilePrintFormat(output, " -> "); + OutputOdinType(entry->children + 0); + } + + FilePrintFormat(output, "{ addr := 0x1000 + %d * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ", entry->function.apiArrayIndex); + + if (hasReturnValue) { + FilePrintFormat(output, "return "); + } + + FilePrintFormat(output, "((proc \"c\" ("); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + + if (variable->variable.type) { + if (0 == strcmp(variable->variable.type, "STRING")) { + FilePrintFormat(output, "^u8, int"); + } else { + OutputOdinType(variable); + } + } else { + FilePrintFormat(output, "..any"); + } + } + + FilePrintFormat(output, ")"); + + if (hasReturnValue) { + FilePrintFormat(output, " -> "); + OutputOdinType(entry->children + 0); + } + + FilePrintFormat(output, ") (fp))("); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + + if (variable->variable.type && 0 == strcmp(variable->variable.type, "STRING")) { + FilePrintFormat(output, "raw_data(%s_), len(%s_)", variable->name, variable->name); + } else { + FilePrintFormat(output, "%s_", variable->name ?: "_varargs"); + } + } + + FilePrintFormat(output, "); "); + + FilePrintFormat(output, "}\n"); +} + +void OutputOdin(Entry *root) { + FilePrintFormat(output, "package es\n"); + + FilePrintFormat(output, "Generic :: rawptr;\n"); + FilePrintFormat(output, "INSTANCE_TYPE :: Instance;\n"); + + for (int i = 0; i < arrlen(root->children); i++) { + Entry *entry = root->children + i; + + if (entry->type == ENTRY_DEFINE) { + FilePrintFormat(output, "%s :: %s;\n", TrimPrefix(entry->name), OdinReplaceTypes(entry->define.value, false)); + } else if (entry->type == ENTRY_STRUCT) { + FilePrintFormat(output, "%s :: struct {\n", TrimPrefix(entry->name)); + OutputOdinRecord(entry, 0); + FilePrintFormat(output, "}\n"); + } else if (entry->type == ENTRY_ENUM) { + FilePrintFormat(output, "using %s :: enum i32 {\n", TrimPrefix(entry->name)); + + for (int i = 0; i < arrlen(entry->children); i++) { + if (entry->children[i].define.value) { + FilePrintFormat(output, "\t%s = %s,\n", TrimPrefix(entry->children[i].name), entry->children[i].define.value); + } else { + FilePrintFormat(output, "\t%s,\n", TrimPrefix(entry->children[i].name)); + } + } + + FilePrintFormat(output, "}\n"); + } else if (entry->type == ENTRY_API_TYPE) { + bool hasParent = 0 != strcmp(entry->apiType.parent, "none"); + FilePrintFormat(output, "%s :: %s;\n", TrimPrefix(entry->name), hasParent ? TrimPrefix(entry->apiType.parent) : "rawptr"); + } else if (entry->type == ENTRY_FUNCTION) { + OutputOdinFunction(entry); + } else if (entry->type == ENTRY_TYPE_NAME) { + FilePrintFormat(output, "%s :: %s;\n", TrimPrefix(entry->name), TrimPrefix(OdinReplaceTypes(entry->oldTypeName, true))); + } + } +} + +char *ZigReplaceTypes(const char *string, bool exact) { + char *copy = (char *) malloc(strlen(string) + 1); + strcpy(copy, string); + + if REPLACE("uint64_t", "u64"); + else if REPLACE("int64_t", "i64"); + else if REPLACE("uint32_t", "u32"); + else if REPLACE("int32_t", "i32"); + else if REPLACE("uint16_t", "u16"); + else if REPLACE("int16_t", "i16"); + else if REPLACE("uint8_t", "u8"); + else if REPLACE("int8_t", "i8"); + else if REPLACE("char", "i8"); + else if REPLACE("intptr_t", "isize"); + else if REPLACE("size_t", "usize"); + else if REPLACE("ptrdiff_t", "isize"); + else if REPLACE("uintptr_t", "usize"); + else if REPLACE("(_EsLongConstant)", ""); + else if REPLACE("unsigned", "u32"); + else if REPLACE("int", "i32"); + else if REPLACE("long", "i64"); + else if REPLACE("double", "f64"); + else if REPLACE("float", "f32"); + else if REPLACE("EsCString", "?*u8"); + + while REPLACE("Es", ""); + while REPLACE("ES_", ""); + while REPLACE("\t", " "); + + return TrimPrefix(copy); +} + +char *ZigRemoveTabs(const char *string) { + bool exact = false; + char *copy = (char *) malloc(strlen(string) + 1); + strcpy(copy, string); + while REPLACE("\t", " "); + return copy; +} + +void OutputZigType(Entry *entry) { + if (0 == strcmp(entry->variable.type, "void") && entry->variable.pointer) { + entry->variable.type = (char *) "u8"; + } else if (0 == strcmp(entry->variable.type, "EsStyle")) { + assert(entry->variable.pointer); + entry->variable.type = (char *) "usize"; + entry->variable.pointer--; + } + + FilePrintFormat(output, "%c%.*s%s%s", + entry->variable.pointer ? '?' : ' ', + entry->variable.pointer, "***************", + entry->variable.isConst && entry->variable.pointer ? "const " : "", + ZigReplaceTypes(entry->variable.type, true)); +} + +void OutputZigVariable(Entry *entry, bool expandStrings, const char *nameSuffix) { + if (0 == strcmp(entry->name, "error")) { + entry->name[3] = ' '; + entry->name[4] = ' '; + } + + FilePrintFormat(output, "%s%s : ", entry->name, nameSuffix); + OutputZigType(entry); +} + +void OutputZigRecord(Entry *record, int indent, bool inUnion) { + for (int i = 0; i < arrlen(record->children); i++) { + Entry *entry = record->children + i; + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, " "); + + if (entry->type == ENTRY_VARIABLE) { + OutputZigVariable(entry, false, ""); + + if (!inUnion) { + if (entry->variable.pointer) { + FilePrintFormat(output, "= null"); + } else if (0 == strcmp(entry->variable.type, "uint64_t") + || 0 == strcmp(entry->variable.type, "int64_t") + || 0 == strcmp(entry->variable.type, "uint32_t") + || 0 == strcmp(entry->variable.type, "int32_t") + || 0 == strcmp(entry->variable.type, "uint16_t") + || 0 == strcmp(entry->variable.type, "int16_t") + || 0 == strcmp(entry->variable.type, "uint8_t") + || 0 == strcmp(entry->variable.type, "int8_t") + || 0 == strcmp(entry->variable.type, "char") + || 0 == strcmp(entry->variable.type, "intptr_t") + || 0 == strcmp(entry->variable.type, "size_t") + || 0 == strcmp(entry->variable.type, "ptrdiff_t") + || 0 == strcmp(entry->variable.type, "uintptr_t") + || 0 == strcmp(entry->variable.type, "unsigned") + || 0 == strcmp(entry->variable.type, "int") + || 0 == strcmp(entry->variable.type, "long") + || 0 == strcmp(entry->variable.type, "double") + || 0 == strcmp(entry->variable.type, "float")) { + FilePrintFormat(output, "= 0"); + } else if (0 == strcmp(entry->variable.type, "bool")) { + FilePrintFormat(output, "= false"); + } else { + FilePrintFormat(output, "= %s {}", TrimPrefix(entry->variable.type)); + } + } + + FilePrintFormat(output, ",\n"); + } else if (entry->type == ENTRY_UNION) { + FilePrintFormat(output, "_unnamed : extern union {\n"); + OutputZigRecord(entry, indent + 1, true); + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, " "); + FilePrintFormat(output, "},\n"); + } else if (entry->type == ENTRY_STRUCT) { + FilePrintFormat(output, "%s : extern struct {\n", entry->name ?: "_unnamed "); + OutputZigRecord(entry, indent + 1, false); + for (int i = 0; i < indent + 1; i++) FilePrintFormat(output, " "); + FilePrintFormat(output, "},\n"); + } + } +} + +void OutputZigFunction(Entry *entry) { + for (int i = 0; i < arrlen(entry->children); i++) { + if (!entry->children[i].variable.type || strstr(entry->children[i].variable.type, "va_list")) { + return; + } + } + + if (entry->function.functionPointer) { + FilePrintFormat(output, "const %s = fn (", TrimPrefix(entry->children[0].name)); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + OutputZigType(variable); + } + + FilePrintFormat(output, ") callconv(.C)"); + + OutputZigType(entry->children + 0); + + FilePrintFormat(output, ";\n"); + + return; + } + + bool hasReturnValue = strcmp(entry->children[0].variable.type, "void") || entry->children[0].variable.pointer; + + FilePrintFormat(output, "pub fn %s(", TrimPrefix(entry->children[0].name)); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + OutputZigVariable(variable, false, "_"); + } + + FilePrintFormat(output, ") "); + OutputZigType(entry->children + 0); + FilePrintFormat(output, "{ "); + + if (hasReturnValue) { + FilePrintFormat(output, "return "); + } + + FilePrintFormat(output, "((@intToPtr(*fn ("); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + OutputZigVariable(variable, false, "_"); + } + + FilePrintFormat(output, ") callconv(.C) "); + OutputZigType(entry->children + 0); + FilePrintFormat(output, ", 0x1000 + %d * 8)).*)(", entry->function.apiArrayIndex); + + for (int i = 1; i < arrlen(entry->children); i++) { + Entry *variable = entry->children + i; + if (i >= 2) FilePrintFormat(output, ", "); + FilePrintFormat(output, "%s_", variable->name ?: "_varargs"); + } + + FilePrintFormat(output, "); }\n"); +} + +void OutputZig(Entry *root) { + FilePrintFormat(output, "pub const Generic = ?*u8;\n"); + FilePrintFormat(output, "const INSTANCE_TYPE = Instance;\n"); + FilePrintFormat(output, "pub const STRING = extern struct { ptr : [*] const u8, len : usize, };\n"); + FilePrintFormat(output, "pub fn Str(x : [] const u8) STRING { return STRING { .ptr = x.ptr, .len = x.len }; }\n"); + FilePrintFormat(output, "fn STYLE_CAST (x : isize) isize { return x; }\n"); + + for (int i = 0; i < arrlen(root->children); i++) { + Entry *entry = root->children + i; + + if (entry->type == ENTRY_DEFINE) { + FilePrintFormat(output, "pub const %s = %s;\n", TrimPrefix(entry->name), ZigReplaceTypes(entry->define.value, false)); + } else if (entry->type == ENTRY_STRUCT) { + FilePrintFormat(output, "pub const %s = extern struct {\n", TrimPrefix(entry->name)); + OutputZigRecord(entry, 0, false); + FilePrintFormat(output, "};\n"); + } else if (entry->type == ENTRY_ENUM) { + FilePrintFormat(output, "pub const %s = extern enum {\n", TrimPrefix(entry->name)); + + for (int i = 0; i < arrlen(entry->children); i++) { + if (entry->children[i].define.value) { + FilePrintFormat(output, " %s = %s,\n", TrimPrefix(entry->children[i].name), ZigRemoveTabs(entry->children[i].define.value)); + } else { + FilePrintFormat(output, " %s,\n", TrimPrefix(entry->children[i].name)); + } + } + + FilePrintFormat(output, "};\n"); + } else if (entry->type == ENTRY_API_TYPE) { + bool hasParent = 0 != strcmp(entry->apiType.parent, "none"); + FilePrintFormat(output, "pub const %s = %s;\n", TrimPrefix(entry->name), hasParent ? TrimPrefix(entry->apiType.parent) : "?*u8"); + } else if (entry->type == ENTRY_FUNCTION) { + OutputZigFunction(entry); + } else if (entry->type == ENTRY_TYPE_NAME) { + FilePrintFormat(output, "pub const %s = %s;\n", TrimPrefix(entry->name), TrimPrefix(ZigReplaceTypes(entry->oldTypeName, true))); + } + } +} + +int HeaderGeneratorMain(int argc, char **argv) { + if (argc < 2) { + outputDependencies = FileOpen(DEST_DEPENDENCIES ".tmp", 'w'); + FilePrintFormat(outputDependencies, ": \n"); + } + + Entry root = {}; + ParseFile(&root, "desktop/os.header"); + + const char *language = "c"; + + if (argc == 3) { + language = argv[1]; + output = FileOpen(argv[2], 'w'); + } else if (argc == 1) { + output = FileOpen(DEST_OS, 'w'); + outputAPIArray = FileOpen(DEST_API_ARRAY, 'w'); + outputSyscallArray = FileOpen(DEST_SYSCALL_ARRAY, 'w'); + outputEnumStringsArray = FileOpen(DEST_ENUM_STRINGS_ARRAY, 'w'); + } else { + Log("Usage: %s <language> <path-to-output-file>\n", argv[0]); + return 1; + } + + { + { + EsINIState s = { (char *) LoadFile("util/api_table.ini", &s.bytes) }; + + int32_t highestIndex = -1; + + struct { + const char *cName; + int32_t index; + } *entries = NULL; + + while (EsINIParse(&s)) { + EsINIZeroTerminate(&s); + int32_t index = atoi(s.value); + if (index < 0 || !s.key[0]) goto done; + if (index > highestIndex) highestIndex = index; + arraddn(entries, 1); + char *copy = (char *) malloc(strlen(s.key) + 1); + arrlast(entries).cName = copy; + strcpy(copy, s.key); + arrlast(entries).index = index; + } + + done:; + + arrsetlen(apiTableEntries, (size_t) (highestIndex + 1)); + + for (int i = 0; i < highestIndex + 1; i++) { + apiTableEntries[i] = "EsUnimplemented"; + } + + for (int i = 0; i < arrlen(entries); i++) { + apiTableEntries[entries[i].index] = entries[i].cName; + } + + arrfree(entries); + } + + for (int i = 0; i < arrlen(root.children); i++) { + Entry *entry = root.children + i; + if (entry->type != ENTRY_FUNCTION || entry->function.functionPointer) continue; + const char *name = entry->children[0].name; + bool found = false; + + for (int i = 0; i < arrlen(apiTableEntries); i++) { + if (0 == strcmp(apiTableEntries[i], name)) { + entry->function.apiArrayIndex = i; + found = true; + break; + } + } + + if (!found) { + for (int i = 0; i < arrlen(apiTableEntries); i++) { + if (0 == strcmp(apiTableEntries[i], "EsUnimplemented")) { + apiTableEntries[i] = name; + entry->function.apiArrayIndex = i; + found = true; + break; + } + } + + if (!found) { + entry->function.apiArrayIndex = arrlen(apiTableEntries); + arrput(apiTableEntries, name); + } + } + } + + for (int i = 0; i < arrlen(apiTableEntries); i++) { + apiTableEntries[i] = "EsUnimplemented"; + } + + for (int i = 0; i < arrlen(root.children); i++) { + Entry *entry = root.children + i; + if (entry->type != ENTRY_FUNCTION || entry->function.functionPointer) continue; + const char *name = entry->children[0].name; + apiTableEntries[entry->function.apiArrayIndex] = name; + } + + if (outputAPIArray.ready) { + File f = FileOpen("util/api_table.ini", 'w'); + + for (int i = 0; i < arrlen(apiTableEntries); i++) { + FilePrintFormat(outputAPIArray, "(void *) %s,\n", apiTableEntries[i]); + + if (strcmp(apiTableEntries[i], "EsUnimplemented")) { + FilePrintFormat(f, "%s=%d\n", apiTableEntries[i], i); + } + } + + FileClose(f); + } + } + + if (0 == strcmp(language, "c")) { + OutputC(&root); + } else if (0 == strcmp(language, "odin")) { + OutputOdin(&root); + } else if (0 == strcmp(language, "zig")) { + OutputZig(&root); + } else { + Log("Unsupported language '%s'.\nLanguage must be one of: 'c', 'odin'.\n", language); + } + + if (argc < 2) { + rename(DEST_DEPENDENCIES ".tmp", DEST_DEPENDENCIES); + } + + if (outputDependencies.ready) FileClose(outputDependencies); + if (output.ready) FileClose(output); + if (outputAPIArray.ready) FileClose(outputAPIArray); + if (outputSyscallArray.ready) FileClose(outputSyscallArray); + if (outputEnumStringsArray.ready) FileClose(outputEnumStringsArray); + + return 0; +} diff --git a/util/linker/api64.ld b/util/linker/api64.ld new file mode 100644 index 0000000..d6a354f --- /dev/null +++ b/util/linker/api64.ld @@ -0,0 +1,23 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x10000000; + .text BLOCK(4K) : ALIGN(4K) + { + *(.text) + } + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } +} diff --git a/util/linker/kernel32.ld b/util/linker/kernel32.ld new file mode 100644 index 0000000..cf2d6ae --- /dev/null +++ b/util/linker/kernel32.ld @@ -0,0 +1,32 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0xC0000000; + + .text BLOCK(4K) : ALIGN(4K) + { + *(.text) + } + + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } + + .tbss BLOCK(4K) : ALIGN(4K) + { + *(.tbss) + } +} diff --git a/util/linker/kernel64.ld b/util/linker/kernel64.ld new file mode 100644 index 0000000..668a324 --- /dev/null +++ b/util/linker/kernel64.ld @@ -0,0 +1,24 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0xFFFFFFFF80000000; + .text BLOCK(4K) : ALIGN(4K) + { + *(.text) + } + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } +} diff --git a/util/linker/userland32.ld b/util/linker/userland32.ld new file mode 100644 index 0000000..5f6d927 --- /dev/null +++ b/util/linker/userland32.ld @@ -0,0 +1,24 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x100000; + .text BLOCK(4K) : ALIGN(4K) + { + *(.text) + } + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } +} diff --git a/util/linker/userland64.ld b/util/linker/userland64.ld new file mode 100644 index 0000000..f56b76d --- /dev/null +++ b/util/linker/userland64.ld @@ -0,0 +1,23 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x100000; + .text : ALIGN(512B) + { + *(.text) + } + .rodata : ALIGN(512B) + { + *(.rodata) + } + .data : ALIGN(512B) + { + *(.data) + } + .bss : ALIGN(512B) + { + *(COMMON) + *(.bss) + } +} diff --git a/util/luigi.h b/util/luigi.h new file mode 100644 index 0000000..f19959c --- /dev/null +++ b/util/luigi.h @@ -0,0 +1,5046 @@ +// TODO UITextbox features - mouse input, multi-line, clipboard, undo, IME support, number dragging. +// TODO New elements - list view, menu bar. +// TODO Keyboard navigation - menus, dialogs, tables. +// TODO Easier to use fonts; GDI font support. +// TODO Formalize the notion of size-stability? See _UIExpandPaneButtonInvoke. + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include <stdarg.h> + +#ifdef UI_LINUX +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/cursorfont.h> + +#include <xmmintrin.h> +#endif + +#define _UI_TO_STRING_1(x) #x +#define _UI_TO_STRING_2(x) _UI_TO_STRING_1(x) + +#ifdef UI_WINDOWS +#include <windows.h> + +#define UI_ASSERT(x) do { if (!(x)) { ui.assertionFailure = true; \ + MessageBox(0, "Assertion failure on line " _UI_TO_STRING_2(__LINE__), 0, 0); \ + ExitProcess(1); } } while (0) +#define UI_CALLOC(x) HeapAlloc(ui.heap, HEAP_ZERO_MEMORY, (x)) +#define UI_FREE(x) HeapFree(ui.heap, 0, (x)) +#define UI_MALLOC(x) HeapAlloc(ui.heap, 0, (x)) +#define UI_REALLOC _UIHeapReAlloc +#define UI_CLOCK GetTickCount +#define UI_CLOCKS_PER_SECOND (1000) +#define UI_CLOCK_T DWORD +#endif + +#if defined(UI_LINUX) +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <time.h> +#include <math.h> + +#define UI_ASSERT assert +#define UI_CALLOC(x) calloc(1, (x)) +#define UI_FREE free +#define UI_MALLOC malloc +#define UI_REALLOC realloc +#define UI_CLOCK clock +#define UI_CLOCKS_PER_SECOND CLOCKS_PER_SEC +#define UI_CLOCK_T clock_t +#endif + +#if defined(UI_ESSENCE) +#include <essence.h> + +#define UI_ASSERT EsAssert +#define UI_CALLOC(x) EsHeapAllocate((x), true) +#define UI_FREE EsHeapFree +#define UI_MALLOC(x) EsHeapAllocate((x), false) +#define UI_REALLOC(x, y) EsHeapReallocate((x), (y), false) +#define UI_CLOCK EsTimeStampMs +#define UI_CLOCKS_PER_SECOND 1000 +#define UI_CLOCK_T uint64_t +#endif + +#ifdef UI_DEBUG +#include <stdio.h> +#endif + +typedef struct UITheme { + uint32_t panel1, panel2, selected, border; + uint32_t text, textDisabled, textSelected; + uint32_t buttonNormal, buttonHovered, buttonPressed, buttonDisabled; + uint32_t textboxNormal, textboxFocused; + uint32_t codeFocused, codeBackground, codeDefault, codeComment, codeString, codeNumber, codeOperator, codePreprocessor; +} UITheme; + +#define UI_SIZE_BUTTON_MINIMUM_WIDTH (100) +#define UI_SIZE_BUTTON_PADDING (16) +#define UI_SIZE_BUTTON_HEIGHT (27) +#define UI_SIZE_BUTTON_CHECKED_AREA (4) + +#define UI_SIZE_MENU_ITEM_HEIGHT (24) +#define UI_SIZE_MENU_ITEM_MINIMUM_WIDTH (160) +#define UI_SIZE_MENU_ITEM_MARGIN (9) + +#define UI_SIZE_GAUGE_WIDTH (200) +#define UI_SIZE_GAUGE_HEIGHT (22) + +#define UI_SIZE_SLIDER_WIDTH (200) +#define UI_SIZE_SLIDER_HEIGHT (25) +#define UI_SIZE_SLIDER_THUMB (15) +#define UI_SIZE_SLIDER_TRACK (5) + +#define UI_SIZE_TEXTBOX_MARGIN (3) +#define UI_SIZE_TEXTBOX_WIDTH (200) +#define UI_SIZE_TEXTBOX_HEIGHT (25) + +#define UI_SIZE_TAB_PANE_SPACE_TOP (2) +#define UI_SIZE_TAB_PANE_SPACE_LEFT (4) + +#define UI_SIZE_SPLITTER (8) + +#define UI_SIZE_SCROLL_BAR (16) +#define UI_SIZE_SCROLL_MINIMUM_THUMB (20) + +#define UI_SIZE_CODE_MARGIN (ui.glyphWidth * 5) +#define UI_SIZE_CODE_MARGIN_GAP (ui.glyphWidth * 1) + +#define UI_SIZE_TABLE_HEADER (26) +#define UI_SIZE_TABLE_COLUMN_GAP (20) +#define UI_SIZE_TABLE_ROW (20) + +#define UI_SIZE_PANE_MEDIUM_BORDER (5) +#define UI_SIZE_PANE_MEDIUM_GAP (5) +#define UI_SIZE_PANE_SMALL_BORDER (3) +#define UI_SIZE_PANE_SMALL_GAP (3) + +#define UI_SIZE_MDI_CHILD_BORDER (6) +#define UI_SIZE_MDI_CHILD_TITLE (30) +#define UI_SIZE_MDI_CHILD_CORNER (12) +#define UI_SIZE_MDI_CHILD_MINIMUM_WIDTH (100) +#define UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT (50) +#define UI_SIZE_MDI_CASCADE (30) + +#define UI_UPDATE_HOVERED (1) +#define UI_UPDATE_PRESSED (2) +#define UI_UPDATE_FOCUSED (3) + +typedef enum UIMessage { + UI_MSG_PAINT, // dp = pointer to UIPainter + UI_MSG_LAYOUT, + UI_MSG_DESTROY, + UI_MSG_UPDATE, // di = UI_UPDATE_... constant + UI_MSG_ANIMATE, + UI_MSG_SCROLLED, + UI_MSG_GET_WIDTH, // di = height (if known); return width + UI_MSG_GET_HEIGHT, // di = width (if known); return height + UI_MSG_FIND_BY_POINT, // dp = pointer to UIFindByPoint; return 1 if handled + UI_MSG_CLIENT_PARENT, // dp = pointer to UIElement *, set it to the parent for client elements + + UI_MSG_INPUT_EVENTS_START, // not sent to disabled elements + UI_MSG_LEFT_DOWN, + UI_MSG_LEFT_UP, + UI_MSG_MIDDLE_DOWN, + UI_MSG_MIDDLE_UP, + UI_MSG_RIGHT_DOWN, + UI_MSG_RIGHT_UP, + UI_MSG_KEY_TYPED, // dp = pointer to UIKeyTyped; return 1 if handled + UI_MSG_MOUSE_MOVE, + UI_MSG_MOUSE_DRAG, + UI_MSG_MOUSE_WHEEL, // di = delta; return 1 if handled + UI_MSG_CLICKED, + UI_MSG_GET_CURSOR, // return cursor code + UI_MSG_PRESSED_DESCENDENT, // dp = pointer to child that is/contains pressed element + UI_MSG_INPUT_EVENTS_END, + + UI_MSG_VALUE_CHANGED, // sent to notify that the element's value has changed + UI_MSG_TABLE_GET_ITEM, // dp = pointer to UITableGetItem; return string length + UI_MSG_CODE_GET_MARGIN_COLOR, // di = line index (starts at 1); return color + UI_MSG_CODE_DECORATE_LINE, // dp = pointer to UICodeDecorateLine + UI_MSG_WINDOW_CLOSE, // return 1 to prevent default (process exit for UIWindow; close for UIMDIChild) + UI_MSG_TAB_SELECTED, // sent to the tab that was selected (not the tab pane itself) + + UI_MSG_USER, +} UIMessage; + +#ifdef UI_ESSENCE +#define UIRectangle EsRectangle +#else +typedef struct UIRectangle { + int l, r, t, b; +} UIRectangle; +#endif + +typedef struct UIPainter { + UIRectangle clip; + uint32_t *bits; + int width, height; +#ifdef UI_DEBUG + int fillCount; +#endif +} UIPainter; + +typedef struct UIShortcut { + intptr_t code; + bool ctrl, shift, alt; + void (*invoke)(void *cp); + void *cp; +} UIShortcut; + +typedef struct UIStringSelection { + int carets[2]; + uint32_t colorText, colorBackground; +} UIStringSelection; + +typedef struct UIKeyTyped { + char *text; + int textBytes; + intptr_t code; +} UIKeyTyped; + +typedef struct UITableGetItem { + char *buffer; + size_t bufferBytes; + int index, column; + bool isSelected; +} UITableGetItem; + +typedef struct UICodeDecorateLine { + UIRectangle bounds; + int index; // Starting at 1! + int x, y; // Position where additional text can be drawn. + UIPainter *painter; +} UICodeDecorateLine; + +typedef struct UIFindByPoint { + int x, y; + struct UIElement *result; +} UIFindByPoint; + +#define UI_RECT_1(x) ((UIRectangle) { (x), (x), (x), (x) }) +#define UI_RECT_1I(x) ((UIRectangle) { (x), -(x), (x), -(x) }) +#define UI_RECT_2(x, y) ((UIRectangle) { (x), (x), (y), (y) }) +#define UI_RECT_2I(x, y) ((UIRectangle) { (x), -(x), (y), -(y) }) +#define UI_RECT_2S(x, y) ((UIRectangle) { 0, (x), 0, (y) }) +#define UI_RECT_4(x, y, z, w) ((UIRectangle) { (x), (y), (z), (w) }) +#define UI_RECT_WIDTH(_r) ((_r).r - (_r).l) +#define UI_RECT_HEIGHT(_r) ((_r).b - (_r).t) +#define UI_RECT_TOTAL_H(_r) ((_r).r + (_r).l) +#define UI_RECT_TOTAL_V(_r) ((_r).b + (_r).t) +#define UI_RECT_SIZE(_r) UI_RECT_WIDTH(_r), UI_RECT_HEIGHT(_r) +#define UI_RECT_TOP_LEFT(_r) (_r).l, (_r).t +#define UI_RECT_BOTTOM_LEFT(_r) (_r).l, (_r).b +#define UI_RECT_BOTTOM_RIGHT(_r) (_r).r, (_r).b +#define UI_RECT_ALL(_r) (_r).l, (_r).r, (_r).t, (_r).b +#define UI_RECT_VALID(_r) (UI_RECT_WIDTH(_r) > 0 && UI_RECT_HEIGHT(_r) > 0) + +#define UI_COLOR_ALPHA_F(x) ((((x) >> 24) & 0xFF) / 255.0f) +#define UI_COLOR_RED_F(x) ((((x) >> 16) & 0xFF) / 255.0f) +#define UI_COLOR_GREEN_F(x) ((((x) >> 8) & 0xFF) / 255.0f) +#define UI_COLOR_BLUE_F(x) ((((x) >> 0) & 0xFF) / 255.0f) +#define UI_COLOR_ALPHA(x) ((((x) >> 24) & 0xFF)) +#define UI_COLOR_RED(x) ((((x) >> 16) & 0xFF)) +#define UI_COLOR_GREEN(x) ((((x) >> 8) & 0xFF)) +#define UI_COLOR_BLUE(x) ((((x) >> 0) & 0xFF)) +#define UI_COLOR_FROM_FLOAT(r, g, b) (((uint32_t) ((r) * 255.0f) << 16) | ((uint32_t) ((g) * 255.0f) << 8) | ((uint32_t) ((b) * 255.0f) << 0)) +#define UI_COLOR_FROM_RGBA_F(r, g, b, a) (((uint32_t) ((r) * 255.0f) << 16) | ((uint32_t) ((g) * 255.0f) << 8) \ + | ((uint32_t) ((b) * 255.0f) << 0) | ((uint32_t) ((a) * 255.0f) << 24)) + +#define UI_SWAP(s, a, b) do { s t = (a); (a) = (b); (b) = t; } while (0) + +#define UI_CURSOR_ARROW (0) +#define UI_CURSOR_TEXT (1) +#define UI_CURSOR_SPLIT_V (2) +#define UI_CURSOR_SPLIT_H (3) +#define UI_CURSOR_FLIPPED_ARROW (4) +#define UI_CURSOR_CROSS_HAIR (5) +#define UI_CURSOR_HAND (6) +#define UI_CURSOR_RESIZE_UP (7) +#define UI_CURSOR_RESIZE_LEFT (8) +#define UI_CURSOR_RESIZE_UP_RIGHT (9) +#define UI_CURSOR_RESIZE_UP_LEFT (10) +#define UI_CURSOR_RESIZE_DOWN (11) +#define UI_CURSOR_RESIZE_RIGHT (12) +#define UI_CURSOR_RESIZE_DOWN_RIGHT (13) +#define UI_CURSOR_RESIZE_DOWN_LEFT (14) +#define UI_CURSOR_COUNT (15) + +#define UI_ALIGN_LEFT (1) +#define UI_ALIGN_RIGHT (2) +#define UI_ALIGN_CENTER (3) + +extern const int UI_KEYCODE_A; +extern const int UI_KEYCODE_BACKSPACE; +extern const int UI_KEYCODE_DELETE; +extern const int UI_KEYCODE_DOWN; +extern const int UI_KEYCODE_END; +extern const int UI_KEYCODE_ENTER; +extern const int UI_KEYCODE_ESCAPE; +extern const int UI_KEYCODE_F1; +extern const int UI_KEYCODE_HOME; +extern const int UI_KEYCODE_LEFT; +extern const int UI_KEYCODE_RIGHT; +extern const int UI_KEYCODE_SPACE; +extern const int UI_KEYCODE_TAB; +extern const int UI_KEYCODE_UP; +extern const int UI_KEYCODE_0; + +#define UI_KEYCODE_LETTER(x) (UI_KEYCODE_A + (x) - 'A') +#define UI_KEYCODE_DIGIT(x) (UI_KEYCODE_0 + (x) - '0') +#define UI_KEYCODE_FKEY(x) (UI_KEYCODE_F1 + (x) - 1) + +typedef struct UIElement { +#define UI_ELEMENT_V_FILL (1 << 16) +#define UI_ELEMENT_H_FILL (1 << 17) +#define UI_ELEMENT_WINDOW (1 << 18) +#define UI_ELEMENT_PARENT_PUSH (1 << 19) +#define UI_ELEMENT_TAB_STOP (1 << 20) +#define UI_ELEMENT_NON_CLIENT (1 << 21) // Don't destroy in UIElementDestroyDescendents, like scroll bars. +#define UI_ELEMENT_DISABLED (1 << 22) // Don't receive input events. + +#define UI_ELEMENT_HIDE (1 << 29) +#define UI_ELEMENT_DESTROY (1 << 30) +#define UI_ELEMENT_DESTROY_DESCENDENT (1 << 31) + + uint32_t flags; // First 16 bits are element specific. + + struct UIElement *parent; + struct UIElement *next; + struct UIElement *children; + struct UIWindow *window; + + UIRectangle bounds, clip; + + void *cp; // Context pointer (for user). + + int (*messageClass)(struct UIElement *element, UIMessage message, int di /* data integer */, void *dp /* data pointer */); + int (*messageUser)(struct UIElement *element, UIMessage message, int di, void *dp); + +#ifdef UI_DEBUG + const char *cClassName; + int id; +#endif +} UIElement; + +#define UI_SHORTCUT(code, ctrl, shift, alt, invoke, cp) ((UIShortcut) { (code), (ctrl), (shift), (alt), (invoke), (cp) }) + +typedef struct UIWindow { +#define UI_WINDOW_MENU (1 << 0) +#define UI_WINDOW_INSPECTOR (1 << 1) +#define UI_WINDOW_CENTER_IN_OWNER (1 << 2) + + UIElement e; + + UIElement *dialog; + + UIShortcut *shortcuts; + size_t shortcutCount, shortcutAllocated; + + float scale; + + uint32_t *bits; + int width, height; + struct UIWindow *next; + + UIElement *hovered, *pressed, *focused, *dialogOldFocus; + int pressedButton; + + int cursorX, cursorY; + int cursorStyle; + + bool ctrl, shift, alt; + + UIRectangle updateRegion; + +#ifdef UI_DEBUG + float lastFullFillCount; +#endif + +#ifdef UI_LINUX + Window window; + XImage *image; + XIC xic; + unsigned ctrlCode, shiftCode, altCode; +#endif + +#ifdef UI_WINDOWS + HWND hwnd; + bool trackingLeave; +#endif + +#ifdef UI_ESSENCE + EsWindow *window; + EsElement *canvas; + int cursor; +#endif +} UIWindow; + +typedef struct UIPanel { +#define UI_PANEL_HORIZONTAL (1 << 0) +#define UI_PANEL_GRAY (1 << 2) +#define UI_PANEL_WHITE (1 << 3) +#define UI_PANEL_EXPAND (1 << 4) +#define UI_PANEL_MEDIUM_SPACING (1 << 5) +#define UI_PANEL_SMALL_SPACING (1 << 6) +#define UI_PANEL_SCROLL (1 << 7) + UIElement e; + struct UIScrollBar *scrollBar; + UIRectangle border; + int gap; +} UIPanel; + +typedef struct UIButton { +#define UI_BUTTON_SMALL (1 << 0) +#define UI_BUTTON_MENU_ITEM (1 << 1) +#define UI_BUTTON_CAN_FOCUS (1 << 2) +#define UI_BUTTON_DROP_DOWN (1 << 3) +#define UI_BUTTON_CHECKED (1 << 15) + UIElement e; + char *label; + ptrdiff_t labelBytes; + void (*invoke)(void *cp); +} UIButton; + +typedef struct UILabel { + UIElement e; + char *label; + ptrdiff_t labelBytes; +} UILabel; + +typedef struct UISpacer { +#define UI_SPACER_LINE (1 << 0) + UIElement e; + int width, height; +} UISpacer; + +typedef struct UISplitPane { +#define UI_SPLIT_PANE_VERTICAL (1 << 0) + UIElement e; + float weight; +} UISplitPane; + +typedef struct UITabPane { + UIElement e; + char *tabs; + int active; +} UITabPane; + +typedef struct UIScrollBar { +#define UI_SCROLL_BAR_HORIZONTAL (1 << 0) + UIElement e; + int64_t maximum, page; + int64_t dragOffset; + double position; + uint64_t lastAnimateTime; + bool inDrag, horizontal; +} UIScrollBar; + +typedef struct UICodeLine { + int offset, bytes; +} UICodeLine; + +typedef struct UICode { +#define UI_CODE_NO_MARGIN (1 << 0) + UIElement e; + UIScrollBar *vScroll; + UICodeLine *lines; + int lineCount, focused; + bool moveScrollToFocusNextLayout; + char *content; + size_t contentBytes; + int tabSize; +} UICode; + +typedef struct UIGauge { + UIElement e; + float position; +} UIGauge; + +typedef struct UITable { + UIElement e; + UIScrollBar *vScroll; + int itemCount; + char *columns; + int *columnWidths, columnCount; +} UITable; + +typedef struct UITextbox { + UIElement e; + char *string; + ptrdiff_t bytes; + int carets[2]; + int scroll; +} UITextbox; + +typedef struct UIMenu { +#define UI_MENU_PLACE_ABOVE (1 << 0) + UIElement e; + int pointX, pointY; + UIScrollBar *vScroll; +} UIMenu; + +typedef struct UISlider { + UIElement e; + float position; + int steps; +} UISlider; + +typedef struct UIColorPicker { +#define UI_COLOR_PICKER_HAS_OPACITY (1 << 0) + UIElement e; + float hue, saturation, value, opacity; +} UIColorPicker; + +typedef struct UIMDIClient { +#define UI_MDI_CLIENT_TRANSPARENT (1 << 0) + UIElement e; + struct UIMDIChild *active; + int cascade; +} UIMDIClient; + +typedef struct UIMDIChild { +#define UI_MDI_CHILD_CLOSE_BUTTON (1 << 0) + UIElement e; + UIRectangle bounds; + char *title; + ptrdiff_t titleBytes; + int dragHitTest; + UIRectangle dragOffset; + struct UIMDIChild *previous; +} UIMDIChild; + +typedef struct UIExpandPane { + UIElement e; + UIButton *button; + UIPanel *panel; + bool expanded; +} UIExpandPane; + +typedef struct UIImageDisplay { +#define UI_IMAGE_DISPLAY_INTERACTIVE (1 << 0) +#define _UI_IMAGE_DISPLAY_ZOOM_FIT (1 << 1) + + UIElement e; + uint32_t *bits; + int width, height; + float panX, panY, zoom; + + // Internals: + int previousWidth, previousHeight; + int previousPanPointX, previousPanPointY; +} UIImageDisplay; + +void UIInitialise(); +int UIMessageLoop(); + +UIElement *UIElementCreate(size_t bytes, UIElement *parent, uint32_t flags, + int (*messageClass)(UIElement *, UIMessage, int, void *), const char *cClassName); + +UIButton *UIButtonCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes); +UIColorPicker *UIColorPickerCreate(UIElement *parent, uint32_t flags); +UIExpandPane *UIExpandPaneCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes, uint32_t panelFlags); +UIGauge *UIGaugeCreate(UIElement *parent, uint32_t flags); +UIMDIClient *UIMDIClientCreate(UIElement *parent, uint32_t flags); +UIMDIChild *UIMDIChildCreate(UIElement *parent, uint32_t flags, UIRectangle initialBounds, const char *title, ptrdiff_t titleBytes); +UIPanel *UIPanelCreate(UIElement *parent, uint32_t flags); +UIScrollBar *UIScrollBarCreate(UIElement *parent, uint32_t flags); +UISlider *UISliderCreate(UIElement *parent, uint32_t flags); +UISpacer *UISpacerCreate(UIElement *parent, uint32_t flags, int width, int height); +UISplitPane *UISplitPaneCreate(UIElement *parent, uint32_t flags, float weight); +UITabPane *UITabPaneCreate(UIElement *parent, uint32_t flags, const char *tabs /* separate with \t, terminate with \0 */); + +UILabel *UILabelCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes); +void UILabelSetContent(UILabel *code, const char *content, ptrdiff_t byteCount); + +UIImageDisplay *UIImageDisplayCreate(UIElement *parent, uint32_t flags, uint32_t *bits, size_t width, size_t height, size_t stride); +void UIImageDisplaySetContent(UIImageDisplay *display, uint32_t *bits, size_t width, size_t height, size_t stride); + +UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, int width, int height); +void UIWindowRegisterShortcut(UIWindow *window, UIShortcut shortcut); +void UIWindowPostMessage(UIWindow *window, UIMessage message, void *dp); // Thread-safe. +void UIWindowPack(UIWindow *window, int width); // Change the size of the window to best match its contents. + +const char *UIDialogShow(UIWindow *window, uint32_t flags, const char *format, ...); + +UIMenu *UIMenuCreate(UIElement *parent, uint32_t flags); +void UIMenuAddItem(UIMenu *menu, uint32_t flags, const char *label, ptrdiff_t labelBytes, void (*invoke)(void *cp), void *cp); +void UIMenuShow(UIMenu *menu); + +UITextbox *UITextboxCreate(UIElement *parent, uint32_t flags); +void UITextboxReplace(UITextbox *textbox, const char *text, ptrdiff_t bytes, bool sendChangedMessage); +void UITextboxClear(UITextbox *textbox, bool sendChangedMessage); +void UITextboxMoveCaret(UITextbox *textbox, bool backward, bool word); + +UITable *UITableCreate(UIElement *parent, uint32_t flags, const char *columns /* separate with \t, terminate with \0 */); +int UITableHitTest(UITable *table, int x, int y); // Returns item index. Returns -1 if not on an item. +bool UITableEnsureVisible(UITable *table, int index); // Returns false if the item was already visible. +void UITableResizeColumns(UITable *table); + +UICode *UICodeCreate(UIElement *parent, uint32_t flags); +void UICodeFocusLine(UICode *code, int index); // Line numbers are 1-indexed!! +int UICodeHitTest(UICode *code, int x, int y); // Returns line number; negates if in margin. Returns 0 if not on a line. +void UICodeInsertContent(UICode *code, const char *content, ptrdiff_t byteCount, bool replace); + +void UIDrawBlock(UIPainter *painter, UIRectangle rectangle, uint32_t color); +void UIDrawInvert(UIPainter *painter, UIRectangle rectangle); +void UIDrawLine(UIPainter *painter, int x0, int y0, int x1, int y1, uint32_t color); +void UIDrawGlyph(UIPainter *painter, int x, int y, int c, uint32_t color); +void UIDrawRectangle(UIPainter *painter, UIRectangle r, uint32_t mainColor, uint32_t borderColor, UIRectangle borderSize); +void UIDrawBorder(UIPainter *painter, UIRectangle r, uint32_t borderColor, UIRectangle borderSize); +void UIDrawString(UIPainter *painter, UIRectangle r, const char *string, ptrdiff_t bytes, uint32_t color, int align, UIStringSelection *selection); +int UIDrawStringHighlighted(UIPainter *painter, UIRectangle r, const char *string, ptrdiff_t bytes, int tabSize); + +int UIMeasureStringWidth(const char *string, ptrdiff_t bytes); +int UIMeasureStringHeight(); + +uint64_t UIAnimateClock(); // In ms. + +bool UIElementAnimate(UIElement *element, bool stop); +void UIElementDestroy(UIElement *element); +void UIElementDestroyDescendents(UIElement *element); +UIElement *UIElementFindByPoint(UIElement *element, int x, int y); +void UIElementFocus(UIElement *element); +UIRectangle UIElementScreenBounds(UIElement *element); // Returns bounds of element in same coordinate system as used by UIWindowCreate. +void UIElementRefresh(UIElement *element); +void UIElementRepaint(UIElement *element, UIRectangle *region); +void UIElementMove(UIElement *element, UIRectangle bounds, bool alwaysLayout); +int UIElementMessage(UIElement *element, UIMessage message, int di, void *dp); +void UIElementChangeParent(UIElement *element, UIElement *newParent, bool insertAtStart); + +UIElement *UIParentPush(UIElement *element); +UIElement *UIParentPop(); + +UIRectangle UIRectangleIntersection(UIRectangle a, UIRectangle b); +UIRectangle UIRectangleBounding(UIRectangle a, UIRectangle b); +UIRectangle UIRectangleAdd(UIRectangle a, UIRectangle b); +UIRectangle UIRectangleTranslate(UIRectangle a, UIRectangle b); +bool UIRectangleEquals(UIRectangle a, UIRectangle b); +bool UIRectangleContains(UIRectangle a, int x, int y); + +bool UIColorToHSV(uint32_t rgb, float *hue, float *saturation, float *value); +void UIColorToRGB(float hue, float saturation, float value, uint32_t *rgb); + +char *UIStringCopy(const char *in, ptrdiff_t inBytes); + +#ifdef UI_DEBUG +void UIInspectorLog(const char *cFormat, ...); +#endif + +#ifdef UI_IMPLEMENTATION + +#ifdef UI_FREETYPE +#include <ft2build.h> +#include FT_FREETYPE_H +#include <freetype/ftbitmap.h> +#endif + +struct { + UIWindow *windows; + UIElement *animating; + UITheme theme; + + UIElement *parentStack[16]; + int parentStackCount; + + int glyphWidth, glyphHeight; + + bool quit; + const char *dialogResult; + UIElement *dialogOldFocus; + +#ifdef UI_DEBUG + UIWindow *inspector; + UITable *inspectorTable; + UIWindow *inspectorTarget; + UICode *inspectorLog; +#endif + +#ifdef UI_LINUX + Display *display; + Visual *visual; + XIM xim; + Atom windowClosedID; + Cursor cursors[UI_CURSOR_COUNT]; +#endif + +#ifdef UI_WINDOWS + HCURSOR cursors[UI_CURSOR_COUNT]; + HANDLE heap; + bool assertionFailure; +#endif + +#ifdef UI_ESSENCE + EsInstance *instance; +#endif + +#ifdef UI_FREETYPE + FT_Face font; + FT_Library ft; + FT_Bitmap glyphs[128]; + bool glyphsRendered[128]; + int glyphOffsetsX[128], glyphOffsetsY[128]; +#endif +} ui; + +UITheme _uiThemeClassic = { + .panel1 = 0xFFF0F0F0, + .panel2 = 0xFFFFFFFF, + .selected = 0xFF94BEFE, + .border = 0xFF404040, + + .text = 0xFF000000, + .textDisabled = 0xFF404040, + .textSelected = 0xFF000000, + + .buttonNormal = 0xFFE0E0E0, + .buttonHovered = 0xFFF0F0F0, + .buttonPressed = 0xFFA0A0A0, + .buttonDisabled = 0xFFF0F0F0, + + .textboxNormal = 0xFFF8F8F8, + .textboxFocused = 0xFFFFFFFF, + + .codeFocused = 0xFFE0E0E0, + .codeBackground = 0xFFFFFFFF, + .codeDefault = 0xFF000000, + .codeComment = 0xFFA11F20, + .codeString = 0xFF037E01, + .codeNumber = 0xFF213EF1, + .codeOperator = 0xFF7F0480, + .codePreprocessor = 0xFF545D70, +}; + +UITheme _uiThemeDark = { + .panel1 = 0xFF252B31, + .panel2 = 0xFF14181E, + .selected = 0xFF94BEFE, + .border = 0xFF000000, + + .text = 0xFFFFFFFF, + .textDisabled = 0xFF787D81, + .textSelected = 0xFF000000, + + .buttonNormal = 0xFF383D41, + .buttonHovered = 0xFF4B5874, + .buttonPressed = 0xFF0D0D0F, + .buttonDisabled = 0xFF1B1F23, + + .textboxNormal = 0xFF31353C, + .textboxFocused = 0xFF4D4D59, + + .codeFocused = 0xFF505055, + .codeBackground = 0xFF212126, + .codeDefault = 0xFFFFFFFF, + .codeComment = 0xFFB4B4B4, + .codeString = 0xFFF5DDD1, + .codeNumber = 0xFFC3F5D3, + .codeOperator = 0xFFF5D499, + .codePreprocessor = 0xFFF5F3D1, +}; + +#ifndef UI_FREETYPE + +// Taken from https://commons.wikimedia.org/wiki/File:Codepage-437.png +// Public domain. + +const uint64_t _uiFont[] = { + 0x0000000000000000UL, 0x0000000000000000UL, 0xBD8181A5817E0000UL, 0x000000007E818199UL, 0xC3FFFFDBFF7E0000UL, 0x000000007EFFFFE7UL, 0x7F7F7F3600000000UL, 0x00000000081C3E7FUL, + 0x7F3E1C0800000000UL, 0x0000000000081C3EUL, 0xE7E73C3C18000000UL, 0x000000003C1818E7UL, 0xFFFF7E3C18000000UL, 0x000000003C18187EUL, 0x3C18000000000000UL, 0x000000000000183CUL, + 0xC3E7FFFFFFFFFFFFUL, 0xFFFFFFFFFFFFE7C3UL, 0x42663C0000000000UL, 0x00000000003C6642UL, 0xBD99C3FFFFFFFFFFUL, 0xFFFFFFFFFFC399BDUL, 0x331E4C5870780000UL, 0x000000001E333333UL, + 0x3C666666663C0000UL, 0x0000000018187E18UL, 0x0C0C0CFCCCFC0000UL, 0x00000000070F0E0CUL, 0xC6C6C6FEC6FE0000UL, 0x0000000367E7E6C6UL, 0xE73CDB1818000000UL, 0x000000001818DB3CUL, + 0x1F7F1F0F07030100UL, 0x000000000103070FUL, 0x7C7F7C7870604000UL, 0x0000000040607078UL, 0x1818187E3C180000UL, 0x0000000000183C7EUL, 0x6666666666660000UL, 0x0000000066660066UL, + 0xD8DEDBDBDBFE0000UL, 0x00000000D8D8D8D8UL, 0x6363361C06633E00UL, 0x0000003E63301C36UL, 0x0000000000000000UL, 0x000000007F7F7F7FUL, 0x1818187E3C180000UL, 0x000000007E183C7EUL, + 0x1818187E3C180000UL, 0x0000000018181818UL, 0x1818181818180000UL, 0x00000000183C7E18UL, 0x7F30180000000000UL, 0x0000000000001830UL, 0x7F060C0000000000UL, 0x0000000000000C06UL, + 0x0303000000000000UL, 0x0000000000007F03UL, 0xFF66240000000000UL, 0x0000000000002466UL, 0x3E1C1C0800000000UL, 0x00000000007F7F3EUL, 0x3E3E7F7F00000000UL, 0x0000000000081C1CUL, + 0x0000000000000000UL, 0x0000000000000000UL, 0x18183C3C3C180000UL, 0x0000000018180018UL, 0x0000002466666600UL, 0x0000000000000000UL, 0x36367F3636000000UL, 0x0000000036367F36UL, + 0x603E0343633E1818UL, 0x000018183E636160UL, 0x1830634300000000UL, 0x000000006163060CUL, 0x3B6E1C36361C0000UL, 0x000000006E333333UL, 0x000000060C0C0C00UL, 0x0000000000000000UL, + 0x0C0C0C0C18300000UL, 0x0000000030180C0CUL, 0x30303030180C0000UL, 0x000000000C183030UL, 0xFF3C660000000000UL, 0x000000000000663CUL, 0x7E18180000000000UL, 0x0000000000001818UL, + 0x0000000000000000UL, 0x0000000C18181800UL, 0x7F00000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL, 0x0000000018180000UL, 0x1830604000000000UL, 0x000000000103060CUL, + 0xDBDBC3C3663C0000UL, 0x000000003C66C3C3UL, 0x1818181E1C180000UL, 0x000000007E181818UL, 0x0C183060633E0000UL, 0x000000007F630306UL, 0x603C6060633E0000UL, 0x000000003E636060UL, + 0x7F33363C38300000UL, 0x0000000078303030UL, 0x603F0303037F0000UL, 0x000000003E636060UL, 0x633F0303061C0000UL, 0x000000003E636363UL, 0x18306060637F0000UL, 0x000000000C0C0C0CUL, + 0x633E6363633E0000UL, 0x000000003E636363UL, 0x607E6363633E0000UL, 0x000000001E306060UL, 0x0000181800000000UL, 0x0000000000181800UL, 0x0000181800000000UL, 0x000000000C181800UL, + 0x060C183060000000UL, 0x000000006030180CUL, 0x00007E0000000000UL, 0x000000000000007EUL, 0x6030180C06000000UL, 0x00000000060C1830UL, 0x18183063633E0000UL, 0x0000000018180018UL, + 0x7B7B63633E000000UL, 0x000000003E033B7BUL, 0x7F6363361C080000UL, 0x0000000063636363UL, 0x663E6666663F0000UL, 0x000000003F666666UL, 0x03030343663C0000UL, 0x000000003C664303UL, + 0x66666666361F0000UL, 0x000000001F366666UL, 0x161E1646667F0000UL, 0x000000007F664606UL, 0x161E1646667F0000UL, 0x000000000F060606UL, 0x7B030343663C0000UL, 0x000000005C666363UL, + 0x637F636363630000UL, 0x0000000063636363UL, 0x18181818183C0000UL, 0x000000003C181818UL, 0x3030303030780000UL, 0x000000001E333333UL, 0x1E1E366666670000UL, 0x0000000067666636UL, + 0x06060606060F0000UL, 0x000000007F664606UL, 0xC3DBFFFFE7C30000UL, 0x00000000C3C3C3C3UL, 0x737B7F6F67630000UL, 0x0000000063636363UL, 0x63636363633E0000UL, 0x000000003E636363UL, + 0x063E6666663F0000UL, 0x000000000F060606UL, 0x63636363633E0000UL, 0x000070303E7B6B63UL, 0x363E6666663F0000UL, 0x0000000067666666UL, 0x301C0663633E0000UL, 0x000000003E636360UL, + 0x18181899DBFF0000UL, 0x000000003C181818UL, 0x6363636363630000UL, 0x000000003E636363UL, 0xC3C3C3C3C3C30000UL, 0x00000000183C66C3UL, 0xDBC3C3C3C3C30000UL, 0x000000006666FFDBUL, + 0x18183C66C3C30000UL, 0x00000000C3C3663CUL, 0x183C66C3C3C30000UL, 0x000000003C181818UL, 0x0C183061C3FF0000UL, 0x00000000FFC38306UL, 0x0C0C0C0C0C3C0000UL, 0x000000003C0C0C0CUL, + 0x1C0E070301000000UL, 0x0000000040607038UL, 0x30303030303C0000UL, 0x000000003C303030UL, 0x0000000063361C08UL, 0x0000000000000000UL, 0x0000000000000000UL, 0x0000FF0000000000UL, + 0x0000000000180C0CUL, 0x0000000000000000UL, 0x3E301E0000000000UL, 0x000000006E333333UL, 0x66361E0606070000UL, 0x000000003E666666UL, 0x03633E0000000000UL, 0x000000003E630303UL, + 0x33363C3030380000UL, 0x000000006E333333UL, 0x7F633E0000000000UL, 0x000000003E630303UL, 0x060F0626361C0000UL, 0x000000000F060606UL, 0x33336E0000000000UL, 0x001E33303E333333UL, + 0x666E360606070000UL, 0x0000000067666666UL, 0x18181C0018180000UL, 0x000000003C181818UL, 0x6060700060600000UL, 0x003C666660606060UL, 0x1E36660606070000UL, 0x000000006766361EUL, + 0x18181818181C0000UL, 0x000000003C181818UL, 0xDBFF670000000000UL, 0x00000000DBDBDBDBUL, 0x66663B0000000000UL, 0x0000000066666666UL, 0x63633E0000000000UL, 0x000000003E636363UL, + 0x66663B0000000000UL, 0x000F06063E666666UL, 0x33336E0000000000UL, 0x007830303E333333UL, 0x666E3B0000000000UL, 0x000000000F060606UL, 0x06633E0000000000UL, 0x000000003E63301CUL, + 0x0C0C3F0C0C080000UL, 0x00000000386C0C0CUL, 0x3333330000000000UL, 0x000000006E333333UL, 0xC3C3C30000000000UL, 0x00000000183C66C3UL, 0xC3C3C30000000000UL, 0x0000000066FFDBDBUL, + 0x3C66C30000000000UL, 0x00000000C3663C18UL, 0x6363630000000000UL, 0x001F30607E636363UL, 0x18337F0000000000UL, 0x000000007F63060CUL, 0x180E181818700000UL, 0x0000000070181818UL, + 0x1800181818180000UL, 0x0000000018181818UL, 0x18701818180E0000UL, 0x000000000E181818UL, 0x000000003B6E0000UL, 0x0000000000000000UL, 0x63361C0800000000UL, 0x00000000007F6363UL, +}; + +#endif + +void _UIWindowEndPaint(UIWindow *window, UIPainter *painter); +void _UIWindowSetCursor(UIWindow *window, int cursor); +void _UIWindowGetScreenPosition(UIWindow *window, int *x, int *y); +void _UIWindowSetPressed(UIWindow *window, UIElement *element, int button); +bool _UIMessageLoopSingle(int *result); +void _UIInspectorRefresh(); +void _UIUpdate(); + +#ifdef UI_WINDOWS +void *_UIHeapReAlloc(void *pointer, size_t size); +#endif + +UIRectangle UIRectangleIntersection(UIRectangle a, UIRectangle b) { + if (a.l < b.l) a.l = b.l; + if (a.t < b.t) a.t = b.t; + if (a.r > b.r) a.r = b.r; + if (a.b > b.b) a.b = b.b; + return a; +} + +UIRectangle UIRectangleBounding(UIRectangle a, UIRectangle b) { + if (a.l > b.l) a.l = b.l; + if (a.t > b.t) a.t = b.t; + if (a.r < b.r) a.r = b.r; + if (a.b < b.b) a.b = b.b; + return a; +} + +UIRectangle UIRectangleAdd(UIRectangle a, UIRectangle b) { + a.l += b.l; + a.t += b.t; + a.r += b.r; + a.b += b.b; + return a; +} + +UIRectangle UIRectangleTranslate(UIRectangle a, UIRectangle b) { + a.l += b.l; + a.t += b.t; + a.r += b.l; + a.b += b.t; + return a; +} + +bool UIRectangleEquals(UIRectangle a, UIRectangle b) { + return a.l == b.l && a.r == b.r && a.t == b.t && a.b == b.b; +} + +bool UIRectangleContains(UIRectangle a, int x, int y) { + return a.l <= x && a.r > x && a.t <= y && a.b > y; +} + +#include <xmmintrin.h> + +typedef union _UIConvertFloatInteger { + float f; + uint32_t i; +} _UIConvertFloatInteger; + +float _UIFloorFloat(float x) { + _UIConvertFloatInteger convert = {x}; + uint32_t sign = convert.i & 0x80000000; + int exponent = (int) ((convert.i >> 23) & 0xFF) - 0x7F; + + if (exponent >= 23) { + // There aren't any bits representing a fractional part. + } else if (exponent >= 0) { + // Positive exponent. + uint32_t mask = 0x7FFFFF >> exponent; + if (!(mask & convert.i)) return x; // Already an integer. + if (sign) convert.i += mask; + convert.i &= ~mask; // Mask out the fractional bits. + } else if (exponent < 0) { + // Negative exponent. + return sign ? -1.0 : 0.0; + } + + return convert.f; +} + +float _UISquareRootFloat(float x) { + float result[4]; + _mm_storeu_ps(result, _mm_sqrt_ps(_mm_set_ps(0, 0, 0, x))); + return result[0]; +} + +#define _F(x) (((_UIConvertFloatInteger) { .i = (x) }).f) + +float _UIArcTanFloatI(float x) { + float x2 = x * x; + return x * (_F(0x3F7FFFF8) + x2 * (_F(0xBEAAA53C) + x2 * (_F(0x3E4BC990) + x2 * (_F(0xBE084A60) + x2 * _F(0x3D8864B0))))); +} + +float _UISinFloatI(float x) { + float x2 = x * x; + return x * (_F(0x3F800000) + x2 * (_F(0xBE2AAAA0) + x2 * (_F(0x3C0882C0) + x2 * _F(0xB94C6000)))); +} + +float _UICosFloatI(float x) { + float x2 = x * x; + return _F(0x3F800000) + x2 * (_F(0xBEFFFFDA) + x2 * (_F(0x3D2A9F60) + x2 * _F(0xBAB22C00))); +} + +#undef _F + +float _UISinFloat(float x) { + bool negate = false; + if (x < 0) { x = -x; negate = true; } + x -= 2 * 3.141592654f * _UIFloorFloat(x / (2 * 3.141592654f)); + if (x < 3.141592654f / 2) {} + else if (x < 3.141592654f) { x = 3.141592654f - x; } + else if (x < 3 * 3.141592654f / 2) { x = x - 3.141592654f; negate = !negate; } + else { x = 3.141592654f * 2 - x; negate = !negate; } + float y = x < 3.141592654f / 4 ? _UISinFloatI(x) : _UICosFloatI(3.141592654f / 2 - x); + return negate ? -y : y; +} + +float _UICosFloat(float x) { + return _UISinFloat(3.141592654f / 2 - x); +} + +float _UIArcTanFloat(float x) { + bool negate = false, reciprocalTaken = false; + if (x < 0) { x = -x; negate = true; } + if (x > 1) { x = 1 / x; reciprocalTaken = true; } + float y = x < 0.5f ? _UIArcTanFloatI(x) : (0.463647609f + _UIArcTanFloatI((2 * x - 1) / (2 + x))); + if (reciprocalTaken) { y = 3.141592654f / 2 - y; } + return negate ? -y : y; +} + +float _UIArcTan2Float(float y, float x) { + if (x == 0) return y > 0 ? 3.141592654f / 2 : -3.141592654f / 2; + else if (x > 0) return _UIArcTanFloat(y / x); + else if (y >= 0) return 3.141592654f + _UIArcTanFloat(y / x); + else return -3.141592654f + _UIArcTanFloat(y / x); +} + +float _UILinearMap(float value, float inFrom, float inTo, float outFrom, float outTo) { + float inRange = inTo - inFrom, outRange = outTo - outFrom; + float normalisedValue = (value - inFrom) / inRange; + return normalisedValue * outRange + outFrom; +} + +bool UIColorToHSV(uint32_t rgb, float *hue, float *saturation, float *value) { + float r = UI_COLOR_RED_F(rgb); + float g = UI_COLOR_GREEN_F(rgb); + float b = UI_COLOR_BLUE_F(rgb); + + float maximum = (r > g && r > b) ? r : (g > b ? g : b), + minimum = (r < g && r < b) ? r : (g < b ? g : b), + difference = maximum - minimum; + *value = maximum; + + if (!difference) { + *saturation = 0; + return false; + } else { + if (r == maximum) *hue = (g - b) / difference + 0; + if (g == maximum) *hue = (b - r) / difference + 2; + if (b == maximum) *hue = (r - g) / difference + 4; + if (*hue < 0) *hue += 6; + *saturation = difference / maximum; + return true; + } +} + +void UIColorToRGB(float h, float s, float v, uint32_t *rgb) { + float r, g, b; + + if (!s) { + r = g = b = v; + } else { + int h0 = ((int) h) % 6; + float f = h - _UIFloorFloat(h); + float x = v * (1 - s), y = v * (1 - s * f), z = v * (1 - s * (1 - f)); + + switch (h0) { + case 0: r = v, g = z, b = x; break; + case 1: r = y, g = v, b = x; break; + case 2: r = x, g = v, b = z; break; + case 3: r = x, g = y, b = v; break; + case 4: r = z, g = x, b = v; break; + default: r = v, g = x, b = y; break; + } + } + + *rgb = UI_COLOR_FROM_FLOAT(r, g, b); +} + +void UIElementRefresh(UIElement *element) { + UIElementMessage(element, UI_MSG_LAYOUT, 0, 0); + UIElementRepaint(element, NULL); +} + +void UIElementRepaint(UIElement *element, UIRectangle *region) { + if (!region) { + region = &element->bounds; + } + + UIRectangle r = UIRectangleIntersection(*region, element->clip); + + if (!UI_RECT_VALID(r)) { + return; + } + + if (UI_RECT_VALID(element->window->updateRegion)) { + element->window->updateRegion = UIRectangleBounding(element->window->updateRegion, r); + } else { + element->window->updateRegion = r; + } +} + +bool UIElementAnimate(UIElement *element, bool stop) { + if (stop) { + if (ui.animating != element) { + return false; + } + + ui.animating = NULL; + } else { + if (ui.animating && ui.animating != element) { + return false; + } + + ui.animating = element; + } + + return true; +} + +uint64_t UIAnimateClock() { + return (uint64_t) UI_CLOCK() * 1000 / UI_CLOCKS_PER_SECOND; +} + +void _UIElementDestroyDescendents(UIElement *element, bool topLevel) { + UIElement *child = element->children; + + while (child) { + if (!topLevel || (~child->flags & UI_ELEMENT_NON_CLIENT)) { + UIElementDestroy(child); + } + + child = child->next; + } + +#ifdef UI_DEBUG + _UIInspectorRefresh(); +#endif +} + +void UIElementDestroyDescendents(UIElement *element) { + _UIElementDestroyDescendents(element, true); +} + +void UIElementDestroy(UIElement *element) { + if (element->flags & UI_ELEMENT_DESTROY) { + return; + } + + element->flags |= UI_ELEMENT_DESTROY | UI_ELEMENT_HIDE; + + UIElement *ancestor = element->parent; + + while (ancestor) { + ancestor->flags |= UI_ELEMENT_DESTROY_DESCENDENT; + ancestor = ancestor->parent; + } + + _UIElementDestroyDescendents(element, false); +} + +void UIDrawBlock(UIPainter *painter, UIRectangle rectangle, uint32_t color) { + rectangle = UIRectangleIntersection(painter->clip, rectangle); + + if (!UI_RECT_VALID(rectangle)) { + return; + } + + for (int line = rectangle.t; line < rectangle.b; line++) { + uint32_t *bits = painter->bits + line * painter->width + rectangle.l; + int count = UI_RECT_WIDTH(rectangle); + + while (count--) { + *bits++ = color; + } + } + +#ifdef UI_DEBUG + painter->fillCount += UI_RECT_WIDTH(rectangle) * UI_RECT_HEIGHT(rectangle); +#endif +} + +void UIDrawLine(UIPainter *painter, int x0, int y0, int x1, int y1, uint32_t color) { + // Clip the line to the painter's clip rectangle. + + if (x0 > x1) { int t = x0; x0 = x1; x1 = t; } + if (y0 > y1) { int t = y0; y0 = y1; y1 = t; } + UIRectangle bounds = UIRectangleIntersection(painter->clip, UI_RECT_4(x0, x1, y0, y1)); + int dx = x1 - x0, dy = y1 - y0; + int points[8], count = 0; + int iLY = dx ? (y0 + (bounds.l - x0) * dy / dx) : 0x7FFFFFFF; + int iRY = dx ? (y0 + (bounds.r - x0) * dy / dx) : 0x7FFFFFFF; + int iTX = dy ? (x0 + (bounds.t - y0) * dx / dy) : 0x7FFFFFFF; + int iBX = dy ? (x0 + (bounds.b - y0) * dx / dy) : 0x7FFFFFFF; + if (iLY >= bounds.t && iLY <= bounds.b) points[count + 0] = bounds.l, points[count + 1] = iLY, count += 2; + if (iRY >= bounds.t && iRY <= bounds.b) points[count + 0] = bounds.r, points[count + 1] = iRY, count += 2; + if (iTX >= bounds.l && iTX <= bounds.r) points[count + 1] = bounds.t, points[count + 0] = iTX, count += 2; + if (iBX >= bounds.l && iBX <= bounds.r) points[count + 1] = bounds.b, points[count + 0] = iBX, count += 2; + if (count < 4) return; + x0 = points[0], y0 = points[1], x1 = points[2], y1 = points[3]; + if (x0 == x1 && y0 == y1 && count > 4) x1 = points[4], y1 = points[5]; + dx = x1 - x0, dy = y1 - y0; + + // Draw the line using Bresenham's line algorithm. + + uint32_t *bits = painter->bits + y0 * painter->width + x0; + + if (dy * dy < dx * dx) { + int m = 2 * dy - dx; + + for (int i = 0; i < dx; i++, bits++) { + *bits = color; + if (m > 0) bits += painter->width, m -= 2 * dx; + m += 2 * dy; + } + } else { + int m = 2 * dx - dy; + + for (int i = 0; i < dy; i++, bits += painter->width) { + *bits = color; + if (m > 0) bits++, m -= 2 * dy; + m += 2 * dx; + } + } +} + +void UIDrawInvert(UIPainter *painter, UIRectangle rectangle) { + rectangle = UIRectangleIntersection(painter->clip, rectangle); + + if (!UI_RECT_VALID(rectangle)) { + return; + } + + for (int line = rectangle.t; line < rectangle.b; line++) { + uint32_t *bits = painter->bits + line * painter->width + rectangle.l; + int count = UI_RECT_WIDTH(rectangle); + + while (count--) { + uint32_t in = *bits; + *bits = in ^ 0xFFFFFF; + bits++; + } + } +} + +#ifdef UI_FREETYPE + +void UIDrawGlyph(UIPainter *painter, int x0, int y0, int c, uint32_t color) { + if (c < 0 || c > 127) c = '?'; + if (c == '\r') c = ' '; + + if (!ui.glyphsRendered[c]) { + FT_Load_Char(ui.font, c == 24 ? 0x2191 : c == 25 ? 0x2193 : c == 26 ? 0x2192 : c == 27 ? 0x2190 : c, FT_LOAD_DEFAULT); +#ifdef UI_FREETYPE_SUBPIXEL + FT_Render_Glyph(ui.font->glyph, FT_RENDER_MODE_LCD); +#else + FT_Render_Glyph(ui.font->glyph, FT_RENDER_MODE_NORMAL); +#endif + FT_Bitmap_Copy(ui.ft, &ui.font->glyph->bitmap, &ui.glyphs[c]); + ui.glyphOffsetsX[c] = ui.font->glyph->bitmap_left; + ui.glyphOffsetsY[c] = ui.font->size->metrics.ascender / 64 - ui.font->glyph->bitmap_top; + ui.glyphsRendered[c] = true; + } + + FT_Bitmap *bitmap = &ui.glyphs[c]; + x0 += ui.glyphOffsetsX[c], y0 += ui.glyphOffsetsY[c]; + + for (int y = 0; y < (int) bitmap->rows; y++) { + if (y0 + y < painter->clip.t) continue; + if (y0 + y >= painter->clip.b) break; + + int width = bitmap->width; +#ifdef UI_FREETYPE_SUBPIXEL + width /= 3; +#endif + + for (int x = 0; x < width; x++) { + if (x0 + x < painter->clip.l) continue; + if (x0 + x >= painter->clip.r) break; + + uint32_t *destination = painter->bits + (x0 + x) + (y0 + y) * painter->width; + uint32_t original = *destination; + +#ifdef UI_FREETYPE_SUBPIXEL + uint32_t ra = ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 0]; + uint32_t ga = ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 1]; + uint32_t ba = ((uint8_t *) bitmap->buffer)[x * 3 + y * bitmap->pitch + 2]; + ra += (ga - ra) / 2, ba += (ga - ba) / 2; +#else + uint32_t ra = ((uint8_t *) bitmap->buffer)[x + y * bitmap->pitch]; + uint32_t ga = ra, ba = ra; +#endif + uint32_t r2 = (255 - ra) * ((original & 0x000000FF) >> 0); + uint32_t g2 = (255 - ga) * ((original & 0x0000FF00) >> 8); + uint32_t b2 = (255 - ba) * ((original & 0x00FF0000) >> 16); + uint32_t r1 = ra * ((color & 0x000000FF) >> 0); + uint32_t g1 = ga * ((color & 0x0000FF00) >> 8); + uint32_t b1 = ba * ((color & 0x00FF0000) >> 16); + + uint32_t result = 0xFF000000 | (0x00FF0000 & ((b1 + b2) << 8)) + | (0x0000FF00 & ((g1 + g2) << 0)) + | (0x000000FF & ((r1 + r2) >> 8)); + *destination = result; + } + } +} + +#else + +void UIDrawGlyph(UIPainter *painter, int x, int y, int c, uint32_t color) { + if (c < 0 || c > 127) c = '?'; + + UIRectangle rectangle = UIRectangleIntersection(painter->clip, UI_RECT_4(x, x + 8, y, y + 16)); + + const uint8_t *data = (const uint8_t *) _uiFont + c * 16; + + for (int i = rectangle.t; i < rectangle.b; i++) { + uint32_t *bits = painter->bits + i * painter->width + rectangle.l; + uint8_t byte = data[i - y]; + + for (int j = rectangle.l; j < rectangle.r; j++) { + if (byte & (1 << (j - x))) { + *bits = color; + } + + bits++; + } + } +} + +#endif + +ptrdiff_t _UIStringLength(const char *cString) { + if (!cString) return 0; + ptrdiff_t length; + for (length = 0; cString[length]; length++); + return length; +} + +char *UIStringCopy(const char *in, ptrdiff_t inBytes) { + if (inBytes == -1) { + inBytes = _UIStringLength(in); + } + + char *buffer = (char *) UI_MALLOC(inBytes + 1); + + for (intptr_t i = 0; i < inBytes; i++) { + buffer[i] = in[i]; + } + + buffer[inBytes] = 0; + return buffer; +} + +int UIMeasureStringWidth(const char *string, ptrdiff_t bytes) { + if (bytes == -1) { + bytes = _UIStringLength(string); + } + + return bytes * ui.glyphWidth; +} + +int UIMeasureStringHeight() { + return ui.glyphHeight; +} + +void UIDrawString(UIPainter *painter, UIRectangle r, const char *string, ptrdiff_t bytes, uint32_t color, int align, UIStringSelection *selection) { + UIRectangle oldClip = painter->clip; + painter->clip = UIRectangleIntersection(r, oldClip); + + if (!UI_RECT_VALID(painter->clip)) { + painter->clip = oldClip; + return; + } + + if (bytes == -1) { + bytes = _UIStringLength(string); + } + + int width = UIMeasureStringWidth(string, bytes); + int height = UIMeasureStringHeight(); + int x = align == UI_ALIGN_CENTER ? ((r.l + r.r - width) / 2) : align == UI_ALIGN_RIGHT ? (r.r - width) : r.l; + int y = (r.t + r.b - height) / 2; + int i = 0, j = 0; + + int selectFrom = -1, selectTo = -1; + + if (selection) { + selectFrom = selection->carets[0]; + selectTo = selection->carets[1]; + + if (selectFrom > selectTo) { + UI_SWAP(int, selectFrom, selectTo); + } + } + + + for (; j < bytes; j++) { + char c = *string++; + uint32_t colorText = color; + + if (j >= selectFrom && j < selectTo) { + UIDrawBlock(painter, UI_RECT_4(x, x + ui.glyphWidth, y, y + height), selection->colorBackground); + colorText = selection->colorText; + } + + if (c != '\t') { + UIDrawGlyph(painter, x, y, c, colorText); + } + + if (selection && selection->carets[0] == j) { + UIDrawInvert(painter, UI_RECT_4(x, x + 1, y, y + height)); + } + + x += ui.glyphWidth, i++; + + if (c == '\t') { + while (i & 3) x += ui.glyphWidth, i++; + } + } + + if (selection && selection->carets[0] == j) { + UIDrawInvert(painter, UI_RECT_4(x, x + 1, y, y + height)); + } + + painter->clip = oldClip; +} + +void UIDrawBorder(UIPainter *painter, UIRectangle r, uint32_t borderColor, UIRectangle borderSize) { + UIDrawBlock(painter, UI_RECT_4(r.l, r.r, r.t, r.t + borderSize.t), borderColor); + UIDrawBlock(painter, UI_RECT_4(r.l, r.l + borderSize.l, r.t + borderSize.t, r.b - borderSize.b), borderColor); + UIDrawBlock(painter, UI_RECT_4(r.r - borderSize.r, r.r, r.t + borderSize.t, r.b - borderSize.b), borderColor); + UIDrawBlock(painter, UI_RECT_4(r.l, r.r, r.b - borderSize.b, r.b), borderColor); +} + +void UIDrawRectangle(UIPainter *painter, UIRectangle r, uint32_t mainColor, uint32_t borderColor, UIRectangle borderSize) { + UIDrawBorder(painter, r, borderColor, borderSize); + UIDrawBlock(painter, UI_RECT_4(r.l + borderSize.l, r.r - borderSize.r, r.t + borderSize.t, r.b - borderSize.b), mainColor); +} + +void UIElementMove(UIElement *element, UIRectangle bounds, bool alwaysLayout) { + UIRectangle oldClip = element->clip; + element->clip = UIRectangleIntersection(element->parent->clip, bounds); + + if (!UIRectangleEquals(element->bounds, bounds) || !UIRectangleEquals(element->clip, oldClip) || alwaysLayout) { + element->bounds = bounds; + UIElementMessage(element, UI_MSG_LAYOUT, 0, 0); + } +} + +int UIElementMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message != UI_MSG_DESTROY && (element->flags & UI_ELEMENT_DESTROY)) { + return 0; + } + + if (message >= UI_MSG_INPUT_EVENTS_START && message <= UI_MSG_INPUT_EVENTS_END && (element->flags & UI_ELEMENT_DISABLED)) { + return 0; + } + + if (element->messageUser) { + int result = element->messageUser(element, message, di, dp); + + if (result) { + return result; + } + } + + if (element->messageClass) { + return element->messageClass(element, message, di, dp); + } else { + return 0; + } +} + +void UIElementChangeParent(UIElement *element, UIElement *newParent, bool insertAtStart) { + UIElement **link = &element->parent->children; + + while (true) { + if (*link == element) { + *link = element->next; + break; + } else { + link = &(*link)->next; + } + } + + if (insertAtStart) { + element->next = newParent->children; + newParent->children = element; + } else { + link = &newParent->children; + element->next = NULL; + + while (true) { + if (!(*link)) { + *link = element; + break; + } else { + link = &(*link)->next; + } + } + } + + element->parent = newParent; + element->window = newParent->window; +} + +UIElement *UIElementCreate(size_t bytes, UIElement *parent, uint32_t flags, int (*message)(UIElement *, UIMessage, int, void *), const char *cClassName) { + UI_ASSERT(bytes >= sizeof(UIElement)); + UIElement *element = (UIElement *) UI_CALLOC(bytes); + element->flags = flags; + element->messageClass = message; + + if (!parent && (~flags & UI_ELEMENT_WINDOW)) { + UI_ASSERT(ui.parentStackCount); + parent = ui.parentStack[ui.parentStackCount - 1]; + } + + if ((~flags & UI_ELEMENT_NON_CLIENT) && parent) { + UIElementMessage(parent, UI_MSG_CLIENT_PARENT, 0, &parent); + } + + if (parent) { + element->window = parent->window; + element->parent = parent; + + if (parent->children) { + UIElement *sibling = parent->children; + + while (sibling->next) { + sibling = sibling->next; + } + + sibling->next = element; + } else { + parent->children = element; + } + + UI_ASSERT(~parent->flags & UI_ELEMENT_DESTROY); + } + +#ifdef UI_DEBUG + element->cClassName = cClassName; + static int id = 0; + element->id = ++id; + _UIInspectorRefresh(); +#endif + + if (flags & UI_ELEMENT_PARENT_PUSH) { + UIParentPush(element); + } + + return element; +} + +UIElement *UIParentPush(UIElement *element) { + UI_ASSERT(ui.parentStackCount != sizeof(ui.parentStack) / sizeof(ui.parentStack[0])); + ui.parentStack[ui.parentStackCount++] = element; + return element; +} + +UIElement *UIParentPop() { + UI_ASSERT(ui.parentStackCount); + ui.parentStackCount--; + return ui.parentStack[ui.parentStackCount]; +} + +int _UIPanelMeasure(UIPanel *panel) { + bool horizontal = panel->e.flags & UI_PANEL_HORIZONTAL; + int size = 0; + UIElement *child = panel->e.children; + + while (child) { + if (~child->flags & UI_ELEMENT_HIDE) { + if (horizontal) { + int height = UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0); + + if (height > size) { + size = height; + } + } else { + int width = UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0); + + if (width > size) { + size = width; + } + } + } + + child = child->next; + } + + int border = 0; + + if (horizontal) { + border = panel->border.t + panel->border.b; + } else { + border = panel->border.l + panel->border.r; + } + + return size + border * panel->e.window->scale; +} + +int _UIPanelLayout(UIPanel *panel, UIRectangle bounds, bool measure) { + bool horizontal = panel->e.flags & UI_PANEL_HORIZONTAL; + float scale = panel->e.window->scale; + int position = (horizontal ? panel->border.l : panel->border.t) * scale; + if (panel->scrollBar && !measure) position -= panel->scrollBar->position; + int hSpace = UI_RECT_WIDTH(bounds) - UI_RECT_TOTAL_H(panel->border) * scale; + int vSpace = UI_RECT_HEIGHT(bounds) - UI_RECT_TOTAL_V(panel->border) * scale; + + int available = horizontal ? hSpace : vSpace; + int fill = 0, count = 0, perFill = 0; + + for (UIElement *child = panel->e.children; child; child = child->next) { + if (child->flags & (UI_ELEMENT_HIDE | UI_ELEMENT_NON_CLIENT)) { + continue; + } + + count++; + + if (horizontal) { + if (child->flags & UI_ELEMENT_H_FILL) { + fill++; + } else if (available > 0) { + available -= UIElementMessage(child, UI_MSG_GET_WIDTH, vSpace, 0); + } + } else { + if (child->flags & UI_ELEMENT_V_FILL) { + fill++; + } else if (available > 0) { + available -= UIElementMessage(child, UI_MSG_GET_HEIGHT, hSpace, 0); + } + } + } + + if (count) { + available -= (count - 1) * (int) (panel->gap * scale); + } + + if (available > 0 && fill) { + perFill = available / fill; + } + + bool expand = panel->e.flags & UI_PANEL_EXPAND; + int scaledBorder2 = (horizontal ? panel->border.t : panel->border.l) * panel->e.window->scale; + + for (UIElement *child = panel->e.children; child; child = child->next) { + if (child->flags & (UI_ELEMENT_HIDE | UI_ELEMENT_NON_CLIENT)) { + continue; + } + + if (horizontal) { + int height = ((child->flags & UI_ELEMENT_V_FILL) || expand) ? vSpace : UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0); + int width = (child->flags & UI_ELEMENT_H_FILL) ? perFill : UIElementMessage(child, UI_MSG_GET_WIDTH, height, 0); + UIRectangle relative = UI_RECT_4(position, position + width, + scaledBorder2 + (vSpace - height) / 2, + scaledBorder2 + (vSpace + height) / 2); + if (!measure) UIElementMove(child, UIRectangleTranslate(relative, bounds), false); + position += width + panel->gap * scale; + } else { + int width = ((child->flags & UI_ELEMENT_H_FILL) || expand) ? hSpace : UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0); + int height = (child->flags & UI_ELEMENT_V_FILL) ? perFill : UIElementMessage(child, UI_MSG_GET_HEIGHT, width, 0); + UIRectangle relative = UI_RECT_4(scaledBorder2 + (hSpace - width) / 2, + scaledBorder2 + (hSpace + width) / 2, position, position + height); + if (!measure) UIElementMove(child, UIRectangleTranslate(relative, bounds), false); + position += height + panel->gap * scale; + } + } + + return position - panel->gap * scale + (horizontal ? panel->border.r : panel->border.b) * scale; +} + +int _UIPanelMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIPanel *panel = (UIPanel *) element; + bool horizontal = element->flags & UI_PANEL_HORIZONTAL; + + if (message == UI_MSG_LAYOUT) { + int scrollBarWidth = panel->scrollBar ? (UI_SIZE_SCROLL_BAR * element->window->scale) : 0; + UIRectangle bounds = element->bounds; + bounds.r -= scrollBarWidth; + + if (panel->scrollBar) { + UIRectangle scrollBarBounds = element->bounds; + scrollBarBounds.l = scrollBarBounds.r - scrollBarWidth; + panel->scrollBar->maximum = _UIPanelLayout(panel, bounds, true); + panel->scrollBar->page = UI_RECT_HEIGHT(element->bounds); + UIElementMove(&panel->scrollBar->e, scrollBarBounds, true); + } + + _UIPanelLayout(panel, bounds, false); + } else if (message == UI_MSG_GET_WIDTH) { + if (horizontal) { + return _UIPanelLayout(panel, UI_RECT_4(0, 0, 0, di), true); + } else { + return _UIPanelMeasure(panel); + } + } else if (message == UI_MSG_GET_HEIGHT) { + if (horizontal) { + return _UIPanelMeasure(panel); + } else { + int width = di && panel->scrollBar ? (di - UI_SIZE_SCROLL_BAR * element->window->scale) : di; + return _UIPanelLayout(panel, UI_RECT_4(0, width, 0, 0), true); + } + } else if (message == UI_MSG_PAINT) { + if (element->flags & UI_PANEL_GRAY) { + UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel1); + } else if (element->flags & UI_PANEL_WHITE) { + UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel2); + } + } else if (message == UI_MSG_MOUSE_WHEEL && panel->scrollBar) { + return UIElementMessage(&panel->scrollBar->e, message, di, dp); + } else if (message == UI_MSG_SCROLLED) { + UIElementRefresh(element); + } + + return 0; +} + +UIPanel *UIPanelCreate(UIElement *parent, uint32_t flags) { + UIPanel *panel = (UIPanel *) UIElementCreate(sizeof(UIPanel), parent, flags, _UIPanelMessage, "Panel"); + + if (flags & UI_PANEL_MEDIUM_SPACING) { + panel->border = UI_RECT_1(UI_SIZE_PANE_MEDIUM_BORDER); + panel->gap = UI_SIZE_PANE_MEDIUM_GAP; + } else if (flags & UI_PANEL_SMALL_SPACING) { + panel->border = UI_RECT_1(UI_SIZE_PANE_SMALL_BORDER); + panel->gap = UI_SIZE_PANE_SMALL_GAP; + } + + if (flags & UI_PANEL_SCROLL) { + panel->scrollBar = UIScrollBarCreate(&panel->e, UI_ELEMENT_NON_CLIENT); + } + + return panel; +} + +int _UIButtonMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIButton *button = (UIButton *) element; + bool isMenuItem = element->flags & UI_BUTTON_MENU_ITEM; + bool isDropDown = element->flags & UI_BUTTON_DROP_DOWN; + + if (message == UI_MSG_GET_HEIGHT) { + if (isMenuItem) { + return UI_SIZE_MENU_ITEM_HEIGHT * element->window->scale; + } else { + return UI_SIZE_BUTTON_HEIGHT * element->window->scale; + } + } else if (message == UI_MSG_GET_WIDTH) { + int labelSize = UIMeasureStringWidth(button->label, button->labelBytes); + int paddedSize = labelSize + UI_SIZE_BUTTON_PADDING * element->window->scale; + if (isDropDown) paddedSize += ui.glyphWidth * 2; + int minimumSize = ((element->flags & UI_BUTTON_SMALL) ? 0 + : isMenuItem ? UI_SIZE_MENU_ITEM_MINIMUM_WIDTH + : UI_SIZE_BUTTON_MINIMUM_WIDTH) + * element->window->scale; + return paddedSize > minimumSize ? paddedSize : minimumSize; + } else if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + + bool disabled = element->flags & UI_ELEMENT_DISABLED; + bool focused = element == element->window->focused; + bool pressed = element == element->window->pressed; + bool hovered = element == element->window->hovered; + uint32_t color = disabled ? ui.theme.buttonDisabled + : (pressed && hovered) ? ui.theme.buttonPressed + : (pressed || hovered) ? ui.theme.buttonHovered + : focused ? ui.theme.selected : ui.theme.buttonNormal; + uint32_t textColor = disabled ? ui.theme.textDisabled + : color == ui.theme.selected ? ui.theme.textSelected : ui.theme.text; + + UIDrawRectangle(painter, element->bounds, color, ui.theme.border, UI_RECT_1(isMenuItem ? 0 : 1)); + + if (element->flags & UI_BUTTON_CHECKED) { + UIDrawBlock(painter, UIRectangleAdd(element->bounds, + UI_RECT_1I((int) (UI_SIZE_BUTTON_CHECKED_AREA * element->window->scale))), ui.theme.buttonPressed); + } + + UIRectangle bounds = UIRectangleAdd(element->bounds, UI_RECT_2I((int) (UI_SIZE_MENU_ITEM_MARGIN * element->window->scale), 0)); + + if (isMenuItem) { + if (button->labelBytes == -1) { + button->labelBytes = _UIStringLength(button->label); + } + + int tab = 0; + for (; tab < button->labelBytes && button->label[tab] != '\t'; tab++); + + UIDrawString(painter, bounds, button->label, tab, textColor, UI_ALIGN_LEFT, NULL); + + if (button->labelBytes > tab) { + UIDrawString(painter, bounds, button->label + tab + 1, button->labelBytes - tab - 1, textColor, UI_ALIGN_RIGHT, NULL); + } + } else if (isDropDown) { + UIDrawString(painter, bounds, button->label, button->labelBytes, textColor, UI_ALIGN_LEFT, NULL); + UIDrawString(painter, bounds, "\x19", 1, textColor, UI_ALIGN_RIGHT, NULL); + } else { + UIDrawString(painter, element->bounds, button->label, button->labelBytes, textColor, UI_ALIGN_CENTER, NULL); + } + } else if (message == UI_MSG_UPDATE) { + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_DESTROY) { + UI_FREE(button->label); + } else if (message == UI_MSG_LEFT_DOWN) { + if (element->flags & UI_BUTTON_CAN_FOCUS) { + UIElementFocus(element); + } + } else if (message == UI_MSG_KEY_TYPED) { + UIKeyTyped *m = (UIKeyTyped *) dp; + + if (m->textBytes == 1 && m->text[0] == ' ') { + UIElementMessage(element, UI_MSG_CLICKED, 0, 0); + UIElementRepaint(element, NULL); + } + } else if (message == UI_MSG_CLICKED) { + if (button->invoke) { + button->invoke(element->cp); + } + } + + return 0; +} + +UIButton *UIButtonCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes) { + UIButton *button = (UIButton *) UIElementCreate(sizeof(UIButton), parent, flags | UI_ELEMENT_TAB_STOP, _UIButtonMessage, "Button"); + button->label = UIStringCopy(label, (button->labelBytes = labelBytes)); + return button; +} + +int _UILabelMessage(UIElement *element, UIMessage message, int di, void *dp) { + UILabel *label = (UILabel *) element; + + if (message == UI_MSG_GET_HEIGHT) { + return UIMeasureStringHeight(); + } else if (message == UI_MSG_GET_WIDTH) { + return UIMeasureStringWidth(label->label, label->labelBytes); + } else if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + UIDrawString(painter, element->bounds, label->label, label->labelBytes, ui.theme.text, UI_ALIGN_LEFT, NULL); + } else if (message == UI_MSG_DESTROY) { + UI_FREE(label->label); + } + + return 0; +} + +void UILabelSetContent(UILabel *label, const char *string, ptrdiff_t stringBytes) { + UI_FREE(label->label); + label->label = UIStringCopy(string, (label->labelBytes = stringBytes)); +} + +UILabel *UILabelCreate(UIElement *parent, uint32_t flags, const char *string, ptrdiff_t stringBytes) { + UILabel *label = (UILabel *) UIElementCreate(sizeof(UILabel), parent, flags, _UILabelMessage, "Label"); + label->label = UIStringCopy(string, (label->labelBytes = stringBytes)); + return label; +} + +int _UISplitPaneMessage(UIElement *element, UIMessage message, int di, void *dp); + +int _UISplitterMessage(UIElement *element, UIMessage message, int di, void *dp) { + UISplitPane *splitPane = (UISplitPane *) element->parent; + bool vertical = splitPane->e.flags & UI_SPLIT_PANE_VERTICAL; + + if (message == UI_MSG_PAINT) { + UIRectangle borders = vertical ? UI_RECT_2(0, 1) : UI_RECT_2(1, 0); + UIDrawRectangle((UIPainter *) dp, element->bounds, ui.theme.buttonNormal, ui.theme.border, borders); + } else if (message == UI_MSG_GET_CURSOR) { + return vertical ? UI_CURSOR_SPLIT_V : UI_CURSOR_SPLIT_H; + } else if (message == UI_MSG_MOUSE_DRAG) { + int cursor = vertical ? element->window->cursorY : element->window->cursorX; + int splitterSize = UI_SIZE_SPLITTER * element->window->scale; + int space = (vertical ? UI_RECT_HEIGHT(splitPane->e.bounds) : UI_RECT_WIDTH(splitPane->e.bounds)) - splitterSize; + float oldWeight = splitPane->weight; + splitPane->weight = (float) (cursor - splitterSize / 2 - (vertical ? splitPane->e.bounds.t : splitPane->e.bounds.l)) / space; + if (splitPane->weight < 0.05f) splitPane->weight = 0.05f; + if (splitPane->weight > 0.95f) splitPane->weight = 0.95f; + + if (element->next->next->messageClass == _UISplitPaneMessage + && (element->next->next->flags & UI_SPLIT_PANE_VERTICAL) == (splitPane->e.flags & UI_SPLIT_PANE_VERTICAL)) { + UISplitPane *subSplitPane = (UISplitPane *) element->next->next; + subSplitPane->weight = (splitPane->weight - oldWeight - subSplitPane->weight + oldWeight * subSplitPane->weight) / (-1 + splitPane->weight); + if (subSplitPane->weight < 0.05f) subSplitPane->weight = 0.05f; + if (subSplitPane->weight > 0.95f) subSplitPane->weight = 0.95f; + } + + UIElementRefresh(&splitPane->e); + } + + return 0; +} + +int _UISplitPaneMessage(UIElement *element, UIMessage message, int di, void *dp) { + UISplitPane *splitPane = (UISplitPane *) element; + bool vertical = splitPane->e.flags & UI_SPLIT_PANE_VERTICAL; + + if (message == UI_MSG_LAYOUT) { + UIElement *splitter = element->children; + UI_ASSERT(splitter); + UIElement *left = splitter->next; + UI_ASSERT(left); + UIElement *right = left->next; + UI_ASSERT(right); + UI_ASSERT(!right->next); + + int splitterSize = UI_SIZE_SPLITTER * element->window->scale; + int space = (vertical ? UI_RECT_HEIGHT(element->bounds) : UI_RECT_WIDTH(element->bounds)) - splitterSize; + int leftSize = space * splitPane->weight; + int rightSize = space - leftSize; + + if (vertical) { + UIElementMove(left, UI_RECT_4(element->bounds.l, element->bounds.r, element->bounds.t, element->bounds.t + leftSize), false); + UIElementMove(splitter, UI_RECT_4(element->bounds.l, element->bounds.r, element->bounds.t + leftSize, element->bounds.t + leftSize + splitterSize), false); + UIElementMove(right, UI_RECT_4(element->bounds.l, element->bounds.r, element->bounds.b - rightSize, element->bounds.b), false); + } else { + UIElementMove(left, UI_RECT_4(element->bounds.l, element->bounds.l + leftSize, element->bounds.t, element->bounds.b), false); + UIElementMove(splitter, UI_RECT_4(element->bounds.l + leftSize, element->bounds.l + leftSize + splitterSize, element->bounds.t, element->bounds.b), false); + UIElementMove(right, UI_RECT_4(element->bounds.r - rightSize, element->bounds.r, element->bounds.t, element->bounds.b), false); + } + } + + return 0; +} + +UISplitPane *UISplitPaneCreate(UIElement *parent, uint32_t flags, float weight) { + UISplitPane *splitPane = (UISplitPane *) UIElementCreate(sizeof(UISplitPane), parent, flags, _UISplitPaneMessage, "Split Pane"); + splitPane->weight = weight; + UIElementCreate(sizeof(UIElement), &splitPane->e, 0, _UISplitterMessage, "Splitter"); + return splitPane; +} + +int _UITabPaneMessage(UIElement *element, UIMessage message, int di, void *dp) { + UITabPane *tabPane = (UITabPane *) element; + + if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + UIRectangle top = element->bounds; + top.b = top.t + UI_SIZE_BUTTON_HEIGHT * element->window->scale; + UIDrawRectangle(painter, top, ui.theme.panel1, ui.theme.border, UI_RECT_4(0, 0, 0, 1)); + + UIRectangle tab = top; + tab.l += UI_SIZE_TAB_PANE_SPACE_LEFT * element->window->scale; + tab.t += UI_SIZE_TAB_PANE_SPACE_TOP * element->window->scale; + + int position = 0; + int index = 0; + + while (true) { + int end = position; + for (; tabPane->tabs[end] != '\t' && tabPane->tabs[end]; end++); + + int width = UIMeasureStringWidth(tabPane->tabs, end - position); + tab.r = tab.l + width + UI_SIZE_BUTTON_PADDING; + + uint32_t color = tabPane->active == index ? ui.theme.buttonPressed : ui.theme.buttonNormal; + + UIRectangle t = tab; + + if (tabPane->active == index) { + t.b++; + t.t--; + } else { + t.t++; + } + + UIDrawRectangle(painter, t, color, ui.theme.border, UI_RECT_1(1)); + UIDrawString(painter, tab, tabPane->tabs + position, end - position, ui.theme.text, UI_ALIGN_CENTER, NULL); + tab.l = tab.r - 1; + + if (tabPane->tabs[end] == '\t') { + position = end + 1; + index++; + } else { + break; + } + } + } else if (message == UI_MSG_LEFT_DOWN) { + UIRectangle tab = element->bounds; + tab.b = tab.t + UI_SIZE_BUTTON_HEIGHT * element->window->scale; + tab.l += UI_SIZE_TAB_PANE_SPACE_LEFT * element->window->scale; + tab.t += UI_SIZE_TAB_PANE_SPACE_TOP * element->window->scale; + + int position = 0; + int index = 0; + + while (true) { + int end = position; + for (; tabPane->tabs[end] != '\t' && tabPane->tabs[end]; end++); + + int width = UIMeasureStringWidth(tabPane->tabs, end - position); + tab.r = tab.l + width + UI_SIZE_BUTTON_PADDING; + + if (UIRectangleContains(tab, element->window->cursorX, element->window->cursorY)) { + tabPane->active = index; + UIElementMessage(element, UI_MSG_LAYOUT, 0, 0); + UIElementRepaint(element, NULL); + break; + } + + tab.l = tab.r - 1; + + if (tabPane->tabs[end] == '\t') { + position = end + 1; + index++; + } else { + break; + } + } + } else if (message == UI_MSG_LAYOUT) { + UIElement *child = element->children; + int index = 0; + + UIRectangle content = element->bounds; + content.t += UI_SIZE_BUTTON_HEIGHT * element->window->scale; + + while (child) { + if (tabPane->active == index) { + child->flags &= ~UI_ELEMENT_HIDE; + UIElementMove(child, content, false); + UIElementMessage(child, UI_MSG_TAB_SELECTED, 0, 0); + } else { + child->flags |= UI_ELEMENT_HIDE; + } + + child = child->next; + index++; + } + } else if (message == UI_MSG_DESTROY) { + UI_FREE(tabPane->tabs); + } + + return 0; +} + +UITabPane *UITabPaneCreate(UIElement *parent, uint32_t flags, const char *tabs) { + UITabPane *tabPane = (UITabPane *) UIElementCreate(sizeof(UITabPane), parent, flags, _UITabPaneMessage, "Tab Pane"); + tabPane->tabs = UIStringCopy(tabs, -1); + return tabPane; +} + +int _UISpacerMessage(UIElement *element, UIMessage message, int di, void *dp) { + UISpacer *spacer = (UISpacer *) element; + + if (message == UI_MSG_GET_HEIGHT) { + return spacer->height * element->window->scale; + } else if (message == UI_MSG_GET_WIDTH) { + return spacer->width * element->window->scale; + } else if (message == UI_MSG_PAINT && (element->flags & UI_SPACER_LINE)) { + UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.border); + } + + return 0; +} + +UISpacer *UISpacerCreate(UIElement *parent, uint32_t flags, int width, int height) { + UISpacer *spacer = (UISpacer *) UIElementCreate(sizeof(UISpacer), parent, flags, _UISpacerMessage, "Spacer"); + spacer->width = width; + spacer->height = height; + return spacer; +} + +int _UIScrollBarMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIScrollBar *scrollBar = (UIScrollBar *) element; + + if (message == UI_MSG_GET_WIDTH || message == UI_MSG_GET_HEIGHT) { + return UI_SIZE_SCROLL_BAR * element->window->scale; + } else if (message == UI_MSG_LAYOUT) { + UIElement *up = element->children; + UIElement *thumb = up->next; + UIElement *down = thumb->next; + + if (scrollBar->page >= scrollBar->maximum || scrollBar->maximum <= 0 || scrollBar->page <= 0) { + up->flags |= UI_ELEMENT_HIDE; + thumb->flags |= UI_ELEMENT_HIDE; + down->flags |= UI_ELEMENT_HIDE; + + scrollBar->position = 0; + } else { + up->flags &= ~UI_ELEMENT_HIDE; + thumb->flags &= ~UI_ELEMENT_HIDE; + down->flags &= ~UI_ELEMENT_HIDE; + + int size = scrollBar->horizontal ? UI_RECT_WIDTH(element->bounds) : UI_RECT_HEIGHT(element->bounds); + int thumbSize = size * scrollBar->page / scrollBar->maximum; + + if (thumbSize < UI_SIZE_SCROLL_MINIMUM_THUMB * element->window->scale) { + thumbSize = UI_SIZE_SCROLL_MINIMUM_THUMB * element->window->scale; + } + + if (scrollBar->position < 0) { + scrollBar->position = 0; + } else if (scrollBar->position > scrollBar->maximum - scrollBar->page) { + scrollBar->position = scrollBar->maximum - scrollBar->page; + } + + int thumbPosition = scrollBar->position / (scrollBar->maximum - scrollBar->page) * (size - thumbSize); + + if (scrollBar->position == scrollBar->maximum - scrollBar->page) { + thumbPosition = size - thumbSize; + } + + if (scrollBar->horizontal) { + UIRectangle r = element->bounds; + r.r = r.l + thumbPosition; + UIElementMove(up, r, false); + r.l = r.r, r.r = r.l + thumbSize; + UIElementMove(thumb, r, false); + r.l = r.r, r.r = element->bounds.r; + UIElementMove(down, r, false); + } else { + UIRectangle r = element->bounds; + r.b = r.t + thumbPosition; + UIElementMove(up, r, false); + r.t = r.b, r.b = r.t + thumbSize; + UIElementMove(thumb, r, false); + r.t = r.b, r.b = element->bounds.b; + UIElementMove(down, r, false); + } + } + } else if (message == UI_MSG_PAINT) { + if (scrollBar->page >= scrollBar->maximum || scrollBar->maximum <= 0 || scrollBar->page <= 0) { + UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel1); + } + } else if (message == UI_MSG_MOUSE_WHEEL) { + scrollBar->position += di; + UIElementRefresh(element); + UIElementMessage(element->parent, UI_MSG_SCROLLED, 0, 0); + return 1; + } + + return 0; +} + +int _UIScrollUpDownMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIScrollBar *scrollBar = (UIScrollBar *) element->parent; + bool isDown = element->cp; + + if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + uint32_t color = element == element->window->pressed ? ui.theme.buttonPressed + : element == element->window->hovered ? ui.theme.buttonHovered : ui.theme.panel2; + UIDrawRectangle(painter, element->bounds, color, ui.theme.border, UI_RECT_1(0)); + + if (scrollBar->horizontal) { + UIDrawGlyph(painter, isDown ? (element->bounds.r - ui.glyphWidth - 2 * element->window->scale) + : (element->bounds.l + 2 * element->window->scale), + (element->bounds.t + element->bounds.b - ui.glyphHeight) / 2, + isDown ? 26 : 27, ui.theme.text); + } else { + UIDrawGlyph(painter, (element->bounds.l + element->bounds.r - ui.glyphWidth) / 2 + 1, + isDown ? (element->bounds.b - ui.glyphHeight - 2 * element->window->scale) + : (element->bounds.t + 2 * element->window->scale), + isDown ? 25 : 24, ui.theme.text); + } + } else if (message == UI_MSG_UPDATE) { + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_LEFT_DOWN) { + UIElementAnimate(element, false); + scrollBar->lastAnimateTime = UI_CLOCK(); + } else if (message == UI_MSG_LEFT_UP) { + UIElementAnimate(element, true); + } else if (message == UI_MSG_ANIMATE) { + UI_CLOCK_T previous = scrollBar->lastAnimateTime; + UI_CLOCK_T current = UI_CLOCK(); + UI_CLOCK_T delta = current - previous; + double deltaSeconds = (double) delta / UI_CLOCKS_PER_SECOND; + if (deltaSeconds > 0.1) deltaSeconds = 0.1; + double deltaPixels = deltaSeconds * scrollBar->page * 3; + scrollBar->lastAnimateTime = current; + if (isDown) scrollBar->position += deltaPixels; + else scrollBar->position -= deltaPixels; + UIElementRefresh(&scrollBar->e); + UIElementMessage(scrollBar->e.parent, UI_MSG_SCROLLED, 0, 0); + } + + return 0; +} + +int _UIScrollThumbMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIScrollBar *scrollBar = (UIScrollBar *) element->parent; + + if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + uint32_t color = element == element->window->pressed ? ui.theme.buttonPressed + : element == element->window->hovered ? ui.theme.buttonHovered : ui.theme.buttonNormal; + UIDrawRectangle(painter, element->bounds, color, ui.theme.border, UI_RECT_1(2)); + } else if (message == UI_MSG_UPDATE) { + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_MOUSE_DRAG && element->window->pressedButton == 1) { + if (!scrollBar->inDrag) { + scrollBar->inDrag = true; + + if (scrollBar->horizontal) { + scrollBar->dragOffset = element->bounds.l - scrollBar->e.bounds.l - element->window->cursorX; + } else { + scrollBar->dragOffset = element->bounds.t - scrollBar->e.bounds.t - element->window->cursorY; + } + } + + int thumbPosition = (scrollBar->horizontal ? element->window->cursorX : element->window->cursorY) + scrollBar->dragOffset; + int size = scrollBar->horizontal ? (UI_RECT_WIDTH(scrollBar->e.bounds) - UI_RECT_WIDTH(element->bounds)) + : (UI_RECT_HEIGHT(scrollBar->e.bounds) - UI_RECT_HEIGHT(element->bounds)); + scrollBar->position = (double) thumbPosition / size * (scrollBar->maximum - scrollBar->page); + UIElementRefresh(&scrollBar->e); + UIElementMessage(scrollBar->e.parent, UI_MSG_SCROLLED, 0, 0); + } else if (message == UI_MSG_LEFT_UP) { + scrollBar->inDrag = false; + } + + return 0; +} + +UIScrollBar *UIScrollBarCreate(UIElement *parent, uint32_t flags) { + UIScrollBar *scrollBar = (UIScrollBar *) UIElementCreate(sizeof(UIScrollBar), parent, flags, _UIScrollBarMessage, "Scroll Bar"); + bool horizontal = scrollBar->horizontal = flags & UI_SCROLL_BAR_HORIZONTAL; + UIElementCreate(sizeof(UIElement), &scrollBar->e, flags, _UIScrollUpDownMessage, !horizontal ? "Scroll Up" : "Scroll Left")->cp = (void *) (uintptr_t) 0; + UIElementCreate(sizeof(UIElement), &scrollBar->e, flags, _UIScrollThumbMessage, "Scroll Thumb"); + UIElementCreate(sizeof(UIElement), &scrollBar->e, flags, _UIScrollUpDownMessage, !horizontal ? "Scroll Down" : "Scroll Right")->cp = (void *) (uintptr_t) 1; + return scrollBar; +} + +bool _UICharIsAlpha(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +bool _UICharIsDigit(char c) { + return c >= '0' && c <= '9'; +} + +bool _UICharIsAlphaOrDigitOrUnderscore(char c) { + return _UICharIsAlpha(c) || _UICharIsDigit(c) || c == '_'; +} + +int UICodeHitTest(UICode *code, int x, int y) { + x -= code->e.bounds.l; + + if (x < 0 || x >= UI_RECT_WIDTH(code->e.bounds) - UI_SIZE_SCROLL_BAR * code->e.window->scale) { + return 0; + } + + y -= code->e.bounds.t - code->vScroll->position; + + int lineHeight = UIMeasureStringHeight(); + + if (y < 0 || y >= lineHeight * code->lineCount) { + return 0; + } + + int line = y / lineHeight + 1; + + if (x < UI_SIZE_CODE_MARGIN && (~code->e.flags & UI_CODE_NO_MARGIN)) { + return -line; + } else { + return line; + } +} + +int UIDrawStringHighlighted(UIPainter *painter, UIRectangle lineBounds, const char *string, ptrdiff_t bytes, int tabSize) { + if (bytes == -1) bytes = _UIStringLength(string); + if (bytes > 10000) bytes = 10000; + + uint32_t colors[] = { + ui.theme.codeDefault, + ui.theme.codeComment, + ui.theme.codeString, + ui.theme.codeNumber, + ui.theme.codeOperator, + ui.theme.codePreprocessor, + }; + + int x = lineBounds.l; + int y = (lineBounds.t + lineBounds.b - UIMeasureStringHeight()) / 2; + int ti = 0; + int lexState = 0; + bool inComment = false, inIdentifier = false, inChar = false, startedString = false; + uint32_t last = 0; + + while (bytes--) { + char c = *string++; + + last <<= 8; + last |= c; + + if (lexState == 4) { + lexState = 0; + } else if (lexState == 1) { + if ((last & 0xFF0000) == ('*' << 16) && (last & 0xFF00) == ('/' << 8) && inComment) { + lexState = 0, inComment = false; + } + } else if (lexState == 3) { + if (!_UICharIsAlpha(c) && !_UICharIsDigit(c)) { + lexState = 0; + } + } else if (lexState == 2) { + if (!startedString) { + if (!inChar && ((last >> 8) & 0xFF) == '"' && ((last >> 16) & 0xFF) != '\\') { + lexState = 0; + } else if (inChar && ((last >> 8) & 0xFF) == '\'' && ((last >> 16) & 0xFF) != '\\') { + lexState = 0; + } + } + + startedString = false; + } + + if (lexState == 0) { + if (c == '#') { + lexState = 5; + } else if (c == '/' && *string == '/') { + lexState = 1; + } else if (c == '/' && *string == '*') { + lexState = 1, inComment = true; + } else if (c == '"') { + lexState = 2; + inChar = false; + startedString = true; + } else if (c == '\'') { + lexState = 2; + inChar = true; + startedString = true; + } else if (_UICharIsDigit(c) && !inIdentifier) { + lexState = 3; + } else if (!_UICharIsAlpha(c) && !_UICharIsDigit(c)) { + lexState = 4; + inIdentifier = false; + } else { + inIdentifier = true; + } + } + + if (c == '\t') { + x += ui.glyphWidth, ti++; + while (ti % tabSize) x += ui.glyphWidth, ti++; + } else { + UIDrawGlyph(painter, x, y, c, colors[lexState]); + x += ui.glyphWidth, ti++; + } + } + + return x; +} + +int _UICodeMessage(UIElement *element, UIMessage message, int di, void *dp) { + UICode *code = (UICode *) element; + + if (message == UI_MSG_LAYOUT) { + if (code->moveScrollToFocusNextLayout) { + code->vScroll->position = (code->focused + 0.5) * UIMeasureStringHeight() - UI_RECT_HEIGHT(code->e.bounds) / 2; + } + + UIRectangle scrollBarBounds = element->bounds; + scrollBarBounds.l = scrollBarBounds.r - UI_SIZE_SCROLL_BAR * code->e.window->scale; + code->vScroll->maximum = code->lineCount * UIMeasureStringHeight(); + code->vScroll->page = UI_RECT_HEIGHT(element->bounds); + UIElementMove(&code->vScroll->e, scrollBarBounds, true); + } else if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + UIRectangle lineBounds = element->bounds; + lineBounds.r -= UI_SIZE_SCROLL_BAR * code->e.window->scale; + + if (~code->e.flags & UI_CODE_NO_MARGIN) { + lineBounds.l += UI_SIZE_CODE_MARGIN + UI_SIZE_CODE_MARGIN_GAP; + } + + int lineHeight = UIMeasureStringHeight(); + lineBounds.t -= (int64_t) code->vScroll->position % lineHeight; + + UIDrawBlock(painter, element->bounds, ui.theme.codeBackground); + + for (int i = code->vScroll->position / lineHeight; i < code->lineCount; i++) { + if (lineBounds.t > element->clip.b) { + break; + } + + lineBounds.b = lineBounds.t + lineHeight; + + if (~code->e.flags & UI_CODE_NO_MARGIN) { + char string[16]; + int p = 16; + int lineNumber = i + 1; + + while (lineNumber) { + string[--p] = (lineNumber % 10) + '0'; + lineNumber /= 10; + } + + UIRectangle marginBounds = lineBounds; + marginBounds.r = marginBounds.l - UI_SIZE_CODE_MARGIN_GAP; + marginBounds.l -= UI_SIZE_CODE_MARGIN + UI_SIZE_CODE_MARGIN_GAP; + + uint32_t marginColor = UIElementMessage(element, UI_MSG_CODE_GET_MARGIN_COLOR, i + 1, 0); + + if (marginColor) { + UIDrawBlock(painter, marginBounds, marginColor); + } + + UIDrawString(painter, marginBounds, string + p, 16 - p, ui.theme.codeDefault, UI_ALIGN_RIGHT, NULL); + } + + if (code->focused == i) { + UIDrawBlock(painter, lineBounds, ui.theme.codeFocused); + } + + int x = UIDrawStringHighlighted(painter, lineBounds, code->content + code->lines[i].offset, code->lines[i].bytes, code->tabSize); + int y = (lineBounds.t + lineBounds.b - UIMeasureStringHeight()) / 2; + + UICodeDecorateLine m = { 0 }; + m.x = x, m.y = y, m.bounds = lineBounds, m.index = i + 1, m.painter = painter; + UIElementMessage(element, UI_MSG_CODE_DECORATE_LINE, 0, &m); + + lineBounds.t += lineHeight; + } + } else if (message == UI_MSG_SCROLLED) { + code->moveScrollToFocusNextLayout = false; + UIElementRefresh(element); + } else if (message == UI_MSG_MOUSE_WHEEL) { + return UIElementMessage(&code->vScroll->e, message, di, dp); + } else if (message == UI_MSG_GET_CURSOR) { + if (UICodeHitTest(code, element->window->cursorX, element->window->cursorY) < 0) { + return UI_CURSOR_FLIPPED_ARROW; + } + } else if (message == UI_MSG_DESTROY) { + UI_FREE(code->content); + UI_FREE(code->lines); + } + + return 0; +} + +void UICodeFocusLine(UICode *code, int index) { + code->focused = index - 1; + code->moveScrollToFocusNextLayout = true; +} + +void UICodeInsertContent(UICode *code, const char *content, ptrdiff_t byteCount, bool replace) { + if (byteCount == -1) { + byteCount = _UIStringLength(content); + } + + if (byteCount > 1000000000) { + byteCount = 1000000000; + } + + if (replace) { + UI_FREE(code->content); + UI_FREE(code->lines); + code->content = NULL; + code->lines = NULL; + code->contentBytes = 0; + code->lineCount = 0; + } + + code->content = (char *) UI_REALLOC(code->content, code->contentBytes + byteCount); + + if (!byteCount) { + return; + } + + int lineCount = content[byteCount - 1] != '\n'; + + for (int i = 0; i < byteCount; i++) { + code->content[i + code->contentBytes] = content[i]; + + if (content[i] == '\n') { + lineCount++; + } + } + + code->lines = (UICodeLine *) UI_REALLOC(code->lines, sizeof(UICodeLine) * (code->lineCount + lineCount)); + int offset = 0, lineIndex = 0; + + for (intptr_t i = 0; i <= byteCount && lineIndex < lineCount; i++) { + if (content[i] == '\n' || i == byteCount) { + UICodeLine line = { 0 }; + line.offset = offset + code->contentBytes; + line.bytes = i - offset; + code->lines[code->lineCount + lineIndex] = line; + lineIndex++; + offset = i + 1; + } + } + + code->lineCount += lineCount; + code->contentBytes += byteCount; + + if (!replace) { + code->vScroll->position = code->lineCount * UIMeasureStringHeight(); + } +} + +UICode *UICodeCreate(UIElement *parent, uint32_t flags) { + UICode *code = (UICode *) UIElementCreate(sizeof(UICode), parent, flags, _UICodeMessage, "Code"); + code->vScroll = UIScrollBarCreate(&code->e, 0); + code->focused = -1; + code->tabSize = 4; + return code; +} + +int _UIGaugeMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIGauge *gauge = (UIGauge *) element; + + if (message == UI_MSG_GET_HEIGHT) { + return UI_SIZE_GAUGE_HEIGHT * element->window->scale; + } else if (message == UI_MSG_GET_WIDTH) { + return UI_SIZE_GAUGE_WIDTH * element->window->scale; + } else if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + UIDrawRectangle(painter, element->bounds, ui.theme.buttonNormal, ui.theme.border, UI_RECT_1(1)); + UIRectangle filled = UIRectangleAdd(element->bounds, UI_RECT_1I(1)); + filled.r = filled.l + UI_RECT_WIDTH(filled) * gauge->position; + UIDrawBlock(painter, filled, ui.theme.selected); + } + + return 0; +} + +UIGauge *UIGaugeCreate(UIElement *parent, uint32_t flags) { + return (UIGauge *) UIElementCreate(sizeof(UIGauge), parent, flags, _UIGaugeMessage, "Gauge"); +} + +int _UISliderMessage(UIElement *element, UIMessage message, int di, void *dp) { + UISlider *slider = (UISlider *) element; + + if (message == UI_MSG_GET_HEIGHT) { + return UI_SIZE_SLIDER_HEIGHT * element->window->scale; + } else if (message == UI_MSG_GET_WIDTH) { + return UI_SIZE_SLIDER_WIDTH * element->window->scale; + } else if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + UIRectangle bounds = element->bounds; + int centerY = (bounds.t + bounds.b) / 2; + int trackSize = UI_SIZE_SLIDER_TRACK * element->window->scale; + int thumbSize = UI_SIZE_SLIDER_THUMB * element->window->scale; + int thumbPosition = (UI_RECT_WIDTH(bounds) - thumbSize) * slider->position; + UIRectangle track = UI_RECT_4(bounds.l, bounds.r, centerY - (trackSize + 1) / 2, centerY + trackSize / 2); + UIDrawRectangle(painter, track, ui.theme.buttonNormal, ui.theme.border, UI_RECT_1(1)); + bool pressed = element == element->window->pressed; + bool hovered = element == element->window->hovered; + bool disabled = element->flags & UI_ELEMENT_DISABLED; + uint32_t color = disabled ? ui.theme.buttonDisabled : pressed ? ui.theme.buttonPressed : hovered ? ui.theme.buttonHovered : ui.theme.buttonNormal; + UIRectangle thumb = UI_RECT_4(bounds.l + thumbPosition, bounds.l + thumbPosition + thumbSize, centerY - (thumbSize + 1) / 2, centerY + thumbSize / 2); + UIDrawRectangle(painter, thumb, color, ui.theme.border, UI_RECT_1(1)); + } else if (message == UI_MSG_LEFT_DOWN || (message == UI_MSG_MOUSE_DRAG && element->window->pressedButton == 1)) { + UIRectangle bounds = element->bounds; + int thumbSize = UI_SIZE_SLIDER_THUMB * element->window->scale; + slider->position = (float) (element->window->cursorX - thumbSize / 2 - bounds.l) / (UI_RECT_WIDTH(bounds) - thumbSize); + if (slider->steps > 1) slider->position = (int) (slider->position * (slider->steps - 1) + 0.5f) / (float) (slider->steps - 1); + if (slider->position < 0) slider->position = 0; + if (slider->position > 1) slider->position = 1; + UIElementMessage(element, UI_MSG_VALUE_CHANGED, 0, 0); + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_UPDATE) { + UIElementRepaint(element, NULL); + } + + return 0; +} + +UISlider *UISliderCreate(UIElement *parent, uint32_t flags) { + return (UISlider *) UIElementCreate(sizeof(UISlider), parent, flags, _UISliderMessage, "Slider"); +} + +int UITableHitTest(UITable *table, int x, int y) { + x -= table->e.bounds.l; + + if (x < 0 || x >= UI_RECT_WIDTH(table->e.bounds) - UI_SIZE_SCROLL_BAR * table->e.window->scale) { + return -1; + } + + y -= (table->e.bounds.t + UI_SIZE_TABLE_HEADER * table->e.window->scale) - table->vScroll->position; + + int rowHeight = UI_SIZE_TABLE_ROW * table->e.window->scale; + + if (y < 0 || y >= rowHeight * table->itemCount) { + return -1; + } + + return y / rowHeight; +} + +bool UITableEnsureVisible(UITable *table, int index) { + int rowHeight = UI_SIZE_TABLE_ROW * table->e.window->scale; + int y = index * rowHeight; + y -= table->vScroll->position; + int height = UI_RECT_HEIGHT(table->e.bounds) - UI_SIZE_TABLE_HEADER * table->e.window->scale - rowHeight; + + if (y < 0) { + table->vScroll->position += y; + UIElementRefresh(&table->e); + return true; + } else if (y > height) { + table->vScroll->position -= height - y; + UIElementRefresh(&table->e); + return true; + } else { + return false; + } +} + +void UITableResizeColumns(UITable *table) { + int position = 0; + int count = 0; + + while (true) { + int end = position; + for (; table->columns[end] != '\t' && table->columns[end]; end++); + count++; + if (table->columns[end] == '\t') position = end + 1; + else break; + } + + UI_FREE(table->columnWidths); + table->columnWidths = (int *) UI_MALLOC(count * sizeof(int)); + table->columnCount = count; + + position = 0; + + char buffer[256]; + UITableGetItem m = { 0 }; + m.buffer = buffer; + m.bufferBytes = sizeof(buffer); + + while (true) { + int end = position; + for (; table->columns[end] != '\t' && table->columns[end]; end++); + + int longest = UIMeasureStringWidth(table->columns + position, end - position); + + for (int i = 0; i < table->itemCount; i++) { + m.index = i; + int bytes = UIElementMessage(&table->e, UI_MSG_TABLE_GET_ITEM, 0, &m); + int width = UIMeasureStringWidth(buffer, bytes); + + if (width > longest) { + longest = width; + } + } + + table->columnWidths[m.column] = longest; + m.column++; + if (table->columns[end] == '\t') position = end + 1; + else break; + } +} + +int _UITableMessage(UIElement *element, UIMessage message, int di, void *dp) { + UITable *table = (UITable *) element; + + if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + UIRectangle bounds = element->bounds; + bounds.r -= UI_SIZE_SCROLL_BAR * element->window->scale; + UIDrawBlock(painter, bounds, ui.theme.panel2); + char buffer[256]; + UIRectangle row = bounds; + int rowHeight = UI_SIZE_TABLE_ROW * element->window->scale; + UITableGetItem m = { 0 }; + m.buffer = buffer; + m.bufferBytes = sizeof(buffer); + row.t += UI_SIZE_TABLE_HEADER * table->e.window->scale; + row.t -= (int64_t) table->vScroll->position % rowHeight; + int hovered = UITableHitTest(table, element->window->cursorX, element->window->cursorY); + + for (int i = table->vScroll->position / rowHeight; i < table->itemCount; i++) { + if (row.t > element->clip.b) { + break; + } + + row.b = row.t + rowHeight; + m.index = i; + m.isSelected = false; + m.column = 0; + int bytes = UIElementMessage(element, UI_MSG_TABLE_GET_ITEM, 0, &m); + uint32_t textColor = ui.theme.text; + + if (m.isSelected) { + UIDrawBlock(painter, row, ui.theme.selected); + textColor = ui.theme.textSelected; + } else if (hovered == i) { + UIDrawBlock(painter, row, ui.theme.buttonHovered); + } + + UIRectangle cell = row; + cell.l += UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale; + + for (int j = 0; j < table->columnCount; j++) { + if (j) { + m.column = j; + bytes = UIElementMessage(element, UI_MSG_TABLE_GET_ITEM, 0, &m); + } + + cell.r = cell.l + table->columnWidths[j]; + if ((size_t) bytes > m.bufferBytes && bytes > 0) bytes = m.bufferBytes; + UIDrawString(painter, cell, buffer, bytes, textColor, UI_ALIGN_LEFT, NULL); + cell.l += table->columnWidths[j] + UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale; + } + + row.t += rowHeight; + } + + UIRectangle header = bounds; + header.b = header.t + UI_SIZE_TABLE_HEADER * table->e.window->scale; + UIDrawRectangle(painter, header, ui.theme.panel1, ui.theme.border, UI_RECT_4(0, 0, 0, 1)); + header.l += UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale; + + int position = 0; + int index = 0; + + if (table->columnCount) { + while (true) { + int end = position; + for (; table->columns[end] != '\t' && table->columns[end]; end++); + + header.r = header.l + table->columnWidths[index]; + UIDrawString(painter, header, table->columns + position, end - position, ui.theme.text, UI_ALIGN_LEFT, NULL); + header.l += table->columnWidths[index] + UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale; + + if (table->columns[end] == '\t') { + position = end + 1; + index++; + } else { + break; + } + } + } + } else if (message == UI_MSG_LAYOUT) { + UIRectangle scrollBarBounds = element->bounds; + scrollBarBounds.l = scrollBarBounds.r - UI_SIZE_SCROLL_BAR * element->window->scale; + table->vScroll->maximum = table->itemCount * UI_SIZE_TABLE_ROW * element->window->scale; + table->vScroll->page = UI_RECT_HEIGHT(element->bounds) - UI_SIZE_TABLE_HEADER * table->e.window->scale; + UIElementMove(&table->vScroll->e, scrollBarBounds, true); + } else if (message == UI_MSG_MOUSE_MOVE || message == UI_MSG_UPDATE) { + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_SCROLLED) { + UIElementRefresh(element); + } else if (message == UI_MSG_MOUSE_WHEEL) { + return UIElementMessage(&table->vScroll->e, message, di, dp); + } else if (message == UI_MSG_DESTROY) { + UI_FREE(table->columns); + UI_FREE(table->columnWidths); + } + + return 0; +} + +UITable *UITableCreate(UIElement *parent, uint32_t flags, const char *columns) { + UITable *table = (UITable *) UIElementCreate(sizeof(UITable), parent, flags, _UITableMessage, "Table"); + table->vScroll = UIScrollBarCreate(&table->e, 0); + table->columns = UIStringCopy(columns, -1); + return table; +} + +void UITextboxReplace(UITextbox *textbox, const char *text, ptrdiff_t bytes, bool sendChangedMessage) { + if (bytes == -1) { + bytes = _UIStringLength(text); + } + + int deleteFrom = textbox->carets[0], deleteTo = textbox->carets[1]; + + if (deleteFrom > deleteTo) { + UI_SWAP(int, deleteFrom, deleteTo); + } + + for (int i = deleteTo; i < textbox->bytes; i++) { + textbox->string[i - deleteTo + deleteFrom] = textbox->string[i]; + } + + textbox->bytes -= deleteTo - deleteFrom; + textbox->carets[0] = textbox->carets[1] = deleteFrom; + + textbox->string = (char *) UI_REALLOC(textbox->string, textbox->bytes + bytes); + + for (int i = textbox->bytes + bytes - 1; i >= textbox->carets[0] + bytes; i--) { + textbox->string[i] = textbox->string[i - bytes]; + } + + for (int i = textbox->carets[0]; i < textbox->carets[0] + bytes; i++) { + textbox->string[i] = text[i - textbox->carets[0]]; + } + + textbox->bytes += bytes; + textbox->carets[0] += bytes; + textbox->carets[1] = textbox->carets[0]; + + if (sendChangedMessage) { + UIElementMessage(&textbox->e, UI_MSG_VALUE_CHANGED, 0, 0); + } +} + +void UITextboxClear(UITextbox *textbox, bool sendChangedMessage) { + textbox->carets[1] = 0; + textbox->carets[0] = textbox->bytes; + UITextboxReplace(textbox, "", 0, sendChangedMessage); +} + +void UITextboxMoveCaret(UITextbox *textbox, bool backward, bool word) { + while (true) { + if (textbox->carets[0] > 0 && backward) { + textbox->carets[0]--; + } else if (textbox->carets[0] < textbox->bytes && !backward) { + textbox->carets[0]++; + } else { + return; + } + + if (!word) { + return; + } else if (textbox->carets[0] != textbox->bytes && textbox->carets[0] != 0) { + char c1 = textbox->string[textbox->carets[0] - 1]; + char c2 = textbox->string[textbox->carets[0]]; + + if (_UICharIsAlphaOrDigitOrUnderscore(c1) != _UICharIsAlphaOrDigitOrUnderscore(c2)) { + return; + } + } + } +} + +int _UITextboxMessage(UIElement *element, UIMessage message, int di, void *dp) { + UITextbox *textbox = (UITextbox *) element; + + if (message == UI_MSG_GET_HEIGHT) { + return UI_SIZE_TEXTBOX_HEIGHT * element->window->scale; + } else if (message == UI_MSG_GET_WIDTH) { + return UI_SIZE_TEXTBOX_WIDTH * element->window->scale; + } else if (message == UI_MSG_PAINT) { + int scaledMargin = UI_SIZE_TEXTBOX_MARGIN * element->window->scale; + int totalWidth = UIMeasureStringWidth(textbox->string, textbox->bytes) + scaledMargin * 2; + UIRectangle textBounds = UIRectangleAdd(element->bounds, UI_RECT_1I(scaledMargin)); + + if (textbox->scroll > totalWidth - UI_RECT_WIDTH(textBounds)) { + textbox->scroll = totalWidth - UI_RECT_WIDTH(textBounds); + } + + if (textbox->scroll < 0) { + textbox->scroll = 0; + } + + int caretX = UIMeasureStringWidth(textbox->string, textbox->carets[0]) - textbox->scroll; + + if (caretX < 0) { + textbox->scroll = caretX + textbox->scroll; + } else if (caretX > UI_RECT_WIDTH(textBounds)) { + textbox->scroll = caretX - UI_RECT_WIDTH(textBounds) + textbox->scroll + 1; + } + + UIPainter *painter = (UIPainter *) dp; + bool focused = element->window->focused == element; + bool disabled = element->flags & UI_ELEMENT_DISABLED; + UIDrawRectangle(painter, element->bounds, + disabled ? ui.theme.buttonDisabled : focused ? ui.theme.textboxFocused : ui.theme.textboxNormal, + ui.theme.border, UI_RECT_1(1)); +#ifdef __cplusplus + UIStringSelection selection = {}; +#else + UIStringSelection selection = { 0 }; +#endif + selection.carets[0] = textbox->carets[0]; + selection.carets[1] = textbox->carets[1]; + selection.colorBackground = ui.theme.selected; + selection.colorText = ui.theme.textSelected; + textBounds.l -= textbox->scroll; + UIDrawString(painter, textBounds, textbox->string, textbox->bytes, + disabled ? ui.theme.textDisabled : ui.theme.text, UI_ALIGN_LEFT, focused ? &selection : NULL); + } else if (message == UI_MSG_GET_CURSOR) { + return UI_CURSOR_TEXT; + } else if (message == UI_MSG_LEFT_DOWN) { + UIElementFocus(element); + } else if (message == UI_MSG_UPDATE) { + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_DESTROY) { + UI_FREE(textbox->string); + } else if (message == UI_MSG_KEY_TYPED) { + UIKeyTyped *m = (UIKeyTyped *) dp; + bool handled = true; + + if (m->code == UI_KEYCODE_BACKSPACE || m->code == UI_KEYCODE_DELETE) { + if (textbox->carets[0] == textbox->carets[1]) { + UITextboxMoveCaret(textbox, m->code == UI_KEYCODE_BACKSPACE, element->window->ctrl); + } + + UITextboxReplace(textbox, NULL, 0, true); + } else if (m->code == UI_KEYCODE_LEFT || m->code == UI_KEYCODE_RIGHT) { + UITextboxMoveCaret(textbox, m->code == UI_KEYCODE_LEFT, element->window->ctrl); + + if (!element->window->shift) { + textbox->carets[1] = textbox->carets[0]; + } + } else if (m->code == UI_KEYCODE_HOME || m->code == UI_KEYCODE_END) { + if (m->code == UI_KEYCODE_HOME) { + textbox->carets[0] = 0; + } else { + textbox->carets[0] = textbox->bytes; + } + + if (!element->window->shift) { + textbox->carets[1] = textbox->carets[0]; + } + } else if (m->code == UI_KEYCODE_LETTER('A') && element->window->ctrl) { + textbox->carets[1] = 0; + textbox->carets[0] = textbox->bytes; + } else if (m->textBytes && !element->window->alt && !element->window->ctrl && m->text[0] >= 0x20) { + UITextboxReplace(textbox, m->text, m->textBytes, true); + } else { + handled = false; + } + + if (handled) { + UIElementRepaint(element, NULL); + return 1; + } + } + + return 0; +} + +UITextbox *UITextboxCreate(UIElement *parent, uint32_t flags) { + return (UITextbox *) UIElementCreate(sizeof(UITextbox), parent, flags | UI_ELEMENT_TAB_STOP, _UITextboxMessage, "Textbox"); +} + +int _UIColorCircleMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIColorPicker *colorPicker = (UIColorPicker *) element->parent; + + if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + + int startY = element->bounds.t, endY = element->bounds.b; + int startX = element->bounds.l, endX = element->bounds.r; + int size = endY - startY; + + for (int i = startY; i < endY; i++) { + uint32_t *out = painter->bits + i * painter->width + startX; + int j = startX; + float y0 = i - startY - size / 2, x0 = -size / 2; + float angle = _UIArcTan2Float((i - startY) * 2.0f / size - 1, -1); + + do { + float distanceFromCenterSquared = x0 * x0 + y0 * y0; + float hue = (angle + 3.14159f) * 0.954929658f; + float saturation = _UISquareRootFloat(distanceFromCenterSquared * 4.0f / size / size); + + if (saturation <= 1 && UIRectangleContains(painter->clip, j, i)) { + UIColorToRGB(hue, saturation, colorPicker->value, out); + *out |= 0xFF000000; + } + + out++, j++, x0++; + + if (distanceFromCenterSquared) { + angle -= y0 / distanceFromCenterSquared; + } else { + angle = _UIArcTan2Float((i - startY) * 2.0f / size - 1, 0.01f); + } + } while (j < endX); + } + + float angle = colorPicker->hue / 0.954929658f - 3.14159f; + float radius = colorPicker->saturation * size / 2; + int cx = (startX + endX) / 2 + radius * _UICosFloat(angle); + int cy = (startY + endY) / 2 + radius * _UISinFloat(angle); + UIDrawInvert(painter, UI_RECT_4(cx - 1, cx + 1, startY, endY)); + UIDrawInvert(painter, UI_RECT_4(startX, endX, cy - 1, cy + 1)); + } else if (message == UI_MSG_GET_CURSOR) { + return UI_CURSOR_CROSS_HAIR; + } else if (message == UI_MSG_LEFT_DOWN || message == UI_MSG_MOUSE_DRAG) { + int startY = element->bounds.t, endY = element->bounds.b, cursorY = element->window->cursorY; + int startX = element->bounds.l, endX = element->bounds.r, cursorX = element->window->cursorX; + int dx = (startX + endX) / 2, dy = (startY + endY) / 2; + int size = endY - startY; + + float angle = _UIArcTan2Float((cursorY - startY) * 2.0f / size - 1, (cursorX - startX) * 2.0f / size - 1); + float distanceFromCenterSquared = (cursorX - dx) * (cursorX - dx) + (cursorY - dy) * (cursorY - dy); + colorPicker->hue = (angle + 3.14159f) * 0.954929658f; + colorPicker->saturation = _UISquareRootFloat(distanceFromCenterSquared * 4.0f / size / size);; + if (colorPicker->saturation > 1) colorPicker->saturation = 1; + + UIElementMessage(&colorPicker->e, UI_MSG_VALUE_CHANGED, 0, 0); + UIElementRepaint(&colorPicker->e, NULL); + } + + return 0; +} + +int _UIColorSliderMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIColorPicker *colorPicker = (UIColorPicker *) element->parent; + float opacitySlider = element->flags & 1; + + if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + + int startY = element->bounds.t, endY = element->bounds.b; + int startX = element->bounds.l, endX = element->bounds.r; + int size = endY - startY; + + for (int i = startY; i < endY; i++) { + if (i < painter->clip.t || i >= painter->clip.b) continue; + uint32_t *out = painter->bits + i * painter->width + startX; + int j = element->clip.l; + uint32_t color; + float p = 1.0f - (float) (i - startY) / size; + + if (opacitySlider) { + UIColorToRGB(colorPicker->hue, colorPicker->saturation, colorPicker->value, &color); + color = UI_COLOR_FROM_FLOAT(p * (UI_COLOR_RED_F(color) - 0.5f) + 0.5f, + p * (UI_COLOR_GREEN_F(color) - 0.5f) + 0.5f, + p * (UI_COLOR_BLUE_F(color) - 0.5f) + 0.5f); + } else { + UIColorToRGB(colorPicker->hue, colorPicker->saturation, p, &color); + } + + color |= 0xFF000000; + + do { + *out = color; + out++, j++; + } while (j < element->clip.r); + } + + int cy = (size - 1) * (1 - (opacitySlider ? colorPicker->opacity : colorPicker->value)) + startY; + UIDrawInvert(painter, UI_RECT_4(startX, endX, cy - 1, cy + 1)); + } else if (message == UI_MSG_GET_CURSOR) { + return UI_CURSOR_CROSS_HAIR; + } else if (message == UI_MSG_LEFT_DOWN || message == UI_MSG_MOUSE_DRAG) { + int startY = element->bounds.t, endY = element->bounds.b, cursorY = element->window->cursorY; + float *value = opacitySlider ? &colorPicker->opacity : &colorPicker->value; + *value = 1 - (float) (cursorY - startY) / (endY - startY); + if (*value < 0) *value = 0; + if (*value > 1) *value = 1; + UIElementMessage(&colorPicker->e, UI_MSG_VALUE_CHANGED, 0, 0); + UIElementRepaint(&colorPicker->e, NULL); + } + + return 0; +} + +int _UIColorPickerMessage(UIElement *element, UIMessage message, int di, void *dp) { + bool hasOpacity = element->flags & UI_COLOR_PICKER_HAS_OPACITY; + + if (message == UI_MSG_GET_WIDTH) { + return (hasOpacity ? 240 : 200) * element->window->scale; + } else if (message == UI_MSG_GET_HEIGHT) { + return 160 * element->window->scale; + } else if (message == UI_MSG_LAYOUT) { + UIRectangle bounds = element->bounds; + + int sliderSize = 35 * element->window->scale; + int gap = 5 * element->window->scale; + + if (hasOpacity) { + UIElementMove(element->children, UI_RECT_4(bounds.l, bounds.r - (sliderSize + gap) * 2, bounds.t, bounds.b), false); + UIElementMove(element->children->next, UI_RECT_4(bounds.r - sliderSize * 2 - gap, bounds.r - sliderSize - gap, bounds.t, bounds.b), false); + UIElementMove(element->children->next->next, UI_RECT_4(bounds.r - sliderSize, bounds.r, bounds.t, bounds.b), false); + } else { + UIElementMove(element->children, UI_RECT_4(bounds.l, bounds.r - sliderSize - gap, bounds.t, bounds.b), false); + UIElementMove(element->children->next, UI_RECT_4(bounds.r - sliderSize, bounds.r, bounds.t, bounds.b), false); + } + } + + return 0; +} + +UIColorPicker *UIColorPickerCreate(UIElement *parent, uint32_t flags) { + UIColorPicker *colorPicker = (UIColorPicker *) UIElementCreate(sizeof(UIColorPicker), parent, flags, _UIColorPickerMessage, "ColorPicker"); + UIElementCreate(sizeof(UIElement), &colorPicker->e, 0, _UIColorCircleMessage, "ColorCircle"); + UIElementCreate(sizeof(UIElement), &colorPicker->e, 0, _UIColorSliderMessage, "ColorSlider"); + + if (flags & UI_COLOR_PICKER_HAS_OPACITY) { + UIElementCreate(sizeof(UIElement), &colorPicker->e, 1, _UIColorSliderMessage, "ColorSlider"); + } + + return colorPicker; +} + +#define UI_MDI_CHILD_CALCULATE_LAYOUT() \ + int titleSize = UI_SIZE_MDI_CHILD_TITLE * element->window->scale; \ + int borderSize = UI_SIZE_MDI_CHILD_BORDER * element->window->scale; \ + UIRectangle title = UIRectangleAdd(element->bounds, UI_RECT_4(borderSize, -borderSize, 0, 0)); \ + title.b = title.t + titleSize; \ + UIRectangle content = UIRectangleAdd(element->bounds, UI_RECT_4(borderSize, -borderSize, titleSize, -borderSize)); + +int _UIMDIChildHitTest(UIMDIChild *mdiChild, int x, int y) { + UIElement *element = &mdiChild->e; + UI_MDI_CHILD_CALCULATE_LAYOUT(); + int cornerSize = UI_SIZE_MDI_CHILD_CORNER * element->window->scale; + if (!UIRectangleContains(element->bounds, x, y) || UIRectangleContains(content, x, y)) return -1; + else if (x < element->bounds.l + cornerSize && y < element->bounds.t + cornerSize) return 0b1010; + else if (x > element->bounds.r - cornerSize && y < element->bounds.t + cornerSize) return 0b0110; + else if (x < element->bounds.l + cornerSize && y > element->bounds.b - cornerSize) return 0b1001; + else if (x > element->bounds.r - cornerSize && y > element->bounds.b - cornerSize) return 0b0101; + else if (x < element->bounds.l + borderSize) return 0b1000; + else if (x > element->bounds.r - borderSize) return 0b0100; + else if (y < element->bounds.t + borderSize) return 0b0010; + else if (y > element->bounds.b - borderSize) return 0b0001; + else if (UIRectangleContains(title, x, y)) return 0b1111; + else return -1; +} + +void _UIMDIChildCloseButton(void *_child) { + UIElement *child = (UIElement *) _child; + + if (!UIElementMessage(child, UI_MSG_WINDOW_CLOSE, 0, 0)) { + UIElementDestroy(child); + UIElementRefresh(child->parent); + } +} + +int _UIMDIChildMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIMDIChild *mdiChild = (UIMDIChild *) element; + + if (message == UI_MSG_PAINT) { + UI_MDI_CHILD_CALCULATE_LAYOUT(); + UIPainter *painter = (UIPainter *) dp; + UIRectangle borders = UI_RECT_4(borderSize, borderSize, titleSize, borderSize); + UIDrawBorder(painter, element->bounds, ui.theme.buttonNormal, borders); + UIDrawBorder(painter, element->bounds, ui.theme.border, UI_RECT_1((int) element->window->scale)); + UIDrawBorder(painter, UIRectangleAdd(content, UI_RECT_1I(-1)), ui.theme.border, UI_RECT_1((int) element->window->scale)); + UIDrawString(painter, title, mdiChild->title, mdiChild->titleBytes, ui.theme.text, UI_ALIGN_LEFT, NULL); + } else if (message == UI_MSG_GET_WIDTH) { + UIElement *child = element->children; + while (child && child->next) child = child->next; + int width = 2 * UI_SIZE_MDI_CHILD_BORDER; + width += (child ? UIElementMessage(child, message, di ? (di - UI_SIZE_MDI_CHILD_TITLE + UI_SIZE_MDI_CHILD_BORDER) : 0, dp) : 0); + if (width < UI_SIZE_MDI_CHILD_MINIMUM_WIDTH) width = UI_SIZE_MDI_CHILD_MINIMUM_WIDTH; + return width; + } else if (message == UI_MSG_GET_HEIGHT) { + UIElement *child = element->children; + while (child && child->next) child = child->next; + int height = UI_SIZE_MDI_CHILD_TITLE + UI_SIZE_MDI_CHILD_BORDER; + height += (child ? UIElementMessage(child, message, di ? (di - 2 * UI_SIZE_MDI_CHILD_BORDER) : 0, dp) : 0); + if (height < UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT) height = UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT; + return height; + } else if (message == UI_MSG_LAYOUT) { + UI_MDI_CHILD_CALCULATE_LAYOUT(); + + UIElement *child = element->children; + int position = title.r; + + while (child && child->next) { + int width = UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0); + UIElementMove(child, UI_RECT_4(position - width, position, title.t, title.b), false); + position -= width, child = child->next; + } + + if (child) { + UIElementMove(child, content, false); + } + } else if (message == UI_MSG_GET_CURSOR) { + int hitTest = _UIMDIChildHitTest(mdiChild, element->window->cursorX, element->window->cursorY); + if (hitTest == 0b1000) return UI_CURSOR_RESIZE_LEFT; + if (hitTest == 0b0010) return UI_CURSOR_RESIZE_UP; + if (hitTest == 0b0110) return UI_CURSOR_RESIZE_UP_RIGHT; + if (hitTest == 0b1010) return UI_CURSOR_RESIZE_UP_LEFT; + if (hitTest == 0b0100) return UI_CURSOR_RESIZE_RIGHT; + if (hitTest == 0b0001) return UI_CURSOR_RESIZE_DOWN; + if (hitTest == 0b1001) return UI_CURSOR_RESIZE_DOWN_LEFT; + if (hitTest == 0b0101) return UI_CURSOR_RESIZE_DOWN_RIGHT; + return UI_CURSOR_ARROW; + } else if (message == UI_MSG_LEFT_DOWN) { + mdiChild->dragHitTest = _UIMDIChildHitTest(mdiChild, element->window->cursorX, element->window->cursorY); + mdiChild->dragOffset = UIRectangleAdd(element->bounds, UI_RECT_2(-element->window->cursorX, -element->window->cursorY)); + } else if (message == UI_MSG_LEFT_UP) { + if (mdiChild->bounds.l < 0) mdiChild->bounds.r -= mdiChild->bounds.l, mdiChild->bounds.l = 0; + if (mdiChild->bounds.t < 0) mdiChild->bounds.b -= mdiChild->bounds.t, mdiChild->bounds.t = 0; + UIElementRefresh(element->parent); + } else if (message == UI_MSG_MOUSE_DRAG) { + if (mdiChild->dragHitTest > 0) { +#define _UI_MDI_CHILD_MOVE_EDGE(bit, edge, cursor, size, opposite, negate, minimum, offset) \ + if (mdiChild->dragHitTest & bit) mdiChild->bounds.edge = mdiChild->dragOffset.edge + element->window->cursor - element->parent->bounds.offset; \ + if ((mdiChild->dragHitTest & bit) && size(mdiChild->bounds) < minimum) mdiChild->bounds.edge = mdiChild->bounds.opposite negate minimum; + _UI_MDI_CHILD_MOVE_EDGE(0b1000, l, cursorX, UI_RECT_WIDTH, r, -, UI_SIZE_MDI_CHILD_MINIMUM_WIDTH, l); + _UI_MDI_CHILD_MOVE_EDGE(0b0100, r, cursorX, UI_RECT_WIDTH, l, +, UI_SIZE_MDI_CHILD_MINIMUM_WIDTH, l); + _UI_MDI_CHILD_MOVE_EDGE(0b0010, t, cursorY, UI_RECT_HEIGHT, b, -, UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT, t); + _UI_MDI_CHILD_MOVE_EDGE(0b0001, b, cursorY, UI_RECT_HEIGHT, t, +, UI_SIZE_MDI_CHILD_MINIMUM_HEIGHT, t); + UIElementRefresh(element->parent); + } + } else if (message == UI_MSG_DESTROY) { + UI_FREE(mdiChild->title); + UIMDIClient *client = (UIMDIClient *) element->parent; + if (client->e.children == element) client->e.children = element->next; + if (mdiChild->previous) mdiChild->previous->e.next = element->next; + if (element->next) ((UIMDIChild *) element->next)->previous = mdiChild->previous; + if (client->active == mdiChild) client->active = mdiChild->previous; + } + + return 0; +} + +int _UIMDIClientMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIMDIClient *client = (UIMDIClient *) element; + + if (message == UI_MSG_PAINT) { + UIDrawBlock((UIPainter *) dp, element->bounds, (element->flags & UI_MDI_CLIENT_TRANSPARENT) ? 0 : ui.theme.panel2); + } else if (message == UI_MSG_LAYOUT) { + UIElement *child = element->children; + + while (child) { + UI_ASSERT(child->messageClass == _UIMDIChildMessage); + + UIMDIChild *mdiChild = (UIMDIChild *) child; + + if (UIRectangleEquals(mdiChild->bounds, UI_RECT_1(0))) { + int width = UIElementMessage(&mdiChild->e, UI_MSG_GET_WIDTH, 0, 0); + int height = UIElementMessage(&mdiChild->e, UI_MSG_GET_HEIGHT, width, 0); + if (client->cascade + width > element->bounds.r || client->cascade + height > element->bounds.b) client->cascade = 0; + mdiChild->bounds = UI_RECT_4(client->cascade, client->cascade + width, client->cascade, client->cascade + height); + client->cascade += UI_SIZE_MDI_CASCADE * element->window->scale; + } + + UIRectangle bounds = UIRectangleAdd(mdiChild->bounds, UI_RECT_2(element->bounds.l, element->bounds.t)); + UIElementMove(child, bounds, false); + child = child->next; + } + } else if (message == UI_MSG_FIND_BY_POINT) { + UIFindByPoint *m = (UIFindByPoint *) dp; + UIMDIChild *child = client->active; + + while (child) { + if (UIRectangleContains(child->e.bounds, m->x, m->y)) { + m->result = UIElementFindByPoint(&child->e, m->x, m->y); + return 1; + } + + child = child->previous; + } + + return 1; + } else if (message == UI_MSG_PRESSED_DESCENDENT) { + UIMDIChild *child = (UIMDIChild *) dp; + + if (child && child != client->active) { + if (client->e.children == &child->e) client->e.children = child->e.next; + if (child->previous) child->previous->e.next = child->e.next; + if (child->e.next) ((UIMDIChild *) child->e.next)->previous = child->previous; + if (client->active) client->active->e.next = &child->e; + child->previous = client->active; + child->e.next = NULL; + client->active = child; + ((UIMDIChild *) client->e.children)->previous = NULL; + UIElementRefresh(element); + } + } + + return 0; +} + +UIMDIChild *UIMDIChildCreate(UIElement *parent, uint32_t flags, UIRectangle initialBounds, const char *title, ptrdiff_t titleBytes) { + UI_ASSERT(parent->messageClass == _UIMDIClientMessage); + + UIMDIChild *mdiChild = (UIMDIChild *) UIElementCreate(sizeof(UIMDIChild), parent, flags, _UIMDIChildMessage, "MDIChild"); + UIMDIClient *mdiClient = (UIMDIClient *) parent; + + mdiChild->bounds = initialBounds; + mdiChild->title = UIStringCopy(title, (mdiChild->titleBytes = titleBytes)); + mdiChild->previous = mdiClient->active; + mdiClient->active = mdiChild; + + if (flags & UI_MDI_CHILD_CLOSE_BUTTON) { + UIButton *closeButton = UIButtonCreate(&mdiChild->e, UI_BUTTON_SMALL | UI_ELEMENT_NON_CLIENT, "X", 1); + closeButton->invoke = _UIMDIChildCloseButton; + closeButton->e.cp = mdiChild; + } + + return mdiChild; +} + +UIMDIClient *UIMDIClientCreate(UIElement *parent, uint32_t flags) { + return (UIMDIClient *) UIElementCreate(sizeof(UIMDIClient), parent, flags, _UIMDIClientMessage, "MDIClient"); +} + +int _UIExpandPaneMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIExpandPane *pane = (UIExpandPane *) element; + + if (message == UI_MSG_GET_HEIGHT) { + int height = UIElementMessage(&pane->button->e, message, di, dp); + + if (pane->expanded) { + height += UIElementMessage(&pane->panel->e, message, di, dp); + } + + return height; + } else if (message == UI_MSG_LAYOUT) { + UIRectangle bounds = pane->e.bounds; + int buttonHeight = UIElementMessage(&pane->button->e, UI_MSG_GET_HEIGHT, UI_RECT_WIDTH(bounds), NULL); + UIElementMove(&pane->button->e, UI_RECT_4(bounds.l, bounds.r, bounds.t, bounds.t + buttonHeight), false); + + if (pane->expanded) { + pane->panel->e.flags &= ~UI_ELEMENT_HIDE; + UIElementMove(&pane->panel->e, UI_RECT_4(bounds.l, bounds.r, bounds.t + buttonHeight, bounds.b), false); + } else { + pane->panel->e.flags |= UI_ELEMENT_HIDE; + } + } else if (message == UI_MSG_CLIENT_PARENT) { + *(UIElement **) dp = &pane->panel->e; + } + + return 0; +} + +void _UIExpandPaneButtonInvoke(void *cp) { + UIExpandPane *pane = (UIExpandPane *) cp; + pane->expanded = !pane->expanded; + if (pane->expanded) pane->button->e.flags |= UI_BUTTON_CHECKED; + else pane->button->e.flags &= ~UI_BUTTON_CHECKED; + + UIElement *ancestor = &pane->e; + + while (ancestor) { + UIElementRefresh(ancestor); + + if ((ancestor->messageClass == _UIPanelMessage && (ancestor->flags & UI_PANEL_SCROLL)) + || (ancestor->messageClass == _UIMDIChildMessage) + || (ancestor->flags & UI_ELEMENT_V_FILL)) { + break; + } + + ancestor = ancestor->parent; + } +} + +UIExpandPane *UIExpandPaneCreate(UIElement *parent, uint32_t flags, const char *label, ptrdiff_t labelBytes, uint32_t panelFlags) { + UIExpandPane *pane = (UIExpandPane *) UIElementCreate(sizeof(UIExpandPane), parent, flags, _UIExpandPaneMessage, "ExpandPane"); + pane->button = UIButtonCreate(parent, UI_ELEMENT_NON_CLIENT, label, labelBytes); + pane->button->e.cp = pane; + pane->button->invoke = _UIExpandPaneButtonInvoke; + pane->panel = UIPanelCreate(parent, UI_ELEMENT_NON_CLIENT | panelFlags); + return pane; +} + +void _UIImageDisplayUpdateViewport(UIImageDisplay *display) { + UIRectangle bounds = display->e.bounds; + bounds.r -= bounds.l, bounds.b -= bounds.t; + + float minimumZoomX = 1, minimumZoomY = 1; + if (display->width > bounds.r) minimumZoomX = (float) bounds.r / display->width; + if (display->height > bounds.b) minimumZoomY = (float) bounds.b / display->height; + float minimumZoom = minimumZoomX < minimumZoomY ? minimumZoomX : minimumZoomY; + + if (display->zoom < minimumZoom || (display->e.flags & _UI_IMAGE_DISPLAY_ZOOM_FIT)) { + display->zoom = minimumZoom; + display->e.flags |= _UI_IMAGE_DISPLAY_ZOOM_FIT; + } + + if (display->panX < 0) display->panX = 0; + if (display->panY < 0) display->panY = 0; + if (display->panX > display->width - bounds.r / display->zoom) display->panX = display->width - bounds.r / display->zoom; + if (display->panY > display->height - bounds.b / display->zoom) display->panY = display->height - bounds.b / display->zoom; + + if (bounds.r && display->width * display->zoom <= bounds.r) display->panX = display->width / 2 - bounds.r / display->zoom / 2; + if (bounds.b && display->height * display->zoom <= bounds.b) display->panY = display->height / 2 - bounds.b / display->zoom / 2; +} + +int _UIImageDisplayMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIImageDisplay *display = (UIImageDisplay *) element; + + if (message == UI_MSG_GET_HEIGHT) { + return display->height; + } else if (message == UI_MSG_GET_WIDTH) { + return display->width; + } else if (message == UI_MSG_DESTROY) { + UI_FREE(display->bits); + } else if (message == UI_MSG_PAINT) { + UIPainter *painter = (UIPainter *) dp; + + int w = UI_RECT_WIDTH(element->bounds), h = UI_RECT_HEIGHT(element->bounds); + int x = _UILinearMap(0, display->panX, display->panX + w / display->zoom, 0, w) + element->bounds.l; + int y = _UILinearMap(0, display->panY, display->panY + h / display->zoom, 0, h) + element->bounds.t; + + UIRectangle image = UI_RECT_4(x, x + (int) (display->width * display->zoom), y, (int) (y + display->height * display->zoom)); + UIRectangle bounds = UIRectangleIntersection(painter->clip, UIRectangleIntersection(display->e.bounds, image)); + if (!UI_RECT_VALID(bounds)) return 0; + + if (display->zoom == 1) { + uint32_t *lineStart = (uint32_t *) painter->bits + bounds.t * painter->width + bounds.l; + uint32_t *sourceLineStart = display->bits + (bounds.l - image.l) + display->width * (bounds.t - image.t); + + for (int i = 0; i < bounds.b - bounds.t; i++, lineStart += painter->width, sourceLineStart += display->width) { + uint32_t *destination = lineStart; + uint32_t *source = sourceLineStart; + int j = bounds.r - bounds.l; + + do { + *destination = *source; + destination++; + source++; + } while (--j); + } + } else { + float zr = 1.0f / display->zoom; + uint32_t *destination = (uint32_t *) painter->bits; + + for (int i = bounds.t; i < bounds.b; i++) { + int ty = (i - image.t) * zr; + + for (int j = bounds.l; j < bounds.r; j++) { + int tx = (j - image.l) * zr; + destination[i * painter->width + j] = display->bits[ty * display->width + tx]; + } + } + } + } else if (message == UI_MSG_MOUSE_WHEEL && (element->flags & UI_IMAGE_DISPLAY_INTERACTIVE)) { + display->e.flags &= ~_UI_IMAGE_DISPLAY_ZOOM_FIT; + int divisions = -di / 72; + float factor = 1; + float perDivision = element->window->ctrl ? 2.0f : element->window->alt ? 1.01f : 1.2f; + while (divisions > 0) factor *= perDivision, divisions--; + while (divisions < 0) factor /= perDivision, divisions++; + if (display->zoom * factor > 64) factor = 64 / display->zoom; + int mx = element->window->cursorX - element->bounds.l; + int my = element->window->cursorY - element->bounds.t; + display->zoom *= factor; + display->panX -= mx / display->zoom * (1 - factor); + display->panY -= my / display->zoom * (1 - factor); + _UIImageDisplayUpdateViewport(display); + UIElementRepaint(&display->e, NULL); + } else if (message == UI_MSG_LAYOUT && (element->flags & UI_IMAGE_DISPLAY_INTERACTIVE)) { + UIRectangle bounds = display->e.bounds; + bounds.r -= bounds.l, bounds.b -= bounds.t; + display->panX -= (bounds.r - display->previousWidth ) / 2 / display->zoom; + display->panY -= (bounds.b - display->previousHeight) / 2 / display->zoom; + display->previousWidth = bounds.r, display->previousHeight = bounds.b; + _UIImageDisplayUpdateViewport(display); + } else if (message == UI_MSG_GET_CURSOR && (element->flags & UI_IMAGE_DISPLAY_INTERACTIVE) + && (UI_RECT_WIDTH(element->bounds) < display->width * display->zoom + || UI_RECT_HEIGHT(element->bounds) < display->height * display->zoom)) { + return UI_CURSOR_HAND; + } else if (message == UI_MSG_MOUSE_DRAG) { + display->panX -= (element->window->cursorX - display->previousPanPointX) / display->zoom; + display->panY -= (element->window->cursorY - display->previousPanPointY) / display->zoom; + _UIImageDisplayUpdateViewport(display); + display->previousPanPointX = element->window->cursorX; + display->previousPanPointY = element->window->cursorY; + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_LEFT_DOWN) { + display->e.flags &= ~_UI_IMAGE_DISPLAY_ZOOM_FIT; + display->previousPanPointX = element->window->cursorX; + display->previousPanPointY = element->window->cursorY; + } + + return 0; +} + +void UIImageDisplaySetContent(UIImageDisplay *display, uint32_t *bits, size_t width, size_t height, size_t stride) { + UI_FREE(display->bits); + + display->bits = (uint32_t *) UI_MALLOC(width * height * 4); + display->width = width; + display->height = height; + + uint32_t *destination = display->bits; + uint32_t *source = bits; + + for (uintptr_t row = 0; row < height; row++, source += stride / 4) { + for (uintptr_t i = 0; i < width; i++) { + *destination++ = source[i]; + } + } +} + +UIImageDisplay *UIImageDisplayCreate(UIElement *parent, uint32_t flags, uint32_t *bits, size_t width, size_t height, size_t stride) { + UIImageDisplay *display = (UIImageDisplay *) UIElementCreate(sizeof(UIImageDisplay), parent, flags, _UIImageDisplayMessage, "ImageDisplay"); + display->zoom = 1.0f; + UIImageDisplaySetContent(display, bits, width, height, stride); + return display; +} + +int _UIDialogWrapperMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_LAYOUT) { + int width = UIElementMessage(element->children, UI_MSG_GET_WIDTH, 0, 0); + int height = UIElementMessage(element->children, UI_MSG_GET_HEIGHT, width, 0); + int cx = (element->bounds.l + element->bounds.r) / 2; + int cy = (element->bounds.t + element->bounds.b) / 2; + UIRectangle bounds = UI_RECT_4(cx - (width + 1) / 2, cx + width / 2, cy - (height + 1) / 2, cy + height / 2); + UIElementMove(element->children, bounds, false); + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_PAINT) { + UIRectangle bounds = UIRectangleAdd(element->children->bounds, UI_RECT_1I(-1)); + UIDrawBorder((UIPainter *) dp, bounds, ui.theme.border, UI_RECT_1(1)); + UIDrawBorder((UIPainter *) dp, UIRectangleAdd(bounds, UI_RECT_1(1)), ui.theme.border, UI_RECT_1(1)); + } + + return 0; +} + +void _UIDialogButtonInvoke(void *cp) { + ui.dialogResult = (const char *) cp; +} + +int _UIDialogTextboxMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_VALUE_CHANGED) { + UITextbox *textbox = (UITextbox *) element; + char **buffer = (char **) element->cp; + *buffer = (char *) UI_REALLOC(*buffer, textbox->bytes + 1); + (*buffer)[textbox->bytes] = 0; + + for (ptrdiff_t i = 0; i < textbox->bytes; i++) { + (*buffer)[i] = textbox->string[i]; + } + } + + return 0; +} + +const char *UIDialogShow(UIWindow *window, uint32_t flags, const char *format, ...) { + // TODO Enter, escape, access keys. + + // Create the dialog wrapper and panel. + + UI_ASSERT(!window->dialog); + window->dialog = UIElementCreate(sizeof(UIElement), &window->e, 0, _UIDialogWrapperMessage, "DialogWrapper"); + UIPanel *panel = UIPanelCreate(window->dialog, UI_PANEL_MEDIUM_SPACING | UI_PANEL_GRAY | UI_PANEL_EXPAND); + panel->border = UI_RECT_1(UI_SIZE_PANE_MEDIUM_BORDER * 2); + window->e.children->flags |= UI_ELEMENT_DISABLED; + + // Create the dialog contents. + + va_list arguments; + va_start(arguments, format); + UIPanel *row = NULL; + UIElement *focus = NULL; + + for (int i = 0; format[i]; i++) { + if (i == 0 || format[i - 1] == '\n') { + row = UIPanelCreate(&panel->e, UI_PANEL_HORIZONTAL); + row->gap = UI_SIZE_PANE_SMALL_GAP; + } + + if (format[i] == ' ' || format[i] == '\n') { + } else if (format[i] == '%') { + i++; + + if (format[i] == 'b') { + const char *label = va_arg(arguments, const char *); + UIButton *button = UIButtonCreate(&row->e, 0, label, -1); + if (!focus) focus = &button->e; + button->invoke = _UIDialogButtonInvoke; + button->e.cp = (void *) label; + } else if (format[i] == 's') { + const char *label = va_arg(arguments, const char *); + UILabelCreate(&row->e, 0, label, -1); + } else if (format[i] == 't') { + char **buffer = va_arg(arguments, char **); + UITextbox *textbox = UITextboxCreate(&row->e, UI_ELEMENT_H_FILL); + if (!focus) focus = &textbox->e; + if (*buffer) UITextboxReplace(textbox, *buffer, _UIStringLength(*buffer), false); + textbox->e.cp = buffer; + textbox->e.messageUser = _UIDialogTextboxMessage; + } else if (format[i] == 'f') { + UISpacerCreate(&row->e, UI_ELEMENT_H_FILL, 0, 0); + } else if (format[i] == 'l') { + UISpacerCreate(&row->e, UI_SPACER_LINE | UI_ELEMENT_H_FILL, 0, 1); + } + } else { + int j = i; + while (format[j] && format[j] != '%' && format[j] != '\n') j++; + UILabelCreate(&row->e, 0, format + i, j - i); + i = j - 1; + } + } + + va_end(arguments); + + window->dialogOldFocus = window->focused; + UIElementFocus(focus); + + // Run the modal message loop. + + int result; + ui.dialogResult = NULL; + for (int i = 1; i <= 3; i++) _UIWindowSetPressed(window, NULL, i); + UIElementRefresh(&window->e); + _UIUpdate(); + while (!ui.dialogResult && _UIMessageLoopSingle(&result)); + ui.quit = !ui.dialogResult; + + // Destroy the dialog. + + window->e.children->flags &= ~UI_ELEMENT_DISABLED; + UIElementDestroy(window->dialog); + window->dialog = NULL; + UIElementRefresh(&window->e); + if (window->dialogOldFocus) UIElementFocus(window->dialogOldFocus); + return ui.dialogResult; +} + +bool _UIMenusClose() { + UIWindow *window = ui.windows; + bool anyClosed = false; + + while (window) { + if (window->e.flags & UI_WINDOW_MENU) { + UIElementDestroy(&window->e); + anyClosed = true; + } + + window = window->next; + } + + return anyClosed; +} + +int _UIMenuItemMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_CLICKED) { + _UIMenusClose(); + } + + return 0; +} + +int _UIMenuMessage(UIElement *element, UIMessage message, int di, void *dp) { + UIMenu *menu = (UIMenu *) element; + + if (message == UI_MSG_GET_WIDTH) { + UIElement *child = element->children; + int width = 0; + + while (child) { + if (~child->flags & UI_ELEMENT_NON_CLIENT) { + int w = UIElementMessage(child, UI_MSG_GET_WIDTH, 0, 0); + if (w > width) width = w; + } + + child = child->next; + } + + return width + 4 + UI_SIZE_SCROLL_BAR; + } else if (message == UI_MSG_GET_HEIGHT) { + UIElement *child = element->children; + int height = 0; + + while (child) { + if (~child->flags & UI_ELEMENT_NON_CLIENT) { + height += UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0); + } + + child = child->next; + } + + return height + 4; + } else if (message == UI_MSG_PAINT) { + UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.border); + } else if (message == UI_MSG_LAYOUT) { + UIElement *child = element->children; + int position = element->bounds.t + 2 - menu->vScroll->position; + int totalHeight = 0; + + while (child) { + if (~child->flags & UI_ELEMENT_NON_CLIENT) { + int height = UIElementMessage(child, UI_MSG_GET_HEIGHT, 0, 0); + UIElementMove(child, UI_RECT_4(element->bounds.l + 2, element->bounds.r - UI_SIZE_SCROLL_BAR - 2, + position, position + height), false); + position += height; + totalHeight += height; + } + + child = child->next; + } + + UIRectangle scrollBarBounds = element->bounds; + scrollBarBounds.l = scrollBarBounds.r - UI_SIZE_SCROLL_BAR * element->window->scale; + menu->vScroll->maximum = totalHeight; + menu->vScroll->page = UI_RECT_HEIGHT(element->bounds); + UIElementMove(&menu->vScroll->e, scrollBarBounds, true); + } else if (message == UI_MSG_KEY_TYPED) { + UIKeyTyped *m = (UIKeyTyped *) dp; + + if (m->code == UI_KEYCODE_ESCAPE) { + _UIMenusClose(); + return 1; + } + } else if (message == UI_MSG_MOUSE_WHEEL) { + return UIElementMessage(&menu->vScroll->e, message, di, dp); + } else if (message == UI_MSG_SCROLLED) { + UIElementRefresh(element); + } + + return 0; +} + +void UIMenuAddItem(UIMenu *menu, uint32_t flags, const char *label, ptrdiff_t labelBytes, void (*invoke)(void *cp), void *cp) { + UIButton *button = UIButtonCreate(&menu->e, flags | UI_BUTTON_MENU_ITEM, label, labelBytes); + button->invoke = invoke; + button->e.messageUser = _UIMenuItemMessage; + button->e.cp = cp; +} + +void _UIMenuPrepare(UIMenu *menu, int *width, int *height) { + *width = UIElementMessage(&menu->e, UI_MSG_GET_WIDTH, 0, 0); + *height = UIElementMessage(&menu->e, UI_MSG_GET_HEIGHT, 0, 0); + + if (menu->e.flags & UI_MENU_PLACE_ABOVE) { + menu->pointY -= *height; + } +} + +UIMenu *UIMenuCreate(UIElement *parent, uint32_t flags) { + UIWindow *window = UIWindowCreate(parent->window, UI_WINDOW_MENU, 0, 0, 0); + UIMenu *menu = (UIMenu *) UIElementCreate(sizeof(UIMenu), &window->e, flags, _UIMenuMessage, "Menu"); + menu->vScroll = UIScrollBarCreate(&menu->e, UI_ELEMENT_NON_CLIENT); + + if (parent->parent) { + UIRectangle screenBounds = UIElementScreenBounds(parent); + menu->pointX = screenBounds.l; + menu->pointY = (flags & UI_MENU_PLACE_ABOVE) ? (screenBounds.t + 1) : (screenBounds.b - 1); + } else { + int x = 0, y = 0; + _UIWindowGetScreenPosition(parent->window, &x, &y); + + menu->pointX = parent->window->cursorX + x; + menu->pointY = parent->window->cursorY + y; + } + + return menu; +} + +UIRectangle UIElementScreenBounds(UIElement *element) { + int x = 0, y = 0; + _UIWindowGetScreenPosition(element->window, &x, &y); + return UIRectangleAdd(element->bounds, UI_RECT_2(x, y)); +} + +void UIWindowRegisterShortcut(UIWindow *window, UIShortcut shortcut) { + if (window->shortcutCount + 1 > window->shortcutAllocated) { + window->shortcutAllocated = (window->shortcutCount + 1) * 2; + window->shortcuts = (UIShortcut *) UI_REALLOC(window->shortcuts, window->shortcutAllocated * sizeof(UIShortcut)); + } + + window->shortcuts[window->shortcutCount++] = shortcut; +} + +void _UIElementPaint(UIElement *element, UIPainter *painter) { + if (element->flags & UI_ELEMENT_HIDE) { + return; + } + + // Clip painting to the element's clip. + + painter->clip = UIRectangleIntersection(element->clip, painter->clip); + + if (!UI_RECT_VALID(painter->clip)) { + return; + } + + // Paint the element. + + UIElementMessage(element, UI_MSG_PAINT, 0, painter); + + // Paint its children. + + UIElement *child = element->children; + UIRectangle previousClip = painter->clip; + + while (child) { + painter->clip = previousClip; + _UIElementPaint(child, painter); + child = child->next; + } +} + +void UIElementFocus(UIElement *element) { + UIElement *previous = element->window->focused; + if (previous == element) return; + element->window->focused = element; + if (previous) UIElementMessage(previous, UI_MSG_UPDATE, UI_UPDATE_FOCUSED, 0); + if (element) UIElementMessage(element, UI_MSG_UPDATE, UI_UPDATE_FOCUSED, 0); + +#ifdef UI_DEBUG + _UIInspectorRefresh(); +#endif +} + +void _UIWindowSetPressed(UIWindow *window, UIElement *element, int button) { + UIElement *previous = window->pressed; + window->pressed = element; + window->pressedButton = button; + if (previous) UIElementMessage(previous, UI_MSG_UPDATE, UI_UPDATE_PRESSED, 0); + if (element) UIElementMessage(element, UI_MSG_UPDATE, UI_UPDATE_PRESSED, 0); + + UIElement *ancestor = element; + UIElement *child = NULL; + + while (ancestor) { + UIElementMessage(ancestor, UI_MSG_PRESSED_DESCENDENT, 0, child); + child = ancestor; + ancestor = ancestor->parent; + } +} + +bool _UIDestroy(UIElement *element) { + if (element->flags & UI_ELEMENT_DESTROY_DESCENDENT) { + element->flags &= ~UI_ELEMENT_DESTROY_DESCENDENT; + + UIElement *child = element->children; + UIElement **link = &element->children; + + while (child) { + UIElement *next = child->next; + + if (_UIDestroy(child)) { + *link = next; + } else { + link = &child->next; + } + + child = next; + } + } + + if (element->flags & UI_ELEMENT_DESTROY) { + UIElementMessage(element, UI_MSG_DESTROY, 0, 0); + + if (element->window->pressed == element) { + _UIWindowSetPressed(element->window, NULL, 0); + } + + if (element->window->hovered == element) { + element->window->hovered = &element->window->e; + } + + if (element->window->focused == element) { + element->window->focused = NULL; + } + + if (element->window->dialogOldFocus == element) { + element->window->dialogOldFocus = NULL; + } + + if (ui.animating == element) { + ui.animating = NULL; + } + + UI_FREE(element); + return true; + } else { + return false; + } +} + +void _UIUpdate() { + UIWindow *window = ui.windows; + UIWindow **link = &ui.windows; + + while (window) { + UIWindow *next = window->next; + + if (_UIDestroy(&window->e)) { + *link = next; + } else { + link = &window->next; + + if (UI_RECT_VALID(window->updateRegion)) { +#ifdef __cplusplus + UIPainter painter = {}; +#else + UIPainter painter = { 0 }; +#endif + painter.bits = window->bits; + painter.width = window->width; + painter.height = window->height; + painter.clip = UIRectangleIntersection(UI_RECT_2S(window->width, window->height), window->updateRegion); + _UIElementPaint(&window->e, &painter); + _UIWindowEndPaint(window, &painter); + window->updateRegion = UI_RECT_1(0); + +#ifdef UI_DEBUG + window->lastFullFillCount = (float) painter.fillCount / (UI_RECT_WIDTH(window->updateRegion) * UI_RECT_HEIGHT(window->updateRegion)); +#endif + } + } + + window = next; + } +} + +UIElement *UIElementFindByPoint(UIElement *element, int x, int y) { + UIFindByPoint m = { 0 }; + m.x = x, m.y = y; + + if (UIElementMessage(element, UI_MSG_FIND_BY_POINT, 0, &m)) { + return m.result ? m.result : element; + } + + UIElement *child = element->children; + + while (child) { + if ((~child->flags & UI_ELEMENT_HIDE) && UIRectangleContains(child->clip, x, y)) { + return UIElementFindByPoint(child, x, y); + } + + child = child->next; + } + + return element; +} + +void _UIProcessAnimations() { + if (ui.animating) { + UIElementMessage(ui.animating, UI_MSG_ANIMATE, 0, 0); + _UIUpdate(); + } +} + +bool _UIMenusOpen() { + UIWindow *window = ui.windows; + + while (window) { + if (window->e.flags & UI_WINDOW_MENU) { + return true; + } + + window = window->next; + } + + return false; +} + +void _UIWindowDestroyCommon(UIWindow *window) { + UI_FREE(window->bits); + UI_FREE(window->shortcuts); +} + +UIElement *_UIElementLastChild(UIElement *element) { + if (!element->children) { + return NULL; + } + + UIElement *child = element->children; + + while (child->next) { + child = child->next; + } + + return child; +} + +UIElement *_UIElementPreviousSibling(UIElement *element) { + if (!element->parent) { + return NULL; + } + + UIElement *sibling = element->parent->children; + + if (sibling == element) { + return NULL; + } + + while (sibling->next != element) { + sibling = sibling->next; + UI_ASSERT(sibling); + } + + return sibling; +} + +void _UIWindowInputEvent(UIWindow *window, UIMessage message, int di, void *dp) { + if (window->pressed) { + if (message == UI_MSG_MOUSE_MOVE) { + UIElementMessage(window->pressed, UI_MSG_MOUSE_DRAG, di, dp); + } else if (message == UI_MSG_LEFT_UP && window->pressedButton == 1) { + if (window->hovered == window->pressed) { + UIElementMessage(window->pressed, UI_MSG_CLICKED, di, dp); + if (ui.quit || ui.dialogResult) goto end; + } + + if (window->pressed) { + UIElementMessage(window->pressed, UI_MSG_LEFT_UP, di, dp); + if (ui.quit || ui.dialogResult) goto end; + _UIWindowSetPressed(window, NULL, 1); + } + } else if (message == UI_MSG_MIDDLE_UP && window->pressedButton == 2) { + UIElementMessage(window->pressed, UI_MSG_MIDDLE_UP, di, dp); + if (ui.quit || ui.dialogResult) goto end; + _UIWindowSetPressed(window, NULL, 2); + } else if (message == UI_MSG_RIGHT_UP && window->pressedButton == 3) { + UIElementMessage(window->pressed, UI_MSG_RIGHT_UP, di, dp); + if (ui.quit || ui.dialogResult) goto end; + _UIWindowSetPressed(window, NULL, 3); + } + } + + if (window->pressed) { + bool inside = UIRectangleContains(window->pressed->clip, window->cursorX, window->cursorY); + + if (inside && window->hovered == &window->e) { + window->hovered = window->pressed; + UIElementMessage(window->pressed, UI_MSG_UPDATE, UI_UPDATE_HOVERED, 0); + } else if (!inside && window->hovered == window->pressed) { + window->hovered = &window->e; + UIElementMessage(window->pressed, UI_MSG_UPDATE, UI_UPDATE_HOVERED, 0); + } + + if (ui.quit || ui.dialogResult) goto end; + } + + if (!window->pressed) { + UIElement *hovered = UIElementFindByPoint(&window->e, window->cursorX, window->cursorY); + + if (message == UI_MSG_MOUSE_MOVE) { + UIElementMessage(hovered, UI_MSG_MOUSE_MOVE, di, dp); + + int cursor = UIElementMessage(window->hovered, UI_MSG_GET_CURSOR, di, dp); + + if (cursor != window->cursorStyle) { + window->cursorStyle = cursor; + _UIWindowSetCursor(window, cursor); + } + } else if (message == UI_MSG_LEFT_DOWN) { + if ((window->e.flags & UI_WINDOW_MENU) || !_UIMenusClose()) { + _UIWindowSetPressed(window, hovered, 1); + UIElementMessage(hovered, UI_MSG_LEFT_DOWN, di, dp); + } + } else if (message == UI_MSG_MIDDLE_DOWN) { + if ((window->e.flags & UI_WINDOW_MENU) || !_UIMenusClose()) { + _UIWindowSetPressed(window, hovered, 2); + UIElementMessage(hovered, UI_MSG_MIDDLE_DOWN, di, dp); + } + } else if (message == UI_MSG_RIGHT_DOWN) { + if ((window->e.flags & UI_WINDOW_MENU) || !_UIMenusClose()) { + _UIWindowSetPressed(window, hovered, 3); + UIElementMessage(hovered, UI_MSG_RIGHT_DOWN, di, dp); + } + } else if (message == UI_MSG_MOUSE_WHEEL) { + UIElement *element = hovered; + + while (element) { + if (UIElementMessage(element, UI_MSG_MOUSE_WHEEL, di, dp)) { + break; + } + + element = element->parent; + } + } else if (message == UI_MSG_KEY_TYPED) { + bool handled = false; + + if (window->focused) { + UIElement *element = window->focused; + + while (element) { + if (UIElementMessage(element, UI_MSG_KEY_TYPED, di, dp)) { + handled = true; + break; + } + + element = element->parent; + } + } else { + if (UIElementMessage(&window->e, UI_MSG_KEY_TYPED, di, dp)) { + handled = true; + } + } + + if (!handled && !_UIMenusOpen()) { + UIKeyTyped *m = (UIKeyTyped *) dp; + + if (m->code == UI_KEYCODE_TAB && !window->ctrl && !window->alt) { + UIElement *start = window->focused ? window->focused : &window->e; + UIElement *element = start; + + do { + if (element->children && !(element->flags & (UI_ELEMENT_HIDE | UI_ELEMENT_DISABLED))) { + element = window->shift ? _UIElementLastChild(element) : element->children; + continue; + } + + while (element) { + if (window->shift ? (element->parent && element->parent->children != element) : !!element->next) { + element = window->shift ? _UIElementPreviousSibling(element) : element->next; + break; + } else { + element = element->parent; + } + } + + if (!element) { + element = &window->e; + } + } while (element != start && ((~element->flags & UI_ELEMENT_TAB_STOP) + || (element->flags & (UI_ELEMENT_HIDE | UI_ELEMENT_DISABLED)))); + + if (~element->flags & UI_ELEMENT_WINDOW) { + UIElementFocus(element); + } + } else if (!window->dialog) { + for (intptr_t i = window->shortcutCount - 1; i >= 0; i--) { + UIShortcut *shortcut = window->shortcuts + i; + + if (shortcut->code == m->code && shortcut->ctrl == window->ctrl + && shortcut->shift == window->shift && shortcut->alt == window->alt) { + shortcut->invoke(shortcut->cp); + break; + } + } + } + } + } + + if (ui.quit || ui.dialogResult) goto end; + + if (hovered != window->hovered) { + UIElement *previous = window->hovered; + window->hovered = hovered; + UIElementMessage(previous, UI_MSG_UPDATE, UI_UPDATE_HOVERED, 0); + UIElementMessage(window->hovered, UI_MSG_UPDATE, UI_UPDATE_HOVERED, 0); + } + } + + end: _UIUpdate(); +} + +void _UIInitialiseCommon() { + ui.theme = _uiThemeDark; + +#ifdef UI_FREETYPE + FT_Init_FreeType(&ui.ft); + FT_New_Face(ui.ft, _UI_TO_STRING_2(UI_FONT_PATH), 0, &ui.font); + FT_Set_Char_Size(ui.font, 0, UI_FONT_SIZE * 64, 100, 100); + FT_Load_Char(ui.font, 'a', FT_LOAD_DEFAULT); + ui.glyphWidth = ui.font->glyph->advance.x / 64; + ui.glyphHeight = (ui.font->size->metrics.ascender - ui.font->size->metrics.descender) / 64; +#else + ui.glyphWidth = 9; + ui.glyphHeight = 16; +#endif +} + +void _UIWindowAdd(UIWindow *window) { + window->scale = 1.0f; + window->e.window = window; + window->hovered = &window->e; + window->next = ui.windows; + ui.windows = window; +} + +int _UIWindowMessageCommon(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_LAYOUT && element->children) { + UIElementMove(element->children, element->bounds, false); + if (element->window->dialog) UIElementMove(element->window->dialog, element->bounds, false); + UIElementRepaint(element, NULL); + } else if (message == UI_MSG_FIND_BY_POINT) { + UIFindByPoint *m = (UIFindByPoint *) dp; + if (element->window->dialog) m->result = UIElementFindByPoint(element->window->dialog, m->x, m->y); + else if (!element->children) m->result = NULL; + else m->result = UIElementFindByPoint(element->children, m->x, m->y); + return 1; + } + + return 0; +} + +#ifdef UI_DEBUG + +void UIInspectorLog(const char *cFormat, ...) { + va_list arguments; + va_start(arguments, cFormat); + char buffer[4096]; + vsnprintf(buffer, sizeof(buffer), cFormat, arguments); + UICodeInsertContent(ui.inspectorLog, buffer, -1, false); + va_end(arguments); + UIElementRefresh(&ui.inspectorLog->e); +} + +UIElement *_UIInspectorFindNthElement(UIElement *element, int *index, int *depth) { + if (*index == 0) { + return element; + } + + *index = *index - 1; + + UIElement *child = element->children; + + while (child) { + if (!(child->flags & (UI_ELEMENT_DESTROY | UI_ELEMENT_HIDE))) { + UIElement *result = _UIInspectorFindNthElement(child, index, depth); + + if (result) { + if (depth) { + *depth = *depth + 1; + } + + return result; + } + } + + child = child->next; + } + + return NULL; +} + +int _UIInspectorTableMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (!ui.inspectorTarget) { + return 0; + } + + if (message == UI_MSG_TABLE_GET_ITEM) { + UITableGetItem *m = (UITableGetItem *) dp; + int index = m->index; + int depth = 0; + UIElement *element = _UIInspectorFindNthElement(&ui.inspectorTarget->e, &index, &depth); + if (!element) return 0; + + if (m->column == 0) { + return snprintf(m->buffer, m->bufferBytes, "%.*s%s", depth * 2, " ", element->cClassName); + } else if (m->column == 1) { + return snprintf(m->buffer, m->bufferBytes, "%d:%d, %d:%d", UI_RECT_ALL(element->bounds)); + } else if (m->column == 2) { + return snprintf(m->buffer, m->bufferBytes, "%d%c", element->id, element->window->focused == element ? '*' : ' '); + } + } else if (message == UI_MSG_MOUSE_MOVE) { + int index = UITableHitTest(ui.inspectorTable, element->window->cursorX, element->window->cursorY); + UIElement *element = NULL; + if (index >= 0) element = _UIInspectorFindNthElement(&ui.inspectorTarget->e, &index, NULL); + UIWindow *window = ui.inspectorTarget; + UIPainter painter = { 0 }; + window->updateRegion = window->e.bounds; + painter.bits = window->bits; + painter.width = window->width; + painter.height = window->height; + painter.clip = UI_RECT_2S(window->width, window->height); + + for (int i = 0; i < window->width * window->height; i++) { + window->bits[i] = 0xFF00FF; + } + + _UIElementPaint(&window->e, &painter); + painter.clip = UI_RECT_2S(window->width, window->height); + + if (element) { + UIDrawInvert(&painter, element->bounds); + UIDrawInvert(&painter, UIRectangleAdd(element->bounds, UI_RECT_1I(4))); + } + + _UIWindowEndPaint(window, &painter); + } + + return 0; +} + +void _UIInspectorCreate() { + ui.inspector = UIWindowCreate(0, UI_WINDOW_INSPECTOR, "Inspector", 0, 0); + UISplitPane *splitPane = UISplitPaneCreate(&ui.inspector->e, 0, 0.5f); + ui.inspectorTable = UITableCreate(&splitPane->e, 0, "Class\tBounds\tID"); + ui.inspectorTable->e.messageUser = _UIInspectorTableMessage; + ui.inspectorLog = UICodeCreate(&splitPane->e, 0); +} + +int _UIInspectorCountElements(UIElement *element) { + UIElement *child = element->children; + int count = 1; + + while (child) { + if (!(child->flags & (UI_ELEMENT_DESTROY | UI_ELEMENT_HIDE))) { + count += _UIInspectorCountElements(child); + } + + child = child->next; + } + + return count; +} + +void _UIInspectorRefresh() { + if (!ui.inspectorTarget || !ui.inspector || !ui.inspectorTable) return; + ui.inspectorTable->itemCount = _UIInspectorCountElements(&ui.inspectorTarget->e); + UITableResizeColumns(ui.inspectorTable); + UIElementRefresh(&ui.inspectorTable->e); +} + +void _UIInspectorSetFocusedWindow(UIWindow *window) { + if (!ui.inspector || !ui.inspectorTable) return; + + if (window->e.flags & UI_WINDOW_INSPECTOR) { + return; + } + + if (ui.inspectorTarget != window) { + ui.inspectorTarget = window; + _UIInspectorRefresh(); + } +} + +#else + +void _UIInspectorCreate() {} +void _UIInspectorSetFocusedWindow(UIWindow *window) {} +void _UIInspectorRefresh() {} + +#endif + +int UIMessageLoop() { + _UIInspectorCreate(); + _UIUpdate(); + int result = 0; + while (!ui.quit && _UIMessageLoopSingle(&result)) ui.dialogResult = NULL; + return result; +} + +#ifdef UI_LINUX + +const int UI_KEYCODE_A = XK_a; +const int UI_KEYCODE_BACKSPACE = XK_BackSpace; +const int UI_KEYCODE_DELETE = XK_Delete; +const int UI_KEYCODE_DOWN = XK_Down; +const int UI_KEYCODE_END = XK_End; +const int UI_KEYCODE_ENTER = XK_Return; +const int UI_KEYCODE_ESCAPE = XK_Escape; +const int UI_KEYCODE_F1 = XK_F1; +const int UI_KEYCODE_HOME = XK_Home; +const int UI_KEYCODE_LEFT = XK_Left; +const int UI_KEYCODE_RIGHT = XK_Right; +const int UI_KEYCODE_SPACE = XK_space; +const int UI_KEYCODE_TAB = XK_Tab; +const int UI_KEYCODE_UP = XK_Up; +const int UI_KEYCODE_0 = XK_0; + +int _UIWindowMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_DESTROY) { + UIWindow *window = (UIWindow *) element; + _UIWindowDestroyCommon(window); + window->image->data = NULL; + XDestroyImage(window->image); + XDestroyIC(window->xic); + XDestroyWindow(ui.display, ((UIWindow *) element)->window); + } + + return _UIWindowMessageCommon(element, message, di, dp); +} + +UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, int _width, int _height) { + _UIMenusClose(); + + UIWindow *window = (UIWindow *) UIElementCreate(sizeof(UIWindow), NULL, flags | UI_ELEMENT_WINDOW, _UIWindowMessage, "Window"); + _UIWindowAdd(window); + if (owner) window->scale = owner->scale; + + int width = (flags & UI_WINDOW_MENU) ? 1 : _width ? _width : 800; + int height = (flags & UI_WINDOW_MENU) ? 1 : _height ? _height : 600; + + XSetWindowAttributes attributes = {}; + attributes.override_redirect = flags & UI_WINDOW_MENU; + + window->window = XCreateWindow(ui.display, DefaultRootWindow(ui.display), 0, 0, width, height, 0, 0, + InputOutput, CopyFromParent, CWOverrideRedirect, &attributes); + if (cTitle) XStoreName(ui.display, window->window, cTitle); + XSelectInput(ui.display, window->window, SubstructureNotifyMask | ExposureMask | PointerMotionMask + | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask + | EnterWindowMask | LeaveWindowMask | ButtonMotionMask | KeymapStateMask | FocusChangeMask); + + if (~flags & UI_WINDOW_MENU) { + XMapRaised(ui.display, window->window); + } + + if (flags & UI_WINDOW_CENTER_IN_OWNER) { + int x = 0, y = 0; + _UIWindowGetScreenPosition(owner, &x, &y); + XMoveResizeWindow(ui.display, window->window, x + owner->width / 2 - width / 2, y + owner->height / 2 - height / 2, width, height); + } + + XSetWMProtocols(ui.display, window->window, &ui.windowClosedID, 1); + window->image = XCreateImage(ui.display, ui.visual, 24, ZPixmap, 0, NULL, 10, 10, 32, 0); + + window->xic = XCreateIC(ui.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, window->window, XNFocusWindow, window->window, NULL); + + return window; +} + +Display *_UIX11GetDisplay() { + return ui.display; +} + +void UIInitialise() { + _UIInitialiseCommon(); + + XInitThreads(); + + ui.display = XOpenDisplay(NULL); + ui.visual = XDefaultVisual(ui.display, 0); + ui.windowClosedID = XInternAtom(ui.display, "WM_DELETE_WINDOW", 0); + + ui.cursors[UI_CURSOR_ARROW] = XCreateFontCursor(ui.display, XC_left_ptr); + ui.cursors[UI_CURSOR_TEXT] = XCreateFontCursor(ui.display, XC_xterm); + ui.cursors[UI_CURSOR_SPLIT_V] = XCreateFontCursor(ui.display, XC_sb_v_double_arrow); + ui.cursors[UI_CURSOR_SPLIT_H] = XCreateFontCursor(ui.display, XC_sb_h_double_arrow); + ui.cursors[UI_CURSOR_FLIPPED_ARROW] = XCreateFontCursor(ui.display, XC_right_ptr); + ui.cursors[UI_CURSOR_CROSS_HAIR] = XCreateFontCursor(ui.display, XC_crosshair); + ui.cursors[UI_CURSOR_HAND] = XCreateFontCursor(ui.display, XC_hand1); + ui.cursors[UI_CURSOR_RESIZE_UP] = XCreateFontCursor(ui.display, XC_top_side); + ui.cursors[UI_CURSOR_RESIZE_LEFT] = XCreateFontCursor(ui.display, XC_left_side); + ui.cursors[UI_CURSOR_RESIZE_UP_RIGHT] = XCreateFontCursor(ui.display, XC_top_right_corner); + ui.cursors[UI_CURSOR_RESIZE_UP_LEFT] = XCreateFontCursor(ui.display, XC_top_left_corner); + ui.cursors[UI_CURSOR_RESIZE_DOWN] = XCreateFontCursor(ui.display, XC_bottom_side); + ui.cursors[UI_CURSOR_RESIZE_RIGHT] = XCreateFontCursor(ui.display, XC_right_side); + ui.cursors[UI_CURSOR_RESIZE_DOWN_LEFT] = XCreateFontCursor(ui.display, XC_bottom_left_corner); + ui.cursors[UI_CURSOR_RESIZE_DOWN_RIGHT] = XCreateFontCursor(ui.display, XC_bottom_right_corner); + + XSetLocaleModifiers(""); + + ui.xim = XOpenIM(ui.display, 0, 0, 0); + + if(!ui.xim){ + XSetLocaleModifiers("@im=none"); + ui.xim = XOpenIM(ui.display, 0, 0, 0); + } +} + +UIWindow *_UIFindWindow(Window window) { + UIWindow *w = ui.windows; + + while (w) { + if (w->window == window) { + return w; + } + + w = w->next; + } + + return NULL; +} + +void _UIWindowSetCursor(UIWindow *window, int cursor) { + XDefineCursor(ui.display, window->window, ui.cursors[cursor]); +} + +void _UIX11ResetCursor(UIWindow *window) { + XDefineCursor(ui.display, window->window, ui.cursors[UI_CURSOR_ARROW]); +} + +void _UIWindowEndPaint(UIWindow *window, UIPainter *painter) { + (void) painter; + + XPutImage(ui.display, window->window, DefaultGC(ui.display, 0), window->image, + UI_RECT_TOP_LEFT(window->updateRegion), UI_RECT_TOP_LEFT(window->updateRegion), + UI_RECT_SIZE(window->updateRegion)); +} + +void _UIWindowGetScreenPosition(UIWindow *window, int *_x, int *_y) { + Window child; + XTranslateCoordinates(ui.display, window->window, DefaultRootWindow(ui.display), 0, 0, _x, _y, &child); +} + +void UIMenuShow(UIMenu *menu) { + int width, height; + _UIMenuPrepare(menu, &width, &height); + + for (int i = 0; i < ScreenCount(ui.display); i++) { + Screen *screen = ScreenOfDisplay(ui.display, i); + + int x, y; + Window child; + XTranslateCoordinates(ui.display, screen->root, DefaultRootWindow(ui.display), 0, 0, &x, &y, &child); + + if (menu->pointX >= x && menu->pointX < x + screen->width + && menu->pointY >= y && menu->pointY < y + screen->height) { + if (menu->pointX + width > x + screen->width) menu->pointX = x + screen->width - width; + if (menu->pointY + height > y + screen->height) menu->pointY = y + screen->height - height; + if (menu->pointX < x) menu->pointX = x; + if (menu->pointY < y) menu->pointY = y; + if (menu->pointX + width > x + screen->width) width = x + screen->width - menu->pointX; + if (menu->pointY + height > y + screen->height) height = y + screen->height - menu->pointY; + break; + } + } + + Atom properties[] = { + XInternAtom(ui.display, "_NET_WM_WINDOW_TYPE", true), + XInternAtom(ui.display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", true), + XInternAtom(ui.display, "_MOTIF_WM_HINTS", true), + }; + + XChangeProperty(ui.display, menu->e.window->window, properties[0], XA_ATOM, 32, PropModeReplace, (uint8_t *) properties, 2); + XSetTransientForHint(ui.display, menu->e.window->window, DefaultRootWindow(ui.display)); + + struct Hints { + int flags; + int functions; + int decorations; + int inputMode; + int status; + }; + + struct Hints hints = { 0 }; + hints.flags = 2; + XChangeProperty(ui.display, menu->e.window->window, properties[2], properties[2], 32, PropModeReplace, (uint8_t *) &hints, 5); + + XMapWindow(ui.display, menu->e.window->window); + XMoveResizeWindow(ui.display, menu->e.window->window, menu->pointX, menu->pointY, width, height); +} + +void UIWindowPack(UIWindow *window, int _width) { + int width = _width ? _width : UIElementMessage(window->e.children, UI_MSG_GET_WIDTH, 0, 0); + int height = UIElementMessage(window->e.children, UI_MSG_GET_HEIGHT, width, 0); + XResizeWindow(ui.display, window->window, width, height); +} + +bool _UIProcessEvent(XEvent *event) { + // printf("x11 event: %d\n", event->type); + + if (event->type == ClientMessage && (Atom) event->xclient.data.l[0] == ui.windowClosedID) { + UIWindow *window = _UIFindWindow(event->xclient.window); + if (!window) return false; + bool exit = !UIElementMessage(&window->e, UI_MSG_WINDOW_CLOSE, 0, 0); + if (exit) return true; + _UIUpdate(); + return false; + } else if (event->type == Expose) { + UIWindow *window = _UIFindWindow(event->xexpose.window); + if (!window) return false; + XPutImage(ui.display, window->window, DefaultGC(ui.display, 0), window->image, 0, 0, 0, 0, window->width, window->height); + } else if (event->type == ConfigureNotify) { + UIWindow *window = _UIFindWindow(event->xconfigure.window); + if (!window) return false; + + if (window->width != event->xconfigure.width || window->height != event->xconfigure.height) { + window->width = event->xconfigure.width; + window->height = event->xconfigure.height; + window->bits = (uint32_t *) UI_REALLOC(window->bits, window->width * window->height * 4); + window->image->width = window->width; + window->image->height = window->height; + window->image->bytes_per_line = window->width * 4; + window->image->data = (char *) window->bits; + window->e.bounds = UI_RECT_2S(window->width, window->height); + window->e.clip = UI_RECT_2S(window->width, window->height); +#ifdef UI_DEBUG + for (int i = 0; i < window->width * window->height; i++) window->bits[i] = 0xFF00FF; +#endif + UIElementMessage(&window->e, UI_MSG_LAYOUT, 0, 0); + _UIUpdate(); + } + } else if (event->type == MotionNotify) { + UIWindow *window = _UIFindWindow(event->xmotion.window); + if (!window) return false; + window->cursorX = event->xmotion.x; + window->cursorY = event->xmotion.y; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (event->type == LeaveNotify) { + UIWindow *window = _UIFindWindow(event->xcrossing.window); + if (!window) return false; + + if (!window->pressed) { + window->cursorX = -1; + window->cursorY = -1; + } + + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (event->type == ButtonPress || event->type == ButtonRelease) { + UIWindow *window = _UIFindWindow(event->xbutton.window); + if (!window) return false; + window->cursorX = event->xbutton.x; + window->cursorY = event->xbutton.y; + + if (event->xbutton.button >= 1 && event->xbutton.button <= 3) { + _UIWindowInputEvent(window, (UIMessage) ((event->type == ButtonPress ? UI_MSG_LEFT_DOWN : UI_MSG_LEFT_UP) + + event->xbutton.button * 2 - 2), 0, 0); + } else if (event->xbutton.button == 4) { + _UIWindowInputEvent(window, UI_MSG_MOUSE_WHEEL, -72, 0); + } else if (event->xbutton.button == 5) { + _UIWindowInputEvent(window, UI_MSG_MOUSE_WHEEL, 72, 0); + } + + _UIInspectorSetFocusedWindow(window); + } else if (event->type == KeyPress) { + UIWindow *window = _UIFindWindow(event->xkey.window); + if (!window) return false; + + if (event->xkey.x == 0x7123 && event->xkey.y == 0x7456) { + // HACK! See UIWindowPostMessage. + UIElementMessage(&window->e, (UIMessage) event->xkey.state, 0, + (void *) (((uintptr_t) (event->xkey.time & 0xFFFFFFFF) << 32) + | ((uintptr_t) (event->xkey.x_root & 0xFFFF) << 0) + | ((uintptr_t) (event->xkey.y_root & 0xFFFF) << 16))); + _UIUpdate(); + } else { + char text[32]; + KeySym symbol = NoSymbol; + Status status; + // printf("%ld, %s\n", symbol, text); + UIKeyTyped m = { 0 }; + m.textBytes = Xutf8LookupString(window->xic, &event->xkey, text, sizeof(text) - 1, &symbol, &status); + m.text = text; + m.code = XLookupKeysym(&event->xkey, 0); + + if (symbol == XK_Control_L || symbol == XK_Control_R) { + window->ctrl = true; + window->ctrlCode = event->xkey.keycode; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (symbol == XK_Shift_L || symbol == XK_Shift_R) { + window->shift = true; + window->shiftCode = event->xkey.keycode; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (symbol == XK_Alt_L || symbol == XK_Alt_R) { + window->alt = true; + window->altCode = event->xkey.keycode; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } + + _UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m); + } + } else if (event->type == KeyRelease) { + UIWindow *window = _UIFindWindow(event->xkey.window); + if (!window) return false; + + if (event->xkey.keycode == window->ctrlCode) { + window->ctrl = false; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (event->xkey.keycode == window->shiftCode) { + window->shift = false; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (event->xkey.keycode == window->altCode) { + window->alt = false; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } + } else if (event->type == FocusIn) { + UIWindow *window = _UIFindWindow(event->xfocus.window); + if (!window) return false; + window->ctrl = window->shift = window->alt = false; + } + + return false; +} + +bool _UIMessageLoopSingle(int *result) { + XEvent events[64]; + + if (ui.animating) { + if (XPending(ui.display)) { + XNextEvent(ui.display, events + 0); + } else { + _UIProcessAnimations(); + return true; + } + } else { + XNextEvent(ui.display, events + 0); + } + + int p = 1; + + int configureIndex = -1, motionIndex = -1, exposeIndex = -1; + + while (p < 64 && XPending(ui.display)) { + XNextEvent(ui.display, events + p); + +#define _UI_MERGE_EVENTS(a, b) \ + if (events[p].type == a) { \ + if (b != -1) events[b].type = 0; \ + b = p; \ + } + + _UI_MERGE_EVENTS(ConfigureNotify, configureIndex); + _UI_MERGE_EVENTS(MotionNotify, motionIndex); + _UI_MERGE_EVENTS(Expose, exposeIndex); + + p++; + } + + for (int i = 0; i < p; i++) { + if (!events[i].type) { + continue; + } + + if (_UIProcessEvent(events + i)) { + return false; + } + } + + return true; +} + +void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) { + // HACK! Xlib doesn't seem to have a nice way to do this, + // so send a specially crafted key press event instead. + uintptr_t dp = (uintptr_t) _dp; + XKeyEvent event = { 0 }; + event.display = ui.display; + event.window = window->window; + event.root = DefaultRootWindow(ui.display); + event.subwindow = None; + event.time = dp >> 32; + event.x = 0x7123; + event.y = 0x7456; + event.x_root = (dp >> 0) & 0xFFFF; + event.y_root = (dp >> 16) & 0xFFFF; + event.same_screen = True; + event.keycode = 1; + event.state = message; + event.type = KeyPress; + XSendEvent(ui.display, window->window, True, KeyPressMask, (XEvent *) &event); + XFlush(ui.display); +} + +#endif + +#ifdef UI_WINDOWS + +const int UI_KEYCODE_A = 'A'; +const int UI_KEYCODE_0 = '0'; +const int UI_KEYCODE_BACKSPACE = VK_BACK; +const int UI_KEYCODE_DELETE = VK_DELETE; +const int UI_KEYCODE_DOWN = VK_DOWN; +const int UI_KEYCODE_END = VK_END; +const int UI_KEYCODE_ENTER = VK_RETURN; +const int UI_KEYCODE_ESCAPE = VK_ESCAPE; +const int UI_KEYCODE_F1 = VK_F1; +const int UI_KEYCODE_HOME = VK_HOME; +const int UI_KEYCODE_LEFT = VK_LEFT; +const int UI_KEYCODE_RIGHT = VK_RIGHT; +const int UI_KEYCODE_SPACE = VK_SPACE; +const int UI_KEYCODE_TAB = VK_TAB; +const int UI_KEYCODE_UP = VK_UP; + +int _UIWindowMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_DESTROY) { + UIWindow *window = (UIWindow *) element; + _UIWindowDestroyCommon(window); + SetWindowLongPtr(window->hwnd, GWLP_USERDATA, 0); + DestroyWindow(window->hwnd); + } + + return _UIWindowMessageCommon(element, message, di, dp); +} + +LRESULT CALLBACK _UIWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + UIWindow *window = (UIWindow *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + + if (!window || ui.assertionFailure) { + return DefWindowProc(hwnd, message, wParam, lParam); + } + + if (message == WM_CLOSE) { + if (UIElementMessage(&window->e, UI_MSG_WINDOW_CLOSE, 0, 0)) { + _UIUpdate(); + return 0; + } else { + PostQuitMessage(0); + } + } else if (message == WM_SIZE) { + RECT client; + GetClientRect(hwnd, &client); + window->width = client.right; + window->height = client.bottom; + window->bits = (uint32_t *) UI_REALLOC(window->bits, window->width * window->height * 4); + window->e.bounds = UI_RECT_2S(window->width, window->height); + window->e.clip = UI_RECT_2S(window->width, window->height); + UIElementMessage(&window->e, UI_MSG_LAYOUT, 0, 0); + _UIUpdate(); + } else if (message == WM_MOUSEMOVE) { + if (!window->trackingLeave) { + window->trackingLeave = true; + TRACKMOUSEEVENT leave = { 0 }; + leave.cbSize = sizeof(TRACKMOUSEEVENT); + leave.dwFlags = TME_LEAVE; + leave.hwndTrack = hwnd; + TrackMouseEvent(&leave); + } + + POINT cursor; + GetCursorPos(&cursor); + ScreenToClient(hwnd, &cursor); + window->cursorX = cursor.x; + window->cursorY = cursor.y; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (message == WM_MOUSELEAVE) { + window->trackingLeave = false; + + if (!window->pressed) { + window->cursorX = -1; + window->cursorY = -1; + } + + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (message == WM_LBUTTONDOWN) { + SetCapture(hwnd); + _UIWindowInputEvent(window, UI_MSG_LEFT_DOWN, 0, 0); + } else if (message == WM_LBUTTONUP) { + if (window->pressedButton == 1) ReleaseCapture(); + _UIWindowInputEvent(window, UI_MSG_LEFT_UP, 0, 0); + } else if (message == WM_MBUTTONDOWN) { + SetCapture(hwnd); + _UIWindowInputEvent(window, UI_MSG_MIDDLE_DOWN, 0, 0); + } else if (message == WM_MBUTTONUP) { + if (window->pressedButton == 2) ReleaseCapture(); + _UIWindowInputEvent(window, UI_MSG_MIDDLE_UP, 0, 0); + } else if (message == WM_RBUTTONDOWN) { + SetCapture(hwnd); + _UIWindowInputEvent(window, UI_MSG_RIGHT_DOWN, 0, 0); + } else if (message == WM_RBUTTONUP) { + if (window->pressedButton == 3) ReleaseCapture(); + _UIWindowInputEvent(window, UI_MSG_RIGHT_UP, 0, 0); + } else if (message == WM_MOUSEWHEEL) { + int delta = (int) wParam >> 16; + _UIWindowInputEvent(window, UI_MSG_MOUSE_WHEEL, -delta, 0); + } else if (message == WM_KEYDOWN) { + window->ctrl = GetKeyState(VK_CONTROL) & 0x8000; + window->shift = GetKeyState(VK_SHIFT) & 0x8000; + window->alt = GetKeyState(VK_MENU) & 0x8000; + + UIKeyTyped m = { 0 }; + m.code = wParam; + _UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m); + } else if (message == WM_CHAR) { + UIKeyTyped m = { 0 }; + char c = wParam; + m.text = &c; + m.textBytes = 1; + _UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m); + } else if (message == WM_PAINT) { + PAINTSTRUCT paint; + HDC dc = BeginPaint(hwnd, &paint); + BITMAPINFOHEADER info = { 0 }; + info.biSize = sizeof(info); + info.biWidth = window->width, info.biHeight = -window->height; + info.biPlanes = 1, info.biBitCount = 32; + StretchDIBits(dc, 0, 0, UI_RECT_SIZE(window->e.bounds), 0, 0, UI_RECT_SIZE(window->e.bounds), + window->bits, (BITMAPINFO *) &info, DIB_RGB_COLORS, SRCCOPY); + EndPaint(hwnd, &paint); + } else if (message == WM_SETCURSOR && LOWORD(lParam) == HTCLIENT) { + SetCursor(ui.cursors[window->cursorStyle]); + return 1; + } else if (message == WM_SETFOCUS || message == WM_KILLFOCUS) { + _UIMenusClose(); + + if (message == WM_SETFOCUS) { + _UIInspectorSetFocusedWindow(window); + } + } else if (message == WM_MOUSEACTIVATE && (window->e.flags & UI_WINDOW_MENU)) { + return MA_NOACTIVATE; + } else if (message == WM_APP + 1) { + UIElementMessage(&window->e, (UIMessage) wParam, 0, (void *) lParam); + _UIUpdate(); + } else { + if (message == WM_NCLBUTTONDOWN || message == WM_NCMBUTTONDOWN || message == WM_NCRBUTTONDOWN) { + if (~window->e.flags & UI_WINDOW_MENU) { + _UIMenusClose(); + _UIUpdate(); + } + } + + return DefWindowProc(hwnd, message, wParam, lParam); + } + + return 0; +} + +void UIInitialise() { + _UIInitialiseCommon(); + + ui.cursors[UI_CURSOR_ARROW] = LoadCursor(NULL, IDC_ARROW); + ui.cursors[UI_CURSOR_TEXT] = LoadCursor(NULL, IDC_IBEAM); + ui.cursors[UI_CURSOR_SPLIT_V] = LoadCursor(NULL, IDC_SIZENS); + ui.cursors[UI_CURSOR_SPLIT_H] = LoadCursor(NULL, IDC_SIZEWE); + ui.cursors[UI_CURSOR_FLIPPED_ARROW] = LoadCursor(NULL, IDC_ARROW); + ui.cursors[UI_CURSOR_CROSS_HAIR] = LoadCursor(NULL, IDC_CROSS); + ui.cursors[UI_CURSOR_HAND] = LoadCursor(NULL, IDC_HAND); + ui.cursors[UI_CURSOR_RESIZE_UP] = LoadCursor(NULL, IDC_SIZENS); + ui.cursors[UI_CURSOR_RESIZE_LEFT] = LoadCursor(NULL, IDC_SIZEWE); + ui.cursors[UI_CURSOR_RESIZE_UP_RIGHT] = LoadCursor(NULL, IDC_SIZENESW); + ui.cursors[UI_CURSOR_RESIZE_UP_LEFT] = LoadCursor(NULL, IDC_SIZENWSE); + ui.cursors[UI_CURSOR_RESIZE_DOWN] = LoadCursor(NULL, IDC_SIZENS); + ui.cursors[UI_CURSOR_RESIZE_RIGHT] = LoadCursor(NULL, IDC_SIZEWE); + ui.cursors[UI_CURSOR_RESIZE_DOWN_LEFT] = LoadCursor(NULL, IDC_SIZENESW); + ui.cursors[UI_CURSOR_RESIZE_DOWN_RIGHT] = LoadCursor(NULL, IDC_SIZENWSE); + + ui.heap = GetProcessHeap(); + + WNDCLASS windowClass = { 0 }; + windowClass.lpfnWndProc = _UIWindowProcedure; + windowClass.lpszClassName = "normal"; + RegisterClass(&windowClass); + windowClass.style |= CS_DROPSHADOW; + windowClass.lpszClassName = "shadow"; + RegisterClass(&windowClass); +} + +bool _UIMessageLoopSingle(int *result) { + MSG message = { 0 }; + + if (ui.animating) { + if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) { + if (message.message == WM_QUIT) { + *result = message.wParam; + return false; + } + + TranslateMessage(&message); + DispatchMessage(&message); + } else { + _UIProcessAnimations(); + } + } else { + if (!GetMessage(&message, NULL, 0, 0)) { + *result = message.wParam; + return false; + } + + TranslateMessage(&message); + DispatchMessage(&message); + } + + return true; +} + +void UIMenuShow(UIMenu *menu) { + int width, height; + _UIMenuPrepare(menu, &width, &height); + MoveWindow(menu->e.window->hwnd, menu->pointX, menu->pointY, width, height, FALSE); + ShowWindow(menu->e.window->hwnd, SW_SHOWNOACTIVATE); +} + +UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, int width, int height) { + _UIMenusClose(); + + UIWindow *window = (UIWindow *) UIElementCreate(sizeof(UIWindow), NULL, flags | UI_ELEMENT_WINDOW, _UIWindowMessage, "Window"); + _UIWindowAdd(window); + if (owner) window->scale = owner->scale; + + if (flags & UI_WINDOW_MENU) { + UI_ASSERT(owner); + + window->hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_NOACTIVATE, "shadow", 0, WS_POPUP, + 0, 0, 0, 0, owner->hwnd, NULL, NULL, NULL); + } else { + window->hwnd = CreateWindow("normal", cTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, width ? width : CW_USEDEFAULT, height ? height : CW_USEDEFAULT, + owner ? owner->hwnd : NULL, NULL, NULL, NULL); + } + + SetWindowLongPtr(window->hwnd, GWLP_USERDATA, (LONG_PTR) window); + + if (~flags & UI_WINDOW_MENU) { + ShowWindow(window->hwnd, SW_SHOW); + PostMessage(window->hwnd, WM_SIZE, 0, 0); + } + + return window; +} + +void _UIWindowEndPaint(UIWindow *window, UIPainter *painter) { + HDC dc = GetDC(window->hwnd); + BITMAPINFOHEADER info = { 0 }; + info.biSize = sizeof(info); + info.biWidth = window->width, info.biHeight = window->height; + info.biPlanes = 1, info.biBitCount = 32; + StretchDIBits(dc, + UI_RECT_TOP_LEFT(window->updateRegion), UI_RECT_SIZE(window->updateRegion), + window->updateRegion.l, window->updateRegion.b + 1, + UI_RECT_WIDTH(window->updateRegion), -UI_RECT_HEIGHT(window->updateRegion), + window->bits, (BITMAPINFO *) &info, DIB_RGB_COLORS, SRCCOPY); + ReleaseDC(window->hwnd, dc); +} + +void _UIWindowSetCursor(UIWindow *window, int cursor) { + SetCursor(ui.cursors[cursor]); +} + +void _UIWindowGetScreenPosition(UIWindow *window, int *_x, int *_y) { + POINT p; + p.x = 0; + p.y = 0; + ClientToScreen(window->hwnd, &p); + *_x = p.x; + *_y = p.y; +} + +void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) { + PostMessage(window->hwnd, WM_APP + 1, (WPARAM) message, (LPARAM) _dp); +} + +void *_UIHeapReAlloc(void *pointer, size_t size) { + if (pointer) { + if (size) { + return HeapReAlloc(ui.heap, 0, pointer, size); + } else { + UI_FREE(pointer); + return NULL; + } + } else { + if (size) { + return UI_MALLOC(size); + } else { + return NULL; + } + } +} + +#endif + +#ifdef UI_ESSENCE + +const int UI_KEYCODE_A = ES_SCANCODE_A; +const int UI_KEYCODE_0 = ES_SCANCODE_0; +const int UI_KEYCODE_BACKSPACE = ES_SCANCODE_BACKSPACE; +const int UI_KEYCODE_DELETE = ES_SCANCODE_DELETE; +const int UI_KEYCODE_DOWN = ES_SCANCODE_DOWN_ARROW; +const int UI_KEYCODE_END = ES_SCANCODE_END; +const int UI_KEYCODE_ENTER = ES_SCANCODE_ENTER; +const int UI_KEYCODE_ESCAPE = ES_SCANCODE_ESCAPE; +const int UI_KEYCODE_F1 = ES_SCANCODE_F1; +const int UI_KEYCODE_HOME = ES_SCANCODE_HOME; +const int UI_KEYCODE_LEFT = ES_SCANCODE_LEFT_ARROW; +const int UI_KEYCODE_RIGHT = ES_SCANCODE_RIGHT_ARROW; +const int UI_KEYCODE_SPACE = ES_SCANCODE_SPACE; +const int UI_KEYCODE_TAB = ES_SCANCODE_TAB; +const int UI_KEYCODE_UP = ES_SCANCODE_UP_ARROW; + +int _UIWindowMessage(UIElement *element, UIMessage message, int di, void *dp) { + if (message == UI_MSG_DESTROY) { + // TODO Non-main windows. + element->window = NULL; + EsInstanceDestroy(ui.instance); + } + + return _UIWindowMessageCommon(element, message, di, dp); +} + +void UIInitialise() { + _UIInitialiseCommon(); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + ui.instance = EsInstanceCreate(message, NULL, 0); + break; + } + } +} + +bool _UIMessageLoopSingle(int *result) { + if (ui.animating) { + // TODO. + } else { + EsMessageReceive(); + } + + return true; +} + +void UIMenuShow(UIMenu *menu) { + // TODO. +} + +int _UIWindowCanvasMessage(EsElement *element, EsMessage *message) { + UIWindow *window = (UIWindow *) element->window->userData.p; + + if (!window) { + return 0; + } else if (message->type == ES_MSG_PAINT) { + EsRectangle bounds = ES_RECT_4PD(message->painter->offsetX, message->painter->offsetY, window->width, window->height); + EsDrawBitmap(message->painter, bounds, window->bits, window->width * 4, 0xFFFF); + } else if (message->type == ES_MSG_LAYOUT) { + EsElementGetSize(element, &window->width, &window->height); + window->bits = (uint32_t *) UI_REALLOC(window->bits, window->width * window->height * 4); + window->e.bounds = UI_RECT_2S(window->width, window->height); + window->e.clip = UI_RECT_2S(window->width, window->height); + UIElementMessage(&window->e, UI_MSG_LAYOUT, 0, 0); + _UIUpdate(); + } else if (message->type == ES_MSG_MOUSE_MOVED || message->type == ES_MSG_HOVERED_END + || message->type == ES_MSG_MOUSE_LEFT_DRAG || message->type == ES_MSG_MOUSE_RIGHT_DRAG || message->type == ES_MSG_MOUSE_MIDDLE_DRAG) { + EsPoint point = EsMouseGetPosition(element); + window->cursorX = point.x, window->cursorY = point.y; + _UIWindowInputEvent(window, UI_MSG_MOUSE_MOVE, 0, 0); + } else if (message->type == ES_MSG_KEY_DOWN) { + window->ctrl = EsKeyboardIsCtrlHeld(); + window->shift = EsKeyboardIsShiftHeld(); + window->alt = EsKeyboardIsAltHeld(); + UIKeyTyped m = { 0 }; + char c[64]; + m.text = c; + m.textBytes = EsMessageGetInputText(message, c); + m.code = message->keyboard.scancode; + _UIWindowInputEvent(window, UI_MSG_KEY_TYPED, 0, &m); + } else if (message->type == ES_MSG_MOUSE_LEFT_CLICK) { + _UIInspectorSetFocusedWindow(window); + } else if (message->type == ES_MSG_USER_START) { + UIElementMessage(&window->e, (UIMessage) message->user.context1.u, 0, (void *) message->user.context2.p); + _UIUpdate(); + } else if (message->type == ES_MSG_GET_CURSOR) { + message->cursorStyle = ES_CURSOR_NORMAL; + if (window->cursor == UI_CURSOR_TEXT) message->cursorStyle = ES_CURSOR_TEXT; + if (window->cursor == UI_CURSOR_SPLIT_V) message->cursorStyle = ES_CURSOR_SPLIT_VERTICAL; + if (window->cursor == UI_CURSOR_SPLIT_H) message->cursorStyle = ES_CURSOR_SPLIT_HORIZONTAL; + if (window->cursor == UI_CURSOR_FLIPPED_ARROW) message->cursorStyle = ES_CURSOR_SELECT_LINES; + if (window->cursor == UI_CURSOR_CROSS_HAIR) message->cursorStyle = ES_CURSOR_CROSS_HAIR_PICK; + if (window->cursor == UI_CURSOR_HAND) message->cursorStyle = ES_CURSOR_HAND_HOVER; + if (window->cursor == UI_CURSOR_RESIZE_UP) message->cursorStyle = ES_CURSOR_RESIZE_VERTICAL; + if (window->cursor == UI_CURSOR_RESIZE_LEFT) message->cursorStyle = ES_CURSOR_RESIZE_HORIZONTAL; + if (window->cursor == UI_CURSOR_RESIZE_UP_RIGHT) message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_1; + if (window->cursor == UI_CURSOR_RESIZE_UP_LEFT) message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_2; + if (window->cursor == UI_CURSOR_RESIZE_DOWN) message->cursorStyle = ES_CURSOR_RESIZE_VERTICAL; + if (window->cursor == UI_CURSOR_RESIZE_RIGHT) message->cursorStyle = ES_CURSOR_RESIZE_HORIZONTAL; + if (window->cursor == UI_CURSOR_RESIZE_DOWN_RIGHT) message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_1; + if (window->cursor == UI_CURSOR_RESIZE_DOWN_LEFT) message->cursorStyle = ES_CURSOR_RESIZE_DIAGONAL_2; + } + + else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) _UIWindowInputEvent(window, UI_MSG_LEFT_DOWN, 0, 0); + else if (message->type == ES_MSG_MOUSE_LEFT_UP) _UIWindowInputEvent(window, UI_MSG_LEFT_UP, 0, 0); + else if (message->type == ES_MSG_MOUSE_MIDDLE_DOWN) _UIWindowInputEvent(window, UI_MSG_MIDDLE_DOWN, 0, 0); + else if (message->type == ES_MSG_MOUSE_MIDDLE_UP) _UIWindowInputEvent(window, UI_MSG_MIDDLE_UP, 0, 0); + else if (message->type == ES_MSG_MOUSE_RIGHT_DOWN) _UIWindowInputEvent(window, UI_MSG_RIGHT_DOWN, 0, 0); + else if (message->type == ES_MSG_MOUSE_RIGHT_UP) _UIWindowInputEvent(window, UI_MSG_RIGHT_UP, 0, 0); + + else return 0; + + return ES_HANDLED; +} + +UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, int width, int height) { + _UIMenusClose(); + + UIWindow *window = (UIWindow *) UIElementCreate(sizeof(UIWindow), NULL, flags | UI_ELEMENT_WINDOW, _UIWindowMessage, "Window"); + _UIWindowAdd(window); + if (owner) window->scale = owner->scale; + + if (flags & UI_WINDOW_MENU) { + // TODO. + } else { + // TODO Non-main windows. + window->window = ui.instance->window; + window->window->userData = window; + window->canvas = EsCustomElementCreate(window->window, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE); + window->canvas->messageUser = _UIWindowCanvasMessage; + EsWindowSetTitle(window->window, cTitle, -1); + EsElementFocus(window->canvas); + } + + return window; +} + +void _UIWindowEndPaint(UIWindow *window, UIPainter *painter) { + EsElementRepaint(window->canvas, &window->updateRegion); +} + +void _UIWindowSetCursor(UIWindow *window, int cursor) { + window->cursor = cursor; +} + +void _UIWindowGetScreenPosition(UIWindow *window, int *_x, int *_y) { + EsRectangle r = EsElementGetScreenBounds(window->window); + *_x = r.l, *_y = r.t; +} + +void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) { + EsMessage m = {}; + m.type = ES_MSG_USER_START; + m.user.context1.u = message; + m.user.context2.p = _dp; + EsMessagePost(window->canvas, &m); +} + +#endif + +#endif diff --git a/util/nanosvg.h b/util/nanosvg.h new file mode 100644 index 0000000..1f5627f --- /dev/null +++ b/util/nanosvg.h @@ -0,0 +1,3018 @@ +/* + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example + * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/) + * + * Arc calculation code based on canvg (https://code.google.com/p/canvg/) + * + * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + * + */ + +#ifndef NANOSVG_H +#define NANOSVG_H + +#ifndef NANOSVG_CPLUSPLUS +#ifdef __cplusplus +extern "C" { +#endif +#endif + +// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. +// +// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game. +// +// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request! +// +// The shapes in the SVG images are transformed by the viewBox and converted to specified units. +// That is, you should get the same looking data as your designed in your favorite app. +// +// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose +// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters. +// +// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. +// DPI (dots-per-inch) controls how the unit conversion is done. +// +// If you don't know or care about the units stuff, "px" and 96 should get you going. + + +/* Example Usage: + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); +*/ + +#define NSVG_ID_SIZE (256) + +enum NSVGpaintType { + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 +}; + +enum NSVGspreadType { + NSVG_SPREAD_PAD = 0, + NSVG_SPREAD_REFLECT = 1, + NSVG_SPREAD_REPEAT = 2 +}; + +enum NSVGlineJoin { + NSVG_JOIN_MITER = 0, + NSVG_JOIN_ROUND = 1, + NSVG_JOIN_BEVEL = 2 +}; + +enum NSVGlineCap { + NSVG_CAP_BUTT = 0, + NSVG_CAP_ROUND = 1, + NSVG_CAP_SQUARE = 2 +}; + +enum NSVGfillRule { + NSVG_FILLRULE_NONZERO = 0, + NSVG_FILLRULE_EVENODD = 1 +}; + +enum NSVGflags { + NSVG_FLAGS_VISIBLE = 0x01 +}; + +typedef struct NSVGgradientStop { + unsigned int color; + float offset; +} NSVGgradientStop; + +typedef struct NSVGgradient { + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; +} NSVGgradient; + +typedef struct NSVGpaint { + char type; + union { + unsigned int color; + NSVGgradient* gradient; + }; +} NSVGpaint; + +typedef struct NSVGpath +{ + float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath* next; // Pointer to next path, or NULL if last element. +} NSVGpath; + +typedef struct NSVGshape +{ + char id[NSVG_ID_SIZE]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + NSVGpath* paths; // Linked list of paths in the image. + struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +} NSVGshape; + +typedef struct NSVGimage +{ + float width; // Width of the image. + float height; // Height of the image. + NSVGshape* shapes; // Linked list of shapes in the image. +} NSVGimage; + +// Parses SVG file from a file, returns SVG image as paths. +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); + +// Parses SVG file from a null terminated string, returns SVG image as paths. +// Important note: changes the string. +NSVGimage* nsvgParse(char* input, const char* units, float dpi); + +// Duplicates a path. +NSVGpath* nsvgDuplicatePath(NSVGpath* p); + +// Deletes an image. +void nsvgDelete(NSVGimage* image); + +#ifndef NANOSVG_CPLUSPLUS +#ifdef __cplusplus +} +#endif +#endif + +#endif // NANOSVG_H + +#ifdef NANOSVG_IMPLEMENTATION + +#include <string.h> +#include <stdlib.h> +#include <math.h> + +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. + +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_SLICE 2 + +#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) + +#ifdef _MSC_VER + #pragma warning (disable: 4996) // Switch off security warnings + #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings + #ifdef __cplusplus + #define NSVG_INLINE inline + #else + #define NSVG_INLINE + #endif +#else + #define NSVG_INLINE inline +#endif + + +static int nsvg__isspace(char c) +{ + return strchr(" \t\n\v\f\r", c) != 0; +} + +static int nsvg__isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } +static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } + + +// Simple XML parser + +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 +#define NSVG_XML_MAX_ATTRIBS 256 + +static void nsvg__parseContent(char* s, + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + // Trim start white spaces + while (*s && nsvg__isspace(*s)) s++; + if (!*s) return; + + if (contentCb) + (*contentCb)(ud, s); +} + +static void nsvg__parseElement(char* s, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void* ud) +{ + const char* attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char* name; + int start = 0; + int end = 0; + char quote; + + // Skip white space after the '<' + while (*s && nsvg__isspace(*s)) s++; + + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } else { + start = 1; + } + + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; + + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) s++; + if (*s) { *s++ = '\0'; } + + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { + char* name = NULL; + char* value = NULL; + + // Skip white space before the attrib name + while (*s && nsvg__isspace(*s)) s++; + if (!*s) break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') s++; + if (*s) { *s++ = '\0'; } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') s++; + if (!*s) break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) s++; + if (*s) { *s++ = '\0'; } + + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } + + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; + + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); +} + +int nsvg__parseXML(char* input, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + char* s = input; + char* mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } else { + s++; + } + } + + return 1; +} + + +/* Simple SVG parser. */ + +#define NSVG_MAX_ATTR 128 + +enum NSVGgradientUnits { + NSVG_USER_SPACE = 0, + NSVG_OBJECT_SPACE = 1 +}; + +#define NSVG_MAX_DASHES 8 + +enum NSVGunits { + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX +}; + +typedef struct NSVGcoordinate { + float value; + int units; +} NSVGcoordinate; + +typedef struct NSVGlinearData { + NSVGcoordinate x1, y1, x2, y2; +} NSVGlinearData; + +typedef struct NSVGradialData { + NSVGcoordinate cx, cy, r, fx, fy; +} NSVGradialData; + +typedef struct NSVGgradientData +{ + char id[NSVG_ID_SIZE]; + char ref[NSVG_ID_SIZE]; + char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop* stops; + struct NSVGgradientData* next; +} NSVGgradientData; + +typedef struct NSVGattrib +{ + char id[NSVG_ID_SIZE]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[NSVG_ID_SIZE]; + char strokeGradient[NSVG_ID_SIZE]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; +} NSVGattrib; + +typedef struct NSVGparser +{ + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float* pts; + int npts; + int cpts; + NSVGpath* plist; + NSVGimage* image; + NSVGgradientData* gradients; + NSVGshape* shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; +} NSVGparser; + +static void nsvg__xformIdentity(float* t) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetTranslation(float* t, float tx, float ty) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = tx; t[5] = ty; +} + +static void nsvg__xformSetScale(float* t, float sx, float sy) +{ + t[0] = sx; t[1] = 0.0f; + t[2] = 0.0f; t[3] = sy; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewX(float* t, float a) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = tanf(a); t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewY(float* t, float a) +{ + t[0] = 1.0f; t[1] = tanf(a); + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetRotation(float* t, float a) +{ + float cs = cosf(a), sn = sinf(a); + t[0] = cs; t[1] = sn; + t[2] = -sn; t[3] = cs; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformMultiply(float* t, float* s) +{ + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; +} + +static void nsvg__xformInverse(float* inv, float* t) +{ + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +} + +static void nsvg__xformPremultiply(float* t, float* s) +{ + float s2[6]; + memcpy(s2, s, sizeof(float)*6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float)*6); +} + +static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2] + t[4]; + *dy = x*t[1] + y*t[3] + t[5]; +} + +static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2]; + *dy = x*t[1] + y*t[3]; +} + +#define NSVG_EPSILON (1e-12) + +static int nsvg__ptInBounds(float* pt, float* bounds) +{ + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +} + + +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) +{ + double it = 1.0-t; + return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; +} + +static void nsvg__curveBounds(float* bounds, float* curve) +{ + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float* v0 = &curve[0]; + float* v1 = &curve[2]; + float* v2 = &curve[4]; + float* v3 = &curve[6]; + + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); + + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; + + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } else { + b2ac = b*b - 4.0*c*a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); + bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); + } + } +} + +static NSVGparser* nsvg__createParser() +{ + NSVGparser* p; + p = (NSVGparser*)malloc(sizeof(NSVGparser)); + if (p == NULL) goto error; + memset(p, 0, sizeof(NSVGparser)); + + p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); + if (p->image == NULL) goto error; + memset(p->image, 0, sizeof(NSVGimage)); + + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0,0,0); + p->attr[0].strokeColor = NSVG_RGB(0,0,0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; + + return p; + +error: + if (p) { + if (p->image) free(p->image); + free(p); + } + return NULL; +} + +static void nsvg__deletePaths(NSVGpath* path) +{ + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } +} + +static void nsvg__deletePaint(NSVGpaint* paint) +{ + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); +} + +static void nsvg__deleteGradientData(NSVGgradientData* grad) +{ + NSVGgradientData* next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } +} + +static void nsvg__deleteParser(NSVGparser* p) +{ + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } +} + +static void nsvg__resetPath(NSVGparser* p) +{ + p->npts = 0; +} + +static void nsvg__addPoint(NSVGparser* p, float x, float y) +{ + if (p->npts+1 > p->cpts) { + p->cpts = p->cpts ? p->cpts*2 : 8; + p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); + if (!p->pts) return; + } + p->pts[p->npts*2+0] = x; + p->pts[p->npts*2+1] = y; + p->npts++; +} + +static void nsvg__moveTo(NSVGparser* p, float x, float y) +{ + if (p->npts > 0) { + p->pts[(p->npts-1)*2+0] = x; + p->pts[(p->npts-1)*2+1] = y; + } else { + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__lineTo(NSVGparser* p, float x, float y) +{ + float px,py, dx,dy; + if (p->npts > 0) { + px = p->pts[(p->npts-1)*2+0]; + py = p->pts[(p->npts-1)*2+1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); + nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) +{ + if (p->npts > 0) { + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); + } +} + +static NSVGattrib* nsvg__getAttr(NSVGparser* p) +{ + return &p->attr[p->attrHead]; +} + +static void nsvg__pushAttr(NSVGparser* p) +{ + if (p->attrHead < NSVG_MAX_ATTR-1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); + } +} + +static void nsvg__popAttr(NSVGparser* p) +{ + if (p->attrHead > 0) + p->attrHead--; +} + +static float nsvg__actualOrigX(NSVGparser* p) +{ + return p->viewMinx; +} + +static float nsvg__actualOrigY(NSVGparser* p) +{ + return p->viewMiny; +} + +static float nsvg__actualWidth(NSVGparser* p) +{ + return p->viewWidth; +} + +static float nsvg__actualHeight(NSVGparser* p) +{ + return p->viewHeight; +} + +static float nsvg__actualLength(NSVGparser* p) +{ + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w*w + h*h) / sqrtf(2.0f); +} + +static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) +{ + NSVGattrib* attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: return c.value; + case NSVG_UNITS_PX: return c.value; + case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: return c.value * p->dpi; + case NSVG_UNITS_EM: return c.value * attr->fontSize; + case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; + default: return c.value; + } + return c.value; +} + +static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) +{ + NSVGgradientData* grad = p->gradients; + if (id == NULL || *id == '\0') + return NULL; + while (grad != NULL) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; +} + +static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) +{ + NSVGattrib* attr = nsvg__getAttr(p); + NSVGgradientData* data = NULL; + NSVGgradientData* ref = NULL; + NSVGgradientStop* stops = NULL; + NSVGgradient* grad; + float ox, oy, sw, sh, sl; + int nstops = 0; + int refIter; + + data = nsvg__findGradientData(p, id); + if (data == NULL) return NULL; + + // TODO: use ref to fill in all unset values too. + ref = data; + refIter = 0; + while (ref != NULL) { + NSVGgradientData* nextRef = NULL; + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + nextRef = nsvg__findGradientData(p, ref->ref); + if (nextRef == ref) break; // prevent infite loops on malformed data + ref = nextRef; + refIter++; + if (refIter > 32) break; // prevent infite loops on malformed data + } + if (stops == NULL) return NULL; + + grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); + if (grad == NULL) return NULL; + + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); + + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; grad->xform[1] = -dx; + grad->xform[2] = dx; grad->xform[3] = dy; + grad->xform[4] = x1; grad->xform[5] = y1; + } else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; grad->xform[1] = 0; + grad->xform[2] = 0; grad->xform[3] = r; + grad->xform[4] = cx; grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } + + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, attr->xform); + + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); + grad->nstops = nstops; + + *paintType = data->type; + + return grad; +} + +static float nsvg__getAverageScale(float* t) +{ + float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); + float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); + return (sx + sy) * 0.5f; +} + +static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) +{ + NSVGpath* path; + float curve[4*2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts-1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } +} + +static void nsvg__addShape(NSVGparser* p) +{ + NSVGattrib* attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape* shape; + NSVGpath* path; + int i; + + if (p->plist == NULL) + return; + + shape = (NSVGshape*)malloc(sizeof(NSVGshape)); + if (shape == NULL) goto error; + memset(shape, 0, sizeof(NSVGshape)); + + memcpy(shape->id, attr->id, sizeof shape->id); + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; + + shape->paths = p->plist; + p->plist = NULL; + + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } + + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; + } else if (attr->hasFill == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); + if (shape->fill.gradient == NULL) { + shape->fill.type = NSVG_PAINT_NONE; + } + } + + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; + } else if (attr->hasStroke == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); + if (shape->stroke.gradient == NULL) + shape->stroke.type = NSVG_PAINT_NONE; + } + + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; + + return; + +error: + if (shape) free(shape); +} + +static void nsvg__addPath(NSVGparser* p, char closed) +{ + NSVGattrib* attr = nsvg__getAttr(p); + NSVGpath* path = NULL; + float bounds[4]; + float* curve; + int i; + + if (p->npts < 4) + return; + + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); + + // Expect 1 + N*3 points (N = number of cubic bezier segments). + if ((p->npts % 3) != 1) + return; + + path = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (path == NULL) goto error; + memset(path, 0, sizeof(NSVGpath)); + + path->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (path->pts == NULL) goto error; + path->closed = closed; + path->npts = p->npts; + + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); + + // Find bounds + for (i = 0; i < path->npts-1; i += 3) { + curve = &path->pts[i*2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } + + path->next = p->plist; + p->plist = path; + + return; + +error: + if (path != NULL) { + if (path->pts != NULL) free(path->pts); + free(path); + } +} + +// We roll our own string to float because the std library one uses locale and messes things up. +static double nsvg__atof(const char* s) +{ + char* cur = (char*)s; + char* end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; + + // Parse optional sign + if (*cur == '+') { + cur++; + } else if (*cur == '-') { + sign = -1; + cur++; + } + + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } + + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } + + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; + + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + long expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } + + return res * sign; +} + + +static const char* nsvg__parseNumber(const char* s, char* it, const int size) +{ + const int last = size-1; + int i = 0; + + // sign + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + // integer part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) it[i++] = *s; + s++; + // fraction part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + // exponent + if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { + if (i < last) it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + it[i] = '\0'; + + return s; +} + +static const char* nsvg__getNextPathItem(const char* s, char* it) +{ + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + if (!*s) return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } + + return s; +} + +static unsigned int nsvg__parseColorHex(const char* str) +{ + unsigned int c = 0, r = 0, g = 0, b = 0; + int n = 0; + str++; // skip # + // Calculate number of characters. + while(str[n] && !nsvg__isspace(str[n])) + n++; + if (n == 6) { + sscanf(str, "%x", &c); + } else if (n == 3) { + sscanf(str, "%x", &c); + c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8); + c |= c<<4; + } + r = (c >> 16) & 0xff; + g = (c >> 8) & 0xff; + b = c & 0xff; + return NSVG_RGB(r,g,b); +} + +static unsigned int nsvg__parseColorRGB(const char* str) +{ + int r = -1, g = -1, b = -1; + char s1[32]="", s2[32]=""; + sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); + if (strchr(s1, '%')) { + return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100); + } else { + return NSVG_RGB(r,g,b); + } +} + +typedef struct NSVGNamedColor { + const char* name; + unsigned int color; +} NSVGNamedColor; + +NSVGNamedColor nsvg__colors[] = { + + { "red", NSVG_RGB(255, 0, 0) }, + { "green", NSVG_RGB( 0, 128, 0) }, + { "blue", NSVG_RGB( 0, 0, 255) }, + { "yellow", NSVG_RGB(255, 255, 0) }, + { "cyan", NSVG_RGB( 0, 255, 255) }, + { "magenta", NSVG_RGB(255, 0, 255) }, + { "black", NSVG_RGB( 0, 0, 0) }, + { "grey", NSVG_RGB(128, 128, 128) }, + { "gray", NSVG_RGB(128, 128, 128) }, + { "white", NSVG_RGB(255, 255, 255) }, + +#ifdef NANOSVG_ALL_COLOR_KEYWORDS + { "aliceblue", NSVG_RGB(240, 248, 255) }, + { "antiquewhite", NSVG_RGB(250, 235, 215) }, + { "aqua", NSVG_RGB( 0, 255, 255) }, + { "aquamarine", NSVG_RGB(127, 255, 212) }, + { "azure", NSVG_RGB(240, 255, 255) }, + { "beige", NSVG_RGB(245, 245, 220) }, + { "bisque", NSVG_RGB(255, 228, 196) }, + { "blanchedalmond", NSVG_RGB(255, 235, 205) }, + { "blueviolet", NSVG_RGB(138, 43, 226) }, + { "brown", NSVG_RGB(165, 42, 42) }, + { "burlywood", NSVG_RGB(222, 184, 135) }, + { "cadetblue", NSVG_RGB( 95, 158, 160) }, + { "chartreuse", NSVG_RGB(127, 255, 0) }, + { "chocolate", NSVG_RGB(210, 105, 30) }, + { "coral", NSVG_RGB(255, 127, 80) }, + { "cornflowerblue", NSVG_RGB(100, 149, 237) }, + { "cornsilk", NSVG_RGB(255, 248, 220) }, + { "crimson", NSVG_RGB(220, 20, 60) }, + { "darkblue", NSVG_RGB( 0, 0, 139) }, + { "darkcyan", NSVG_RGB( 0, 139, 139) }, + { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, + { "darkgray", NSVG_RGB(169, 169, 169) }, + { "darkgreen", NSVG_RGB( 0, 100, 0) }, + { "darkgrey", NSVG_RGB(169, 169, 169) }, + { "darkkhaki", NSVG_RGB(189, 183, 107) }, + { "darkmagenta", NSVG_RGB(139, 0, 139) }, + { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, + { "darkorange", NSVG_RGB(255, 140, 0) }, + { "darkorchid", NSVG_RGB(153, 50, 204) }, + { "darkred", NSVG_RGB(139, 0, 0) }, + { "darksalmon", NSVG_RGB(233, 150, 122) }, + { "darkseagreen", NSVG_RGB(143, 188, 143) }, + { "darkslateblue", NSVG_RGB( 72, 61, 139) }, + { "darkslategray", NSVG_RGB( 47, 79, 79) }, + { "darkslategrey", NSVG_RGB( 47, 79, 79) }, + { "darkturquoise", NSVG_RGB( 0, 206, 209) }, + { "darkviolet", NSVG_RGB(148, 0, 211) }, + { "deeppink", NSVG_RGB(255, 20, 147) }, + { "deepskyblue", NSVG_RGB( 0, 191, 255) }, + { "dimgray", NSVG_RGB(105, 105, 105) }, + { "dimgrey", NSVG_RGB(105, 105, 105) }, + { "dodgerblue", NSVG_RGB( 30, 144, 255) }, + { "firebrick", NSVG_RGB(178, 34, 34) }, + { "floralwhite", NSVG_RGB(255, 250, 240) }, + { "forestgreen", NSVG_RGB( 34, 139, 34) }, + { "fuchsia", NSVG_RGB(255, 0, 255) }, + { "gainsboro", NSVG_RGB(220, 220, 220) }, + { "ghostwhite", NSVG_RGB(248, 248, 255) }, + { "gold", NSVG_RGB(255, 215, 0) }, + { "goldenrod", NSVG_RGB(218, 165, 32) }, + { "greenyellow", NSVG_RGB(173, 255, 47) }, + { "honeydew", NSVG_RGB(240, 255, 240) }, + { "hotpink", NSVG_RGB(255, 105, 180) }, + { "indianred", NSVG_RGB(205, 92, 92) }, + { "indigo", NSVG_RGB( 75, 0, 130) }, + { "ivory", NSVG_RGB(255, 255, 240) }, + { "khaki", NSVG_RGB(240, 230, 140) }, + { "lavender", NSVG_RGB(230, 230, 250) }, + { "lavenderblush", NSVG_RGB(255, 240, 245) }, + { "lawngreen", NSVG_RGB(124, 252, 0) }, + { "lemonchiffon", NSVG_RGB(255, 250, 205) }, + { "lightblue", NSVG_RGB(173, 216, 230) }, + { "lightcoral", NSVG_RGB(240, 128, 128) }, + { "lightcyan", NSVG_RGB(224, 255, 255) }, + { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, + { "lightgray", NSVG_RGB(211, 211, 211) }, + { "lightgreen", NSVG_RGB(144, 238, 144) }, + { "lightgrey", NSVG_RGB(211, 211, 211) }, + { "lightpink", NSVG_RGB(255, 182, 193) }, + { "lightsalmon", NSVG_RGB(255, 160, 122) }, + { "lightseagreen", NSVG_RGB( 32, 178, 170) }, + { "lightskyblue", NSVG_RGB(135, 206, 250) }, + { "lightslategray", NSVG_RGB(119, 136, 153) }, + { "lightslategrey", NSVG_RGB(119, 136, 153) }, + { "lightsteelblue", NSVG_RGB(176, 196, 222) }, + { "lightyellow", NSVG_RGB(255, 255, 224) }, + { "lime", NSVG_RGB( 0, 255, 0) }, + { "limegreen", NSVG_RGB( 50, 205, 50) }, + { "linen", NSVG_RGB(250, 240, 230) }, + { "maroon", NSVG_RGB(128, 0, 0) }, + { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, + { "mediumblue", NSVG_RGB( 0, 0, 205) }, + { "mediumorchid", NSVG_RGB(186, 85, 211) }, + { "mediumpurple", NSVG_RGB(147, 112, 219) }, + { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, + { "mediumslateblue", NSVG_RGB(123, 104, 238) }, + { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, + { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, + { "mediumvioletred", NSVG_RGB(199, 21, 133) }, + { "midnightblue", NSVG_RGB( 25, 25, 112) }, + { "mintcream", NSVG_RGB(245, 255, 250) }, + { "mistyrose", NSVG_RGB(255, 228, 225) }, + { "moccasin", NSVG_RGB(255, 228, 181) }, + { "navajowhite", NSVG_RGB(255, 222, 173) }, + { "navy", NSVG_RGB( 0, 0, 128) }, + { "oldlace", NSVG_RGB(253, 245, 230) }, + { "olive", NSVG_RGB(128, 128, 0) }, + { "olivedrab", NSVG_RGB(107, 142, 35) }, + { "orange", NSVG_RGB(255, 165, 0) }, + { "orangered", NSVG_RGB(255, 69, 0) }, + { "orchid", NSVG_RGB(218, 112, 214) }, + { "palegoldenrod", NSVG_RGB(238, 232, 170) }, + { "palegreen", NSVG_RGB(152, 251, 152) }, + { "paleturquoise", NSVG_RGB(175, 238, 238) }, + { "palevioletred", NSVG_RGB(219, 112, 147) }, + { "papayawhip", NSVG_RGB(255, 239, 213) }, + { "peachpuff", NSVG_RGB(255, 218, 185) }, + { "peru", NSVG_RGB(205, 133, 63) }, + { "pink", NSVG_RGB(255, 192, 203) }, + { "plum", NSVG_RGB(221, 160, 221) }, + { "powderblue", NSVG_RGB(176, 224, 230) }, + { "purple", NSVG_RGB(128, 0, 128) }, + { "rosybrown", NSVG_RGB(188, 143, 143) }, + { "royalblue", NSVG_RGB( 65, 105, 225) }, + { "saddlebrown", NSVG_RGB(139, 69, 19) }, + { "salmon", NSVG_RGB(250, 128, 114) }, + { "sandybrown", NSVG_RGB(244, 164, 96) }, + { "seagreen", NSVG_RGB( 46, 139, 87) }, + { "seashell", NSVG_RGB(255, 245, 238) }, + { "sienna", NSVG_RGB(160, 82, 45) }, + { "silver", NSVG_RGB(192, 192, 192) }, + { "skyblue", NSVG_RGB(135, 206, 235) }, + { "slateblue", NSVG_RGB(106, 90, 205) }, + { "slategray", NSVG_RGB(112, 128, 144) }, + { "slategrey", NSVG_RGB(112, 128, 144) }, + { "snow", NSVG_RGB(255, 250, 250) }, + { "springgreen", NSVG_RGB( 0, 255, 127) }, + { "steelblue", NSVG_RGB( 70, 130, 180) }, + { "tan", NSVG_RGB(210, 180, 140) }, + { "teal", NSVG_RGB( 0, 128, 128) }, + { "thistle", NSVG_RGB(216, 191, 216) }, + { "tomato", NSVG_RGB(255, 99, 71) }, + { "turquoise", NSVG_RGB( 64, 224, 208) }, + { "violet", NSVG_RGB(238, 130, 238) }, + { "wheat", NSVG_RGB(245, 222, 179) }, + { "whitesmoke", NSVG_RGB(245, 245, 245) }, + { "yellowgreen", NSVG_RGB(154, 205, 50) }, +#endif +}; + +static unsigned int nsvg__parseColorName(const char* str) +{ + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); + + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } + + return NSVG_RGB(128, 128, 128); +} + +static unsigned int nsvg__parseColor(const char* str) +{ + size_t len = 0; + while(*str == ' ') ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); +} + +static float nsvg__parseOpacity(const char* str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) val = 0.0f; + if (val > 1.0f) val = 1.0f; + return val; +} + +static float nsvg__parseMiterLimit(const char* str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) val = 0.0f; + return val; +} + +static int nsvg__parseUnits(const char* units) +{ + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; +} + +static int nsvg__isCoordinate(const char* s) +{ + // optional sign + if (*s == '-' || *s == '+') + s++; + // must have at least one digit, or start by a dot + return (nsvg__isdigit(*s) || *s == '.'); +} + +static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) +{ + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char buf[64]; + coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); + coord.value = nsvg__atof(buf); + return coord; +} + +static NSVGcoordinate nsvg__coord(float v, int units) +{ + NSVGcoordinate coord = {v, units}; + return coord; +} + +static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) +{ + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); +} + +static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) +{ + const char* end; + const char* ptr; + char it[64]; + + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') ++end; + if (*end == 0) + return 1; + + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } else { + ++ptr; + } + } + return (int)(end - str); +} + + +static int nsvg__parseMatrix(float* xform, const char* str) +{ + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) return len; + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseTranslate(float* xform, const char* str) +{ + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = 0.0; + + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseScale(float* xform, const char* str) +{ + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewX(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewY(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseRotate(float* xform, const char* str) +{ + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); + + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } + + nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); + nsvg__xformMultiply(m, t); + + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } + + memcpy(xform, m, sizeof(float)*6); + + return len; +} + +static void nsvg__parseTransform(float* xform, const char* str) +{ + float t[6]; + int len; + nsvg__xformIdentity(xform); + while (*str) + { + if (strncmp(str, "matrix", 6) == 0) + len = nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + len = nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + len = nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + len = nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + len = nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + len = nsvg__parseSkewY(t, str); + else{ + ++str; + continue; + } + if (len != 0) { + str += len; + } else { + ++str; + continue; + } + + nsvg__xformPremultiply(xform, t); + } +} + +static void nsvg__parseUrl(char* id, const char* str) +{ + int i = 0; + str += 4; // "url("; + if (*str == '#') + str++; + while (i < NSVG_ID_SIZE - 1 && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; +} + +static char nsvg__parseLineCap(const char* str) +{ + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseLineJoin(const char* str) +{ + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_JOIN_MITER; +} + +static char nsvg__parseFillRule(const char* str) +{ + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; +} + +static const char* nsvg__getNextDashItem(const char* s, char* it) +{ + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; +} + +static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) +{ + char item[64]; + int count = 0, i; + float sum = 0.0f; + + // Handle "none" + if (str[0] == 'n') + return 0; + + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } + + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; + + return count; +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str); + +static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) +{ + float xform[6]; + NSVGattrib* attr = nsvg__getAttr(p); + if (!attr) return 0; + + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree + + } else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, NSVG_ID_SIZE - 1); + attr->id[NSVG_ID_SIZE - 1] = '\0'; + } else { + return 0; + } + return 1; +} + +static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) +{ + const char* str; + const char* val; + char name[512]; + char value[512]; + int n; + + str = start; + while (str < end && *str != ':') ++str; + + val = str; + + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; + ++str; + + n = (int)(str - start); + if (n > 511) n = 511; + if (n) memcpy(name, start, n); + name[n] = 0; + + while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; + + n = (int)(end - val); + if (n > 511) n = 511; + if (n) memcpy(value, val, n); + value[n] = 0; + + return nsvg__parseAttr(p, name, value); +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str) +{ + const char* start; + const char* end; + + while (*str) { + // Left Trim + while(*str && nsvg__isspace(*str)) ++str; + start = str; + while(*str && *str != ';') ++str; + end = str; + + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; + ++end; + + nsvg__parseNameValue(p, start, end); + if (*str) ++str; + } +} + +static void nsvg__parseAttribs(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) + { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } +} + +static int nsvg__getArgsPerElement(char cmd) +{ + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + case 'z': + case 'Z': + return 0; + } + return -1; +} + +static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); +} + +static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x2, y2, cx1, cy1, cx2, cy2; + + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + cx1 = 2*x1 - *cpx2; + cy1 = 2*y1 - *cpy2; + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + // Convert to cubic bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } else { + x2 = args[0]; + y2 = args[1]; + } + + cx = 2*x1 - *cpx2; + cy = 2*y1 - *cpy2; + + // Convert to cubix bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static float nsvg__sqr(float x) { return x*x; } +static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } + +static float nsvg__vecrat(float ux, float uy, float vx, float vy) +{ + return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); +} + +static float nsvg__vecang(float ux, float uy, float vx, float vy) +{ + float r = nsvg__vecrat(ux,uy, vx,vy); + if (r < -1.0f) r = -1.0f; + if (r > 1.0f) r = 1.0f; + return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); +} + +static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; + + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } else { + x2 = args[5]; + y2 = args[6]; + } + + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx*dx + dy*dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } + + sinrx = sinf(rotx); + cosrx = cosf(rotx); + + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); + sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); + if (sa < 0.0f) sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; + + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; + cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; + + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle + da = nsvg__vecang(ux,uy, vx,vy); // Delta angle + +// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; +// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; + + // Approximate the arc using cubic spline segments. + t[0] = cosrx; t[1] = sinrx; + t[2] = -sinrx; t[3] = cosrx; + t[4] = cx; t[5] = cy; + + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); + if (da < 0.0f) + kappa = -kappa; + + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i/(float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } + + *cpx = x2; + *cpy = y2; +} + +static void nsvg__parsePath(NSVGparser* p, const char** attr) +{ + const char* s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + char initPoint; + float cpx, cpy, cpx2, cpy2; + const char* tmp[4]; + char closedFlag; + int i; + char item[64]; + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } + + if (s) { + nsvg__resetPath(p); + cpx = 0; cpy = 0; + cpx2 = 0; cpy2 = 0; + initPoint = 0; + closedFlag = 0; + nargs = 0; + + while (*s) { + s = nsvg__getNextPathItem(s, item); + if (!*item) break; + if (cmd != '\0' && nsvg__isCoordinate(item)) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; cpy2 = cpy; + initPoint = 1; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs-2]; + cpy = args[nargs-1]; + cpx2 = cpx; cpy2 = cpy; + } + break; + } + nargs = 0; + } + } else { + cmd = item[0]; + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } else if (initPoint == 0) { + // Do not allow other commands until initial point has been set (moveTo called once). + cmd = '\0'; + } + if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + rargs = nsvg__getArgsPerElement(cmd); + if (rargs == -1) { + // Command not recognized + cmd = '\0'; + rargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } + + nsvg__addShape(p); +} + +static void nsvg__parseRect(NSVGparser* p, const char** attr) +{ + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx < 0.0f && ry > 0.0f) rx = ry; + if (ry < 0.0f && rx > 0.0f) ry = rx; + if (rx < 0.0f) rx = 0.0f; + if (ry < 0.0f) ry = 0.0f; + if (rx > w/2.0f) rx = w/2.0f; + if (ry > h/2.0f) ry = h/2.0f; + + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); + + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x+w, y); + nsvg__lineTo(p, x+w, y+h); + nsvg__lineTo(p, x, y+h); + } else { + // Rounded rectangle + nsvg__moveTo(p, x+rx, y); + nsvg__lineTo(p, x+w-rx, y); + nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); + nsvg__lineTo(p, x+w, y+h-ry); + nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); + nsvg__lineTo(p, x+rx, y+h); + nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); + nsvg__lineTo(p, x, y+ry); + nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); + } + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseCircle(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); + } + } + + if (r > 0.0f) { + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+r, cy); + nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); + nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); + nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); + nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseEllipse(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx > 0.0f && ry > 0.0f) { + + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+rx, cy); + nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); + nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); + nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); + nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseLine(NSVGparser* p, const char** attr) +{ + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } + + nsvg__resetPath(p); + + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); + + nsvg__addPath(p, 0); + + nsvg__addShape(p); +} + +static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) +{ + int i; + const char* s; + float args[2]; + int nargs, npts = 0; + char item[64]; + + nsvg__resetPath(p); + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } + + nsvg__addPath(p, (char)closeFlag); + + nsvg__addShape(p); +} + +static void nsvg__parseSVG(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "viewBox") == 0) { + const char *s = attr[i + 1]; + char buf[64]; + s = nsvg__parseNumber(s, buf, 64); + p->viewMinx = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewMiny = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewWidth = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewHeight = nsvg__atof(buf); + } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } +} + +static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) +{ + int i; + NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } + + nsvg__xformIdentity(grad->xform); + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i+1], NSVG_ID_SIZE - 1); + grad->id[NSVG_ID_SIZE - 1] = '\0'; + } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i+1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i+1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i+1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i+1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i+1]; + strncpy(grad->ref, href+1, NSVG_ID_SIZE - 2); + grad->ref[NSVG_ID_SIZE - 2] = '\0'; + } + } + } + + grad->next = p->gradients; + p->gradients = grad; +} + +static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) +{ + NSVGattrib* curAttr = nsvg__getAttr(p); + NSVGgradientData* grad; + NSVGgradientStop* stop; + int i, idx; + + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; + + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } + + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) return; + + grad->nstops++; + grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); + if (grad->stops == NULL) return; + + // Insert + idx = grad->nstops-1; + for (i = 0; i < grad->nstops-1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops-1) { + for (i = grad->nstops-1; i > idx; i--) + grad->stops[i] = grad->stops[i-1]; + } + + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; + stop->offset = curAttr->stopOffset; +} + +static void nsvg__startElement(void* ud, const char* el, const char** attr) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } + + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } +} + +static void nsvg__endElement(void* ud, const char* el) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (strcmp(el, "g") == 0) { + nsvg__popAttr(p); + } else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } +} + +static void nsvg__content(void* ud, const char* s) +{ + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty +} + +static void nsvg__imageBounds(NSVGparser* p, float* bounds) +{ + NSVGshape* shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } +} + +static float nsvg__viewAlign(float content, float container, int type) +{ + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; +} + +static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) +{ + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply (grad->xform, t); + + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply (grad->xform, t); +} + +static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) +{ + NSVGshape* shape; + NSVGpath* path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float* pt; + + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); + + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; + + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } + + // Transform + sx *= us; + sy *= us; + avgs = (sx+sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i =0; i < path->npts; i++) { + pt = &path->pts[i*2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } + + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } + + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } +} + +NSVGimage* nsvgParse(char* input, const char* units, float dpi) +{ + NSVGparser* p; + NSVGimage* ret = 0; + + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; + + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + + // Scale to viewBox + nsvg__scaleToViewbox(p, units); + + ret = p->image; + p->image = NULL; + + nsvg__deleteParser(p); + + return ret; +} + +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) +{ + FILE* fp = NULL; + size_t size; + char* data = NULL; + NSVGimage* image = NULL; + + fp = fopen(filename, "rb"); + if (!fp) goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char*)malloc(size+1); + if (data == NULL) goto error; + if (fread(data, 1, size, fp) != size) goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); + + return image; + +error: + if (fp) fclose(fp); + if (data) free(data); + if (image) nsvgDelete(image); + return NULL; +} + +NSVGpath* nsvgDuplicatePath(NSVGpath* p) +{ + NSVGpath* res = NULL; + + if (p == NULL) + return NULL; + + res = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (res == NULL) goto error; + memset(res, 0, sizeof(NSVGpath)); + + res->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (res->pts == NULL) goto error; + memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); + res->npts = p->npts; + + memcpy(res->bounds, p->bounds, sizeof(p->bounds)); + + res->closed = p->closed; + + return res; + +error: + if (res != NULL) { + free(res->pts); + free(res); + } + return NULL; +} + +void nsvgDelete(NSVGimage* image) +{ + NSVGshape *snext, *shape; + if (image == NULL) return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); +} + +#endif diff --git a/util/render_svg.c b/util/render_svg.c new file mode 100644 index 0000000..e342b87 --- /dev/null +++ b/util/render_svg.c @@ -0,0 +1,281 @@ +// Expects icons-master/ to contain the contents of https://github.com/elementary/icons. +// You can find the license for the elementary Icon pack in "res/Icons/elementary Icons License.txt". +// The utility produces "res/Icons/elementary Icons.icon_pack". This is a pre-parsed format of the SVG files. + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <ctype.h> +#include <limits.h> + +#define NANOSVG_IMPLEMENTATION +#include "nanosvg.h" +#include "stb_ds.h" + +void BlendPixel(uint32_t *a, uint32_t b, bool c) {} +#define EsCRTsqrtf sqrtf +#define EsAssert assert +#define EsHeapAllocate(x, y) ((y) ? calloc(1, (x)) : malloc((x))) +#define EsHeapFree free +#define EsCRTfabsf fabsf +#define EsCRTfmodf fmodf +#define EsCRTisnanf isnan +#define EsCRTfloorf floorf +#define AbsoluteFloat fabsf +#define EsCRTatan2f atan2f +#define EsCRTsinf sinf +#define EsCRTcosf cosf +#define EsCRTacosf acosf +#define EsCRTceilf ceilf +#define ES_INFINITY INFINITY +#define IN_DESIGNER +#include "../desktop/renderer.cpp" + +const char *metadataFiles[] = { + "COPYING", + "README.md", +}; + +uint32_t checkShape = 0x12, checkPath = 0x34, zero = 0; + +void OutputPaint(NSVGpaint paint, FILE *pack) { + fwrite(&paint.type, 1, sizeof(char), pack); + + if (paint.type == NSVG_PAINT_COLOR) { + fwrite(&paint.color, 1, sizeof(unsigned int), pack); + } else if (paint.type == NSVG_PAINT_LINEAR_GRADIENT || paint.type == NSVG_PAINT_RADIAL_GRADIENT) { + fwrite(&paint.gradient->xform, 1, 6 * sizeof(float), pack); + + { + char spread = 0; + + if (paint.gradient->spread == NSVG_SPREAD_PAD) { + spread = RAST_REPEAT_CLAMP; + } else if (paint.gradient->spread == NSVG_SPREAD_REFLECT) { + spread = RAST_REPEAT_MIRROR; + } else if (paint.gradient->spread == NSVG_SPREAD_REPEAT) { + spread = RAST_REPEAT_NORMAL; + } + + fwrite(&spread, 1, sizeof(char), pack); + } + + fwrite(&paint.gradient->fx, 1, sizeof(float), pack); + fwrite(&paint.gradient->fy, 1, sizeof(float), pack); + fwrite(&paint.gradient->nstops, 1, sizeof(int), pack); + + for (int i = 0; i < paint.gradient->nstops; i++) { + fwrite(&paint.gradient->stops[i].color, 1, sizeof(unsigned int), pack); + fwrite(&paint.gradient->stops[i].offset, 1, sizeof(float), pack); + } + } +} + +void OutputPath(NSVGpath *path, FILE *pack) { + next:; + fwrite(&checkPath, 1, sizeof(uint8_t), pack); + + fwrite(&path->npts, 1, sizeof(int), pack); + fwrite(&path->closed, 1, sizeof(char), pack); + + for (int i = 0; i < path->npts; i++) { + fwrite(&path->pts[i * 2 + 0], 1, sizeof(float), pack); + fwrite(&path->pts[i * 2 + 1], 1, sizeof(float), pack); + } + + path = path->next; + if (path) goto next; + else fwrite(&zero, 1, sizeof(uint8_t), pack); +} + +void OutputShape(NSVGshape *shape, FILE *pack) { + next:; + + if (!shape) { + fwrite(&zero, 1, sizeof(uint8_t), pack); + return; + } + + if (shape->flags & NSVG_FLAGS_VISIBLE) { + fwrite(&checkShape, 1, sizeof(uint8_t), pack); + + fwrite(&shape->opacity, 1, sizeof(float), pack); + fwrite(&shape->strokeWidth, 1, sizeof(float), pack); + fwrite(&shape->strokeDashOffset, 1, sizeof(float), pack); + fwrite(&shape->strokeDashArray, 1, 8 * sizeof(float), pack); + fwrite(&shape->strokeDashCount, 1, sizeof(char), pack); + + { + char join = 0; + + if (shape->strokeLineJoin == NSVG_JOIN_MITER) { + join = RAST_LINE_JOIN_MITER; + } else if (shape->strokeLineJoin == NSVG_JOIN_ROUND) { + join = RAST_LINE_JOIN_ROUND; + } else if (shape->strokeLineJoin == NSVG_JOIN_BEVEL) { + join = RAST_LINE_JOIN_MITER; + shape->miterLimit = 0; + } + + fwrite(&join, 1, sizeof(char), pack); + } + + { + char cap = 0; + + if (shape->strokeLineCap == NSVG_CAP_BUTT) { + cap = RAST_LINE_CAP_FLAT; + } else if (shape->strokeLineCap == NSVG_CAP_ROUND) { + cap = RAST_LINE_CAP_ROUND; + } else if (shape->strokeLineCap == NSVG_CAP_SQUARE) { + cap = RAST_LINE_CAP_SQUARE; + } + + fwrite(&cap, 1, sizeof(char), pack); + } + + fwrite(&shape->miterLimit, 1, sizeof(float), pack); + fwrite(&shape->fillRule, 1, sizeof(char), pack); + + OutputPaint(shape->fill, pack); + OutputPaint(shape->stroke, pack); + OutputPath(shape->paths, pack); + } + + shape = shape->next; + goto next; +} + +void OutputImage(NSVGimage *image, FILE *pack) { + fwrite(&image->width, 1, sizeof(float), pack); + fwrite(&image->height, 1, sizeof(float), pack); + OutputShape(image->shapes, pack); +} + +char buffer[65536]; + +typedef struct Icon { + char group[128], name[128]; + bool metadata; +} Icon; + +void GenerateMainIconPack() { + Icon *icons = NULL; + + { + FILE *f = fopen("desktop/icons.header", "wb"); + fprintf(f, "%s", "enum EsStandardIcon { // Taken from the elementary icon pack, see res/Icons for license.\n\tES_ICON_NONE\n"); + fclose(f); + } + + { + system("find bin/icons-master/ -name *.svg -type f | grep -v cursors | awk -F '/' 'BEGIN { OFS=\" \" } { print $3, $5 }' | awk -F '.' '{ print $1 }'" + " | tr '-' '_' | grep -v '_rtl' | tr '_' '-' | sort -u > icons.txt"); + system("awk -F ' ' 'BEGIN { OFS=\"\" } { print \"\tES_ICON_\", $2 }' icons.txt | tr '[:lower:]' '[:upper:]'" + " | tr '+-' '__' >> desktop/icons.header"); + system("echo '}' >> desktop/icons.header"); + + FILE *iconList = fopen("icons.txt", "rb"); + Icon icon = {}; + + while (fscanf(iconList, "%s %s\n", icon.group, icon.name) == 2) { + arrput(icons, icon); + } + + fclose(iconList); + system("rm icons.txt"); + + for (uintptr_t i = 0; i < sizeof(metadataFiles) / sizeof(metadataFiles[0]); i++) { + icon.metadata = true; + strcpy(icon.name, metadataFiles[i]); + arrput(icons, icon); + } + } + + FILE *pack = fopen("res/Themes/elementary Icons.dat", "wb"); + uint32_t zero = 0; + + uint32_t count = arrlen(icons); + fwrite(&count, 1, sizeof(uint32_t), pack); + for (int i = 0; i < arrlen(icons); i++) fwrite(&zero, 1, sizeof(uint32_t), pack); + + int total = 0; + + for (int i = 0; i < arrlen(icons); i++) { + Icon *icon = icons + i; + uint32_t offset = ftell(pack); + fseek(pack, (i + 1) * sizeof(uint32_t), SEEK_SET); + fwrite(&offset, 1, sizeof(uint32_t), pack); + fseek(pack, offset, SEEK_SET); + + if (icon->metadata) { + sprintf(buffer, "bin/icons-master/%s", icon->name); + FILE *f = fopen(buffer, "rb"); + fwrite(buffer, 1, fread(buffer, 1, 65536, f), pack); + fclose(f); + } else { + printf("%s %s\n", icon->group, icon->name); + + uint32_t variants[] = { 1 /* Symbolic */, 16, 21, 24, 32, 48, 64, 128, + 1 | 0x8000, 16 | 0x8000, 21 | 0x8000, 24 | 0x8000, 32 | 0x8000, 48 | 0x8000, 64 | 0x8000, 128 | 0x8000 }; + + for (uint32_t i = 0; i < sizeof(variants) / sizeof(variants[0]); i++) { + if ((variants[i] & 0x7FFF) != 1) { + sprintf(buffer, "bin/icons-master/%s/%d/%s%s.svg", icon->group, variants[i] & 0x7FFF, icon->name, (variants[i] & 0x8000) ? "-rtl" : ""); + } else { + sprintf(buffer, "bin/icons-master/%s/symbolic/%s%s.svg", icon->group, icon->name, (variants[i] & 0x8000) ? "-rtl" : ""); + } + + NSVGimage *image = nsvgParseFromFile(buffer, "px", 96.0f); + + if (image) { + printf("\t%s\n", buffer); + total++; + + fwrite(&variants[i], 1, sizeof(uint32_t), pack); + uint32_t skip = ftell(pack); + fwrite(&zero, 1, sizeof(uint32_t), pack); + OutputImage(image, pack); + nsvgDelete(image); + uint32_t restore = ftell(pack); + fseek(pack, skip, SEEK_SET); + fwrite(&restore, 1, sizeof(uint32_t), pack); + fseek(pack, restore, SEEK_SET); + } else { + // printf("\tcould not find %s\n", buffer); + } + } + + fwrite(&zero, 1, sizeof(uint32_t), pack); + } + } + + fclose(pack); + printf("total = %d\n", total); +} + +int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, "Usage: %s <command> <options...>\n", argv[0]); + return 1; + } + + if (0 == strcmp(argv[1], "generate-main-icon-pack")) { + GenerateMainIconPack(); + } else if (0 == strcmp(argv[1], "convert")) { + if (argc != 4) { + fprintf(stderr, "Usage: %s convert <input> <output>\n", argv[0]); + return 1; + } + + NSVGimage *image = nsvgParseFromFile(argv[2], "px", 96.0f); + FILE *f = fopen(argv[3], "wb"); + + if (!image) { fprintf(stderr, "Error: Could not access/parse file '%s'.\n", argv[2]); return 1; } + if (!f) { fprintf(stderr, "Error: Could not access/parse file '%s'.\n", argv[3]); return 1; } + + OutputImage(image, f); + } + + return 0; +} diff --git a/util/stb_ds.h b/util/stb_ds.h new file mode 100644 index 0000000..4140858 --- /dev/null +++ b/util/stb_ds.h @@ -0,0 +1,1736 @@ +#ifndef STB_DS_DEFINITIONS_ONLY +#define STB_DS_IMPLEMENTATION +#endif + +#define DS_ARRAY(v) v * +#define DS_MAP(k, v) struct { k key; v value; } * + +#ifdef OS_ESSENCE +#define STBDS_REALLOC(a, b, c) EsCRTrealloc(b, c) +#define STBDS_FREE(a, b) EsCRTfree(b) +#define STBDS_MEMSET EsCRTmemset +#define STBDS_STRCMP EsCRTstrcmp +#define STBDS_MEMMOVE EsCRTmemmove +#define STBDS_STRLEN EsCRTstrlen +#define STBDS_MEMCMP EsCRTmemcmp +#else +#define STBDS_MEMSET memset +#define STBDS_STRCMP strcmp +#define STBDS_MEMMOVE memmove +#define STBDS_STRLEN strlen +#define STBDS_MEMCMP memcmp +#endif + + +/* stb_ds.h - v0.62 - public domain data structures - Sean Barrett 2019 + + This is a single-header-file library that provides easy-to-use + dynamic arrays and hash tables for C (also works in C++). + + For a gentle introduction: + http://nothings.org/stb_ds + + To use this library, do this in *one* C or C++ file: + #define STB_DS_IMPLEMENTATION + #include "stb_ds.h" + +TABLE OF CONTENTS + + Table of Contents + Compile-time options + License + Documentation + Notes + Notes - Dynamic arrays + Notes - Hash maps + Credits + +COMPILE-TIME OPTIONS + + #define STBDS_NO_SHORT_NAMES + + This flag needs to be set globally. + + By default stb_ds exposes shorter function names that are not qualified + with the "stbds_" prefix. If these names conflict with the names in your + code, define this flag. + + #define STBDS_SIPHASH_2_4 + + This flag only needs to be set in the file containing #define STB_DS_IMPLEMENTATION. + + By default stb_ds.h hashes using a weaker variant of SipHash and a custom hash for + 4- and 8-byte keys. On 64-bit platforms, you can define the above flag to force + stb_ds.h to use specification-compliant SipHash-2-4 for all keys. Doing so makes + hash table insertion about 20% slower on 4- and 8-byte keys, 5% slower on + 64-byte keys, and 10% slower on 256-byte keys on my test computer. + + #define STBDS_REALLOC(context,ptr,size) better_realloc + #define STBDS_FREE(context,ptr) better_free + + These defines only need to be set in the file containing #define STB_DS_IMPLEMENTATION. + + By default stb_ds uses stdlib realloc() and free() for memory management. You can + substitute your own functions instead by defining these symbols. You must either + define both, or neither. Note that at the moment, 'context' will always be NULL. + @TODO add an array/hash initialization function that takes a memory context pointer. + + #define STBDS_UNIT_TESTS + + Defines a function stbds_unit_tests() that checks the functioning of the data structures. + + Note that on older versions of gcc (e.g. 5.x.x) you may need to build with '-std=c++0x' + (or equivalentally '-std=c++11') when using anonymous structures as seen on the web + page or in STBDS_UNIT_TESTS. + +LICENSE + + Placed in the public domain and also MIT licensed. + See end of file for detailed license information. + +DOCUMENTATION + + Dynamic Arrays + + Non-function interface: + + Declare an empty dynamic array of type T + T* foo = NULL; + + Access the i'th item of a dynamic array 'foo' of type T, T* foo: + foo[i] + + Functions (actually macros) + + arrfree: + void arrfree(T*); + Frees the array. + + arrlen: + ptrdiff_t arrlen(T*); + Returns the number of elements in the array. + + arrlenu: + size_t arrlenu(T*); + Returns the number of elements in the array as an unsigned type. + + arrpop: + T arrpop(T* a) + Removes the final element of the array and returns it. + + arrput: + T arrput(T* a, T b); + Appends the item b to the end of array a. Returns b. + + arrins: + T arrins(T* a, int p, T b); + Inserts the item b into the middle of array a, into a[p], + moving the rest of the array over. Returns b. + + arrinsn: + void arrins(T* a, int p, int n); + Inserts n uninitialized items into array a starting at a[p], + moving the rest of the array over. + + arrdel: + void arrdel(T* a, int p); + Deletes the element at a[p], moving the rest of the array over. + + arrdeln: + void arrdel(T* a, int p, int n); + Deletes n elements starting at a[p], moving the rest of the array over. + + arrdelswap: + void arrdelswap(T* a, int p); + Deletes the element at a[p], replacing it with the element from + the end of the array. O(1) performance. + + arrsetlen: + void arrsetlen(T* a, int n); + Changes the length of the array to n. Allocates uninitialized + slots at the end if necessary. + + arrsetcap: + size_t arrsetcap(T* a, int n); + Sets the length of allocated storage to at least n. It will not + change the length of the array. + + arrcap: + size_t arrcap(T* a); + Returns the number of total elements the array can contain without + needing to be reallocated. + + Hash maps & String hash maps + + Given T is a structure type: struct { TK key; TV value; }. Note that some + functions do not require TV value and can have other fields. For string + hash maps, TK must be 'char *'. + + Special interface: + + stbds_rand_seed: + void stbds_rand_seed(size_t seed); + For security against adversarially chosen data, you should seed the + library with a strong random number. Or at least seed it with time(). + + stbds_hash_string: + size_t stbds_hash_string(char *str, size_t seed); + Returns a hash value for a string. + + stbds_hash_bytes: + size_t stbds_hash_bytes(void *p, size_t len, size_t seed); + These functions hash an arbitrary number of bytes. The function + uses a custom hash for 4- and 8-byte data, and a weakened version + of SipHash for everything else. On 64-bit platforms you can get + specification-compliant SipHash-2-4 on all data by defining + STBDS_SIPHASH_2_4, at a significant cost in speed. + + Non-function interface: + + Declare an empty hash map of type T + T* foo = NULL; + + Access the i'th entry in a hash table T* foo: + foo[i] + + Function interface (actually macros): + + hmfree + shfree + void hmfree(T*); + void shfree(T*); + Frees the hashmap and sets the pointer to NULL. + + hmlen + shlen + ptrdiff_t hmlen(T*) + ptrdiff_t shlen(T*) + Returns the number of elements in the hashmap. + + hmlenu + shlenu + size_t hmlenu(T*) + size_t shlenu(T*) + Returns the number of elements in the hashmap. + + hmgeti + shgeti + ptrdiff_t hmgeti(T*, TK key) + ptrdiff_t shgeti(T*, char* key) + Returns the index in the hashmap which has the key 'key', or -1 + if the key is not present. + + hmget + shget + TV hmget(T*, TK key) + TV shget(T*, char* key) + Returns the value corresponding to 'key' in the hashmap. + The structure must have a 'value' field + + hmgets + shgets + T hmgets(T*, TK key) + T shgets(T*, char* key) + Returns the structure corresponding to 'key' in the hashmap. + + hmdefault + shdefault + TV hmdefault(T*, TV value) + TV shdefault(T*, TV value) + Sets the default value for the hashmap, the value which will be + returned by hmget/shget if the key is not present. + + hmdefaults + shdefaults + TV hmdefaults(T*, T item) + TV shdefaults(T*, T item) + Sets the default struct for the hashmap, the contents which will be + returned by hmgets/shgets if the key is not present. + + hmput + shput + TV hmput(T*, TK key, TV value) + TV shput(T*, char* key, TV value) + Inserts a <key,value> pair into the hashmap. If the key is already + present in the hashmap, updates its value. + + hmputs + shputs + T hmputs(T*, T item) + T shputs(T*, T item) + Inserts a struct with T.key and T.value into the hashmap. If the struct is already + present in the hashmap, updates it. + + hmdel + shdel + int hmdel(T*, TK key) + int shdel(T*, char* key) + If 'key' is in the hashmap, deletes its entry and returns 1. + Otherwise returns 0. + + Function interface (actually macros) for strings only: + + sh_new_strdup + void sh_new_strdup(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate and free + each string key using realloc/free + + sh_new_arena + void sh_new_arena(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate each string + key to a string arena. Every string key ever used by this + hash table remains in the arena until the arena is freed. + Additionally, any key which is deleted and reinserted will + be allocated multiple times in the string arena. + +NOTES + + * These data structures are realloc'd when they grow, and the macro "functions" + write to the provided pointer. This means: (a) the pointer must be an lvalue, + and (b) the pointer to the data structure is not stable, and you must maintain + it the same as you would a realloc'd pointer. For example, if you pass a pointer + to a dynamic array to a function which updates it, the function must return + back the new pointer to the caller. This is the price of trying to do this in C. + + * You iterate over the contents of a dynamic array and a hashmap in exactly + the same way, using arrlen/hmlen/shlen: + + for (i=0; i < arrlen(foo); ++i) + ... foo[i] ... + + * All operations except arrins/arrdel are O(1) amortized, but individual + operations can be slow, so these data structures may not be suitable + for real time use. Dynamic arrays double in capacity as needed, so + elements are copied an average of once. Hash tables double/halve + their size as needed, with appropriate hysteresis to maintain O(1) + performance. + +NOTES - DYNAMIC ARRAY + + * If you know how long a dynamic array is going to be in advance, you can avoid + extra memory allocations by using arrsetlen to allocate it to that length in + advance and use foo[n] while filling it out, or arrsetcap to allocate the memory + for that length and use arrput/arrpush as normal. + + * Unlike some other versions of the dynamic array, this version should + be safe to use with strict-aliasing optimizations. + +NOTES - HASH MAP + + * For compilers other than GCC and clang (e.g. Visual Studio), for hmput/hmget/hmdel + and variants, the key must be an lvalue (so the macro can take the address of it). + Extensions are used that eliminate this requirement if you're using C99 and later + in GCC or clang, or if you're using C++ in GCC. + + * To test for presence of a key in a hashmap, just do 'hmgeti(foo,key) >= 0'. + + * The iteration order of your data in the hashmap is determined solely by the + order of insertions and deletions. In particular, if you never delete, new + keys are always added at the end of the array. This will be consistent + across all platforms and versions of the library. However, you should not + attempt to serialize the internal hash table, as the hash is not consistent + between different platforms, and may change with future versions of the library. + + * Use sh_new_arena() for string hashmaps that you never delete from. Initialize + with NULL if you're managing the memory for your strings, or your strings are + never freed (at least until the hashmap is freed). Otherwise, use sh_new_strdup(). + @TODO: make an arena variant that garbage collects the strings with a trivial + copy collector into a new arena whenever the table shrinks / rebuilds. Since + current arena recommendation is to only use arena if it never deletes, then + this can just replace current arena implementation. + + * If adversarial input is a serious concern and you're on a 64-bit platform, + enable STBDS_SIPHASH_2_4 (see the 'Compile-time options' section), and pass + a strong random number to stbds_rand_seed. + + * The default value for the hash table is stored in foo[-1], so if you + use code like 'hmget(T,k)->value = 5' you can accidentally overwrite + the value stored by hmdefault if 'k' is not present. + +CREDITS + + Sean Barrett -- library, idea for dynamic array API/implementation + Per Vognsen -- idea for hash table API/implementation + Rafael Sachetto -- arrpop() + + Bugfixes: + Andy Durdin + Shane Liesegang + Vinh Truong +*/ + +#ifdef STBDS_UNIT_TESTS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef INCLUDE_STB_DS_H +#define INCLUDE_STB_DS_H + +#include <stddef.h> +#ifndef OS_ESSENCE +#include <string.h> +#endif + +#ifndef STBDS_NO_SHORT_NAMES +#define arrlen stbds_arrlen +#define arrlenu stbds_arrlenu +#define arrput stbds_arrput +#define arrpush stbds_arrput +#define arrpop stbds_arrpop +#define arrfree stbds_arrfree +#define arraddn stbds_arraddn +#define arrsetlen stbds_arrsetlen +#define arrclear stbds_arrclear +#define arrlast stbds_arrlast +#define arrins stbds_arrins +#define arrinsn stbds_arrinsn +#define arrdel stbds_arrdel +#define arrdeln stbds_arrdeln +#define arrdelswap stbds_arrdelswap +#define arrcap stbds_arrcap +#define arrsetcap stbds_arrsetcap + +#define hmput stbds_hmput +#define hmputs stbds_hmputs +#define hmget stbds_hmget +#define hmgets stbds_hmgets +#define hmgetp stbds_hmgetp +#define hmgeti stbds_hmgeti +#define hmdel stbds_hmdel +#define hmlen stbds_hmlen +#define hmlenu stbds_hmlenu +#define hmfree stbds_hmfree +#define hmdefault stbds_hmdefault +#define hmdefaults stbds_hmdefaults + +#define shput stbds_shput +#define shputs stbds_shputs +#define shget stbds_shget +#define shgets stbds_shgets +#define shgetp stbds_shgetp +#define shgeti stbds_shgeti +#define shdel stbds_shdel +#define shlen stbds_shlen +#define shlenu stbds_shlenu +#define shfree stbds_shfree +#define shdefault stbds_shdefault +#define shdefaults stbds_shdefaults +#define sh_new_arena stbds_sh_new_arena +#define sh_new_strdup stbds_sh_new_strdup + +#define stralloc stbds_stralloc +#define strreset stbds_strreset +#endif + +#if defined(STBDS_REALLOC) && !defined(STBDS_FREE) || !defined(STBDS_REALLOC) && defined(STBDS_FREE) +#error "You must define both STBDS_REALLOC and STBDS_FREE, or neither." +#endif +#if !defined(STBDS_REALLOC) && !defined(STBDS_FREE) +#include <stdlib.h> +#define STBDS_REALLOC(c,p,s) realloc(p,s) +#define STBDS_FREE(c,p) free(p) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// for security against attackers, seed the library with a random number, at least time() but stronger is better +extern void stbds_rand_seed(size_t seed); + +// these are the hash functions used internally if you want to test them or use them for other purposes +extern size_t stbds_hash_bytes(void *p, size_t len, size_t seed); +extern size_t stbds_hash_string(char *str, size_t seed); + +// this is a simple string arena allocator, initialize with e.g. 'stbds_string_arena my_arena={0}'. +typedef struct stbds_string_arena stbds_string_arena; +extern char * stbds_stralloc(stbds_string_arena *a, char *str); +extern void stbds_strreset(stbds_string_arena *a); + +// have to #define STBDS_UNIT_TESTS to call this +extern void stbds_unit_tests(void); + +/////////////// +// +// Everything below here is implementation details +// + +extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap); +extern void stbds_hmfree_func(void *p, size_t elemsize, size_t keyoff); +extern void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); +extern void * stbds_hmput_default(void *a, size_t elemsize); +extern void * stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); +extern void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode); +extern void * stbds_shmode_func(size_t elemsize, int mode); + +#ifdef __cplusplus +} +#endif + +#if defined(__GNUC__) || defined(__clang__) +#ifdef __cplusplus +#define STBDS_HAS_TYPEOF +//#define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang +#endif +#endif + +#if !defined(__cplusplus) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define STBDS_HAS_LITERAL_ARRAY +#endif +#endif + +// this macro takes the address of the argument, but on gcc/clang can accept rvalues +#if defined(STBDS_HAS_LITERAL_ARRAY) && defined(STBDS_HAS_TYPEOF) + #if __clang__ + #define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value + #else + #define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value + #endif +#else +#define STBDS_ADDRESSOF(typevar, value) &(value) +#endif + +#define STBDS_OFFSETOF(var,field) ((char *) &(var)->field - (char *) (var)) + +#define stbds_header(t) ((stbds_array_header *) (t) - 1) +#define stbds_temp(t) stbds_header(t)->temp + +#define stbds_arrsetcap(a,n) (stbds_arrgrow(a,0,n)) +#define stbds_arrclear(a) ((a) ? stbds_header(a)->length = (0) : 0) +#define stbds_arrsetlen(a,n) ((stbds_arrcap(a) < n ? stbds_arrsetcap(a,n),0 : 0), (a) ? stbds_header(a)->length = (n) : 0) +#define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0) +#define stbds_arrlen(a) ((a) ? (ptrdiff_t) stbds_header(a)->length : 0) +#define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0) +#define stbds_arrput(a,v) (stbds_arrmaybegrow(a,1), (a)[stbds_header(a)->length++] = (v)) +#define stbds_arrpush stbds_arrput // synonym +#define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length]) +#define stbds_arraddn(a,n) (stbds_arrmaybegrow(a,n), stbds_header(a)->length += (n)) +#define stbds_arrlast(a) ((a)[stbds_header(a)->length-1]) +#define stbds_arrfree(a) ((void) ((a) ? STBDS_FREE(NULL,stbds_header(a)) : (void)0), (a)=NULL) +#define stbds_arrdel(a,i) stbds_arrdeln(a,i,1) +#define stbds_arrdeln(a,i,n) (STBDS_MEMMOVE(&(a)[i], &(a)[(i)+(n)], sizeof *(a) * (stbds_header(a)->length-(n)-(i))), stbds_header(a)->length -= (n)) +#define stbds_arrdelswap(a,i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) +#define stbds_arrinsn(a,i,n) (stbds_arraddn((a),(n)), STBDS_MEMMOVE(&(a)[(i)+(n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length-(n)-(i)))) +#define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v)) + +#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ + ? (stbds_arrgrow(a,n,0),0) : 0) + +#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) + +#define stbds_hmput(t, k, v) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, 0), \ + (t)[stbds_temp((t)-1)].key = (k), \ + (t)[stbds_temp((t)-1)].value = (v)) + +#define stbds_hmputs(t, s) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof (s).key, STBDS_HM_BINARY), \ + (t)[stbds_temp((t)-1)] = (s)) + +#define stbds_hmgeti(t,k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_HM_BINARY), \ + stbds_temp((t)-1)) + +#define stbds_hmgetp(t, k) \ + ((void) stbds_hmgeti(t,k), &(t)[stbds_temp((t)-1)]) + +#define stbds_hmdel(t,k) \ + (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_BINARY)),(t)?stbds_temp((t)-1):0) + +#define stbds_hmdefault(t, v) \ + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) + +#define stbds_hmdefaults(t, s) \ + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) + +#define stbds_hmfree(p) \ + ((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p),STBDS_OFFSETOF((p),key)),0 : 0),(p)=NULL) + +#define stbds_hmgets(t, k) (*stbds_hmgetp(t,k)) +#define stbds_hmget(t, k) (stbds_hmgetp(t,k)->value) +#define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0) +#define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0) + +#define stbds_shput(t, k, v) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ + (t)[stbds_temp((t)-1)].value = (v)) + +#define stbds_shputs(t, s) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (s).key, sizeof (s).key, STBDS_HM_STRING), \ + (t)[stbds_temp((t)-1)] = (s)) + +#define stbds_shgeti(t,k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ + stbds_temp((t)-1)) + +#define stbds_shgetp(t, k) \ + ((void) stbds_shgeti(t,k), &(t)[stbds_temp((t)-1)]) + +#define stbds_shdel(t,k) \ + (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_STRING)),(t)?stbds_temp((t)-1):0) + +#define stbds_sh_new_arena(t) \ + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA)) +#define stbds_sh_new_strdup(t) \ + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP)) + +#define stbds_shdefault(t, v) stbds_hmdefault(t,v) +#define stbds_shdefaults(t, s) stbds_hmdefaults(t,s) + +#define stbds_shfree stbds_hmfree +#define stbds_shlenu stbds_hmlenu + +#define stbds_shgets(t, k) (*stbds_shgetp(t,k)) +#define stbds_shget(t, k) (stbds_shgetp(t,k)->value) +#define stbds_shlen stbds_hmlen + +typedef struct +{ + size_t length; + size_t capacity; + void * hash_table; + ptrdiff_t temp; +} stbds_array_header; + +typedef struct stbds_string_block +{ + struct stbds_string_block *next; + char storage[8]; +} stbds_string_block; + +struct stbds_string_arena +{ + stbds_string_block *storage; + size_t remaining; + unsigned char block; + unsigned char mode; // this isn't used by the string arena itself +}; + +#define STBDS_HM_BINARY 0 +#define STBDS_HM_STRING 1 + +enum +{ + STBDS_SH_NONE, + STBDS_SH_STRDUP, + STBDS_SH_ARENA +}; + +#ifdef __cplusplus +// in C we use implicit assignment from these void*-returning functions to T*. +// in C++ these templates make the same code work +template<class T> static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap) { + return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap); +} +template<class T> static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { + return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode); +} +template<class T> static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) { + return (T*)stbds_hmput_default((void *)a, elemsize); +} +template<class T> static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { + return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); +} +template<class T> static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode){ + return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); +} +template<class T> static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int mode) { + return (T*)stbds_shmode_func(elemsize, mode); +} +#else +#define stbds_arrgrowf_wrapper stbds_arrgrowf +#define stbds_hmget_key_wrapper stbds_hmget_key +#define stbds_hmput_default_wrapper stbds_hmput_default +#define stbds_hmput_key_wrapper stbds_hmput_key +#define stbds_hmdel_key_wrapper stbds_hmdel_key +#define stbds_shmode_func_wrapper(t,e,m) stbds_shmode_func(e,m) +#endif + +#endif // INCLUDE_STB_DS_H + + +////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION +// + +#ifdef STB_DS_IMPLEMENTATION +#ifndef OS_ESSENCE +#include <assert.h> +#include <string.h> +#endif + +#ifndef STBDS_ASSERT +#define STBDS_ASSERT_WAS_UNDEFINED +#define STBDS_ASSERT(x) ((void) 0) +#endif + +#ifdef STBDS_STATISTICS +#define STBDS_STATS(x) x +size_t stbds_array_grow; +size_t stbds_hash_grow; +size_t stbds_hash_shrink; +size_t stbds_hash_rebuild; +size_t stbds_hash_probes; +size_t stbds_hash_alloc; +size_t stbds_rehash_probes; +size_t stbds_rehash_items; +#else +#define STBDS_STATS(x) +#endif + +// +// stbds_arr implementation +// + +void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap) +{ + void *b; + size_t min_len = stbds_arrlen(a) + addlen; + + // compute the minimum capacity needed + if (min_len > min_cap) + min_cap = min_len; + + if (min_cap <= stbds_arrcap(a)) + return a; + + // increase needed capacity to guarantee O(1) amortized + if (min_cap < 2 * stbds_arrcap(a)) + min_cap = 2 * stbds_arrcap(a); + else if (min_cap < 4) + min_cap = 4; + + b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header)); + b = (char *) b + sizeof(stbds_array_header); + if (a == NULL) { + stbds_header(b)->length = 0; + stbds_header(b)->hash_table = 0; + } else { + STBDS_STATS(++stbds_array_grow); + } + stbds_header(b)->capacity = min_cap; + return b; +} + +// +// stbds_hm hash table implementation +// + +#ifdef STBDS_INTERNAL_SMALL_BUCKET +#define STBDS_BUCKET_LENGTH 4 +#else +#define STBDS_BUCKET_LENGTH 8 +#endif + +#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) +#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH-1) +#define STBDS_CACHE_LINE_SIZE 64 + +#define STBDS_ALIGN_FWD(n,a) (((n) + (a) - 1) & ~((a)-1)) + +typedef struct +{ + size_t hash [STBDS_BUCKET_LENGTH]; + ptrdiff_t index[STBDS_BUCKET_LENGTH]; +} stbds_hash_bucket; // in 32-bit, this is one 64-byte cache line; in 64-bit, each array is one 64-byte cache line + +typedef struct +{ + size_t slot_count; + size_t used_count; + size_t used_count_threshold; + size_t used_count_shrink_threshold; + size_t tombstone_count; + size_t tombstone_count_threshold; + size_t seed; + size_t slot_count_log2; + stbds_string_arena string; + stbds_hash_bucket *storage; // not a separate allocation, just 64-byte aligned storage after this struct +} stbds_hash_index; + +#define STBDS_INDEX_EMPTY -1 +#define STBDS_INDEX_DELETED -2 +#define STBDS_INDEX_IN_USE(x) ((x) >= 0) + +#define STBDS_HASH_EMPTY 0 +#define STBDS_HASH_DELETED 1 + +static size_t stbds_hash_seed=0x31415926; + +void stbds_rand_seed(size_t seed) +{ + stbds_hash_seed = seed; +} + +#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ + temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ + var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ + var ^= temp ^ v32 + +#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8) + +static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) +{ + (void) slot_log2; + size_t pos; + pos = hash & (slot_count-1); + #ifdef STBDS_INTERNAL_BUCKET_START + pos &= ~STBDS_BUCKET_MASK; + #endif + return pos; +} + +static size_t stbds_log2(size_t slot_count) +{ + size_t n=0; + while (slot_count > 1) { + slot_count >>= 1; + ++n; + } + return n; +} + +static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot) +{ + stbds_hash_index *t; + t = (stbds_hash_index *) STBDS_REALLOC(NULL,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1); + t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE); + t->slot_count = slot_count; + t->slot_count_log2 = stbds_log2(slot_count); + t->tombstone_count = 0; + t->used_count = 0; + + #if 0 // A1 + t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink + #elif 1 // A2 + //t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow + //t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild + //t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink + + // compute without overflowing + t->used_count_threshold = slot_count - (slot_count>>2); + t->tombstone_count_threshold = (slot_count>>3) + (slot_count>>4); + t->used_count_shrink_threshold = slot_count >> 2; + + #elif 0 // B1 + t->used_count_threshold = slot_count*13/16; // if 13/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 5/16; // if table is only 5/16th full, shrink + #else // C1 + t->used_count_threshold = slot_count*14/16; // if 14/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 6/16; // if table is only 6/16th full, shrink + #endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // A1 A2 B1 C1 + // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table + // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table + // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table + // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table + // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table + // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table + // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table + // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table + // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table + // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table + // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table + + if (slot_count <= STBDS_BUCKET_LENGTH) + t->used_count_shrink_threshold = 0; + // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes + STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); + STBDS_STATS(++stbds_hash_alloc); + if (ot) { + t->string = ot->string; + // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing + t->seed = ot->seed; + } else { + size_t a,b,temp; + STBDS_MEMSET(&t->string, 0, sizeof(t->string)); + t->seed = stbds_hash_seed; + // LCG + // in 32-bit, a = 2147001325 b = 715136305 + // in 64-bit, a = 2862933555777941757 b = 3037000493 + stbds_load_32_or_64(a,temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); + stbds_load_32_or_64(b,temp, 715136305, 0, 0xb504f32d); + stbds_hash_seed = stbds_hash_seed * a + b; + } + + { + size_t i,j; + for (i=0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket *b = &t->storage[i]; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) + b->hash[j] = STBDS_HASH_EMPTY; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) + b->index[j] = STBDS_INDEX_EMPTY; + } + } + + // copy out the old data, if any + if (ot) { + size_t i,j; + t->used_count = ot->used_count; + for (i=0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket *ob = &ot->storage[i]; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) { + if (STBDS_INDEX_IN_USE(ob->index[j])) { + size_t hash = ob->hash[j]; + size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); + size_t step = STBDS_BUCKET_LENGTH; + STBDS_STATS(++stbds_rehash_items); + for (;;) { + size_t limit,z; + stbds_hash_bucket *bucket; + bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; + STBDS_STATS(++stbds_rehash_probes); + + for (z=pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { + if (bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } + + limit = pos & STBDS_BUCKET_MASK; + for (z = 0; z < limit; ++z) { + if (bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } + + pos += step; // quadratic probing + step += STBDS_BUCKET_LENGTH; + pos &= (t->slot_count-1); + } + } + done: + ; + } + } + } + + return t; +} + +#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) +#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) + +size_t stbds_hash_string(char *str, size_t seed) +{ + size_t hash = seed; + while (*str) + hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++; + + // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits + hash ^= seed; + hash = (~hash) + (hash << 18); + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,31); + hash = hash * 21; + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,11); + hash += (hash << 6); + hash ^= STBDS_ROTATE_RIGHT(hash,22); + return hash+seed; +} + +#ifdef STBDS_SIPHASH_2_4 +#define STBDS_SIPHASH_C_ROUNDS 2 +#define STBDS_SIPHASH_D_ROUNDS 4 +typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) == 8 ? 1 : -1]; +#endif + +#ifndef STBDS_SIPHASH_C_ROUNDS +#define STBDS_SIPHASH_C_ROUNDS 1 +#endif +#ifndef STBDS_SIPHASH_D_ROUNDS +#define STBDS_SIPHASH_D_ROUNDS 1 +#endif + +static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed) +{ + unsigned char *d = (unsigned char *) p; + size_t i,j; + size_t v0,v1,v2,v3, data; + + // hash that works on 32- or 64-bit registers without knowing which we have + // (computes different results on 32-bit and 64-bit platform) + // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit + v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; + v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; + v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; + v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; + + #ifdef STBDS_TEST_SIPHASH_2_4 + // hardcoded with key material in the siphash test vectors + v0 ^= 0x0706050403020100ull ^ seed; + v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; + v2 ^= 0x0706050403020100ull ^ seed; + v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; + #endif + + #define STBDS_SIPROUND() \ + do { \ + v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \ + v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \ + v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \ + v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \ + } while (0) + + for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { + data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 + + v3 ^= data; + for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + } + data = len << (STBDS_SIZE_T_BITS-8); + switch (len - i) { + case 7: data |= ((size_t) d[6] << 24) << 24; // fallthrough + case 6: data |= ((size_t) d[5] << 20) << 20; // fallthrough + case 5: data |= ((size_t) d[4] << 16) << 16; // fallthrough + case 4: data |= (d[3] << 24); // fallthrough + case 3: data |= (d[2] << 16); // fallthrough + case 2: data |= (d[1] << 8); // fallthrough + case 1: data |= d[0]; // fallthrough + case 0: break; + } + v3 ^= data; + for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + v2 ^= 0xff; + for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j) + STBDS_SIPROUND(); +#ifdef STBDS_SIPHASH_2_4 + return v0^v1^v2^v3; +#else + return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply +#endif +} + +size_t stbds_hash_bytes(void *p, size_t len, size_t seed) +{ +#ifdef STBDS_SIPHASH_2_4 + return stbds_siphash_bytes(p,len,seed); +#else + unsigned char *d = (unsigned char *) p; + + if (len == 4) { + unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + #if 0 + // HASH32-A Bob Jenkin's hash function w/o large constants + hash ^= seed; + hash -= (hash<<6); + hash ^= (hash>>17); + hash -= (hash<<9); + hash ^= seed; + hash ^= (hash<<4); + hash -= (hash<<3); + hash ^= (hash<<10); + hash ^= (hash>>15); + #elif 1 + // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. + // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm + // not really sure what's going on. + hash ^= seed; + hash = (hash ^ 61) ^ (hash >> 16); + hash = hash + (hash << 3); + hash = hash ^ (hash >> 4); + hash = hash * 0x27d4eb2d; + hash ^= seed; + hash = hash ^ (hash >> 15); + #else // HASH32-C - Murmur3 + hash ^= seed; + hash *= 0xcc9e2d51; + hash = (hash << 17) | (hash >> 15); + hash *= 0x1b873593; + hash ^= seed; + hash = (hash << 19) | (hash >> 13); + hash = hash*5 + 0xe6546b64; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= seed; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + #endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // HASH32-A // HASH32-BB // HASH32-C + // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table + // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table + // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table + // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table + // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table + // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table + // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table + // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table + // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table + // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table + // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table + // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing + + return (((size_t) hash << 16 << 16) | hash) ^ seed; + } else if (len == 8 && sizeof(size_t) == 8) { + size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 + hash ^= seed; + hash = (~hash) + (hash << 21); + hash ^= STBDS_ROTATE_RIGHT(hash,24); + hash *= 265; + hash ^= STBDS_ROTATE_RIGHT(hash,14); + hash ^= seed; + hash *= 21; + hash ^= STBDS_ROTATE_RIGHT(hash,28); + hash += (hash << 31); + hash = (~hash) + (hash << 18); + return hash; + } else { + return stbds_siphash_bytes(p,len,seed); + } +#endif +} + +static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, int mode, size_t i) +{ + if (mode >= STBDS_HM_STRING) + return 0==STBDS_STRCMP((char *) key, * (char **) ((char *) a + elemsize*i)); + else + return 0==STBDS_MEMCMP(key, (char *) a + elemsize*i, keysize); +} + +#define STBDS_HASH_TO_ARR(x,elemsize) ((char*) (x) - (elemsize)) +#define STBDS_ARR_TO_HASH(x,elemsize) ((char*) (x) + (elemsize)) + +#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table) + +void stbds_hmfree_func(void *a, size_t elemsize, size_t keyoff) +{ + (void) keyoff; + if (a == NULL) return; + if (stbds_hash_table(a) != NULL) { + if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) { + size_t i; + // skip 0th element, which is default + for (i=1; i < stbds_header(a)->length; ++i) + STBDS_FREE(NULL, *(char**) ((char *) a + elemsize*i)); + } + stbds_strreset(&stbds_hash_table(a)->string); + } + STBDS_FREE(NULL, stbds_header(a)->hash_table); + STBDS_FREE(NULL, stbds_header(a)); +} + +static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, int mode) +{ + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + stbds_hash_index *table = stbds_hash_table(raw_a); + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t limit,i; + size_t pos; + stbds_hash_bucket *bucket; + + if (hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots + + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + + for (;;) { + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + + // start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache + for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(a, elemsize, key, keysize, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK)+i; + } + } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } + + // search from beginning of bucket to pos + limit = pos & STBDS_BUCKET_MASK; + for (i = 0; i < limit; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(a, elemsize, key, keysize, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK)+i; + } + } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } + + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count-1); + } + /* NOTREACHED */ + return -1; +} + +void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) +{ + if (a == NULL) { + // make it non-empty so we can return a temp + a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_header(a)->length += 1; + STBDS_MEMSET(a, 0, elemsize); + stbds_temp(a) = STBDS_INDEX_EMPTY; + // adjust a to point after the default element + return STBDS_ARR_TO_HASH(a,elemsize); + } else { + stbds_hash_index *table; + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + // adjust a to point to the default element + table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; + if (table == 0) { + stbds_temp(raw_a) = -1; + } else { + ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, mode); + if (slot < 0) { + stbds_temp(raw_a) = STBDS_INDEX_EMPTY; + } else { + stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + stbds_temp(raw_a) = b->index[slot & STBDS_BUCKET_MASK]; + } + } + return a; + } +} + +void * stbds_hmput_default(void *a, size_t elemsize) +{ + // three cases: + // a is NULL <- allocate + // a has a hash table but no entries, because of shmode <- grow + // a has entries <- do nothing + if (a == NULL || stbds_header(STBDS_HASH_TO_ARR(a,elemsize))->length == 0) { + a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a,elemsize) : NULL, elemsize, 0, 1); + stbds_header(a)->length += 1; + STBDS_MEMSET(a, 0, elemsize); + a=STBDS_ARR_TO_HASH(a,elemsize); + } + return a; +} + +static char *stbds_strdup(char *str); + +void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) +{ + void *raw_a; + stbds_hash_index *table; + + if (a == NULL) { + a = stbds_arrgrowf(0, elemsize, 0, 1); + STBDS_MEMSET(a, 0, elemsize); + stbds_header(a)->length += 1; + // adjust a to point AFTER the default element + a = STBDS_ARR_TO_HASH(a,elemsize); + } + + // adjust a to point to the default element + raw_a = a; + a = STBDS_HASH_TO_ARR(a,elemsize); + + table = (stbds_hash_index *) stbds_header(a)->hash_table; + + if (table == NULL || table->used_count >= table->used_count_threshold) { + stbds_hash_index *nt; + size_t slot_count; + + slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2; + nt = stbds_make_hash_index(slot_count, table); + if (table) { + STBDS_FREE(NULL, table); + } + stbds_header(a)->hash_table = table = nt; + STBDS_STATS(++stbds_hash_grow); + } + + // we iterate hash table explicitly because we want to track if we saw a tombstone + { + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t limit,i; + size_t pos; + ptrdiff_t tombstone = -1; + stbds_hash_bucket *bucket; + + // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly + if (hash < 2) hash += 2; + + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + + for (;;) { + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + + // start searching from pos to end of bucket + for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(raw_a, elemsize, key, keysize, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + return STBDS_ARR_TO_HASH(a,elemsize); + } + } else if (bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if (tombstone < 0) { + if (bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); + } + } + + // search from beginning of bucket to pos + limit = pos & STBDS_BUCKET_MASK; + for (i = 0; i < limit; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(raw_a, elemsize, key, keysize, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + return STBDS_ARR_TO_HASH(a,elemsize); + } + } else if (bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if (tombstone < 0) { + if (bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); + } + } + + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count-1); + } + found_empty_slot: + if (tombstone >= 0) { + pos = tombstone; + --table->tombstone_count; + } + ++table->used_count; + + { + ptrdiff_t i = (ptrdiff_t) stbds_arrlen(a); + // we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type + if ((size_t) i+1 > stbds_arrcap(a)) + *(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0); + raw_a = STBDS_ARR_TO_HASH(a,elemsize); + + STBDS_ASSERT((size_t) i+1 <= stbds_arrcap(a)); + stbds_header(a)->length = i+1; + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + bucket->hash[pos & STBDS_BUCKET_MASK] = hash; + bucket->index[pos & STBDS_BUCKET_MASK] = i-1; + stbds_temp(a) = i-1; + + switch (table->string.mode) { + case STBDS_SH_STRDUP: *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break; + case STBDS_SH_ARENA: *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break; + default: *(char **) ((char *) a + elemsize*i) = (char *) key; break; + } + } + return STBDS_ARR_TO_HASH(a,elemsize); + } +} + +void * stbds_shmode_func(size_t elemsize, int mode) +{ + void *a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_hash_index *h; + STBDS_MEMSET(a, 0, elemsize); + stbds_header(a)->length = 1; + stbds_header(a)->hash_table = h = (stbds_hash_index *) stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL); + h->string.mode = mode; + return STBDS_ARR_TO_HASH(a,elemsize); +} + +void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) +{ + if (a == NULL) { + return 0; + } else { + stbds_hash_index *table; + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; + stbds_temp(raw_a) = 0; + if (table == 0) { + return a; + } else { + ptrdiff_t slot; + slot = stbds_hm_find_slot(a, elemsize, key, keysize, mode); + if (slot < 0) + return a; + else { + stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + int i = slot & STBDS_BUCKET_MASK; + ptrdiff_t old_index = b->index[i]; + ptrdiff_t final_index = (ptrdiff_t) stbds_arrlen(raw_a)-1-1; // minus one for the raw_a vs a, and minus one for 'last' + STBDS_ASSERT(slot < (ptrdiff_t) table->slot_count); + --table->used_count; + ++table->tombstone_count; + stbds_temp(raw_a) = 1; + STBDS_ASSERT(table->used_count >= 0); + //STBDS_ASSERT(table->tombstone_count < table->slot_count/4); + b->hash[i] = STBDS_HASH_DELETED; + b->index[i] = STBDS_INDEX_DELETED; + + if (mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) + STBDS_FREE(NULL, *(char**) ((char *) a+elemsize*old_index)); + + // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip + if (old_index != final_index) { + // swap delete + STBDS_MEMMOVE((char*) a + elemsize*old_index, (char*) a + elemsize*final_index, elemsize); + + // now find the slot for the last element + if (mode == STBDS_HM_STRING) + slot = stbds_hm_find_slot(a, elemsize, *(char**) ((char *) a+elemsize*old_index + keyoffset), keysize, mode); + else + slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, mode); + STBDS_ASSERT(slot >= 0); + b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + i = slot & STBDS_BUCKET_MASK; + STBDS_ASSERT(b->index[i] == final_index); + b->index[i] = old_index; + } + stbds_header(raw_a)->length -= 1; + + if (table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count>>1, table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_shrink); + } else if (table->tombstone_count > table->tombstone_count_threshold) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count , table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_rebuild); + } + + return a; + } + } + } + /* NOTREACHED */ + return 0; +} + +static char *stbds_strdup(char *str) +{ + // to keep replaceable allocator simple, we don't want to use strdup. + // rolling our own also avoids problem of strdup vs _strdup + size_t len = STBDS_STRLEN(str)+1; + char *p = (char*) STBDS_REALLOC(NULL, 0, len); + STBDS_MEMMOVE(p, str, len); + return p; +} + +#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN +#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512 +#endif +#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX +#define STBDS_STRING_ARENA_BLOCKSIZE_MAX 1<<20 +#endif + +char *stbds_stralloc(stbds_string_arena *a, char *str) +{ + char *p; + size_t len = STBDS_STRLEN(str)+1; + if (len > a->remaining) { + // compute the next blocksize + size_t blocksize = a->block; + + // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that + // there are log(SIZE) allocations to free when we destroy the table + blocksize = (size_t) (STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize>>1); + + // if size is under 1M, advance to next blocktype + if (blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) + ++a->block; + + if (len > blocksize) { + // if string is larger than blocksize, then just allocate the full size. + // note that we still advance string_block so block size will continue + // increasing, so e.g. if somebody only calls this with 1000-long strings, + // eventually the arena will start doubling and handling those as well + stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + len); + STBDS_MEMMOVE(sb->storage, str, len); + if (a->storage) { + // insert it after the first element, so that we don't waste the space there + sb->next = a->storage->next; + a->storage->next = sb; + } else { + sb->next = 0; + a->storage = sb; + a->remaining = 0; // this is redundant, but good for clarity + } + return sb->storage; + } else { + stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + blocksize); + sb->next = a->storage; + a->storage = sb; + a->remaining = blocksize; + } + } + + STBDS_ASSERT(len <= a->remaining); + p = a->storage->storage + a->remaining - len; + a->remaining -= len; + STBDS_MEMMOVE(p, str, len); + return p; +} + +void stbds_strreset(stbds_string_arena *a) +{ + stbds_string_block *x,*y; + x = a->storage; + while (x) { + y = x->next; + STBDS_FREE(NULL, x); + x = y; + } + STBDS_MEMSET(a, 0, sizeof(*a)); +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// UNIT TESTS +// + +#ifdef STBDS_UNIT_TESTS +#include <stdio.h> +#ifdef STBDS_ASSERT_WAS_UNDEFINED +#undef STBDS_ASSERT +#endif +#ifndef STBDS_ASSERT +#define STBDS_ASSERT assert +#include <assert.h> +#endif + +typedef struct { int key,b,c,d; } stbds_struct; + +static char buffer[256]; +char *strkey(int n) +{ +#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) + sprintf_s(buffer, sizeof(buffer), "test_%d", n); +#else + sprintf(buffer, "test_%d", n); +#endif + return buffer; +} + +void stbds_unit_tests(void) +{ +#if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus) + // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! + STBDS_ASSERT(0); +#else + const int testsize = 100000; + int *arr=NULL; + struct { int key; int value; } *intmap = NULL; + struct { char *key; int value; } *strmap = NULL; + struct { stbds_struct key; int value; } *map = NULL; + stbds_struct *map2 = NULL; + stbds_string_arena sa = { 0 }; + + int i,j; + + STBDS_ASSERT(arrlen(arr)==0); + for (i=0; i < 20000; i += 50) { + for (j=0; j < i; ++j) + arrpush(arr,j); + arrfree(arr); + } + + for (i=0; i < 4; ++i) { + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + arrdel(arr,i); + arrfree(arr); + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + arrdelswap(arr,i); + arrfree(arr); + } + + for (i=0; i < 5; ++i) { + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + stbds_arrins(arr,i,5); + STBDS_ASSERT(arr[i] == 5); + if (i < 4) + STBDS_ASSERT(arr[4] == 4); + arrfree(arr); + } + + i = 1; + STBDS_ASSERT(hmgeti(intmap,i) == -1); + hmdefault(intmap, -2); + STBDS_ASSERT(hmgeti(intmap, i) == -1); + STBDS_ASSERT(hmget (intmap, i) == -2); + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*5); + for (i=0; i < testsize; i+=1) + if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); + else STBDS_ASSERT(hmget(intmap, i) == i*5); + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*3); + for (i=0; i < testsize; i+=1) + if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); + else STBDS_ASSERT(hmget(intmap, i) == i*3); + for (i=2; i < testsize; i+=4) + hmdel(intmap, i); // delete half the entries + for (i=0; i < testsize; i+=1) + if (i & 3) STBDS_ASSERT(hmget(intmap, i) == -2 ); + else STBDS_ASSERT(hmget(intmap, i) == i*3); + for (i=0; i < testsize; i+=1) + hmdel(intmap, i); // delete the rest of the entries + for (i=0; i < testsize; i+=1) + STBDS_ASSERT(hmget(intmap, i) == -2 ); + hmfree(intmap); + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*3); + hmfree(intmap); + + #if defined(__clang__) || defined(__GNUC__) + #ifndef __cplusplus + intmap = NULL; + hmput(intmap, 15, 7); + hmput(intmap, 11, 3); + hmput(intmap, 9, 5); + STBDS_ASSERT(hmget(intmap, 9) == 5); + STBDS_ASSERT(hmget(intmap, 11) == 3); + STBDS_ASSERT(hmget(intmap, 15) == 7); + #endif + #endif + + for (i=0; i < testsize; ++i) + stralloc(&sa, strkey(i)); + strreset(&sa); + + for (j=0; j < 2; ++j) { + STBDS_ASSERT(shgeti(strmap,"foo") == -1); + if (j == 0) + sh_new_strdup(strmap); + else + sh_new_arena(strmap); + STBDS_ASSERT(shgeti(strmap,"foo") == -1); + shdefault(strmap, -2); + STBDS_ASSERT(shgeti(strmap,"foo") == -1); + for (i=0; i < testsize; i+=2) + shput(strmap, strkey(i), i*3); + for (i=0; i < testsize; i+=1) + if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); + else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); + for (i=2; i < testsize; i+=4) + shdel(strmap, strkey(i)); // delete half the entries + for (i=0; i < testsize; i+=1) + if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); + else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); + for (i=0; i < testsize; i+=1) + shdel(strmap, strkey(i)); // delete the rest of the entries + for (i=0; i < testsize; i+=1) + STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); + shfree(strmap); + } + + { + struct { char *key; char value; } *hash = NULL; + char name[4] = "jen"; + shput(hash, "bob" , 'h'); + shput(hash, "sally" , 'e'); + shput(hash, "fred" , 'l'); + shput(hash, "jen" , 'x'); + shput(hash, "doug" , 'o'); + + shput(hash, name , 'l'); + shfree(hash); + } + + for (i=0; i < testsize; i += 2) { + stbds_struct s = { i,i*2,i*3,i*4 }; + hmput(map, s, i*5); + } + + for (i=0; i < testsize; i += 1) { + stbds_struct s = { i,i*2,i*3 ,i*4 }; + stbds_struct t = { i,i*2,i*3+1,i*4 }; + if (i & 1) STBDS_ASSERT(hmget(map, s) == 0); + else STBDS_ASSERT(hmget(map, s) == i*5); + STBDS_ASSERT(hmget(map, t) == 0); + } + + for (i=0; i < testsize; i += 2) { + stbds_struct s = { i,i*2,i*3,i*4 }; + hmputs(map2, s); + } + hmfree(map); + + for (i=0; i < testsize; i += 1) { + stbds_struct s = { i,i*2,i*3,i*4 }; + stbds_struct t = { i,i*2,i*3+1,i*4 }; + if (i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0); + else STBDS_ASSERT(hmgets(map2, s.key).d == i*4); + STBDS_ASSERT(hmget(map, t) == 0); + } + hmfree(map2); +#endif +} +#endif + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2019 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/util/stb_truetype.h b/util/stb_truetype.h new file mode 100644 index 0000000..62595a1 --- /dev/null +++ b/util/stb_truetype.h @@ -0,0 +1,5011 @@ +// stb_truetype.h - v1.24 - public domain +// authored from 2009-2020 by Sean Barrett / RAD Game Tools +// +// ======================================================================= +// +// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES +// +// This library does no range checking of the offsets found in the file, +// meaning an attacker can use it to read arbitrary memory. +// +// ======================================================================= +// +// This library processes TrueType files: +// parse files +// extract glyph metrics +// extract glyph shapes +// render glyphs to one-channel bitmaps with antialiasing (box filter) +// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// +// Todo: +// non-MS cmaps +// crashproof on bad data +// hinting? (no longer patented) +// cleartype-style AA? +// optimize: use simple memory allocator for intermediates +// optimize: build edge-list directly from curves +// optimize: rasterize directly from curves? +// +// ADDITIONAL CONTRIBUTORS +// +// Mikko Mononen: compound shape support, more cmap formats +// Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning +// +// Misc other: +// Ryan Gordon +// Simon Glass +// github:IntellectualKitty +// Imanol Celaya +// Daniel Ribeiro Maciel +// +// Bug/warning reports/fixes: +// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe +// Cass Everitt Martins Mozeiko github:aloucks +// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam +// Brian Hook Omar Cornut github:vassvik +// Walter van Niftrik Ryan Griege +// David Gow Peter LaValle +// David Given Sergey Popov +// Ivan-Assen Ivanov Giumo X. Clanjor +// Anthony Pesch Higor Euripedes +// Johan Duparc Thomas Fields +// Hou Qiming Derek Vinyard +// Rob Loach Cort Stratton +// Kenney Phillis Jr. Brian Costabile +// Ken Voskuil (kaesve) +// +// VERSION HISTORY +// +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// variant PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// +// Full history can be found at the end of this file. +// +// LICENSE +// +// See end of file for license information. +// +// USAGE +// +// Include this file in whatever places need to refer to it. In ONE C/C++ +// file, write: +// #define STB_TRUETYPE_IMPLEMENTATION +// before the #include of this file. This expands out the actual +// implementation into that C/C++ file. +// +// To make the implementation private to the file that generates the implementation, +// #define STBTT_STATIC +// +// Simple 3D API (don't ship this, but it's fine for tools and quick start) +// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture +// stbtt_GetBakedQuad() -- compute quad to draw for a given char +// +// Improved 3D API (more shippable): +// #include "stb_rect_pack.h" -- optional, but you really want it +// stbtt_PackBegin() +// stbtt_PackSetOversampling() -- for improved quality on small fonts +// stbtt_PackFontRanges() -- pack and renders +// stbtt_PackEnd() +// stbtt_GetPackedQuad() +// +// "Load" a font file from a memory buffer (you have to keep the buffer loaded) +// stbtt_InitFont() +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections +// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections +// +// Render a unicode codepoint to a bitmap +// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap +// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide +// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be +// +// Character advance/positioning +// stbtt_GetCodepointHMetrics() +// stbtt_GetFontVMetrics() +// stbtt_GetFontVMetricsOS2() +// stbtt_GetCodepointKernAdvance() +// +// Starting with version 1.06, the rasterizer was replaced with a new, +// faster and generally-more-precise rasterizer. The new rasterizer more +// accurately measures pixel coverage for anti-aliasing, except in the case +// where multiple shapes overlap, in which case it overestimates the AA pixel +// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If +// this turns out to be a problem, you can re-enable the old rasterizer with +// #define STBTT_RASTERIZER_VERSION 1 +// which will incur about a 15% speed hit. +// +// ADDITIONAL DOCUMENTATION +// +// Immediately after this block comment are a series of sample programs. +// +// After the sample programs is the "header file" section. This section +// includes documentation for each API function. +// +// Some important concepts to understand to use this library: +// +// Codepoint +// Characters are defined by unicode codepoints, e.g. 65 is +// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is +// the hiragana for "ma". +// +// Glyph +// A visual character shape (every codepoint is rendered as +// some glyph) +// +// Glyph index +// A font-specific integer ID representing a glyph +// +// Baseline +// Glyph shapes are defined relative to a baseline, which is the +// bottom of uppercase characters. Characters extend both above +// and below the baseline. +// +// Current Point +// As you draw text to the screen, you keep track of a "current point" +// which is the origin of each character. The current point's vertical +// position is the baseline. Even "baked fonts" use this model. +// +// Vertical Font Metrics +// The vertical qualities of the font, used to vertically position +// and space the characters. See docs for stbtt_GetFontVMetrics. +// +// Font Size in Pixels or Points +// The preferred interface for specifying font sizes in stb_truetype +// is to specify how tall the font's vertical extent should be in pixels. +// If that sounds good enough, skip the next paragraph. +// +// Most font APIs instead use "points", which are a common typographic +// measurement for describing font size, defined as 72 points per inch. +// stb_truetype provides a point API for compatibility. However, true +// "per inch" conventions don't make much sense on computer displays +// since different monitors have different number of pixels per +// inch. For example, Windows traditionally uses a convention that +// there are 96 pixels per inch, thus making 'inch' measurements have +// nothing to do with inches, and thus effectively defining a point to +// be 1.333 pixels. Additionally, the TrueType font data provides +// an explicit scale factor to scale a given font's glyphs to points, +// but the author has observed that this scale factor is often wrong +// for non-commercial fonts, thus making fonts scaled in points +// according to the TrueType spec incoherently sized in practice. +// +// DETAILED USAGE: +// +// Scale: +// Select how high you want the font to be, in points or pixels. +// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute +// a scale factor SF that will be used by all other functions. +// +// Baseline: +// You need to select a y-coordinate that is the baseline of where +// your text will appear. Call GetFontBoundingBox to get the baseline-relative +// bounding box for all characters. SF*-y0 will be the distance in pixels +// that the worst-case character could extend above the baseline, so if +// you want the top edge of characters to appear at the top of the +// screen where y=0, then you would set the baseline to SF*-y0. +// +// Current point: +// Set the current point where the first character will appear. The +// first character could extend left of the current point; this is font +// dependent. You can either choose a current point that is the leftmost +// point and hope, or add some padding, or check the bounding box or +// left-side-bearing of the first character to be displayed and set +// the current point based on that. +// +// Displaying a character: +// Compute the bounding box of the character. It will contain signed values +// relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1, +// then the character should be displayed in the rectangle from +// <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1). +// +// Advancing for the next character: +// Call GlyphHMetrics, and compute 'current_point += SF * advance'. +// +// +// ADVANCED USAGE +// +// Quality: +// +// - Use the functions with Subpixel at the end to allow your characters +// to have subpixel positioning. Since the font is anti-aliased, not +// hinted, this is very import for quality. (This is not possible with +// baked fonts.) +// +// - Kerning is now supported, and if you're supporting subpixel rendering +// then kerning is worth using to give your text a polished look. +// +// Performance: +// +// - Convert Unicode codepoints to glyph indexes and operate on the glyphs; +// if you don't do this, stb_truetype is forced to do the conversion on +// every call. +// +// - There are a lot of memory allocations. We should modify it to take +// a temp buffer and allocate from the temp buffer (without freeing), +// should help performance a lot. +// +// NOTES +// +// The system uses the raw data found in the .ttf file without changing it +// and without building auxiliary data structures. This is a bit inefficient +// on little-endian systems (the data is big-endian), but assuming you're +// caching the bitmaps or glyph shapes this shouldn't be a big deal. +// +// It appears to be very hard to programmatically determine what font a +// given file is in a general way. I provide an API for this, but I don't +// recommend it. +// +// +// PERFORMANCE MEASUREMENTS FOR 1.06: +// +// 32-bit 64-bit +// Previous release: 8.83 s 7.68 s +// Pool allocations: 7.72 s 6.34 s +// Inline sort : 6.54 s 5.65 s +// New rasterizer : 5.63 s 5.00 s + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +//// +//// SAMPLE PROGRAMS +//// +// +// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless +// +#if 0 +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#include "stb_truetype.h" + +unsigned char ttf_buffer[1<<20]; +unsigned char temp_bitmap[512*512]; + +stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs +GLuint ftex; + +void my_stbtt_initfont(void) +{ + fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); + stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! + // can free ttf_buffer at this point + glGenTextures(1, &ftex); + glBindTexture(GL_TEXTURE_2D, ftex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); + // can free temp_bitmap at this point + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +} + +void my_stbtt_print(float x, float y, char *text) +{ + // assume orthographic projection with units = screen pixels, origin at top left + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, ftex); + glBegin(GL_QUADS); + while (*text) { + if (*text >= 32 && *text < 128) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); + } + ++text; + } + glEnd(); +} +#endif +// +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program (this compiles): get a single bitmap, print as ASCII art +// +#if 0 +#include <stdio.h> +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#include "stb_truetype.h" + +char ttf_buffer[1<<25]; + +int main(int argc, char **argv) +{ + stbtt_fontinfo font; + unsigned char *bitmap; + int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); + + fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); + + stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); + bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); + + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) + putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); + putchar('\n'); + } + return 0; +} +#endif +// +// Output: +// +// .ii. +// @@@@@@. +// V@Mio@@o +// :i. V@V +// :oM@@M +// :@@@MM@M +// @@o o@M +// :@@. M@M +// @@@o@@@@ +// :M@@V:@@. +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program: print "Hello World!" banner, with bugs +// +#if 0 +char buffer[24<<20]; +unsigned char screen[20][79]; + +int main(int arg, char **argv) +{ + stbtt_fontinfo font; + int i,j,ascent,baseline,ch=0; + float scale, xpos=2; // leave a little padding in case the character extends left + char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness + + fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); + stbtt_InitFont(&font, buffer, 0); + + scale = stbtt_ScaleForPixelHeight(&font, 15); + stbtt_GetFontVMetrics(&font, &ascent,0,0); + baseline = (int) (ascent*scale); + + while (text[ch]) { + int advance,lsb,x0,y0,x1,y1; + float x_shift = xpos - (float) floor(xpos); + stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); + stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); + stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); + // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong + // because this API is really for baking character bitmaps into textures. if you want to render + // a sequence of characters, you really need to render each bitmap to a temp buffer, then + // "alpha blend" that into the working buffer + xpos += (advance * scale); + if (text[ch+1]) + xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); + ++ch; + } + + for (j=0; j < 20; ++j) { + for (i=0; i < 78; ++i) + putchar(" .:ioVM@"[screen[j][i]>>5]); + putchar('\n'); + } + + return 0; +} +#endif + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +//// +//// INTEGRATION WITH YOUR CODEBASE +//// +//// The following sections allow you to supply alternate definitions +//// of C library functions used by stb_truetype, e.g. if you don't +//// link with the C runtime library. + +#ifdef STB_TRUETYPE_IMPLEMENTATION + // #define your own (u)stbtt_int8/16/32 before including to override this + #ifndef stbtt_uint8 + typedef unsigned char stbtt_uint8; + typedef signed char stbtt_int8; + typedef unsigned short stbtt_uint16; + typedef signed short stbtt_int16; + typedef unsigned int stbtt_uint32; + typedef signed int stbtt_int32; + #endif + + typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; + typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; + + // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h + #ifndef STBTT_ifloor + #include <math.h> + #define STBTT_ifloor(x) ((int) floor(x)) + #define STBTT_iceil(x) ((int) ceil(x)) + #endif + + #ifndef STBTT_sqrt + #include <math.h> + #define STBTT_sqrt(x) sqrt(x) + #define STBTT_pow(x,y) pow(x,y) + #endif + + #ifndef STBTT_fmod + #include <math.h> + #define STBTT_fmod(x,y) fmod(x,y) + #endif + + #ifndef STBTT_cos + #include <math.h> + #define STBTT_cos(x) cos(x) + #define STBTT_acos(x) acos(x) + #endif + + #ifndef STBTT_fabs + #include <math.h> + #define STBTT_fabs(x) fabs(x) + #endif + + // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h + #ifndef STBTT_malloc + #include <stdlib.h> + #define STBTT_malloc(x,u) ((void)(u),malloc(x)) + #define STBTT_free(x,u) ((void)(u),free(x)) + #endif + + #ifndef STBTT_assert + #include <assert.h> + #define STBTT_assert(x) assert(x) + #endif + + #ifndef STBTT_strlen + #include <string.h> + #define STBTT_strlen(x) strlen(x) + #endif + + #ifndef STBTT_memcpy + #include <string.h> + #define STBTT_memcpy memcpy + #define STBTT_memset memset + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// INTERFACE +//// +//// + +#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ +#define __STB_INCLUDE_STB_TRUETYPE_H__ + +#ifdef STBTT_STATIC +#define STBTT_DEF static +#else +#define STBTT_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// private structure +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + +////////////////////////////////////////////////////////////////////////////// +// +// TEXTURE BAKING API +// +// If you use this API, you only have to call two functions ever. +// + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; +} stbtt_bakedchar; + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +// if return is positive, the first unused row of the bitmap +// if return is negative, returns the negative of the number of characters that fit +// if return is 0, no characters fit and no rows were used +// This uses a very crappy packing. + +typedef struct +{ + float x0,y0,s0,t0; // top-left + float x1,y1,s1,t1; // bottom-right +} stbtt_aligned_quad; + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +// Call GetBakedQuad with char_index = 'character - first_char', and it +// creates the quad you need to draw and advances the current position. +// +// The coordinate system used assumes y increases downwards. +// +// Characters will extend both above and below the current position; +// see discussion of "BASELINE" above. +// +// It's inefficient; you might want to c&p it and optimize it. + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +// Query the font vertical metrics without having to create a font first. + + +////////////////////////////////////////////////////////////////////////////// +// +// NEW TEXTURE BAKING API +// +// This provides options for packing multiple fonts into one atlas, not +// perfectly but better than nothing. + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; + float xoff2,yoff2; +} stbtt_packedchar; + +typedef struct stbtt_pack_context stbtt_pack_context; +typedef struct stbtt_fontinfo stbtt_fontinfo; +#ifndef STB_RECT_PACK_VERSION +typedef struct stbrp_rect stbrp_rect; +#endif + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +// Initializes a packing context stored in the passed-in stbtt_pack_context. +// Future calls using this context will pack characters into the bitmap passed +// in here: a 1-channel bitmap that is width * height. stride_in_bytes is +// the distance from one row to the next (or 0 to mean they are packed tightly +// together). "padding" is the amount of padding to leave between each +// character (normally you want '1' for bitmaps you'll use as textures with +// bilinear filtering). +// +// Returns 0 on failure, 1 on success. + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +// Cleans up the packing context and frees all memory. + +#define STBTT_POINT_SIZE(x) (-(x)) + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +// Creates character bitmaps from the font_index'th font found in fontdata (use +// font_index=0 if you don't know what that is). It creates num_chars_in_range +// bitmaps for characters with unicode values starting at first_unicode_char_in_range +// and increasing. Data for how to render them is stored in chardata_for_range; +// pass these to stbtt_GetPackedQuad to get back renderable quads. +// +// font_size is the full height of the character from ascender to descender, +// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed +// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() +// and pass that result as 'font_size': +// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall + +typedef struct +{ + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, v_oversample; // don't set these, they're used internally +} stbtt_pack_range; + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +// Creates character bitmaps from multiple ranges of characters stored in +// ranges. This will usually create a better-packed bitmap than multiple +// calls to stbtt_PackFontRange. Note that you can call this multiple +// times within a single PackBegin/PackEnd. + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +// Oversampling a font increases the quality by allowing higher-quality subpixel +// positioning, and is especially valuable at smaller text sizes. +// +// This function sets the amount of oversampling for all following calls to +// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given +// pack context. The default (no oversampling) is achieved by h_oversample=1 +// and v_oversample=1. The total number of pixels required is +// h_oversample*v_oversample larger than the default; for example, 2x2 +// oversampling requires 4x the storage of 1x1. For best results, render +// oversampled textures with bilinear filtering. Look at the readme in +// stb/tests/oversample for information about oversampled fonts +// +// To use with PackFontRangesGather etc., you must set it before calls +// call to PackFontRangesGatherRects. + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +// If skip != 0, this tells stb_truetype to skip any codepoints for which +// there is no corresponding glyph. If skip=0, which is the default, then +// codepoints without a glyph recived the font's "missing character" glyph, +// typically an empty box by convention. + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); + +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +// Calling these functions in sequence is roughly equivalent to calling +// stbtt_PackFontRanges(). If you more control over the packing of multiple +// fonts, or if you want to pack custom data into a font texture, take a look +// at the source to of stbtt_PackFontRanges() and create a custom version +// using these functions, e.g. call GatherRects multiple times, +// building up a single array of rects, then call PackRects once, +// then call RenderIntoRects repeatedly. This may result in a +// better packing than calling PackFontRanges multiple times +// (or it may not). + +// this is an opaque structure that you shouldn't mess with which holds +// all the context needed from PackBegin to PackEnd. +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// FONT LOADING +// +// + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +// This function will determine the number of fonts in a font file. TrueType +// collection (.ttc) files may contain multiple fonts, while TrueType font +// (.ttf) files only contain one font. The number of fonts can be used for +// indexing with the previous function where the index is between zero and one +// less than the total fonts. If an error occurs, -1 is returned. + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); +// Each .ttf/.ttc file may have more than one font. Each font has a sequential +// index number starting from 0. Call this function to get the font offset for +// a given index; it returns -1 if the index is out of range. A regular .ttf +// file will only define one font and it always be at offset 0, so it will +// return '0' for index 0, and -1 for all other indices. + +// The following structure is defined publicly so you can declare one on +// the stack or as a global or etc, but you should treat it as opaque. +struct stbtt_fontinfo +{ + void * userdata; + unsigned char * data; // pointer to .ttf file + int fontstart; // offset of start of font + + int numGlyphs; // number of glyphs, needed for range checking + + int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict +}; + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); +// Given an offset into the file that defines a font, this function builds +// the necessary cached info for the rest of the system. You must allocate +// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't +// need to do anything special to free it, because the contents are pure +// value data with no additional data structures. Returns 0 on failure. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER TO GLYPH-INDEX CONVERSIOn + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); +// If you're going to perform multiple operations on the same character +// and you want a speed-up, call this function with the character you're +// going to process, then use glyph-based functions instead of the +// codepoint-based functions. +// Returns 0 if the character codepoint is not defined in the font. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER PROPERTIES +// + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose "height" is 'pixels' tall. +// Height is measured as the distance from the highest ascender to the lowest +// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics +// and computing: +// scale = pixels / (ascent - descent) +// so if you prefer to measure height by the ascent only, use a similar calculation. + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose EM size is mapped to +// 'pixels' tall. This is probably what traditional APIs compute, but +// I'm not positive. + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +// ascent is the coordinate above the baseline the font extends; descent +// is the coordinate below the baseline the font extends (i.e. it is typically negative) +// lineGap is the spacing between one row's descent and the next row's ascent... +// so you should advance the vertical position by "*ascent - *descent + *lineGap" +// these are expressed in unscaled coordinates, so you must multiply by +// the scale factor for a given size + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 +// table (specific to MS/Windows TTF files). +// +// Returns 1 on success (table present), 0 on failure. + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +// the bounding box around all possible characters + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +// leftSideBearing is the offset from the current horizontal position to the left edge of the character +// advanceWidth is the offset from the current horizontal position to the next horizontal position +// these are expressed in unscaled coordinates + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +// an additional amount to add to the 'advance' value between ch1 and ch2 + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); +// Gets the bounding box of the visible part of the glyph, in unscaled coordinates + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); +// as above, but takes one or more glyph indices for greater efficiency + +typedef struct stbtt_kerningentry +{ + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; +} stbtt_kerningentry; + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +// Retrieves a complete list of all of the kerning pairs provided by the font +// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. +// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) + +////////////////////////////////////////////////////////////////////////////// +// +// GLYPH SHAPES (you probably don't need these, but they have to go before +// the bitmaps for C declaration-order reasons) +// + +#ifndef STBTT_vmove // you can predefine these to use different values (but why?) + enum { + STBTT_vmove=1, + STBTT_vline, + STBTT_vcurve, + STBTT_vcubic + }; +#endif + +#ifndef stbtt_vertex // you can predefine this to use different values + // (we share this with other code at RAD) + #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file + typedef struct + { + stbtt_vertex_type x,y,cx,cy,cx1,cy1; + unsigned char type,padding; + } stbtt_vertex; +#endif + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); +// returns non-zero if nothing is drawn for this glyph + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); +// returns # of vertices and fills *vertices with the pointer to them +// these are expressed in "unscaled" coordinates +// +// The shape is a series of contours. Each one starts with +// a STBTT_moveto, then consists of a series of mixed +// STBTT_lineto and STBTT_curveto segments. A lineto +// draws a line from previous endpoint to its x,y; a curveto +// draws a quadratic bezier from previous endpoint to +// its x,y, using cx,cy as the bezier control point. + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +// frees the data allocated above + +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); +// fills svg with the character's SVG data. +// returns data size or 0 if SVG not found. + +////////////////////////////////////////////////////////////////////////////// +// +// BITMAP RENDERING +// + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); +// frees the bitmap allocated below + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// allocates a large-enough single-channel 8bpp bitmap and renders the +// specified character/glyph at the specified scale into it, with +// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). +// *width & *height are filled out with the width & height of the bitmap, +// which is stored left-to-right, top-to-bottom. +// +// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap +// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap +// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the +// width and height and positioning info for it first. + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering +// is performed (see stbtt_PackSetOversampling) + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +// get the bbox of the bitmap centered around the glyph origin; so the +// bitmap width is ix1-ix0, height is iy1-iy0, and location to place +// the bitmap top left is (leftSideBearing*scale,iy0). +// (Note that the bitmap uses y-increases-down, but the shape uses +// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel +// shift for the character + +// the following functions are equivalent to the above functions, but operate +// on glyph indices instead of Unicode codepoints (for efficiency) +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); + + +// @TODO: don't expose this structure +typedef struct +{ + int w,h,stride; + unsigned char *pixels; +} stbtt__bitmap; + +// rasterize a shape with quadratic beziers into a bitmap +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC + +////////////////////////////////////////////////////////////////////////////// +// +// Signed Distance Function (or Field) rendering + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); +// frees the SDF bitmap allocated below + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +// These functions compute a discretized SDF field for a single character, suitable for storing +// in a single-channel texture, sampling with bilinear filtering, and testing against +// larger than some threshold to produce scalable fonts. +// info -- the font +// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap +// glyph/codepoint -- the character to generate the SDF for +// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// which allows effects like bit outlines +// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) +// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) +// if positive, > onedge_value is inside; if negative, < onedge_value is inside +// width,height -- output height & width of the SDF bitmap (including padding) +// xoff,yoff -- output origin of the character +// return value -- a 2D array of bytes 0..255, width*height in size +// +// pixel_dist_scale & onedge_value are a scale & bias that allows you to make +// optimal use of the limited 0..255 for your application, trading off precision +// and special effects. SDF values outside the range 0..255 are clamped to 0..255. +// +// Example: +// scale = stbtt_ScaleForPixelHeight(22) +// padding = 5 +// onedge_value = 180 +// pixel_dist_scale = 180/5.0 = 36.0 +// +// This will create an SDF bitmap in which the character is about 22 pixels +// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled +// shape, sample the SDF at each pixel and fill the pixel if the SDF value +// is greater than or equal to 180/255. (You'll actually want to antialias, +// which is beyond the scope of this example.) Additionally, you can compute +// offset outlines (e.g. to stroke the character border inside & outside, +// or only outside). For example, to fill outside the character up to 3 SDF +// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above +// choice of variables maps a range from 5 pixels outside the shape to +// 2 pixels inside the shape to 0..255; this is intended primarily for apply +// outside effects only (the interior range is needed to allow proper +// antialiasing of the font at *smaller* sizes) +// +// The function computes the SDF analytically at each SDF pixel, not by e.g. +// building a higher-res bitmap and approximating it. In theory the quality +// should be as high as possible for an SDF of this size & representation, but +// unclear if this is true in practice (perhaps building a higher-res bitmap +// and computing from that can allow drop-out prevention). +// +// The algorithm has not been optimized at all, so expect it to be slow +// if computing lots of characters or very large sizes. + + + +////////////////////////////////////////////////////////////////////////////// +// +// Finding the right font... +// +// You should really just solve this offline, keep your own tables +// of what font is what, and don't try to get it out of the .ttf file. +// That's because getting it out of the .ttf file is really hard, because +// the names in the file can appear in many possible encodings, in many +// possible languages, and e.g. if you need a case-insensitive comparison, +// the details of that depend on the encoding & language in a complex way +// (actually underspecified in truetype, but also gigantic). +// +// But you can use the provided functions in two possible ways: +// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on +// unicode-encoded names to try to find the font you want; +// you can run this before calling stbtt_InitFont() +// +// stbtt_GetFontNameString() lets you get any of the various strings +// from the file yourself and do your own comparisons on them. +// You have to have called stbtt_InitFont() first. + + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +// returns the offset (not index) of the font that matches, or -1 if none +// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". +// if you use any other flag, use a font name like "Arial"; this checks +// the 'macStyle' header field; i don't know if fonts set this consistently +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +// returns 1/0 whether the first string interpreted as utf8 is identical to +// the second string interpreted as big-endian utf16... useful for strings from next func + +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +// returns the string (which may be big-endian double byte, e.g. for unicode) +// and puts the length in bytes in *length. +// +// some of the values for the IDs are below; for more see the truetype spec: +// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html +// http://www.microsoft.com/typography/otspec/name.htm + +enum { // platformID + STBTT_PLATFORM_ID_UNICODE =0, + STBTT_PLATFORM_ID_MAC =1, + STBTT_PLATFORM_ID_ISO =2, + STBTT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_UNICODE + STBTT_UNICODE_EID_UNICODE_1_0 =0, + STBTT_UNICODE_EID_UNICODE_1_1 =1, + STBTT_UNICODE_EID_ISO_10646 =2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT + STBTT_MS_EID_SYMBOL =0, + STBTT_MS_EID_UNICODE_BMP =1, + STBTT_MS_EID_SHIFTJIS =2, + STBTT_MS_EID_UNICODE_FULL =10 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes + STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, + STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, + STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, + STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 +}; + +enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... + // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs + STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, + STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, + STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, + STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, + STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, + STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D +}; + +enum { // languageID for STBTT_PLATFORM_ID_MAC + STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, + STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, + STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, + STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , + STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , + STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, + STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 +}; + +#ifdef __cplusplus +} +#endif + +#endif // __STB_INCLUDE_STB_TRUETYPE_H__ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// IMPLEMENTATION +//// +//// + +#ifdef STB_TRUETYPE_IMPLEMENTATION + +#ifndef STBTT_MAX_OVERSAMPLE +#define STBTT_MAX_OVERSAMPLE 8 +#endif + +#if STBTT_MAX_OVERSAMPLE > 255 +#error "STBTT_MAX_OVERSAMPLE cannot be > 255" +#endif + +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; + +#ifndef STBTT_RASTERIZER_VERSION +#define STBTT_RASTERIZER_VERSION 2 +#endif + +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + +////////////////////////////////////////////////////////////////////////// +// +// stbtt__buf helpers to parse data from file +// + +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; +} + +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; +} + +static void stbtt__buf_seek(stbtt__buf *b, int o) +{ + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; +} + +static void stbtt__buf_skip(stbtt__buf *b, int o) +{ + stbtt__buf_seek(b, b->cursor + o); +} + +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) +{ + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; +} + +static stbtt__buf stbtt__new_buf(const void *p, size_t size) +{ + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8*) p; + r.size = (int) size; + r.cursor = 0; + return r; +} + +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) + +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) +{ + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; + r.data = b->data + o; + r.size = s; + return r; +} + +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) +{ + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); +} + +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) +{ + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) return b0 - 139; + else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) return stbtt__buf_get16(b); + else if (b0 == 29) return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; +} + +static void stbtt__cff_skip_operand(stbtt__buf *b) { + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) +{ + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) op = stbtt__buf_get8(b) | 0x100; + if (op == key) return stbtt__buf_range(b, start, end-start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) +{ + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) +{ + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) +{ + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i*offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +} + +////////////////////////////////////////////////////////////////////////// +// +// accessors to parse data from file +// + +// on platforms that don't allow misaligned reads, if we want to allow +// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE + +#define ttBYTE(p) (* (stbtt_uint8 *) (p)) +#define ttCHAR(p) (* (stbtt_int8 *) (p)) +#define ttFixed(p) ttLONG(p) + +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } + +#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) + +static int stbtt__isfont(stbtt_uint8 *font) +{ + // check the version number + if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF + if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts + return 0; +} + +// @OPTIMIZE: binary search +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) +{ + stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i=0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16*i; + if (stbtt_tag(data+loc+0, tag)) + return ttULONG(data+loc+8); + } + return 0; +} + +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) +{ + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection+8); + if (index >= n) + return -1; + return ttULONG(font_collection+12+index*4); + } + } + return -1; +} + +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) +{ + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + return ttLONG(font_collection+8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) +{ + stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1]+subrsoff); + return stbtt__cff_get_index(&cff); +} + +// since most people won't use this, find this table the first time it's needed +static int stbtt__get_svg(stbtt_fontinfo *info) +{ + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) +{ + stbtt_uint32 cmap, t; + stbtt_int32 i,numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data+t+4); + else + info->numGlyphs = 0xffff; + + info->svg = -1; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch(ttUSHORT(data+encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data+encoding_record+2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + // Mac/iOS has these + // all the encodingIDs are unicode, so we don't bother to check it + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data+info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) +{ + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes-6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges + stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); + stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) + search += rangeShift*2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange*2); + if (unicode_codepoint > end) + search += searchRange*2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + if (unicode_codepoint < start) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + + return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data+index_map+12); + stbtt_int32 low,high; + low = 0; high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); + stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); + if ((stbtt_uint32) unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32) unicode_codepoint > end_char) + low = mid+1; + else { + stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); + if (format == 12) + return start_glyph + unicode_codepoint-start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; +} + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) +{ + return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +} + +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) +{ + v->type = type; + v->x = (stbtt_int16) x; + v->y = (stbtt_int16) y; + v->cx = (stbtt_int16) cx; + v->cy = (stbtt_int16) cy; +} + +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) +{ + int g1,g2; + + STBTT_assert(!info->cff.size); + + if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); + } + + return g1==g2 ? -1 : g1; // if length is 0, return -1 +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); + +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; + + if (x0) *x0 = ttSHORT(info->data + g + 2); + if (y0) *y0 = ttSHORT(info->data + g + 4); + if (x1) *x1 = ttSHORT(info->data + g + 6); + if (y1) *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) +{ + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, + stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) +{ + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices=0; + int num_vertices=0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags=0,flagcount; + stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; + stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); + + m = n + 2*numberOfContours; // a loose bound on how many vertices we might need + vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated + + // first load flags + + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off+i].type = flags; + } + + // now load x coordinates + x=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? + } else { + if (!(flags & 16)) { + x = x + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].x = (stbtt_int16) x; + } + + // now load y coordinates + y=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? + } else { + if (!(flags & 32)) { + y = y + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].y = (stbtt_int16) y; + } + + // now convert them to our format + num_vertices=0; + sx = sy = cx = cy = scx = scy = 0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + x = (stbtt_int16) vertices[off+i].x; + y = (stbtt_int16) vertices[off+i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find a point on the curve + // where we can start, and we need to save some state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + // next point is also a curve point, so interpolate an on-point curve + sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; + sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32) vertices[off+i+1].x; + sy = (stbtt_int32) vertices[off+i+1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours+j*2); + ++j; + } else { + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + } else if (numberOfContours < 0) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1,0,0,1,0,0}, m, n; + + flags = ttSHORT(comp); comp+=2; + gidx = ttSHORT(comp); comp+=2; + + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); comp+=2; + mtx[5] = ttSHORT(comp); comp+=2; + } else { + mtx[4] = ttCHAR(comp); comp+=1; + mtx[5] = ttCHAR(comp); comp+=1; + } + } + else { + // @TODO handle matching point + STBTT_assert(0); + } + if (flags & (1<<3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } + + // Find transformation scales. + m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex* v = &comp_verts[i]; + stbtt_vertex_type x,y; + x=v->x; y=v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + x=v->cx; y=v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); + if (!tmp) { + if (vertices) STBTT_free(vertices, info->userdata); + if (comp_verts) STBTT_free(comp_verts, info->userdata); + return 0; + } + if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); + STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); + if (vertices) STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; + } + // More components ? + more = flags & (1<<5); + } + } else { + // numberOfCounters == 0, do nothing + } + + *pvertices = vertices; + return num_vertices; +} + +typedef struct +{ + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; +} stbtt__csctx; + +#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) +{ + if (x > c->max_x || !c->started) c->max_x = x; + if (y > c->max_y || !c->started) c->max_y = y; + if (x < c->min_x || !c->started) c->min_x = x; + if (y < c->min_y || !c->started) c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) +{ + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) +{ + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) +{ + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) +{ + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) +{ + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) +{ + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); +} + +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) +{ + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; + +#define STBTT__CSERR(s) (0) + + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; + + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: // rlineto + if (sp < 2) return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; + + case 0x1F: // hvcurveto + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); + i += 4; + } + break; + + case 0x08: // rrcurveto + if (sp < 6) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x18: // rcurveline + if (sp < 8) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + case 0x19: // rlinecurve + if (sp < 8) return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { f = s[i]; i++; } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); + f = 0.0; + } + break; + + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // fallthrough + case 0x1D: // callgsubr + if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); + v = (int) s[--sp]; + if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; + + case 0x0B: // return + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + //fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1+dx2+dx3+dx4+dx5; + dy = dy1+dy2+dy3+dy4+dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + default: + return STBTT__CSERR("unimplemented"); + } + } break; + + default: + if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) sp = 0; + } + return STBTT__CSERR("no endchar"); + +#undef STBTT__CSERR +} + +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) *x0 = r ? c.min_x : 0; + if (y0) *y0 = r ? c.min_y : 0; + if (x1) *x1 = r ? c.max_x : 0; + if (y1) *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) +{ + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); + } else { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); + } +} + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) +{ + stbtt_uint8 *data = info->data + info->kern; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + return ttUSHORT(data+10); +} + +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) +{ + stbtt_uint8 *data = info->data + info->kern; + int k, length; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + length = ttUSHORT(data+10); + if (table_length < length) + length = table_length; + + for (k = 0; k < length; k++) + { + table[k].glyph1 = ttUSHORT(data+18+(k*6)); + table[k].glyph2 = ttUSHORT(data+20+(k*6)); + table[k].advance = ttSHORT(data+22+(k*6)); + } + + return length; +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + l = 0; + r = ttUSHORT(data+10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data+18+(m*6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data+22+(m*6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +{ + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch(coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; + } + } + } break; + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } + } + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + } break; + } + + return -1; +} + +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) +{ + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch(classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + + classDefTable = classDef1ValueArray + 2 * glyphCount; + } break; + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + + classDefTable = classRangeRecords + 6 * classRangeCount; + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + } break; + } + + return -1; +} + +// Define to STBTT_assert(x) if you want to break on unimplemented formats. +#define STBTT_GPOS_TODO_assert(x) + +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i<lookupCount; ++i) { + stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); + stbtt_uint8 *lookupTable = lookupList + lookupOffset; + + stbtt_uint16 lookupType = ttUSHORT(lookupTable); + stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); + stbtt_uint8 *subTableOffsets = lookupTable + 6; + switch(lookupType) { + case 2: { // Pair Adjustment Positioning Subtable + stbtt_int32 sti; + for (sti=0; sti<subTableCount; sti++) { + stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); + stbtt_uint8 *table = lookupTable + subtableOffset; + stbtt_uint16 posFormat = ttUSHORT(table); + stbtt_uint16 coverageOffset = ttUSHORT(table + 2); + stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); + if (coverageIndex == -1) continue; + + switch (posFormat) { + case 1: { + stbtt_int32 l, r, m; + int straw, needle; + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + stbtt_int32 valueRecordPairSizeInBytes = 2; + stbtt_uint16 pairSetCount = ttUSHORT(table + 8); + stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); + stbtt_uint8 *pairValueTable = table + pairPosOffset; + stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); + stbtt_uint8 *pairValueArray = pairValueTable + 2; + // TODO: Support more formats. + STBTT_GPOS_TODO_assert(valueFormat1 == 4); + if (valueFormat1 != 4) return 0; + STBTT_GPOS_TODO_assert(valueFormat2 == 0); + if (valueFormat2 != 0) return 0; + + STBTT_assert(coverageIndex < pairSetCount); + STBTT__NOTUSED(pairSetCount); + + needle=glyph2; + r=pairValueCount-1; + l=0; + + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } break; + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + STBTT_assert(glyph1class < class1Count); + STBTT_assert(glyph2class < class2Count); + + // TODO: Support more formats. + STBTT_GPOS_TODO_assert(valueFormat1 == 4); + if (valueFormat1 != 4) return 0; + STBTT_GPOS_TODO_assert(valueFormat2 == 0); + if (valueFormat2 != 0) return 0; + + if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { + stbtt_uint8 *class1Records = table + 16; + stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); + stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + break; + }; + } + } + break; + }; + + default: + // TODO: Implement other stuff. + break; + } + } + + return 0; +} + +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) +{ + int xAdvance = 0; + + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + + return xAdvance; +} + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) +{ + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +} + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) +{ + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +} + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) +{ + if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); + if (descent) *descent = ttSHORT(info->data+info->hhea + 6); + if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +} + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) +{ + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); + if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); + if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); + return 1; +} + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) +{ + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); +} + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) +{ + int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); + return (float) height / fheight; +} + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) +{ + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; +} + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) +{ + STBTT_free(v, info->userdata); +} + +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) +{ + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); + + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; + + for(i=0; i<numEntries; i++) { + stbtt_uint8 *svg_doc = svg_docs + (12 * i); + if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; +} + +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) +{ + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; + + if (info->svg == 0) + return 0; + + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } +} + +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) +{ + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +} + +////////////////////////////////////////////////////////////////////////////// +// +// antialiasing software rasterizer +// + +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + // e.g. space character + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels get touched)? + if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); + if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); + if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); + } +} + +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Rasterizer + +typedef struct stbtt__hheap_chunk +{ + struct stbtt__hheap_chunk *next; +} stbtt__hheap_chunk; + +typedef struct stbtt__hheap +{ + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; +} stbtt__hheap; + +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) +{ + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = * (void **) p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; + } +} + +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) +{ + *(void **) p = hh->first_free; + hh->first_free = p; +} + +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) +{ + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } +} + +typedef struct stbtt__edge { + float x0,y0, x1,y1; + int invert; +} stbtt__edge; + + +typedef struct stbtt__active_edge +{ + struct stbtt__active_edge *next; + #if STBTT_RASTERIZER_VERSION==1 + int x,dx; + float ey; + int direction; + #elif STBTT_RASTERIZER_VERSION==2 + float fx,fdx,fdy; + float direction; + float sy; + float ey; + #else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" + #endif +} stbtt__active_edge; + +#if STBTT_RASTERIZER_VERSION == 1 +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX-1) + +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) return z; + + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + + z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; + + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; +} +#elif STBTT_RASTERIZER_VERSION == 2 +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + //STBTT_assert(e->y0 <= start_point); + if (!z) return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#if STBTT_RASTERIZER_VERSION == 1 +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) +{ + // non-zero winding fill + int x0=0, w=0; + + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->direction; + } else { + int x1 = e->x; w += e->direction; + // if we went to zero, we need to draw + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8) max_weight; + } + } + } + } + + e = e->next; + } +} + +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; + + if (result->w > 512) + scanline = (unsigned char *) STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; + + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; + + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s=0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for(;;) { + int changed=0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; + + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); + + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} + +#elif STBTT_RASTERIZER_VERSION == 2 + +// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 +// (i.e. it has already been clipped to those) +static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) +{ + if (y0 == y1) return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) return; + if (y1 < e->sy) return; + if (y0 < e->sy) { + x0 += (x1-x0) * (e->sy - y0) / (y1-y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1-x0) * (e->ey - y1) / (y1-y0); + y1 = e->ey; + } + + if (x0 == x) + STBTT_assert(x1 <= x+1); + else if (x0 == x+1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x+1) + STBTT_assert(x1 >= x+1); + else + STBTT_assert(x1 >= x && x1 <= x+1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1-y0); + else if (x0 >= x+1 && x1 >= x+1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); + scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position + } +} + +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) +{ + float y_bottom = y_top+1; + + while (e) { + // brute force every pixel + + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); + + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); + stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0,sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; + } else { + x_top = x0; + sy0 = y_top; + } + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; + } else { + x_bottom = xb; + sy1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int) x_top == (int) x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int) x_top; + height = sy1 - sy0; + STBTT_assert(x >= 0 && x < len); + scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; + scanline_fill[x] += e->direction * height; // everything right of this pixel is filled + } else { + int x,x1,x2; + float y_crossing, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + } + + x1 = (int) x_top; + x2 = (int) x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = (x1+1 - x0) * dy + y_top; + + sign = e->direction; + // area of the rectangle covered from y0..y_crossing + area = sign * (y_crossing-sy0); + // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) + scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); + + step = sign * dy; + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; + area += step; + } + y_crossing += dy * (x2 - (x1+1)); + + STBTT_assert(STBTT_fabs(area) <= 1.01f); + + scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); + + scanline_fill[x2] += sign * (sy1-sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + int x; + for (x=0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any intersection + // with left or right edges can be handled by splitting into two (or three) + // regions. intersections with top & bottom do not necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & right edges, + // then used some simple logic to produce up to three segments in sorted order + // from top-to-bottom. however, this had a problem: if an x edge was epsilon + // across the x border, then the corresponding y position might not be distinct + // from the other y segment, and it might ignored as an empty segment. to avoid + // that, we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x1 && x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); + } + } + } + } + e = e->next; + } +} + +// directly AA rasterize edges w/o supersampling +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0, i; + float scanline_data[129], *scanline, *scanline2; + + STBTT__NOTUSED(vsubsample); + + if (result->w > 64) + scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); + else + scanline = scanline_data; + + scanline2 = scanline + result->w; + + y = off_y; + e[n].y0 = (float) (off_y + result->h) + 1; + + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; + + STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); + + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list + } + } + + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds + // insert at front + z->next = active; + active = z; + } + } + ++e; + } + + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i=0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float) STBTT_fabs(k)*255 + 0.5f; + m = (int) k; + if (m > 255) m = 255; + result->pixels[j*result->stride + i] = (unsigned char) m; + } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + + ++y; + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) + +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) +{ + int i,j; + for (i=1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j-1]; + int c = STBTT__COMPARE(a,b); + if (!c) break; + p[j] = p[j-1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) +{ + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01,c12,c,m,i,j; + + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0],&p[m]); + c12 = STBTT__COMPARE(&p[m],&p[n-1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0],&p[n-1]); + /* 0>mid && mid<n: 0>n => n; 0<n => 0 */ + /* 0<mid && mid>n: 0>n => 0; 0<n => n */ + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i=1; + j=n-1; + for(;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;;++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!STBTT__COMPARE(&p[0], &p[j])) break; + } + /* make sure we haven't crossed */ + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n-i)) { + stbtt__sort_edges_quicksort(p,j); + p = p+i; + n = n-i; + } else { + stbtt__sort_edges_quicksort(p+i, n-i); + n = j; + } + } +} + +static void stbtt__sort_edges(stbtt__edge *p, int n) +{ + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); +} + +typedef struct +{ + float x,y; +} stbtt__point; + +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) +{ + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n,i,j,k,m; +#if STBTT_RASTERIZER_VERSION == 1 + int vsubsample = result->h < 8 ? 15 : 5; +#elif STBTT_RASTERIZER_VERSION == 2 + int vsubsample = 1; +#else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel + if (e == 0) return; + n = 0; + + m=0; + for (i=0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i]-1; + for (k=0; k < wcount[i]; j=k++) { + int a=k,b=j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a=j,b=k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } + + // now sort the edges by their highest point (should snap to integer, and then by x) + //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); + + // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + + STBTT_free(e, userdata); +} + +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) +{ + if (!points) return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; +} + +// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) +{ + // midpoint + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + // versus directly drawn line + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA + stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x2,y2); + *num_points = *num_points+1; + } + return 1; +} + +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) +{ + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1-x0; + float dy0 = y1-y0; + float dx1 = x2-x1; + float dy1 = y2-y1; + float dx2 = x3-x2; + float dy2 = y3-y2; + float dx = x3-x0; + float dy = y3-y0; + float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); + float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); + float flatness_squared = longlen*longlen-shortlen*shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0+x1)/2; + float y01 = (y0+y1)/2; + float x12 = (x1+x2)/2; + float y12 = (y1+y2)/2; + float x23 = (x2+x3)/2; + float y23 = (y2+y3)/2; + + float xa = (x01+x12)/2; + float ya = (y01+y12)/2; + float xb = (x12+x23)/2; + float yb = (y12+y23)/2; + + float mx = (xa+xb)/2; + float my = (ya+yb)/2; + + stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x3,y3); + *num_points = *num_points+1; + } +} + +// returns number of contours +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) +{ + stbtt__point *points=0; + int num_points=0; + + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i,n=0,start=0, pass; + + // count how many "moves" there are to get the contour count + for (i=0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; + + *num_contours = n; + if (n == 0) return 0; + + *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + // make two passes through the points so we don't need to realloc + for (pass=0; pass < 2; ++pass) { + float x=0,y=0; + if (pass == 1) { + points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); + if (points == NULL) goto error; + } + num_points = 0; + n= -1; + for (i=0; i < num_verts; ++i) { + switch (vertices[i].type) { + case STBTT_vmove: + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x,y); + break; + case STBTT_vline: + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vcurve: + stbtt__tesselate_curve(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + } + } + (*contour_lengths)[n] = num_points - start; + } + + return points; +error: + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; +} + +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) +{ + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } +} + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + int ix0,iy0,ix1,iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error + + if (width ) *width = gbm.w; + if (height) *height = gbm.h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; + + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) +{ + int ix0,iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; + + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + + STBTT_free(vertices, info->userdata); +} + +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) +{ + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +} + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-CRAPPY packing to keep source code small + +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) +{ + float scale; + int x,y,bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + x=y=1; + bottom_y = 1; + + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + + for (i=0; i < num_chars; ++i) { + int advance, lsb, x0,y0,x1,y1,gw,gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); + gw = x1-x0; + gh = y1-y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x+gw < pw); + STBTT_assert(y+gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); + chardata[i].x0 = (stbtt_int16) x; + chardata[i].y0 = (stbtt_int16) y; + chardata[i].x1 = (stbtt_int16) (x + gw); + chardata[i].y1 = (stbtt_int16) (y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float) x0; + chardata[i].yoff = (float) y0; + x = x + gw + 1; + if (y+gh+1 > bottom_y) + bottom_y = y+gh+1; + } + return bottom_y; +} + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) +{ + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); + + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// rectangle packing replacement routines if you don't have stb_rect_pack.h +// + +#ifndef STB_RECT_PACK_VERSION + +typedef int stbrp_coord; + +//////////////////////////////////////////////////////////////////////////////////// +// // +// // +// COMPILER WARNING ?!?!? // +// // +// // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// // +//////////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int width,height; + int x,y,bottom_y; +} stbrp_context; + +typedef struct +{ + unsigned char x; +} stbrp_node; + +struct stbrp_rect +{ + stbrp_coord x,y; + int id,w,h,was_packed; +}; + +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) +{ + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) +{ + int i; + for (i=0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for ( ; i < num_rects; ++i) + rects[i].was_packed = 0; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If +// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) +{ + stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) STBTT_free(context, alloc_context); + if (nodes != NULL) STBTT_free(nodes , alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; + + stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + + if (pixels) + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + + return 1; +} + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) +{ + STBTT_free(spc->nodes , spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) +{ + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) +{ + spc->skip_missing = skip; +} + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char) (total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < h; ++i) { + STBTT_assert(pixels[i*stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + + pixels += 1; + } +} + +static float stbtt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k; + int missing_glyph_added = 0; + + k=0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char) spc->h_oversample; + ranges[i].v_oversample = (unsigned char) spc->v_oversample; + for (j=0; j < ranges[i].num_chars; ++j) { + int x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + if (glyph == 0) + missing_glyph_added = 1; + } + ++k; + } + } + + return k; +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, + output, + out_w - (prefilter_x - 1), + out_h - (prefilter_y - 1), + out_stride, + scale_x, + scale_y, + shift_x, + shift_y, + glyph); + + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k, missing_glyph = -1, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h,recip_v,sub_x,sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j=0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord) spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + &x0,&y0,&x1,&y1); + stbtt_MakeGlyphBitmapSubpixel(info, + spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w - spc->h_oversample+1, + r->h - spc->v_oversample+1, + spc->stride_in_bytes, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + + bc->x0 = (stbtt_int16) r->x; + bc->y0 = (stbtt_int16) r->y; + bc->x1 = (stbtt_int16) (r->x + r->w); + bc->y1 = (stbtt_int16) (r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; + } else { + return_value = 0; // if any fail, report failure + } + + ++k; + } + } + + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; +} + +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) +{ + stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); +} + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) +{ + stbtt_fontinfo info; + int i,j,n, return_value = 1; + //stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; + + // flag all characters as NOT packed + for (i=0; i < num_ranges; ++i) + for (j=0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = + ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i=0; i < num_ranges; ++i) + n += ranges[i].num_chars; + + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; + + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + + stbtt_PackFontRangesPackRects(spc, rects, n); + + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + + STBTT_free(rects, spc->user_allocator_context); + return return_value; +} + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) +{ + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +} + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) +{ + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float) i_ascent * scale; + *descent = (float) i_descent * scale; + *lineGap = (float) i_lineGap * scale; +} + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) +{ + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; + + if (align_to_integer) { + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// sdf computation +// + +#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) + +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) +{ + float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; + float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; + float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; + float roperp = orig[1]*ray[0] - orig[0]*ray[1]; + + float a = q0perp - 2*q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; + + float s0 = 0., s1 = 0.; + int num_s = 0; + + if (a != 0.0) { + float discr = b*b - a*c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float) STBTT_sqrt(discr); + s0 = (b+d) * rcpna; + s1 = (b-d) * rcpna; + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) s0 = s1; + ++num_s; + } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0]*rayn_x + q0[1]*rayn_y; + float q1d = q1[0]*rayn_x + q1[1]*rayn_y; + float q2d = q2[0]*rayn_x + q2[1]*rayn_y; + float rod = orig[0]*rayn_x + orig[1]*rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; + hits[0][1] = a*s0+b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; + hits[1][1] = a*s1+b; + return 2; + } else { + return 1; + } + } +} + +static int equal(float *a, float *b) +{ + return (a[0] == b[0] && a[1] == b[1]); +} + +static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) +{ + int i; + float orig[2], ray[2] = { 1, 0 }; + float y_frac; + int winding = 0; + + orig[0] = x; + orig[1] = y; + + // make sure y never passes through a vertex of the shape + y_frac = (float) STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; + orig[1] = y; + + // test a ray from (-infinity,y) to (x,y) + for (i=0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; + int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; + int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; + int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; + int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); + int by = STBTT_max(y0,STBTT_max(y1,y2)); + if (y > ay && y < by && x > ax) { + float q0[2],q1[2],q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0,q1) || equal(q1,q2)) { + x0 = (int)verts[i-1].x; + y0 = (int)verts[i-1].y; + x1 = (int)verts[i ].x; + y1 = (int)verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } + } + } + } + return winding; +} + +static float stbtt__cuberoot( float x ) +{ + if (x<0) + return -(float) STBTT_pow(-x,1.0f/3.0f); + else + return (float) STBTT_pow( x,1.0f/3.0f); +} + +// x^3 + c*x^2 + b*x + a = 0 +static int stbtt__solve_cubic(float a, float b, float c, float* r) +{ + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; + float p3 = p*p*p; + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); + float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); + + //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? + //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); + //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } +} + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + float scale_x = scale, scale_y = scale; + int ix0,iy0,ix1,iy1; + int w,h; + unsigned char *data; + + if (scale == 0) return NULL; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; + + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; + + w = (ix1 - ix0); + h = (iy1 - iy0); + + if (width ) *width = w; + if (height) *height = h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + // invert for y-downwards bitmaps + scale_y = -scale_y; + + { + int x,y,i,j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *) STBTT_malloc(w * h, info->userdata); + precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); + + for (i=0,j=num_verts-1; i < num_verts; j=i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; + float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); + precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; + float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; + float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float len2 = bx*bx + by*by; + if (len2 != 0.0f) + precompute[i] = 1.0f / (bx*bx + by*by); + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } + + for (y=iy0; y < iy1; ++y) { + for (x=ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float) x + 0.5f; + float sy = (float) y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); + + int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path + + for (i=0; i < num_verts; ++i) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + + // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve + float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + if (verts[i].type == STBTT_vline) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + // coarse culling against bbox + //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) + float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1-x0, dy = y1-y0; + float px = x0-sx, py = y0-sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy + // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px*dx + py*dy) / (dx*dx + dy*dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; + } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; + float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; + float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); + float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); + float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); + float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); + // coarse culling against bbox to avoid computing cubic unnecessarily + if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { + int num=0; + float ax = x1-x0, ay = y1-y0; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3],px,py,t,it; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula + float a = 3*(ax*bx + ay*by); + float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); + float c = mx*ax+my*ay; + if (a == 0.0) { // if a is 0, it's linear + if (b != 0.0) { + res[num++] = -c/b; + } + } else { + float discriminant = b*b - 4*a*c; + if (discriminant < 0) + num = 0; + else { + float root = (float) STBTT_sqrt(discriminant); + res[0] = (-b - root)/(2*a); + res[1] = (-b + root)/(2*a); + num = 2; // don't bother distinguishing 1-solution case, as code below will still work + } + } + } else { + float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point + float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; + float d = (mx*ax+my*ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; + } + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; +} + +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// font name matching -- recommended not to use this +// + +// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{ + stbtt_int32 i=0; + + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0]*256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) return -1; + if (s1[i++] != ch) return -1; + } else if (ch < 0x800) { + if (i+1 >= len1) return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2]*256 + s2[3]; + if (i+3 >= len1) return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; + s2 += 2; // plus another 2 below + len2 -= 2; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i+2 >= len1) return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; + } + s2 += 2; + len2 -= 2; + } + return i; +} + +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +{ + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +} + +// returns results in whatever encoding you request... but note that 2-byte encodings +// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) +{ + stbtt_int32 i,count,stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return NULL; + + count = ttUSHORT(fc+nm+2); + stringOffset = nm + ttUSHORT(fc+nm+4); + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) + && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { + *length = ttUSHORT(fc+loc+8); + return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); + } + } + return NULL; +} + +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) +{ + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc+nm+2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); + + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc+loc+6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc+loc+8); + stbtt_int32 off = ttUSHORT(fc+loc+10); + + // check if there's a prefix match + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & language + if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { + slen = ttUSHORT(fc+loc+12+8); + off = ttUSHORT(fc+loc+12+10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) + return 1; + } + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } + } + + // @TODO handle other encodings + } + } + return 0; +} + +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) +{ + stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); + stbtt_uint32 nm,hd; + if (!stbtt__isfont(fc+offset)) return 0; + + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; + } + + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return 0; + + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } + + return 0; +} + +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) +{ + stbtt_int32 i; + for (i=0;;++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) return off; + if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) + return off; + } +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, + float pixel_height, unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, stbtt_bakedchar *chardata) +{ + return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +} + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) +{ + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +} + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) +{ + return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +} + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) +{ + return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +} + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) +{ + return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +} + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +{ + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif // STB_TRUETYPE_IMPLEMENTATION + + +// FULL VERSION HISTORY +// +// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) allow user-defined fabs() replacement +// fix memory leak if fontsize=0.0 +// fix warning from duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// allow PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) +// also more precise AA rasterizer, except if shapes overlap +// remove need for STBTT_sort +// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC +// 1.04 (2015-04-15) typo in example +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes +// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ +// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// non-oversampled; STBTT_POINT_SIZE for packed case only +// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling +// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) +// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID +// 0.8b (2014-07-07) fix a warning +// 0.8 (2014-05-25) fix a few more warnings +// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back +// 0.6c (2012-07-24) improve documentation +// 0.6b (2012-07-20) fix a few more warnings +// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, +// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty +// 0.5 (2011-12-09) bugfixes: +// subpixel glyph renderer computed wrong bounding box +// first vertex of shape can be off-curve (FreeSans) +// 0.4b (2011-12-03) fixed an error in the font baking example +// 0.4 (2011-12-01) kerning, subpixel rendering (tor) +// bugfixes for: +// codepoint-to-glyph conversion using table fmt=12 +// codepoint-to-glyph conversion using table fmt=4 +// stbtt_GetBakedQuad with non-square texture (Zer) +// updated Hello World! sample to use kerning and subpixel +// fixed some warnings +// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) +// userdata, malloc-from-userdata, non-zero fill (stb) +// 0.2 (2009-03-11) Fix unsigned/signed char warnings +// 0.1 (2009-03-09) First public release +// + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/util/test.txt b/util/test.txt new file mode 100644 index 0000000..c8f122e --- /dev/null +++ b/util/test.txt @@ -0,0 +1,3 @@ +I am a text file, + with Unix line endings, + but no final newline. \ No newline at end of file diff --git a/util/w32/build.bat b/util/w32/build.bat new file mode 100644 index 0000000..542f25c --- /dev/null +++ b/util/w32/build.bat @@ -0,0 +1,16 @@ +@ECHO OFF + +ECHO 101 TEXT bin\embed.dat > bin\embed.rc +rc /nologo bin\embed.rc + +SET CFLAGS=%2 -g -fno-exceptions -Ibin -I. -DARCH_X86_64 -DARCH_X86_COMMON -DARCH_64 -DNO_API_TABLE -DUSE_PLATFORM_HEAP -DUSE_HARFBUZZ -DUSE_FREETYPE -DUSE_STB_SPRINTF -Wall -Wextra -Wno-empty-body -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-unknown-attributes -Wno-c99-designator -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function +SET LINKFLAGS=/DEBUG /NOLOGO /NODEFAULTLIB /IGNORE:4217 /subsystem:windows /OPT:REF /OPT:ICF /STACK:0x100000,0x100000 +SET APPFLAGS=-D_start=_ApplicationStart -DES_FORWARD -DES_EXTERN_FORWARD=ES_EXTERN_C -DES_DIRECT_API + +clang -o bin\header_generator.exe util\header_generator.c %CFLAGS% +bin\header_generator c bin\essence.h + +clang++ -o bin\desktop.o -c desktop\api.cpp -DOS_ESSENCE %CFLAGS% +clang++ -o bin\w32.o -c util\w32\platform.cpp %CFLAGS% +clang++ -o bin\application.o -c %1 %APPFLAGS% %CFLAGS% +link %LINKFLAGS% /OUT:bin\desktop.exe bin\desktop.o bin\w32.o bin\application.o bin\freetype.lib bin\harfbuzz.lib bin\embed.res kernel32.lib user32.lib gdi32.lib dwmapi.lib shell32.lib diff --git a/util/w32/embed.cpp b/util/w32/embed.cpp new file mode 100644 index 0000000..7b3d1a3 --- /dev/null +++ b/util/w32/embed.cpp @@ -0,0 +1,51 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +const char *files[] = { + "res/Fonts/Inter Thin.otf", + "res/Fonts/Inter Thin Italic.otf", + "res/Fonts/Inter Extra Light.otf", + "res/Fonts/Inter Extra Light Italic.otf", + "res/Fonts/Inter Light.otf", + "res/Fonts/Inter Light Italic.otf", + "res/Fonts/Inter Regular.otf", + "res/Fonts/Inter Regular Italic.otf", + "res/Fonts/Inter Medium.otf", + "res/Fonts/Inter Medium Italic.otf", + "res/Fonts/Inter Semi Bold.otf", + "res/Fonts/Inter Semi Bold Italic.otf", + "res/Fonts/Inter Bold.otf", + "res/Fonts/Inter Bold Italic.otf", + "res/Fonts/Inter Extra Bold.otf", + "res/Fonts/Inter Extra Bold Italic.otf", + "res/Fonts/Inter Black.otf", + "res/Fonts/Inter Black Italic.otf", + "res/Fonts/Hack Regular.ttf", + "res/Fonts/Hack Regular Italic.ttf", + "res/Fonts/Hack Bold.ttf", + "res/Fonts/Hack Bold Italic.ttf", + "res/Theme.dat", + "res/Icons/elementary Icons.icon_pack", + nullptr, +}; + +int main() { + FILE *f = fopen("bin/embed.dat", "wb"); + + for (uintptr_t i = 0; files[i]; i++) { + FILE *in = fopen(files[i], "rb"); + fseek(in, 0, SEEK_END); + size_t size = ftell(in); + fseek(in, 0, SEEK_SET); + void *buffer = malloc(size); + fread(buffer, 1, size, in); + fwrite(files[i], 1, strlen(files[i]) + 1, f); + fwrite(&size, 1, 4, f); + fwrite(buffer, 1, size, f); + fclose(in); + free(buffer); + } + + return 0; +} diff --git a/util/w32/platform.cpp b/util/w32/platform.cpp new file mode 100644 index 0000000..a8e7340 --- /dev/null +++ b/util/w32/platform.cpp @@ -0,0 +1,924 @@ +#define ES_API +#define ES_FORWARD(x) x +#define ES_EXTERN_FORWARD extern "C" +#define ES_DIRECT_API +#include <essence.h> + +#define OS_ESSENCE +#include <util/stb_ds.h> + +#define UNICODE +#include <windows.h> +#include <dwmapi.h> +#include <xmmintrin.h> + +struct CompositionAttributeData { + DWORD attribute; + PVOID pData; + ULONG dataSize; +}; + +struct AccentPolicy { + uint32_t state, flags, color, animation; +}; + +//////////////////////////////////////// + +extern "C" int _fltused = 0; +extern "C" void __chkstk() {} +extern "C" void _init() {} + +#pragma function(memset) +extern "C" void *memset(void *s, int c, size_t n) { + uint8_t *s8 = (uint8_t *) s; + for (uintptr_t i = 0; i < n; i++) { + s8[i] = (uint8_t) c; + } + return s; +} + +#pragma function(memcpy) +extern "C" void *memcpy(void *dest, const void *src, size_t n) { + uint8_t *dest8 = (uint8_t *) dest; + const uint8_t *src8 = (const uint8_t *) src; + for (uintptr_t i = 0; i < n; i++) { + dest8[i] = src8[i]; + } + return dest; +} + +#pragma function(strlen) +extern "C" size_t strlen(const char *s) { + size_t n = 0; + while (s[n]) n++; + return n; +} + +#pragma function(memcmp) +extern "C" int memcmp(const void *a, const void *b, size_t bytes) { + if (!bytes) { + return 0; + } + + const uint8_t *x = (const uint8_t *) a; + const uint8_t *y = (const uint8_t *) b; + + for (uintptr_t i = 0; i < bytes; i++) { + if (x[i] < y[i]) { + return -1; + } else if (x[i] > y[i]) { + return 1; + } + } + + return 0; +} + +#pragma function(strcmp) +extern "C" int strcmp(const char *s1, const char *s2) { + while (true) { + if (*s1 != *s2) { + if (*s1 == 0) return -1; + else if (*s2 == 0) return 1; + return *s1 - *s2; + } + + if (*s1 == 0) { + return 0; + } + + s1++; + s2++; + } +} + +#pragma function(memmove) +extern "C" void *memmove(void *dest, const void *src, size_t n) { + if ((uintptr_t) dest < (uintptr_t) src) { + return EsCRTmemcpy(dest, src, n); + } else { + uint8_t *dest8 = (uint8_t *) dest; + const uint8_t *src8 = (const uint8_t *) src; + for (uintptr_t i = n; i; i--) { + dest8[i - 1] = src8[i - 1]; + } + return dest; + } +} + +//////////////////////////////////////// + +HANDLE heap; +size_t heapAllocatedTotal; + +void *PlatformHeapAllocate(size_t size, bool zero) { + heapAllocatedTotal += size; + return HeapAlloc(heap, zero ? HEAP_ZERO_MEMORY : 0, size); +} + +void PlatformHeapFree(void *address) { + heapAllocatedTotal -= HeapSize(heap, 0, address); + HeapFree(heap, 0, address); +} + +void *PlatformHeapReallocate(void *oldAddress, size_t newAllocationSize, bool zeroNewSpace) { + heapAllocatedTotal += newAllocationSize - HeapSize(heap, 0, oldAddress); + return HeapReAlloc(heap, zeroNewSpace ? HEAP_ZERO_MEMORY : 0, oldAddress, newAllocationSize); +} + +wchar_t *ToWide(const char *in, size_t bytes) { + if (!in) return nullptr; + int characters = MultiByteToWideChar(CP_UTF8, 0, in, bytes, NULL, 0); + if (!characters) return nullptr; + wchar_t *out = (wchar_t *) HeapAlloc(heap, 0, characters * 2 + 2); + out[MultiByteToWideChar(CP_UTF8, 0, in, bytes, out, characters)] = 0; + return out; +} + +char *ToUTF8(const wchar_t *in) { + if (!in) return nullptr; + int byteCount = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL); + if (!byteCount) return nullptr; + char *out = (char *) HeapAlloc(heap, 0, byteCount + 1); + out[WideCharToMultiByte(CP_UTF8, 0, in, -1, out, byteCount, NULL, NULL)] = 0; + return out; +} + +//////////////////////////////////////// + +uint64_t EsTimeStamp() { + LARGE_INTEGER result; + QueryPerformanceCounter(&result); + return result.QuadPart; +} + +float EsCRTsqrtf(float x) { + float y[4]; + _mm_storeu_ps(y, _mm_sqrt_ps(_mm_set_ps(0, 0, 0, x))); + return y[0]; +} + +double EsCRTsqrt(double x) { + double y[2]; + _mm_storeu_pd(y, _mm_sqrt_pd(_mm_set_pd(0, x))); + return y[0]; +} + +int _EsCRTsetjmp(EsCRTjmp_buf *env) { + // TODO. + return 0; +} + +void _EsCRTlongjmp(EsCRTjmp_buf *env, int val) { + // TODO. + while (1); +} + +DWORD threadLocalStorageIndex; + +extern "C" uintptr_t ProcessorTLSRead(uintptr_t offset) { + return (uintptr_t) TlsGetValue(threadLocalStorageIndex); +} + +//////////////////////////////////////// + +struct Object { + HANDLE handle; + HWND window; + void (*close)(Object *); + bool isEmbedFile, isMenu; +}; + +struct Timer : Object { + void *data1, *data2; + bool set; + UINT_PTR id; +}; + +struct ConstantBuffer : Object { + void *data; + size_t bytes; +}; + +EsMountPoint initialMountPoint = { + .name = "0:", + .nameBytes = 2, + .base = ES_INVALID_HANDLE, +}; + +_EsMessageWithObject *messageQueue; +HCURSOR cursor, blankCursor; +Timer **allTimers; +bool allowSynchronousMessages; +bool inWindows10; +HWND recentMenu; + +const char *systemConfiguration = R"( +[ui] +theme=0:$res/Theme.dat +icon_pack=0:$res/Icons/elementary Icons.icon_pack +font_fallback=Inter +font_sans=Inter +font_serif=Inter +font_mono=Hack + +[@font Inter] +category=Sans +scripts=Latn,Grek,Cyrl +.1=0:$res/Fonts/Inter Thin.otf +.1i=0:$res/Fonts/Inter Thin Italic.otf +.2=0:$res/Fonts/Inter Extra Light.otf +.2i=0:$res/Fonts/Inter Extra Light Italic.otf +.3=0:$res/Fonts/Inter Light.otf +.3i=0:$res/Fonts/Inter Light Italic.otf +.4=0:$res/Fonts/Inter Regular.otf +.4i=0:$res/Fonts/Inter Regular Italic.otf +.5=0:$res/Fonts/Inter Medium.otf +.5i=0:$res/Fonts/Inter Medium Italic.otf +.6=0:$res/Fonts/Inter Semi Bold.otf +.6i=0:$res/Fonts/Inter Semi Bold Italic.otf +.7=0:$res/Fonts/Inter Bold.otf +.7i=0:$res/Fonts/Inter Bold Italic.otf +.8=0:$res/Fonts/Inter Extra Bold.otf +.8i=0:$res/Fonts/Inter Extra Bold Italic.otf +.9=0:$res/Fonts/Inter Black.otf +.9i=0:$res/Fonts/Inter Black Italic.otf + +[@font Hack] +category=Mono +scripts=Latn,Grek,Cyrl +.4=0:$res/Fonts/Hack Regular.ttf +.4i=0:$res/Fonts/Hack Regular Italic.ttf +.7=0:$res/Fonts/Hack Bold.ttf +.7i=0:$res/Fonts/Hack Bold Italic.ttf +)"; + +//////////////////////////////////////// + +uint8_t *embed; + +uint32_t *EmbedFind(const char *path, size_t pathBytes) { + uint8_t *position = embed; + + while (true) { + uint32_t *size = (uint32_t *) (position + EsCStringLength((char *) position) + 1); + + if (position[0] == 0) { + return nullptr; + } else if (0 == EsMemoryCompare(position, path, pathBytes) && position[pathBytes] == 0) { + return size; + } else { + position = (uint8_t *) size + *size + sizeof(uint32_t); + } + } +} + +//////////////////////////////////////// + +void CALLBACK TimerProcedure(HWND window, UINT message, UINT_PTR id, DWORD time) { + Timer *timer = nullptr; + + for (uintptr_t i = 0; i < arrlenu(allTimers); i++) { + if (allTimers[i]->id == id) { + timer = allTimers[i]; + break; + } + } + + if (!timer) return; + KillTimer(window, id); + if (!timer->set) return; + timer->set = false; + EsMessage m; + m.type = ES_MSG_TIMER; + m._argument = timer->data2; + EsMessagePost((EsElement *) timer->data1, &m); +} + +void UIProcessWindowManagerMessage(EsWindow *window, EsMessage *message, struct ProcessMessageTiming *timing); + +void SendInputMessage(EsElement *element, EsMessage *message, bool now = false) { + if (now && allowSynchronousMessages) { + EsMessageMutexAcquire(); + UIProcessWindowManagerMessage((EsWindow *) element, message, nullptr); + EsMessageMutexRelease(); + } else { + EsMessagePost(element, message); + } +} + +int ConvertVirtualKeyCode(int key) { + switch (key) { + case 0x08: return ES_SCANCODE_BACKSPACE; + case 0x09: return ES_SCANCODE_TAB; + case 0x0D: return ES_SCANCODE_ENTER; + case 0x13: return ES_SCANCODE_PAUSE; + case 0x14: return ES_SCANCODE_CAPS_LOCK; + case 0x1B: return ES_SCANCODE_ESCAPE; + case 0x20: return ES_SCANCODE_SPACE; + case 0x21: return ES_SCANCODE_PAGE_UP; + case 0x22: return ES_SCANCODE_PAGE_DOWN; + case 0x23: return ES_SCANCODE_END; + case 0x24: return ES_SCANCODE_HOME; + case 0x25: return ES_SCANCODE_LEFT_ARROW; + case 0x26: return ES_SCANCODE_UP_ARROW; + case 0x27: return ES_SCANCODE_RIGHT_ARROW; + case 0x28: return ES_SCANCODE_DOWN_ARROW; + case 0x2D: return ES_SCANCODE_INSERT; + case 0x2E: return ES_SCANCODE_DELETE; + case 0x30: return ES_SCANCODE_0; + case 0x31: return ES_SCANCODE_1; + case 0x32: return ES_SCANCODE_2; + case 0x33: return ES_SCANCODE_3; + case 0x34: return ES_SCANCODE_4; + case 0x35: return ES_SCANCODE_5; + case 0x36: return ES_SCANCODE_6; + case 0x37: return ES_SCANCODE_7; + case 0x38: return ES_SCANCODE_8; + case 0x39: return ES_SCANCODE_9; + case 0x41: return ES_SCANCODE_A; + case 0x42: return ES_SCANCODE_B; + case 0x43: return ES_SCANCODE_C; + case 0x44: return ES_SCANCODE_D; + case 0x45: return ES_SCANCODE_E; + case 0x46: return ES_SCANCODE_F; + case 0x47: return ES_SCANCODE_G; + case 0x48: return ES_SCANCODE_H; + case 0x49: return ES_SCANCODE_I; + case 0x4A: return ES_SCANCODE_J; + case 0x4B: return ES_SCANCODE_K; + case 0x4C: return ES_SCANCODE_L; + case 0x4D: return ES_SCANCODE_M; + case 0x4E: return ES_SCANCODE_N; + case 0x4F: return ES_SCANCODE_O; + case 0x50: return ES_SCANCODE_P; + case 0x51: return ES_SCANCODE_Q; + case 0x52: return ES_SCANCODE_R; + case 0x53: return ES_SCANCODE_S; + case 0x54: return ES_SCANCODE_T; + case 0x55: return ES_SCANCODE_U; + case 0x56: return ES_SCANCODE_V; + case 0x57: return ES_SCANCODE_W; + case 0x58: return ES_SCANCODE_X; + case 0x59: return ES_SCANCODE_Y; + case 0x5A: return ES_SCANCODE_Z; + case 0x5B: return ES_SCANCODE_LEFT_FLAG; + case 0x5C: return ES_SCANCODE_LEFT_FLAG; + case 0x5D: return ES_SCANCODE_CONTEXT_MENU; + case 0x5F: return ES_SCANCODE_ACPI_SLEEP; + case 0x70: return ES_SCANCODE_F1; + case 0x71: return ES_SCANCODE_F2; + case 0x72: return ES_SCANCODE_F3; + case 0x73: return ES_SCANCODE_F4; + case 0x74: return ES_SCANCODE_F5; + case 0x75: return ES_SCANCODE_F6; + case 0x76: return ES_SCANCODE_F7; + case 0x77: return ES_SCANCODE_F8; + case 0x78: return ES_SCANCODE_F9; + case 0x79: return ES_SCANCODE_F10; + case 0x7A: return ES_SCANCODE_F11; + case 0x7B: return ES_SCANCODE_F12; + case 0x90: return ES_SCANCODE_NUM_LOCK; + case 0x91: return ES_SCANCODE_SCROLL_LOCK; + case 0xA0: return ES_SCANCODE_LEFT_SHIFT; + case 0xA1: return ES_SCANCODE_RIGHT_SHIFT; + case 0xA2: return ES_SCANCODE_LEFT_CTRL; + case 0xA3: return ES_SCANCODE_RIGHT_CTRL; + case 0xA4: return ES_SCANCODE_LEFT_ALT; + case 0xA5: return ES_SCANCODE_RIGHT_ALT; + case 0xA6: return ES_SCANCODE_WWW_BACK; + case 0xA7: return ES_SCANCODE_WWW_FORWARD; + case 0xA8: return ES_SCANCODE_WWW_REFRESH; + case 0xA9: return ES_SCANCODE_WWW_STOP; + case 0xAA: return ES_SCANCODE_WWW_SEARCH; + case 0xAB: return ES_SCANCODE_WWW_STARRED; + case 0xAC: return ES_SCANCODE_WWW_HOME; + case 0xAD: return ES_SCANCODE_MM_MUTE; + case 0xAE: return ES_SCANCODE_MM_QUIETER; + case 0xAF: return ES_SCANCODE_MM_LOUDER; + case 0xB0: return ES_SCANCODE_MM_NEXT; + case 0xB1: return ES_SCANCODE_MM_PREVIOUS; + case 0xB2: return ES_SCANCODE_MM_STOP; + case 0xB3: return ES_SCANCODE_MM_PAUSE; + case 0xB4: return ES_SCANCODE_MM_EMAIL; + case 0xBA: return ES_SCANCODE_PUNCTUATION_3; + case 0xBB: return ES_SCANCODE_EQUALS; + case 0xBC: return ES_SCANCODE_COMMA; + case 0xBD: return ES_SCANCODE_HYPHEN; + case 0xBE: return ES_SCANCODE_PERIOD; + case 0xBF: return ES_SCANCODE_SLASH; + case 0xC0: return ES_SCANCODE_PUNCTUATION_5; + case 0xDB: return ES_SCANCODE_LEFT_BRACE; + case 0xDC: return ES_SCANCODE_PUNCTUATION_1; + case 0xDD: return ES_SCANCODE_RIGHT_BRACE; + case 0xDE: return ES_SCANCODE_PUNCTUATION_4; + default: return 0; + } +} + +LRESULT CALLBACK WindowProcedure(HWND window, UINT message, WPARAM wParam, LPARAM lParam) { + EsElement *element = (EsElement *) GetWindowLongPtr(window, GWLP_USERDATA); + + if (!element) { + return DefWindowProc(window, message, wParam, lParam); + } + + if (message == WM_CLOSE) { + // TODO. + ExitProcess(0); + } else if (message == WM_MOVE) { + if (~GetWindowLongPtr(window, GWL_EXSTYLE) & WS_EX_NOACTIVATE) { + EsMessageMutexAcquire(); + if (recentMenu) ShowWindow(recentMenu, SW_HIDE); + EsMenuCloseAll(); + EsMessageMutexRelease(); + } + } else if (message == WM_SIZE) { + EsMessage m = {}; + m.type = ES_MSG_WINDOW_RESIZED; + RECT client; + GetClientRect(window, &client); + m.windowResized.content = ES_MAKE_RECTANGLE(0, client.right, 0, client.bottom); + SendInputMessage(element, &m, true); + } else if (message == WM_MOUSEMOVE) { + POINT point, screen; + static POINT old; + GetCursorPos(&point); + screen = point; + ScreenToClient(window, &point); + EsMessage m = {}; + m.type = ES_MSG_MOUSE_MOVED; + m.mouseMoved.newPositionX = point.x; + m.mouseMoved.newPositionY = point.y; + m.mouseMoved.newPositionXScreen = screen.x; + m.mouseMoved.newPositionYScreen = screen.y; + m.mouseMoved.oldPositionX = old.x; + m.mouseMoved.oldPositionY = old.y; + old = point; + SendInputMessage(element, &m); + } else if (message == WM_KILLFOCUS) { + EsMessageMutexAcquire(); + EsMenuCloseAll(); + EsMessageMutexRelease(); + EsMessage m; + m.type = ES_MSG_WINDOW_DEACTIVATED; + SendInputMessage(element, &m); + } else if (message == WM_SETFOCUS) { + EsMessage m; + m.type = ES_MSG_WINDOW_ACTIVATED; + SendInputMessage(element, &m); + } else if (message == WM_KEYDOWN || message == WM_KEYUP || message == WM_SYSKEYDOWN || message == WM_SYSKEYUP) { + EsMessage m = {}; + m.type = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) ? ES_MSG_KEY_DOWN : ES_MSG_KEY_UP; + m.keyboard.scancode = ConvertVirtualKeyCode(wParam); + if (message == WM_KEYDOWN && (lParam & (1 << 30))) m.keyboard.repeat = true; + m.keyboard.alt = (GetKeyState(VK_MENU) & 0x8000) ? true : false; + m.keyboard.shift = (GetKeyState(VK_SHIFT) & 0x8000) ? true : false; + m.keyboard.ctrl = (GetKeyState(VK_CONTROL) & 0x8000) ? true : false; + if (m.keyboard.scancode == ES_SCANCODE_F4 && m.keyboard.alt) SendMessage(window, WM_CLOSE, 0, 0); + // TODO Numpad, VK_PACKET, IME. + if (m.keyboard.scancode) SendInputMessage(element, &m); + } else if (message == WM_LBUTTONDOWN || message == WM_LBUTTONUP || message == WM_RBUTTONDOWN + || message == WM_RBUTTONUP || message == WM_MBUTTONDOWN || message == WM_MBUTTONUP) { + // TODO clickChainCount. + + if (~GetWindowLongPtr(window, GWL_EXSTYLE) & WS_EX_NOACTIVATE) { + EsMessageMutexAcquire(); + EsMenuCloseAll(); + EsMessageMutexRelease(); + } + + if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) { + SetCapture(window); + } else { + ReleaseCapture(); + } + + EsMessage m = {}; + if (message == WM_LBUTTONDOWN) m.type = ES_MSG_MOUSE_LEFT_DOWN; + if (message == WM_LBUTTONUP) m.type = ES_MSG_MOUSE_LEFT_UP; + if (message == WM_RBUTTONDOWN) m.type = ES_MSG_MOUSE_RIGHT_DOWN; + if (message == WM_RBUTTONUP) m.type = ES_MSG_MOUSE_RIGHT_UP; + if (message == WM_MBUTTONDOWN) m.type = ES_MSG_MOUSE_MIDDLE_DOWN; + if (message == WM_MBUTTONUP) m.type = ES_MSG_MOUSE_MIDDLE_UP; + POINT point, screen; + GetCursorPos(&point); + screen = point; + ScreenToClient(window, &point); + m.mouseDown.clickChainCount = 1; + m.mouseDown.positionX = point.x; + m.mouseDown.positionY = point.y; + m.mouseDown.positionXScreen = screen.x; + m.mouseDown.positionYScreen = screen.y; + m.mouseDown.alt = (GetKeyState(VK_MENU) & 0x8000) ? true : false; + m.mouseDown.shift = (GetKeyState(VK_SHIFT) & 0x8000) ? true : false; + m.mouseDown.ctrl = (GetKeyState(VK_CONTROL) & 0x8000) ? true : false; + SendInputMessage(element, &m); + } else if (message == WM_NCDESTROY) { + EsMessage m; + m.type = ES_MSG_WINDOW_DESTROYED; + SendInputMessage(element, &m); + } else if (message == WM_MOUSEACTIVATE && (GetWindowLongPtr(window, GWL_EXSTYLE) & WS_EX_NOACTIVATE)) { + return MA_NOACTIVATE; + } else if (message == WM_SETCURSOR && LOWORD(lParam) == HTCLIENT) { + SetCursor(cursor); + return TRUE; + } else { + return DefWindowProc(window, message, wParam, lParam); + } + + return 0; +} + +//////////////////////////////////////// + +static DWORD CALLBACK ThreadEntry(void *parameter) { + uintptr_t *_arguments = (uintptr_t *) parameter; + uintptr_t arguments[4]; + EsMemoryCopy(arguments, _arguments, sizeof(arguments)); + EsHeapFree(_arguments); + ((void (*)(uintptr_t, uintptr_t)) arguments[0])(arguments[3], arguments[1]); + return 0; +} + +uintptr_t _APISyscall(uintptr_t type, uintptr_t argument0, uintptr_t argument1, uintptr_t unused, uintptr_t argument2, uintptr_t argument3) { + if (type == ES_SYSCALL_PRINT) { + char buffer[256]; + buffer[EsStringFormat(buffer, sizeof(buffer) - 1, "%s", argument1, argument0)] = 0; + OutputDebugStringA(buffer); + } else if (type == ES_SYSCALL_CREATE_EVENT) { + Object *object = (Object *) HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(Object)); + object->handle = CreateEvent(NULL, !argument0, FALSE, NULL); + return (uintptr_t) object; + } else if (type == ES_SYSCALL_GET_SYSTEM_CONSTANTS) { + uint64_t *systemConstants = (uint64_t *) argument0; + LARGE_INTEGER performanceFrequency; + QueryPerformanceFrequency(&performanceFrequency); + systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] = performanceFrequency.QuadPart / 1000000; + systemConstants[ES_SYSTEM_CONSTANT_UI_SCALE] = 100; // TODO Proper scaling support. + } else if (type == ES_SYSCALL_ALLOCATE) { + // TODO Protection. + return (uintptr_t) VirtualAlloc(NULL, argument0, MEM_RESERVE | ((argument1 & ES_MEMORY_RESERVE_COMMIT_ALL) ? MEM_COMMIT : 0), PAGE_READWRITE); + } else if (type == ES_SYSCALL_FREE) { + VirtualFree((void *) argument0, 0, MEM_RELEASE); + } else if (type == ES_SYSCALL_SYSTEM_CONFIGURATION_READ) { + ConstantBuffer *object = (ConstantBuffer *) HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(ConstantBuffer)); + object->bytes = *(size_t *) argument2 = EsCRTstrlen(systemConfiguration); + object->data = (void *) systemConfiguration; + object->close = [] (Object *) {}; + return (uintptr_t) object; + } else if (type == ES_SYSCALL_READ_CONSTANT_BUFFER) { + ConstantBuffer *buffer = (ConstantBuffer *) argument0; + if (!argument1) return buffer->bytes; + EsMemoryCopy((void *) argument1, buffer->data, buffer->bytes); + } else if (type == ES_SYSCALL_CLOSE_HANDLE) { + Object *object = (Object *) argument0; + if (!object->close) CloseHandle(object->handle); + HeapFree(heap, 0, object); + } else if (type == ES_SYSCALL_TIMER_CREATE) { + Timer *object = (Timer *) HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(Timer)); + arrput(allTimers, object); + return (uintptr_t) object; + } else if (type == ES_SYSCALL_TIMER_SET) { + Timer *timer = (Timer *) argument0; + timer->data1 = (void *) argument2; + timer->data2 = (void *) argument3; + timer->set = true; + timer->id = SetTimer(NULL, 0, argument1, TimerProcedure); + } else if (type == ES_SYSCALL_OPEN_NODE) { + // TODO Error handling and opening other node types. + + const char *path = (const char *) argument0; + size_t pathLength = (size_t) argument1; + uint64_t flags = (uint64_t) argument2; + _EsNodeInformation *information = (_EsNodeInformation *) argument3; + Object *object = (Object *) HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(Object)); + information->handle = (EsHandle) object; + information->type = ES_NODE_FILE; + + if (path[0] == '$') { + uint32_t *data = EmbedFind(path + 1, pathLength - 1); + object->handle = (HANDLE) (data + 1); + object->isEmbedFile = true; + object->close = [] (Object *) {}; + information->fileSize = *data; + } else { + wchar_t *pathWide = ToWide(path, pathLength); + object->handle = CreateFileW(pathWide, + GENERIC_READ | ((flags & (ES_FILE_WRITE | ES_FILE_WRITE_EXCLUSIVE)) ? GENERIC_WRITE : 0), + (flags & (ES_FILE_WRITE | ES_FILE_READ_SHARED)) ? (FILE_SHARE_READ | FILE_SHARE_READ) + : (flags & ES_FILE_READ) ? FILE_SHARE_READ : 0, NULL, + (flags & ES_NODE_FAIL_IF_FOUND) ? CREATE_NEW : (flags & ES_NODE_FAIL_IF_NOT_FOUND) ? OPEN_EXISTING : CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + HeapFree(heap, 0, pathWide); + DWORD fileSizeHigh; + DWORD fileSizeLow = GetFileSize(object->handle, &fileSizeHigh); + information->fileSize = (uint64_t) fileSizeLow | ((uint64_t) fileSizeHigh << 32); + } + } else if (type == ES_SYSCALL_MAP_OBJECT) { + // TODO Protection. + // TODO Mapping handle is leaked. + if (!argument0) return 0; + Object *object = (Object *) argument0; + + if (object->isEmbedFile) { + return (uintptr_t) object->handle; + } else { + HANDLE mapping = CreateFileMapping(object->handle, NULL, PAGE_READONLY, 0, 0, NULL); + return (uintptr_t) MapViewOfFile(mapping, FILE_MAP_READ, (DWORD) (argument1 >> 32), (DWORD) argument1, argument2); + } + } else if (type == ES_SYSCALL_OPEN_SHARED_MEMORY) { + // TODO. + return 0; + } else if (type == ES_SYSCALL_GET_THREAD_ID) { + // TODO Other threads and processes. + return GetCurrentThreadId(); + } else if (type == ES_SYSCALL_SET_TLS) { + TlsSetValue(threadLocalStorageIndex, (void *) argument0); + } else if (type == ES_SYSCALL_GET_MESSAGE) { + allowSynchronousMessages = true; + + while (true) { + MSG message; + + if (!PeekMessage(&message, NULL, 0, 0, TRUE)) { + break; + } + + TranslateMessage(&message); + DispatchMessage(&message); + } + + allowSynchronousMessages = false; + + if (!arrlen(messageQueue)) { + return ES_ERROR_NO_MESSAGES_AVAILABLE; + } + + *(_EsMessageWithObject *) argument0 = messageQueue[0]; + arrdel(messageQueue, 0); + } else if (type == ES_SYSCALL_WAIT_MESSAGE) { + // TODO Timeout. + + allowSynchronousMessages = true; + + if (!arrlen(messageQueue)) { + MSG message; + GetMessage(&message, NULL, 0, 0); + TranslateMessage(&message); + DispatchMessage(&message); + } + + allowSynchronousMessages = false; + } else if (type == ES_SYSCALL_WINDOW_CREATE) { + // TODO Other window types. + + Object *object = (Object *) HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(Object)); + + if (argument0 == ES_WINDOW_MENU) { + DWORD exStyle = WS_EX_TOPMOST | WS_EX_NOACTIVATE; + object->window = CreateWindowEx(exStyle, L"host", 0, WS_POPUP, + 0, 0, 0, 0, NULL, NULL, NULL, NULL); + MARGINS margins = { -1 }; + DwmExtendFrameIntoClientArea(object->window, &margins); + object->isMenu = true; + recentMenu = object->window; + } else { + object->window = CreateWindow(L"host", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, NULL, NULL); + } + + SetWindowLongPtr(object->window, GWLP_USERDATA, argument2); + return (uintptr_t) object; + } else if (type == ES_SYSCALL_POST_MESSAGE) { + _EsMessageWithObject message; + message.object = (void *) argument1; + message.message = *(EsMessage *) argument0; + arrput(messageQueue, message); + } else if (type == ES_SYSCALL_WINDOW_SET_OBJECT) { + Object *object = (Object *) argument0; + SetWindowLongPtr(object->window, GWLP_USERDATA, argument2); + RECT client; + GetClientRect(object->window, &client); + EsMessage message = {}; + message.type = ES_MSG_WINDOW_RESIZED; + message.windowResized.content = ES_MAKE_RECTANGLE(0, client.right, 0, client.bottom); + EsMessagePost((EsElement *) argument2, &message); + } else if (type == ES_SYSCALL_WINDOW_SET_RESIZE_CLEAR_COLOR) { + } else if (type == ES_SYSCALL_EMBED_WINDOW_SEND_MESSAGE) { + Object *object = (Object *) argument2; + const uint8_t *buffer = (const uint8_t *) argument0; + size_t bytes = (size_t) argument1; + + if (buffer[0] == 1 /* EMBED_WINDOW_MESSAGE_SET_TITLE */) { + wchar_t *title = ToWide((const char *) buffer + 1, bytes - 1); + SetWindowTextW(object->window, title); + HeapFree(heap, 0, title); + } + } else if (type == ES_SYSCALL_GET_CURSOR_POSITION) { + POINT point = {}; + GetCursorPos(&point); + EsPoint *result = (EsPoint *) argument0; + result->x = point.x; + result->y = point.y; + } else if (type == ES_SYSCALL_WINDOW_GET_BOUNDS) { + Object *object = (Object *) argument0; + EsRectangle *result = (EsRectangle *) argument1; + RECT bounds; + GetClientRect(object->window, &bounds); + MapWindowPoints(object->window, NULL, (POINT *) &bounds, 2); + result->l = bounds.left; + result->r = bounds.right; + result->t = bounds.top; + result->b = bounds.bottom; + } else if (type == ES_SYSCALL_WINDOW_SET_CURSOR) { + if (cursor && cursor != blankCursor) { + DestroyCursor(cursor); + } + + switch ((EsCursorStyle) (argument3 >> 24)) { + case ES_CURSOR_NORMAL : cursor = LoadCursor(NULL, IDC_ARROW); break; + case ES_CURSOR_TEXT : cursor = LoadCursor(NULL, IDC_IBEAM); break; + case ES_CURSOR_RESIZE_VERTICAL : cursor = LoadCursor(NULL, IDC_SIZENS); break; + case ES_CURSOR_RESIZE_HORIZONTAL: cursor = LoadCursor(NULL, IDC_SIZEWE); break; + case ES_CURSOR_RESIZE_DIAGONAL_1: cursor = LoadCursor(NULL, IDC_SIZENESW); break; + case ES_CURSOR_RESIZE_DIAGONAL_2: cursor = LoadCursor(NULL, IDC_SIZENWSE); break; + case ES_CURSOR_SPLIT_VERTICAL : cursor = LoadCursor(NULL, IDC_SIZEWE); break; + case ES_CURSOR_SPLIT_HORIZONTAL : cursor = LoadCursor(NULL, IDC_SIZENS); break; + case ES_CURSOR_HAND_HOVER : cursor = LoadCursor(NULL, IDC_HAND); break; + case ES_CURSOR_HAND_DRAG : cursor = LoadCursor(NULL, IDC_HAND); break; + case ES_CURSOR_HAND_POINT : cursor = LoadCursor(NULL, IDC_HAND); break; + case ES_CURSOR_SCROLL_UP_LEFT : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SCROLL_UP : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SCROLL_UP_RIGHT : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SCROLL_LEFT : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SCROLL_CENTER : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SCROLL_RIGHT : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SCROLL_DOWN_LEFT : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SCROLL_DOWN : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SCROLL_DOWN_RIGHT: cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_SELECT_LINES : cursor = LoadCursor(NULL, IDC_ARROW); break; + case ES_CURSOR_DROP_TEXT : cursor = LoadCursor(NULL, IDC_ARROW); break; + case ES_CURSOR_CROSS_HAIR_PICK : cursor = LoadCursor(NULL, IDC_CROSS); break; + case ES_CURSOR_CROSS_HAIR_RESIZE: cursor = LoadCursor(NULL, IDC_CROSS); break; + case ES_CURSOR_MOVE_HOVER : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_MOVE_DRAG : cursor = LoadCursor(NULL, IDC_SIZEALL); break; + case ES_CURSOR_ROTATE_HOVER : cursor = LoadCursor(NULL, IDC_ARROW); break; + case ES_CURSOR_ROTATE_DRAG : cursor = LoadCursor(NULL, IDC_ARROW); break; + case ES_CURSOR_BLANK : cursor = blankCursor; break; + default : cursor = NULL; break; + } + + SetCursor(cursor); + } else if (type == ES_SYSCALL_WINDOW_SET_BITS) { + Object *object = (Object *) argument0; + EsRectangle *region = (EsRectangle *) argument1; + HDC dc = GetDC(object->window); + BITMAPINFO information = {}; + information.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + information.bmiHeader.biWidth = region->r - region->l; + information.bmiHeader.biHeight = region->t - region->b; + information.bmiHeader.biPlanes = 1; + information.bmiHeader.biBitCount = 32; + + uint32_t *bits = (uint32_t *) argument2; + + if (object->isMenu) { + for (intptr_t i = 0; i < (region->r - region->l) * (region->b - region->t); i++) { + // Pre-multiply alpha. + uint32_t alpha = bits[i] >> 24; + uint32_t c0 = bits[i] >> 16, c1 = bits[i] >> 8, c2 = bits[i] >> 0; + c0 = (c0 & 0xFF) * alpha / 255, c1 = (c1 & 0xFF) * alpha / 255, c2 = (c2 & 0xFF) * alpha / 255; + bits[i] = (alpha << 24) | (c0 << 16) | (c1 << 8) | c2; + } + } + + StretchDIBits(dc, region->l, region->t, region->r - region->l, region->b - region->t, + 0, 0, region->r - region->l, region->b - region->t, + bits, &information, DIB_RGB_COLORS, SRCCOPY); + ReleaseDC(object->window, dc); + } else if (type == ES_SYSCALL_FORCE_SCREEN_UPDATE) { + } else if (type == ES_SYSCALL_WINDOW_SET_BLUR_BOUNDS) { + Object *object = (Object *) argument0; + EsRectangle *region = (EsRectangle *) argument1; + + if (inWindows10) { + auto setAttribute = (void (*)(HWND, void *)) GetProcAddress(LoadLibrary(L"user32.dll"), "SetWindowCompositionAttribute"); + AccentPolicy policy = { 3 }; + CompositionAttributeData data = { 19, &policy, sizeof(policy) }; + setAttribute(object->window, &data); + // TODO Only blur the specified region. + } else { + DWM_BLURBEHIND blur; + blur.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + blur.fEnable = TRUE; + blur.hRgnBlur = CreateRectRgn(region->l, region->t, region->r, region->b); + DwmEnableBlurBehindWindow(object->window, &blur); + DeleteObject(blur.hRgnBlur); + } + } else if (type == ES_SYSCALL_WINDOW_SET_OPAQUE_BOUNDS) { + // TODO. + } else if (type == ES_SYSCALL_WINDOW_SET_SOLID) { + // TODO. + } else if (type == ES_SYSCALL_WINDOW_CLOSE) { + Object *object = (Object *) argument0; + if (object->window == recentMenu) recentMenu = NULL; + DestroyWindow(object->window); + } else if (type == ES_SYSCALL_WINDOW_MOVE) { + Object *object = (Object *) argument0; + EsRectangle *region = (EsRectangle *) argument1; + + if (argument3 & ES_MOVE_WINDOW_HIDDEN) { + ShowWindow(object->window, SW_HIDE); + } else { + MoveWindow(object->window, region->l, region->t, region->r - region->l, region->b - region->t, FALSE); + ShowWindow(object->window, SW_SHOWNOACTIVATE); + } + } else if (type == ES_SYSCALL_CLIPBOARD_HAS) { + return false; // TODO. + } else if (type == ES_SYSCALL_CREATE_THREAD) { + EsThreadInformation *thread = (EsThreadInformation *) argument2; + EsMemoryZero(thread, sizeof(EsThreadInformation)); + + Object *object = (Object *) HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(Object)); + uintptr_t *arguments = (uintptr_t *) EsHeapAllocate(sizeof(uintptr_t) * 4, true); + arguments[0] = argument0; + arguments[1] = argument1; + arguments[2] = argument2; + arguments[3] = argument3; + object->handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadEntry, arguments, 0, (LPDWORD) &thread->tid); + thread->handle = (EsHandle) object; + } else if (type == ES_SYSCALL_TERMINATE_THREAD) { + if (argument0 == ES_CURRENT_THREAD) { + TerminateThread(GetCurrentThread(), 0); + } else { + Object *object = (Object *) argument0; + TerminateThread(object->handle, 0); + } + } else if (type == ES_SYSCALL_WAIT) { + Object **handles = (Object **) argument0; + size_t handleCount = argument1; + int timeout = argument2; + HANDLE handles2[ES_MAX_WAIT_COUNT]; + + for (uintptr_t i = 0; i < handleCount; i++) { + handles2[i] = handles[i]->handle; + } + + int result = WaitForMultipleObjects(handleCount, handles2, FALSE, timeout == ES_WAIT_NO_TIMEOUT ? INFINITE : timeout); + return result == WAIT_TIMEOUT ? ES_ERROR_TIMEOUT_REACHED : result; + } else if (type == ES_SYSCALL_SET_CURSOR_POSITION) { + SetCursorPos(argument0, argument1); + } else if (type == ES_SYSCALL_GET_CREATION_ARGUMENT) { + if (argument1 == CREATION_ARGUMENT_INITIAL_MOUNT_POINTS) { + ConstantBuffer *object = (ConstantBuffer *) HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(ConstantBuffer)); + object->bytes = sizeof(EsMountPoint); + object->data = (void *) &initialMountPoint; + object->close = [] (Object *) {}; + return (uintptr_t) object; + } else { + return 0; + } + } else if (type == ES_SYSCALL_MEMORY_FAULT_RANGE) { + } else if (type == ES_SYSCALL_WINDOW_SET_MATERIAL) { + } else { + MessageBox(NULL, L"Unimplemented system call.", L"Error", MB_OK); + ExitProcess(1); + } + + return ES_SUCCESS; +} + +//////////////////////////////////////// + +extern "C" void _ApplicationStart(); +extern "C" void _start(EsProcessStartupInformation *startupInformation); + +void WinMainCRTStartup() { + heap = GetProcessHeap(); + threadLocalStorageIndex = TlsAlloc(); + + embed = (uint8_t *) LockResource(LoadResource(nullptr, FindResource(nullptr, MAKEINTRESOURCEW(101), L"TEXT"))); + + uint8_t bitmask1 = 0xFF, bitmask2 = 0; + blankCursor = CreateCursor(nullptr, 0, 0, 1, 1, &bitmask1, &bitmask2); + + OSVERSIONINFOEXW version = { sizeof(version) }; + ((LONG (*)(PRTL_OSVERSIONINFOEXW)) GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion"))(&version); + inWindows10 = version.dwMajorVersion >= 10; + + WNDCLASSW windowClass = {}; + windowClass.lpfnWndProc = WindowProcedure; + windowClass.lpszClassName = L"host"; + RegisterClassW(&windowClass); + + EsMessage m = {}; + m.type = ES_MSG_INSTANCE_CREATE; + m.createInstance.window = EsSyscall(ES_SYSCALL_WINDOW_CREATE, ES_WINDOW_NORMAL, 0, 0, 0); + EsMessagePost(nullptr, &m); + + EsProcessStartupInformation startupInformation = {}; + startupInformation.applicationStartAddress = (uintptr_t) _ApplicationStart; + _start(&startupInformation); +}